记录一次数据库同步elasticsearch的问题

1,146 阅读4分钟

数据同步elasticsearch的问题

1.问题现象

有这么一个需求,我们需要将我们数据库的表数据刷新入elasticsearch,以便我们完成档案功能的检索,所以后端开发了一个接口,提供给测试人员可以手动刷新数据入elasticsearch;

突然有一天,测试人员跟我们说,你们swagger上,从数据库同步elasticsearch的接口,执行完成后elasticsearch的数据总是比数据库少一些,至于少多少条,这个数据每次还都不一样;

2.分析

听到测试这样说,我们第一感觉就是数据有问题吧,因为从数据库到elasticsearch,我们取的表的id作为elasticsearch索引的id,可能表的id部分有问题?打开数据库,执行了一下,发现数据并没有重复的,神奇,那问题在哪呢?

select count(distinct a.id) from a;
select count(a.id) from a;

查询的数据总数是一样的

然后我们排查代码,发现同步接口的代码并没有报错

那会不会是elasticsearch动态模板的问题,因为熟悉elasticsearch的人知道,如果dynamic mapping开启的话,elasticsearch会根据我们刷新的第一条数据动态决定我们elasticsearch字段的类型,比如rq字段第一条数据是2022-05-07,那么它就会被识别为date,在后面的数据中,如果有些rq不是date,它是不是就不会刷新入elasticsearch?我们修改代码,将所有的字段都指定为text,发现还是没有什么用;

没办法,我们只能用arthas工具,通过watch命令一步步定位跟踪刷新ElasticSearch接口的入参和出参,看能不能发现什么不一样的地方

这个时候我们定位到,数据刷新入elasticsearch的时候,elasticsearch提示有部分数据已经存在,所以变成了更新操作,但是明明是先删除索引,再同步新增的啊!那看来可能是不是elasticsearch哪里出问题了?

目前elasticsearch主要有三个节点,master节点,search节点,data节点,查看master节点发现,elasticsearch有数据更新时候,集群状态从yellow变成green,那会不会是elasticsearch部署问题

日志如下: Cluster health status changed from [YELLOW] to [GREEN] (reason: [shards started [[archive_dev] [0]]])

后来经过排查和查阅资料,发现elasticsearch数据刷新时候,确实节点会从yellow变成green,是我之前孤陋寡闻了。

既然不是elasticsearch本身问题,那会是什么原因呢,这时候注意到一个很重要的点,就是之前数据库是mysql时候,没发现过类似的问题,换成达梦数据库后,也不知道什么时候出现这样的问题,那会不会是达梦数据库的问题

这时候我们利用达梦数据库的同步工具,将达梦数据库的数据同步到mysql一份,然后数据库切mysql,发现数据同步elasticsearch没出现问题,也没有漏下相关的数据,那这说明,是达梦数据库的问题!

问题找到了,但是达梦为什么会有这样的问题,达梦环境部署的是否有问题?问题出现在哪里?又改怎么修改呢?仍然是一头雾水,没有办法,只能在代码里面多加一点输出日志一点一点调试

我们将请求打印出来,同时将elasticsearch保存的出参返回出来,将status不等于201的数据打印出来,看这些数据特殊在哪里

然后我们分析日志

我们搜索保存失败的_id数据,看它是什么时候保存的,9de24333325e5862e0ea32aaa6d170d2

这时候我们竟然,搜出来了三条

也就是说,第一次数据库查出来结果的时候,刷新入elasticsearch,状态码是201,create,所以日志只打印了入参,没有错误的出参

第二次数据库又重复查出来,再次刷新入elasticsearch,这时候elasticsearch已经存在了,所以状态码是200,update,因为不是201,所以第三次日志打印出来报错的id了。。

那看来是达梦的sql有问题,我们复制sql出来试一下

select a.id as id, count(b.id) as num 
from a left join b on (a.id = b.archive_id ) where 1=1 group by a.id limit 1800,100

放到控制台执行一下,绝了,每次执行的结果都不相同

难怪每次从数据库查询出来之后,然后刷新elasticsearch多多少少都有数据丢失,而且数据还不是确定的。

后来咨询了一下达梦官方,说limit属于随机,没有一个排序基准,两个数据库机制不一样,所以必须要在group by后面再加个order by..

sql调整:

select a.id as id, count(b.id) as num 
from a left join b on (a.id = b.archive_id ) where 1=1 group by a.id order by a.id limit 1800,100

sql修改,问题解决,改完后就想吐槽

以前没感觉mysql好在哪里,现在感觉mysql是真的好

3.结论

总结一下,达梦数据库下,如果使用limit,则每次查出结果不一定相同(随机),顺序也是不确定的;