前天在使用Druid完成一个新项目时遇到了查询时间错误的问题。就是日志一直在往Druid里灌,但是查近一个小时的数据怎么也查不到。经检查,日志消费情况,时间戳的填充也都是没有问题的。后来尝试将查询起始时间往前推了1天,总算查到了数据(查询时间巨长)。而且根据查询结果中的一些时间字段来看,还是有最近一个小时的记录的。这说明我的查询json是OK的,问题出在时间上。
尝试调整了几次interval时间后,确定了要把查询起止时间往前推8个小时才能查到预期的结果。8 这个数字引起了我的注意——我们通常采用的北京时间就是东八区时区时间。是不是向Druid写入日志时,把时间戳给处理成0时区时间了。赶紧和Druid管理员沟通,确定了如我猜测:如果写入的时间是时间戳格式就会被处理成0时区UTC时间。
再说下解决方案。大体有仨:
- 调整Druid时区配置
- 我将日志中的时间戳(13位长整型毫秒值)改为格式化后的时间(如:2019-03-01 12:12:12)。
- 接受现状,查询时把时间往前推8小时
接受现状是不可能的,因为不符合个人美学。
其中第一个方案,我记得Druid官方文档是有说明的,这个应该可以改。(查了下官网,具体在JVM调优这一节)。但是不能指望运维改,毕竟在线服务都跑了好久了,贸然改了默认时区线上服务是要受影响的。
因此只剩第二个选项了。和运维沟通后,确认了虽然我之前写的是时间戳,但现在直接改成格式化后的时间也是OK的,只是会损失一些数据。最终定下了就采用这种方式。(今天试了下,不能直接改,之前写入的数据被丢弃了,运维重置了元数据才搞定)
其实还可以从其他方向考虑下,大概有两种:
第一种:使用Druid SQL来查询,查询时间仍然采用长整型时间戳,下面是一个范例:
1 2 3 |
select TIMESTAMP_TO_MILLIS("__time") "__time","value" from "_log" where "__time">=MILLIS_TO_TIMESTAMP(1576259650000) and "__time"<=MILLIS_TO_TIMESTAMP(1576302850000) |
另外使用Druid SQL查询时也可以在context
中通过sqlTimeZone
设置查询时区(知道有,但没试过)。
但是我不喜欢使用Druid SQL(有一点点性能的考虑)。PASS!
第二种:使用period
Granularities,在查询时指定查询使用的时区。这个在官网有一个例子:Period Granularities。但是嫌繁琐,而且结果未必尽如人意,仍然PASS!
另外,这次我还开发了一些Druid JSON查询的工具类,如果有需要可以从GitHub拉取:zhyea / druid-explore 。代码中仅包括我现在用到的功能,后续用到了其他功能(如Filter)也会继续补充。
扯点儿闲白:这篇文我从早上就开始酝酿,但是先后出现了博客服务器问题,游戏晋级,零食,水果等种种阻碍,终于才能开始着手写,然后在半个多小时的时间内一气完成——但是完成时天色已全黑。再次感叹之前多次的感叹:小事开头难,大事坚持难。
END!!
发表评论