PostgreSQL 同步到 ES 后时间类型少了 8 小时

简述

最近我致力于实现 PostgreSQL 到 Elasticsearch(ES)的实时同步功能。

在源端,我利用 PostgreSQL(PG)的 Write-Ahead Logging(WAL)日志来实现实时同步,将 WAL 转换为 ES 的相关写入操作。

源端 PG 数据库和 ES 均采用 UTC 时区,因此 Timestamp 类型的同步应该无需进行任何处理。

然而,在将数据写入 ES 后,我们却发现 Timestamp 类型的数值少了 8 个小时。

原因分析

首先,让我们梳理一下整个同步链路:

PG 的数据经过 SYNC 程序处理,然后同步到 ES。

经过初步分析,我们得出两个可能的原因:

  1. ES 中的时间存储正确,而 Kibana 使用的是浏览器的时区(Asia/Shanghai)。
  2. SYNC 程序在处理时间时出现了问题。

在 Kibana 设置中查看后,发现其设置为 UTC,即不会默认进行任何时区转换,因此我们推断问题出现在 SYNC 程序的时间处理中。

代码分析

在处理时间类型的代码中,存在以下逻辑,首先会使用parseDate方法将时间类型的字符串转换为DateTime

java 复制代码
public static DateTime parseDate(String datetimeStr) {
    // ... 省略部分代码 ...
    try {
        return new DateTime(datetimeStr);
    } catch (IllegalFieldValueException e) {
        String errMsg = "Parse date fail, Root cause is " + ExceptionUtils.getRootCauseMessage(e);
        log.error(errMsg);
        throw e;
    }
}

通过调试,我们发现在parseDate后,时间减少了 8 小时。

源码分析

TimeZone.getDefault()是 JDK 自带的方法:

获取 Java 虚拟机的默认时区。

如果缓存的默认时区可用,则返回其克隆。

否则,该方法采取以下步骤来确定默认时区。

使用默认时区的风险

当JVM中的user.timezone变量未设置值时,根据上述源码分析,将读取系统的默认时区。

风险就出在这里,如果系统安装时时区未正确设置,将导致程序获取的默认时区与预期不符,从而引发异常。

在 Java 程序中设置时区

  1. 在 Java 程序启动时,在 JVM 参数中添加-Duser.timezone=UTC
  2. 在程序首次启动时,使用TimeZone.setDefault()来设置时区。
相关推荐
YQ_ZJH2 分钟前
Redisson 看门狗机制详解
java·redis
ssshooter2 分钟前
传参优于外部变量
前端·后端·面试
那我掉的头发算什么6 分钟前
【javaEE】多线程——线程安全进阶☆☆☆
java·jvm·安全·java-ee·intellij-idea
qq_22589174668 分钟前
基于Python+Django餐饮评论大数据分析与智能推荐系统 毕业论文
开发语言·后端·python·信息可视化·数据分析·django
悟空CRM服务14 分钟前
我用一条命令部署了完整CRM系统!
java·人工智能·开源·开源软件
组合缺一15 分钟前
Solon AI 开发学习 - 1导引
java·人工智能·学习·ai·openai·solon
百***490017 分钟前
基于SpringBoot和PostGIS的各省与地级市空间距离分析
java·spring boot·spring
bcbnb20 分钟前
网络调试与API测试必修课 Fiddler抓包工具使用教程、代理配置与HTTPS抓包技巧全解析
后端
华仔啊28 分钟前
解决 XXL-Job 定时任务时间偏差8小时的问题
后端
南山安35 分钟前
让 LLM 与外界对话:使用 Function Calling 实现天气查询工具
人工智能·后端·python