一、bug描述
点击资讯页面,展示资讯列表,等过段时间往下拉查看下一页时,发现第二页的资讯信息发布时间比第一页的资讯信息更晚一些,从而出现上图的问题。
二、bug原因
资讯数据处理流程:首先由爬虫爬取各个网站的资讯数据,落到A表,然后经过定时任务处理后放到B表,之后flink监听B表中有新增数据,就会把这条新增的数据放到es中,最后用户访问页面请求接口展示出这条数据。
已知信息:
1、由于各个网站数据源的数据刷新频率不同,为了降低成本,所以有的爬虫是一分钟爬取一次,有的是几分钟爬取一次,有的是一两个小时爬取一次。
2、从A表处理到B表的定时任务是每分钟执行一次。
3、资讯列表是通过发布时间倒序排列的。
排查过程:
- 一开始以为是es查询的Bouncing Result问题,因为有部分数据的发布时间是相同的,后来发现第二页的数据发布时间是不同的,所以排除这个问题。
- 然后想起来动态索引是实时的,所以会实时添加数据,比如总共有100条数据,第一页会展示1-10条数据,后来索引新增了5条数据,导致第二页查询出来第5-15条数据。这个时候需要在前端请求时添加过滤条件,即在下一次请求时携带上一次请求最后一条数据的发布时间。
- 后来又捋了一遍逻辑,发现还有个问题,由于页面展示时取的是发布时间,而发布时间是由各个网站数据源爬取出来的,此时会出现一种情况,比如一个网站上A数据的发布时间是5点,爬虫爬取的时间是6点,经过处理后放到es中的发布时间也是5点,而页面是根据发布时间倒序的,所以会导致用户查看资讯列表时,一直往下拉到5点才能看到这条数据。
Bouncing Results:
想象一下有两个文档有同样值的时间戳字段,搜索结果用 timestamp 字段来排序。 由于搜索请求是在所有有效的分片副本间轮询的,那就有可能发生主分片处理请求时,这两个文档是一种顺序, 而副本分片处理请求时又是另一种顺序。
这就是所谓的Bouncing Results问题: 每次用户刷新页面时,搜索结果表现是不同的顺序。
三、解决办法
跟产品商量后可以把数据源的发布时间改为落到B表的createTime时间,同时在前端请求时添加查询小于第一页最后一条的createTime时间,并且设置es的preference参数,让同一个用户始终使用同一个分片,保证用户每次查询的结果是相同的,避免Bouncing Results问题。
preference取值:
1、_primary:该操作将只在主分片上执行,性能会打折扣,达不到性能的水平扩展。
2、_primary_first:优先在主分片执行,如果主分片挂掉,会在副分片上执行请求。
3、_replica:该操作将只在副分片上执行。
4、_replica_first:优先在副分片执行,如果副分片挂掉,会在主分片上执行请求。
5、_local:优先在本地节点上的分片查询数据然后再去其他节点上的分片查询,本地节点没有IO问题但有可能造成负载不均问题。
6、_prefer_nodes:abc,xyz:倾向于使用提供的节点id上执行。
7、_shards:2,3:该操作限制在指定的分片2、3上执行,这种方式可以与其他方式相结合,但必须首先出现:_shards:2,3|_primary
8、_only_nodes:该操作限制在指定的节点上执行。
9、Custom (string) value:自定义值,可以保证同样的请求,被分配到同样的分片上面,从而保证请求结果的稳定性,比如用户ID。
10、不配置:默认采用轮询的方法查询主副分片
四、参考资料
1.https://www.elastic.co/guide/cn/elasticsearch/guide/current/_search_options.html