Elasticsearch 滞后8个小时等时区问题,一网打尽!
1、实战问题
如下都是实战环节遇到的问题:
logstash谁解决过时区问题,mysql是东八区shanghai 但是这玩意读完存到es就少了8小时?
目前索引会比真正时间晚8小时,导致8点前的日志写到昨天索引里,大佬们有招吗?
问一下 logstash输出日志到本地文件中,按照小时生成索引,但是他这边的时区是utc,生成的时间和北京时间少8小时,这一块大佬们是咋操作的?
......从浏览器kibana那里看timestamp时间戳变成了utc的时区?
上面的问题都涉及到时区问题,涉及到数据的同步(logstash)、写入、检索(elasticsearch)、可视化(kibana)的几个环节。
2、时区问题拆解
2.1 Elasticserch 默认时区是?能改吗?
官方文档强调:在 Elasticsearch 内部,日期被转换为 UTC时区并存储为一个表示自1970-01-01 00:00:00 以来经过的毫秒数的值。
Internally, dates are converted to UTC (if the time-zone is specified) and stored as a long number representing milliseconds-since-the-epoch.
https://www.elastic.co/guide/en/elasticsearch/reference/current/date.html
Elasticsearch date 类型默认时区:UTC。
正如官方工程师强调(如下截图所示):Elasticsearch 默认时区不可以修改。
ingest pipeline 预处理方式写入的时候修改时区; logstash filter 环节做时区转换; 查询时指定时区; 聚合时指定时区。
2.2 Kibana 默认时区是?能改吗?
2.3 Logstash 默认时区是?能改吗?
logstash 默认 UTC 时区。 Elasticsearch 默认 UTC 时区。 Kibana 默认浏览器时区,基本我们用就是:东八区。 如果基于Mysql 同步数据,Mysql 数据是:东八区。
3、时区问题解决方案
3.1 方案一:ingest 预处理为东8区时区
步骤 1:定义预处理管道:chage_utc_to_asiash(名称自己定义即可)。
步骤 2:创建索引同时指定缺省管道:chage_utc_to_asiash。 步骤 3:写入数据(单条或 bulk 批量均可)
PUT _ingest/pipeline/chage_utc_to_asiash
{
"processors": [
{
"date" : {
"field" : "my_time",
"target_field": "my_time",
"formats" : ["yyyy-MM-dd HH:mm:ss"],
"timezone" : "Asia/Shanghai"
}
}
]
}
PUT my-index-000001
{
"settings": {
"default_pipeline": "chage_utc_to_asiash"
},
"mappings": {
"properties": {
"my_time": {
"type": "date"
}
}
}
}
PUT my-index-000001/_doc/1
{
"my_time": "2021-08-09 08:07:16"
}
"hits" : [
{
"_index" : "my-index-000001",
"_type" : "_doc",
"_id" : "1",
"_score" : 1.0,
"_source" : {
"my_time" : "2021-08-09T08:07:16.000+08:00"
}
}
]
3.2 方案二:logstash 中间 filter 环节处理
数据源端:Mysql; 数据目的端:Elasticsearch; 同步方式:logstash,本质借助:logstash_input_jdbc 插件同步; 时区处理:logstash filter 环节 ruby 脚本处理。
filter {
ruby {
code => "event.set('timestamp', event.get('publish_time').time.localtime + 8*60*60)"
}
ruby {
code => "event.set('publish_time',event.get('timestamp'))"
}
mutate {
remove_field => ["timestamp"]
}
}
第一行:将 publish_time 时间加 8 小时处理,赋值给 timestamp。
第二行:将 timestamp 时间赋值给 publish_time。 第三行:删除中转字段:timestamp。
源数据Mysql 效果:
publish_time 做了时区处理,两者时间已一致,都是东 8 区。 update_time 未做时间处理,写入Elasticsearch 后由东8区时间 10:57:31 转为UTC时区时间 02:57:31,少了8小时。
4、检索和聚合的时候指定时区
假定我们写入ES前未做时区处理(实战环节常有的场景),但是检索或者聚合的时候想做时区处理可以吗?
可以的,具体实现方式如下:
POST testindex/_search?pretty
{
"query": {
"range": {
"date": {
"gte": "2020-01-01 00:00:00",
"lte": "2020-01-03 23:59:59",
"format": "yyyy-MM-dd HH:mm:ss",
"time_zone": "+08:00"
}
}
},
"size": 0,
"aggs": {
"per_day": {
"date_histogram": {
"calendar_interval": "day",
"field": "date",
"time_zone": "+08:00"
}
}
}
}
要点1:range query 中指定时区检索。 要点2:data_histogram 聚合中指定时区聚合。
5、小结
参考
https://t.zsxq.com/2nYnq76