1. 程式人生 > >【elasticsearch】資料早8小時Or晚8小時,你知道為什麼嗎,附解決方案

【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設定時區。

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

  • 資料打印出來如下:
{
    "AsiaTime":"2019-12-30T16:32:07.616+0800",
    "newDateTime":1577694727581,
    "localTimeNow":"2019-12-30T16:32:07.615",
    "systemCurrentTimeMilis":1577694727581,
    "newDate":1577694727581
}
  • 預設不設定索引模板的情況,寫入es後,我們發現帶 時區‘T’的資料型別為date。

  • 接下來,我們將輪流設定這兩個欄位為kibana的時間搜尋欄位,看看會發生什麼。

兩個實驗對時區的思考
  • 實驗一:以localTimeNow做時間搜尋欄位,顯示比資料時間晚了8小時。

  • 實驗二:以AsiaTime做時間搜尋欄位,顯示比資料時間早了8小時。

  • 如何解釋?當然是由於時區影響。記住這幾個點,就很好理解了:
    • 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時區改為東八區後顯示正常。

總結

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

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