【elasticsearch】數據早8小時Or晚8小時,你知道為什么嗎,附解決方案


前言
  • 這篇文章,不會解釋什么是本初子午線,只想以做實驗的方式來理解數據差8小時的問題。下面就先說結論,再來談原理。
解決方案
  • 想必大家都很清楚:中國標准時間= UTC + 8小時。
  • 那么所有和時區有關的地方,都有可能成為“凶手”。
如果是java寫入es怎么解決時區問題?
  • 如果你使用java程序來寫入es,我推薦你寫入帶T的時間字符串。提供程序如下:
/**
	 * String timeZoneConvert = timeZoneConvert(
	 * 				new Date().getTime()
	 * 				, "yyyy-MM-dd'T'HH:mm:ss.SSSZ",
	 * 				"Asia/Shanghai");
	 * 				
	 * @param date 毫秒
	 * @param pattern format時間格式
	 * @param timeZone 時區
	 * @return 如:2019-12-30T16:32:07.616+0800
	 */
	public static String timeZoneConvert(Long date,String pattern,String timeZone){
		SimpleDateFormat simpleDateFormat=new SimpleDateFormat(pattern);
		simpleDateFormat.setTimeZone(TimeZone.getTimeZone(timeZone));
		return simpleDateFormat.format(date);
	}
  • 為什么?因為java有些api是帶時區的。如new Date().getTime()默認是東八區,System.currentTimeMillis() 依賴於當前時區來計算毫秒值。
  • 雖然上述例子依賴了這個api,但是這里只是想說明java程序所處的環境的時區同樣有影響,特別是這個程序很可能是容器化的,那么可能又和系統鏡像的時區有關了。
如果是logstash寫入es怎么解決時區問題?
  • 建議input的時間源數據就是帶上時區的字符串,否則就要進行轉換。
 mutate{
        gsub => [
           "time", "[+]", "T"
        ]
      } 
        mutate{
      replace => ["time","%{time}+08:00"]
      }

或是:

date {
    match => ["timestamp", "yyyy-MM-dd HH:mm:ss"]
    target => "my_timestamp"
    timezone => "+08:00"
}
如果是語句聚合es數據怎么解決時區問題?
  • 指定time_zone配置
"aggs": {
    "by_day": {
      "date_histogram": {
        "field":     "date",
        "interval":  "day",
        "time_zone": "Asia/Shanghai"
      }
    }
  }
kibana顯示怎么解決時區問題?
  • Management>>Advanced Settings設置時區。

file

原理&試驗
Es中和時間相關的數據類型
  • 一般在寫入es的時候,會以json的方式寫入,由於json中沒有日期數據類型,所以日期如何存儲顯示,是由es決定的,也就是說es會進行隱式的類型轉換。
  • es中的日期可以是:
  • 格式化日期的字符串,例如"2019-12-30"或"2019/12/30 12:10:30"。
  • 毫秒值。
  • 秒值。
試驗
  • 這里以不同的時間api准備了一些數據寫入es,讓我們來看看會發生什么。

file

  • 數據打印出來如下:
{
    "AsiaTime":"2019-12-30T16:32:07.616+0800",
    "newDateTime":1577694727581,
    "localTimeNow":"2019-12-30T16:32:07.615",
    "systemCurrentTimeMilis":1577694727581,
    "newDate":1577694727581
}
  • 默認不設置索引模板的情況,寫入es后,我們發現帶 時區‘T’的數據類型為date。
    file

  • 接下來,我們將輪流設置這兩個字段為kibana的時間搜索字段,看看會發生什么。

兩個實驗對時區的思考
  • 實驗一:以localTimeNow做時間搜索字段,顯示比數據時間晚了8小時。
    file

  • 實驗二:以AsiaTime做時間搜索字段,顯示比數據時間早了8小時。
    file

  • 如何解釋?當然是由於時區影響。記住這幾個點,就很好理解了:

    • es內部,時間會轉換成UTC格式,實際按照數值型存儲。可以理解為毫秒數。
    • kibana會通過獲取時區配置顯示時間到界面。

首先來說實驗一,為什么kibana上顯示的時比數據時間多8個小時呢?明明是30號的數據,愣是跑到31號去了?

  • 這條數據 "localTimeNow":"2019-12-30T16:32:07.615"。帶時區T,默認是UTC時區,
    而kibana獲取的時區配置是Asia/Shanghai,為東8區,相當於在原來的時間上加上8個小時顯示,所以跑到31號去了。
    用大腿想一下,你肯定知道,這種情況下如果把kibana時區設置為UTC,當然數據就顯示正常啦。

  • 再來說實驗二, "AsiaTime":"2019-12-30T16:32:07.616+0800,由於上面設置了當前kibana時區為UTC,數據帶東八區的時區,所以晚了8小時。同理將kibana時區改為東八區后顯示正常。

總結

  • 時區問題,萬變不離其宗,搞清楚原理后,任意數據怎么變化,我們都能夠有方法應對,希望這篇文章對你有所幫助。

歡迎來公眾號【俠夢的開發筆記】 一起交流進步


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM