记录一次增量数据一致性问题

最近收到客户投诉出现数据无法操作的问题,经过排查,Mysql 和 ES 数据出现一致性问题。我们的使用场景是定于 Mysql binlog 投递到 Kafka,增量服务顺序消费 Kafka 中的消息,更新 ES 中的文档。

索引结构

在分析问题前先简单看下索引结构,这里只看出现问题的字段,主要就是用于存储标签 id 的一个 long 类型的字段,存的是一个数组。

json 复制代码
{
  "mappings" : {
    "f_tag_id" : {
      "type" : "long"
    },
    "f_status" : {
      "type" : "byte"
    }
  }
}

问题分析

  • 先简单看一下标签增量的逻辑,由于标签存的是一个数组,所以在更新的时候是先把文档查询出来,再对相应的数组字段做元素的新增或者删除,然后再重新索引到 ES 中。
  • 生产中的场景是同时有两个 binlog 并发,但是是分两次消费(同一批次的消息我们这边会在内存进行组装),A 表的 binlog 先更新 f_status,B 表 (标签关联表) 的 binlog 先将文档查询出来,更新完之后再将整个文档索引回 ES(更新代码通用性,所以是更新整个文档)。
  • 由于 ES 索引更新刷盘并非实时的,导致 B 表查询出来的文档是旧的,所以 B 表在更新索引时将旧的数据覆盖了新的数据。
  • 举一个简单的例子:
    • 假设原本 f_status = 0, f_tag_id = \[\]
    • A 表更新 f_status =1,此时 f_status = 1, f_tag_id = \[\]
    • B 表更新 f_tag_id = 1,由于 ES 刷盘存在延迟,导致更新的数据为 f_status = 0, f_tag_id = 1

解决方案

  • 最初的想法是只更新 f_tag_id 字段,但是这样其实还是会有问题,举个例子 B 表 (标签关联表) 针对同一条记录两个标签关联数据,意味着会有两个 binlog 生成,假设很不巧,Kafka 消费者分了两个批次去更新索引,就会造成和上述类似的场景。
    • 假设原本 f_tag_id = 1,2
    • 第一条 binlog 更新 f_tag_id = 1,2,3
    • 第二条 binlog 消费时,先查询 f_tag_id = 1,2,此时在去更新 f_tag_id 就会变成 1,2,4,还是会出现数据不一致问题
  • 第一个方案行不通,那能不能让 f_tag_id 像更新其他字段一样,不需要先查询出来组装再重新索引回 ES,答案是可以,那就是利用 ES 脚本更新,因为更新操作是可以直接更新内存的数据,所以数据是实时的。
json 复制代码
{
  "script": {
    "source": """
      List tagIdList = ctx._source.f_tag_id == null 
          ? new ArrayList() 
          : ctx._source.f_tag_id;
      if("insert".equals(params.method) 
        && !tagIdList.contains(params.changeTagId)){
        tagIdList.add(params.changeTagId);
      } else if("delete".equals(params.method)
        && tagIdList.contains(params.changeTagId)){
         tagIdList.remove(tagIdList.indexOf(params.changeTagId));
      }
      ctx._source.f_tag_id = tagIdList;
    """,
    "lang": "painless",
    "params": {
      "changeTagId": 12,
      "method": "insert"
    }
  },
  "upsert": {
    "f_tag_id": [12]
  }
}
  • 大概思路就是利用脚本直接针对 f_tag_id 进行元素变更,这样就不用担心查出来的 f_tad_id 是旧的了。

参考

www.elastic.co/guide/en/el... www.elastic.co/guide/en/el...

相关推荐
阿里云大数据AI技术8 小时前
阿里云 ES AI 引擎版:面向 Agent 场景,为亿级租户、千亿规模向量设计的搜索引擎
人工智能·elasticsearch·agent
阿里云大数据AI技术8 小时前
FalconSeek 技术解析:阿里云 Elasticsearch 云原生内核如何让查询性能飙升600%
人工智能·elasticsearch
Elastic 中国社区官方博客9 小时前
将你的 Grafana Kubernetes 仪表板迁移到 Elastic Observability:相同的 PromQL,30 倍更快的查询
大数据·人工智能·elasticsearch·搜索引擎·容器·kubernetes·grafana
Elasticsearch10 小时前
使用重新设计的 AutoOps 更快地进行 Elasticsearch 问题排查
elasticsearch
Elastic 中国社区官方博客12 小时前
如何使用 OpenTelemetry 对你的搜索 API 进行埋点,并使用 ES|QL 对其进行查询
大数据·功能测试·elasticsearch·搜索引擎·全文检索·可用性测试
菜地里的小菜鸟1 天前
logstash定时同步elasticsearch数据
elasticsearch·数据同步·logstash定时同步elastics
BerryS3N1 天前
Code Git 工作树:多分支开发的痛点与工作树的曙光
大数据·git·elasticsearch
Elasticsearch1 天前
Elastic 与 Deductive AI 携手合作,加速工程团队的 agent 式事件调查
elasticsearch
Elasticsearch1 天前
将你的 Grafana Kubernetes 仪表板迁移到 Elastic Observability:相同的 PromQL,30 倍更快的查询
elasticsearch
爱莉希雅&&&2 天前
elasticsearch+kibana+logstash+filebeat链路部署流程
大数据·elasticsearch·搜索引擎·kibana·logstash·filebeat