1、實(shí)戰(zhàn)問題
如下都是實(shí)戰(zhàn)環(huán)節(jié)遇到的問題:
logstash誰解決過時(shí)區(qū)問題,mysql是東八區(qū)shanghai 但是這玩意讀完存到es就少了8小時(shí)?
目前索引會(huì)比真正時(shí)間晚8小時(shí),導(dǎo)致8點(diǎn)前的日志寫到昨天索引里,大佬們有招嗎?
問一下 logstash輸出日志到本地文件中,按照小時(shí)生成索引,但是他這邊的時(shí)區(qū)是utc,生成的時(shí)間和北京時(shí)間少8小時(shí),這一塊大佬們是咋操作的?
......從瀏覽器kibana那里看timestamp時(shí)間戳變成了utc的時(shí)區(qū)?
上面的問題都涉及到時(shí)區(qū)問題,涉及到數(shù)據(jù)的同步(logstash)、寫入、檢索(elasticsearch)、可視化(kibana)的幾個(gè)環(huán)節(jié)。
2、時(shí)區(qū)問題拆解
2.1 Elasticserch 默認(rèn)時(shí)區(qū)是?能改嗎?
官方文檔強(qiáng)調(diào):在 Elasticsearch 內(nèi)部,日期被轉(zhuǎn)換為 UTC時(shí)區(qū)并存儲(chǔ)為一個(gè)表示自1970-01-01 00:00:00 以來經(jīng)過的毫秒數(shù)的值。
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 類型默認(rèn)時(shí)區(qū):UTC。
正如官方工程師強(qiáng)調(diào)(如下截圖所示):Elasticsearch 默認(rèn)時(shí)區(qū)不可以修改。
https://discuss.elastic.co/t/index-creates-in-different-timezone-other-than-utc/148941- ingest pipeline 預(yù)處理方式寫入的時(shí)候修改時(shí)區(qū);
- logstash filter 環(huán)節(jié)做時(shí)區(qū)轉(zhuǎn)換;
2.2 Kibana 默認(rèn)時(shí)區(qū)是?能改嗎?
kibana 默認(rèn)時(shí)區(qū)是瀏覽器時(shí)區(qū)??梢孕薷模薷姆绞饺缦拢?/span>Stack Management -> Advanced Settings ->Timezone for data formatting.2.3 Logstash 默認(rèn)時(shí)區(qū)是?能改嗎?
可以通過中間:filter 環(huán)節(jié)進(jìn)行日期數(shù)據(jù)處理,包括:轉(zhuǎn)時(shí)區(qū)操作。- logstash 默認(rèn) UTC 時(shí)區(qū)。
- Elasticsearch 默認(rèn) UTC 時(shí)區(qū)。
- Kibana 默認(rèn)瀏覽器時(shí)區(qū),基本我們用就是:東八區(qū)。
- 如果基于Mysql 同步數(shù)據(jù),Mysql 數(shù)據(jù)是:東八區(qū)。
我們看一下東8區(qū)百度百科定義:東八區(qū)(UTC/GMT+08:00)是比世界協(xié)調(diào)時(shí)間(UTC)/格林尼治時(shí)間(GMT)快8小時(shí)的時(shí)區(qū),理論上的位置是位于東經(jīng)112.5度至127.5度之間,是東盟標(biāo)準(zhǔn)的其中一個(gè)候選時(shí)區(qū)。當(dāng)格林尼治標(biāo)準(zhǔn)時(shí)間為0:00時(shí),東八區(qū)的標(biāo)準(zhǔn)時(shí)間為08:00。通過上面的定義,能加深對(duì) logstash 同步數(shù)據(jù)后,數(shù)據(jù)滯后8小時(shí)的理解。3、時(shí)區(qū)問題解決方案
基于上面的分析,如何解決時(shí)區(qū)問題呢?由于 kibana 支持手動(dòng)修改時(shí)區(qū),不在下文討論 的范圍之內(nèi)。實(shí)戰(zhàn)項(xiàng)目中,自己根據(jù)業(yè)務(wù)需求修改即可。那么問題就轉(zhuǎn)嫁為:寫入的時(shí)候轉(zhuǎn)換成給定時(shí)區(qū)(如:東8區(qū))就可以了。3.1 方案一:ingest 預(yù)處理為東8區(qū)時(shí)區(qū)
- 步驟 1:定義預(yù)處理管道:chage_utc_to_asiash(名稱自己定義即可)。
在該管道中實(shí)現(xiàn)了時(shí)區(qū)轉(zhuǎn)換。- 步驟 2:創(chuàng)建索引同時(shí)指定缺省管道:chage_utc_to_asiash。
- 步驟 3:寫入數(shù)據(jù)(單條或 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"
}
當(dāng)寫入數(shù)據(jù)后,執(zhí)行檢索時(shí),kibana dev tool 返回結(jié)果如下: "hits" : [
{
"_index" : "my-index-000001",
"_type" : "_doc",
"_id" : "1",
"_score" : 1.0,
"_source" : {
"my_time" : "2021-08-09T08:07:16.000+08:00"
}
}
]
最明顯的特征是:多了+08:00 時(shí)區(qū)(東8區(qū))標(biāo)志。然后,我們用:kibana discover可視化展示一下:上圖中,kibana 采用默認(rèn)瀏覽器時(shí)區(qū)。如果不做上面的 ingest 預(yù)處理實(shí)現(xiàn),會(huì)怎么樣呢?大家如果實(shí)現(xiàn)過,肯定會(huì)感觸很深。需要我們?cè)趉ibana中切換時(shí)間范圍,才能找到之前寫入的數(shù)據(jù)。ingest 預(yù)處理時(shí)區(qū)的好處:方便、靈活的實(shí)現(xiàn)了寫入數(shù)據(jù)的時(shí)區(qū)轉(zhuǎn)換。3.2 方案二:logstash 中間 filter 環(huán)節(jié)處理
拿真實(shí)同步案例講解一下時(shí)區(qū)處理:- 數(shù)據(jù)目的端:Elasticsearch;
- 同步方式:logstash,本質(zhì)借助:logstash_input_jdbc 插件同步;
- 時(shí)區(qū)處理:logstash filter 環(huán)節(jié) ruby 腳本處理。
如下只給出了中間 filter 環(huán)節(jié)的腳本: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 時(shí)間加 8 小時(shí)處理,賦值給 timestamp。
publish_time 到了 logstash 已轉(zhuǎn)成了 UTC 時(shí)區(qū)了。timestamp 類似似 C 語言中的交換兩個(gè)數(shù)函數(shù)中的 temp 臨時(shí)變量。- 第二行:將 timestamp 時(shí)間賦值給 publish_time。
- 第三行:刪除中轉(zhuǎn)字段:timestamp。
源數(shù)據(jù)Mysql 效果:
如上兩個(gè)截圖,對(duì)比一下區(qū)別:- publish_time 做了時(shí)區(qū)處理,兩者時(shí)間已一致,都是東 8 區(qū)。
- update_time 未做時(shí)間處理,寫入Elasticsearch 后由東8區(qū)時(shí)間 10:57:31 轉(zhuǎn)為UTC時(shí)區(qū)時(shí)間 02:57:31,少了8小時(shí)。
4、檢索和聚合的時(shí)候指定時(shí)區(qū)
假定我們寫入ES前未做時(shí)區(qū)處理(實(shí)戰(zhàn)環(huán)節(jié)常有的場景),但是檢索或者聚合的時(shí)候想做時(shí)區(qū)處理可以嗎?
可以的,具體實(shí)現(xiàn)方式如下:
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"
}
}
}
}
如上示例中,整合了檢索和聚合,有兩個(gè)要點(diǎn):- 要點(diǎn)1:range query 中指定時(shí)區(qū)檢索。
- 要點(diǎn)2:data_histogram 聚合中指定時(shí)區(qū)聚合。
5、小結(jié)
數(shù)據(jù)寫入時(shí)間不一致、數(shù)據(jù)滯后8小時(shí)等時(shí)區(qū)問題的本質(zhì)是:各個(gè)處理端時(shí)區(qū)不一致,寫入源的時(shí)區(qū)、Kibana默認(rèn)是本地時(shí)區(qū)(如中國為:東8區(qū)時(shí)區(qū)),而 logstash、Elasticsearch 是UTC時(shí)區(qū)。本文給出了兩種寫入前預(yù)處理的解決方案,方案一:基于管道預(yù)處理;方案二:基于logstash filter 中間環(huán)節(jié)過濾。兩種方案各有利弊,預(yù)處理管道相對(duì)更輕量級(jí),實(shí)戰(zhàn)選型建議根據(jù)業(yè)務(wù)需求。本文最后指出在檢索和聚合環(huán)節(jié)使用時(shí)區(qū)處理方式。大家在實(shí)戰(zhàn)中有沒有遇到時(shí)區(qū)問題,是怎么解決的呢?歡迎大家留言交流。參考
https://t.zsxq.com/2nYnq76