假设歌曲总量200万条,每天的播放日志1亿条,日志索引每天建立一个,primary shard数量为10,命名格式playlog-yyyyMMdd,需求是搜索当天的播放排行榜,取排名前10的记录。
如果直接统计,就只能硬扛了,基本过程如下:
每个shard根据music_id做分组统计,理论上单shard数量量最多200万条。
Coordinate Node收集10个shard的数据,进行合并,数据处理量上限2000万条,最后合并成200万条。
从这200万条数据取前面10条,返回给客户端。
这个过程绝对是重量级,如果每次都实时统计的话,ES集群的压力可想而知。
改进方案播放功能增加数据更新逻辑
预先增加按日期统计的索引数据结构,每次有用户点击播放时,额外发送一条更新消息将其数据更新,查询时直接从统计的索引里出结果,避免每次查询。
定时任务统计数据
数据统计的需求,可以用定时任务进行计算,将计算结果存储起来,通过降低实时性,来避免全索引扫描计算的压力。
简单对比:
相同点:都是以空间换时间的做法,避免全索引扫描。
不同点:前者通过更改业务实现逻辑,增加数据级联更新,有一定的业务耦合性;后者将实时计算变定时任务,灵活性较高,与业务耦合性低,但实时性差。
补充一点良好的数据结构设计可以很大程度地降低ES查询压力,提高实时查询的性能,但有一点需要接受:考虑得再周全的设计,也难适应千变万化的需求;需求变更是无法避免的,没有一劳永逸的方案。
小结本篇从分页查询入手,阐述了deep paging的问题原因,并顺带将自己对分布式系统与集中式系统处理的思维差异做了简单描述,最后引申了top N场景的问题,上面提到的改进方案,只是针对比较简单的场景,实际生产要面临的情况肯定更复杂,比如采用分布式计算组件storm来解决top N 问题的,这里当做是抛砖引玉,欢迎各位分享自己的看法。
专注Java高并发、分布式架构,更多技术干货分享与心得,请关注公众号:Java架构社区