背景:使用中发现iotdb关于时区处理的相关bug,iotdb 版本1.1.2,对于反馈的bug,iotdb会在新版本中修复。所以老版本如果希望修复bug只有两个选择,1是自己修复,2是升级到修复后的新版本。当然也可以考虑企业版,企业版会有更多支持。
原创文字,IoTDB 社区可进行使用与传播
问题发现:
最近新增了国际业务,应用查询时新增了基于时区的查询,在使用iotdb时区时,发现其java-api在使用了sessionPool.setTimeZone(xxx)后,接口耗时增加。
于是查看该处源码(org.apache.iotdb.session.pool.SessionPool#setTimeZone),可以发现默认的RETRY值为3,而此处SetTimeZone执行完之后没有return,导致setTimeZone不管是否成功都会连续执行3次。
在相关监控中也可以验证,对于每次查询,setTimeZone都执行了3次。
解决:
这里自己修改源码打包修复即可。打包方法可以参考链接
修改完源码后执行
mvn clean package -pl distribution -am -Dmaven.test.skip=true
即可获取修改后的包
补充:关于夏令时的bug
iotdb时区在夏令时处理时的相关bug
命令行或者api中设置了时区为德国时区Europe/Berlin,查询当天按小时分组的聚合数据,发现结果返回24条数据,但是理论上由于德国在2024-03-31T02:00:00+02:00 开始进入夏令时,时钟会拨快1小时,这一天只有23个小时,应该返回23条数据。
在社区提问后,得到回复为
sql解析是根据ZoneOffset给你的字符串加上对应的时区信息。 比如[2024-03-31, 2024-04-01),如果你设置了德国时区,在IoTDB里会被翻译成 [2024-03-31T00:00:00+02:00, 2024-04-01T00:00:00+02:00)
实际验证后发现当前iotdb对于时区的处理是以设置时区后当前时区对应的ZoneOffset来解析处理sql,而不是以SQL中指定的开始和结束时间来设置。
即如果现实中当前时间在2024-03-31T01:00:00+00:00时间之前执行sql的时间区间为
[2024-03-31, 2024-04-01)
此时sql会被解析为
[2024-03-31T00:00:00+01:00, 2024-04-01T00:00:00+01:00)
而当现实世界过了2024-03-31T01:00:00+00:00后,德国从中欧时间(CET,Central European Time,UTC+1)进入中欧夏令时(CEST,Central European Summer Time,UTC+2)
此时sql的时间区间会被解析为
[2024-03-31T00:00:00+02:00, 2024-04-01T00:00:00+02:00)
而我们期望的时间区间其实是
[2024-03-31T00:00:00+01:00, 2024-04-01T00:00:00+02:00)
明白了原因后,这个问题的解决方案也很简单,既然当前sql解析是有这个bug的,我们就在查询前自己解析时区的信息,实现将查询的时间区间[2024-03-31, 2024-04-01),在德国时区时翻译为 [2024-03-31T00:00:00+01:00, 2024-04-01T00:00:00+02:00),同时也不需要在执行查询时再设置TimeZone
下面是方法
public static String getOffsetFormat(LocalDateTime time, String timeZone) {
if (timeZone == null || timeZone.trim().isEmpty()) {
timeZone = "UTC+00:00";
}
ZonedDateTime zonedDateTime = ZonedDateTime.of(time, ZoneId.of(timeZone));
return zonedDateTime.format(IConstants.IOT_TIME_FORMAT);
}
//其中 IOT_TIME_FORMAT的值是
DateTimeFormatter IOT_TIME_FORMAT = new DateTimeFormatterBuilder().appendPattern("yyyy-MM-dd'T'HH:mm:ssxxx").toFormatter();
用此方式可以实现规避setTimeZone bug同时解决夏令时问题。
可以看到返回结果正常