【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设置时区。

file

原理&试验

Es中和时间相关的数据类型

  • 一般在写入es的时候,会以json的方式写入,由于json中没有日期数据类型,所以日期如何存储显示,是由es决定的,也就是说es会进行隐式的类型转换。
  • es中的日期可以是:
    • 格式化日期的字符串,例如"2019-12-30"或"2019/12/30 12:10:30"。
    • 毫秒值。
    • 秒值。
试验

  • 这里以不同的时间api准备了一些数据写入es,让我们来看看会发生什么。

file

  • 数据打印出来如下:
{
    "AsiaTime":"2019-12-30T16:32:07.616 0800",
    "newDateTime":1577694727581,
    "localTimeNow":"2019-12-30T16:32:07.615",
    "systemCurrentTimeMilis":1577694727581,
    "newDate":1577694727581
}

  • 默认不设置索引模板的情况,写入es后,我们发现带 时区‘T’的数据类型为date。
    file
  • 接下来,我们将轮流设置这两个字段为kibana的时间搜索字段,看看会发生什么。
两个实验对时区的思考

  • 实验一:以localTimeNow做时间搜索字段,显示比数据时间晚了8小时。
    file
  • 实验二:以AsiaTime做时间搜索字段,显示比数据时间早了8小时。
    file
  • 如何解释?当然是由于时区影响。记住这几个点,就很好理解了:
    • 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时区改为东八区后显示正常。
总结
  • 时区问题,万变不离其宗,搞清楚原理后,任意数据怎么变化,我们都能够有方法应对,希望这篇文章对你有所帮助。

欢迎来公众号【侠梦的开发笔记】 一起交流进步

### Elasticsearch 与 MySQL 数据同步方案 #### 方案概述 为了实现 Elasticsearch (ES) 和 MySQL 之间的数据同步,通常有多种技术手段可供选择。这些方法可以分为 **单向同步** 和 **双向同步**。以下是几种常见的方式及其特点: --- #### 单向同步方案 ##### 1. 同步双写 在应用层面同时操作两个存储系统,即每次更新 MySQL 的时候也直接更新 ES。这种方式的优点在于实现简单,缺点则是增了系统的耦合度,并可能导致一致性问题。 > 应用场景下,如果需要快速部署简单的解决方案,则可以选择此方式[^2]。 ##### 2. 异步调用 通过引入消息队列(Message Queue, MQ),将 MySQL 中的变化记录发送到 MQ,再由消费者程序监听并更新至 ES。这种模式降低了服务间的耦合度,但也带来了额外的运维成本和技术复杂性。 > 使用 Kafka 或 RabbitMQ 等工具可以帮助构建高可用的消息传递机制,从而提升异步调用的成功率和稳定性[^3]。 ##### 3. Binlog 监听 利用 MySQL 的二进制日志(Binlog)来捕获数据库中的变更事件,并将其转发给 ES。具体来说,可以通过 Canal、Maxwell 或 Debezium 等开源工具完成这一过程。该方法无需修改现有应用程序逻辑即可实现实时增量同步。 > 开启 binlog 功能虽然会对数据库性能造成一定影响,但它提供了非常可靠的审计跟踪以及实时复制能力。 --- #### 双向同步方案 对于某些特殊需求场景可能涉及从 ES 到 MySQL 的反向同步或者两者间相互作用的情况,此时就需要考虑更复杂的架构设计。例如,在电商领域中商品库存管理可能会涉及到跨平台订单处理等业务流程。 一种可行的办法是借助专门用于多源异构环境下的数据集成产品——如 CloudCanal 来搭建完整的双向同步链条。它不仅支持标准 SQL 查询语句转换成目标端可识别的操作命令序列,还具备自动解决潜在冲突的能力。 > 当面对频繁交互且要求强一致性的场合时,采用专业的中间件可能是最优选项之一[^1]。 --- #### 推荐工具对比表 | 工具名称 | 主要特性 | 适用范围 | |----------------|----------------------------------------------------------------------------------------------|-----------------------------------| | Canal | 基于 MySQL Binlog 提供准实时的数据订阅与分发 | 小规模项目 | | Maxwell | 类似于 Canal,但更轻量级 | 对延迟容忍较高的情况 | | Debezium | 支持更多类型的数据库作为源头 | 大型分布式系统 | | Logstash | ELK Stack 组件之一,灵活配置输入输出插件 | 日志采集及初步工 | | CloudCanal | 商业化软件,专注于企业级多云/混合环境下大规模关系型数据库与其他 NoSQL 存储之间无缝衔接 | 关键任务驱动的企业内部信息化建设 | --- #### 同步策略总结 - 如果追求低延迟能力并且愿意承担一定的基础设施投入,则推荐基于 Binlog 的监听方式; - 若希望减少开发工作量而接受稍高的失败概率的话,那么可以直接采取同步双写的办法; - 考虑到长期维护便利性和扩展灵活性因素,选用成熟的第三方框架往往是明智之举。 ```python import pymysql from elasticsearch import Elasticsearch def sync_mysql_to_es(mysql_conn_info, es_host): """ A simple example of syncing data from MySQL to Elasticsearch. Args: mysql_conn_info (dict): Connection parameters for the MySQL database. es_host (str): Hostname or IP address where Elasticsearch is running. Returns: None """ # Connect to MySQL and fetch records connection = pymysql.connect(**mysql_conn_info) cursor = connection.cursor() query = "SELECT id, name FROM users" cursor.execute(query) rows = cursor.fetchall() # Initialize an Elasticsearch client es_client = Elasticsearch([es_host]) # Index each record into Elasticsearch for row in rows: doc_id, doc_name = row document = {"id": doc_id, "name": doc_name} es_client.index(index="users", id=doc_id, body=document) sync_mysql_to_es({"host": "localhost", "user": "root", "password": "", "db": "test"}, "http://localhost:9200") ``` ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值