Back to home

不要使用周数作为索引名字

不要使用周数作为索引名字

我们最近碰到一个奇怪的问题,Elastalert 漏报部分数据。一番调查之后了解到了 Python 和 Java 中对周数的定义不同。

用周数作为 Elasticsearch 索引名

ElasticSearch 索引名称一般包含一个时间参数作为拆分依据,比如 monthly: index-%m, daily: index-%d。其中时间颗粒度取决于数据量大小,如果索引过多,时间范围比较大的查询可能因为同时打开的文件句柄数过多而引发错误。如果索引过少,文档数量可能会超过 Lucene 的最大限度 (Integer.MAX_VALUE - 128).

作为折中,有一些索引我们是按照 weekly 创建的。

Logstash - JVM 创建索引,Elastalert - Python 访问索引

作为 ELK 的关键组件,Logstash 负责将上有数据插入到 ElasticSearch 中。我们配置的索引名称规则就在 Logstash 配置里。

elasticsearch {
  hosts => ["HOST_1", "HOST_2"]
  index => "index-%{+YYYY.ww}"
}

我们使用 Elastalert 进行数据的查询,进而发出警报。

index: index-%Y.%W
filter:
- query:
    query_string:
      query: "RawText: \"Error\""

业务出了问题,回头看数据在 ElasticSearch 中,Elastalert 也执行没问题。

周数的定义 Java vs. Python

Java 给出来的周数很容易理解。每年的第一天作为第一周的开始,第二周从周日开始。你可以通过这个链接测试image.png

然后是 Python 版本链接isocalendar() 返回所属 ISO calendar 年份、周数、星期数(星期一到星期日:1-7)。datetime 的库文档给出了详细说明。简单表述为每年的 ISO 日历的第一周以阳历的第一个星期四为准。并且将第一周周一之前的日子作为第零周。所以才有如图的结果。 image2.png

如何解决?

统一日历规则。配置相同的时区、每周第一天是周几,或者干脆不要用周数作为索引名字。将索引按照业务进一步拆分,使用 monthly,或者归并几个小业务的索引到一起,然后使用 daily 细粒度。

为什么要有这么多日历

因为世界是混乱的。 https://en.wikipedia.org/wiki/Week#Week_numbering

image3.png