
37

常见分布式应用系统设计图解(三):Top K 系统
source link: https://www.raychase.net/6275
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.

“ Top K 系统 ” 是非常常见的一种子系统,基本上,就是从全量巨大的统计数据中,筛选出数值最大的 K 个来并按序展示。这样的筛选可以是全时间内的,也可以是最近某一段时间内的;可以是全分类的,也可以是某个特定分类的。
具体来说,像 Twitter 的 Trending Topic,微博热搜,视频网站的点击排行,下载排行(可以是日榜、月榜、总榜)等等。这样的系统,在统计数据非常大(heavy hitters)的时候,其中的挑战性在于两个:
- 无法简单地在单台机器的内存中进行目标 id -> count 计数的简单映射,因为数据量太大,内存放不下。
- 无法用实时的方式高效地显示出动态变化的 Top K 列表来。

- 上图包含了两个思路,一个是实时排行(榜单),通过 Count-min Sketch 实现,快速,但是不够精确;另一个是周期性排行,通过异步的 MR 数据处理实现,数据上看比较准确,但是处理是异步的,实时性差。
- 第一个思路方面,统计要尽可能实时。通过不同的数据源,进入队列,为了提高处理效率,这样的队列event是可以是将源数据经过批量打包的,即每一个目标id对应的count计数可以多于1,且每个event可以包含多个id->count 条目。
- 接着经过简单的 filtering 和 parsing 去掉不关心的数据,比如对于微博的话题来说,某一些词是小词,或者是我们不希望成为话题的词;而某一些近似词可以合并。完成以后数据有两个去向,一个是右侧的即时统计,一个是持久化到下方的数据库中(这个数据库可以是 Redis 这样的 KV 数据库)。
- 对于每一个词,经过 hash 以后,到 Count-min Sketch 表格中累积计数,并根据计数到当前大小为 K 的最小堆(这个最小堆用来存放一定时间内累计的前 K 大条目)中寻找是否比堆顶更大,如果是,就入堆并移除原堆顶,从而保持堆的大小为 K。由于 Count-min Sketch 这个堆的大小都是确定并可控的,这样的统计就可以在单个节点上完成了。
- 如果需要的即时统计数据不是 “总榜”,而是最近一段时间的 “趋势榜”,那就可以借助 Ring Buffer——比如我们只关心最近一小时的趋势,就可以把一小时划分为 ring 上的 60 个区间,每个区间使用 Count-min Sketch 甚至简单的 Map 分别统计,趋势榜每次可聚合这 60 个区间得出 top K;每过一分钟都覆写最老的那一个区间的数据,从而保证 ring 上的数据始终是最近一小时的。
- 第二个思路方面,统计不实时,但相对精确。对于这些持久化的数据,由 MR 的 job 定期执行来处理,并更新结果到数据库中。
- 读取数据的时候,根据需要可以读取即时统计或者异步计算得到的统计数据,数据可以在外部缓存。
Recommend
About Joyk
Aggregate valuable and interesting links.
Joyk means Joy of geeK