知识卡片

超热数据缓存:用一个定长队列实现秒级的热点SKU识别

结构图卡

内容

面对十亿级商品,要在一秒钟内从中筛选出当前访问量最高的一小批热点商品(SKU),既要求识别速度极快(秒级或毫秒级),又要求这个识别机制本身足够轻量、不能自己成为新的性能瓶颈。京东给出的实现方式非常简洁:维护一个固定长度(比如50)的队列,每当一个SKU被访问,就把它塞进这个队列,队列内部的位置会根据访问的先后不断往前移动——排在队列前面的SKU,因为不断被新的访问顶到前面,天然就是当前时间窗口内访问次数最多的那一批商品,不需要额外的统计计算或排序开销,直接读取队列前几位就能知道当前的热点是谁。这个机制在真实秒杀场景下发挥了巨大作用:面对500万级别的秒杀请求,其中会有十几二十万的请求命中的正是这批已经被识别为热点的SKU,这部分请求绝大多数直接被这层超热数据缓存挡了下来,根本不会继续往后穿透到更深层的存储系统。这个设计的精妙之处在于用一个结构极其简单、天然具备”最近高频访问者排在前面”这个性质的数据结构(本质是一个近似LRU/访问计数的滑动窗口),零成本地实现了”识别热点”这个原本需要复杂统计才能完成的任务——它没有去计算精确的访问次数排名,只是利用了”频繁被访问的SKU会不断被顶到队列前面”这个统计学上的自然结果,用极低的实现和运行成本换来了足够用的近似精确度,这正是热点探测类问题里”近似解往往比精确解划算得多”的典型体现。

结构图

flowchart LR
    A["请求到达\n访问某个SKU"] --> B["把该SKU塞入定长队列(长度50)"]
    B --> C{"队列已满?"}
    C -->|"是"| D["挤出队尾最久未被访问的SKU"]
    C -->|"否"| E["直接加入"]
    D --> F["队列前部\n= 当前高频热点SKU"]
    E --> F
    G["新请求到达"] --> H{"命中队列前部热点SKU?"}
    H -->|"命中(占比高,如秒杀500万请求中10~20万)"| I["直接由超热缓存响应\n不穿透到后端存储"]
    H -->|"未命中"| J["继续往后层存储查询"]

参考来源

- 位置:《高可用架构(第1卷)》第3章《电商架构热点专题》"3.2 大促系统全流量压测及稳定性保证——京东交易架构"节,"3.2.5 应对大促的第2步:根据压力表现进行调优"(源文件:_epub-src/OEBPS/Text/Chapter3_2_6.xhtml) - 结论依据:原文说明"我们利用Queue的原理,不断往里塞SKU,队列的长只有50……传进来之后,有的位置会往前移,我们能很快地在一秒内知道,排在前面的SKU肯定是访问次数最多的……如果是秒杀商品,在500万的请求中会有10~20万,它大部分的请求肯定在这块就出去了,不会穿透进来",直接支撑本卡片结论与结构图。 - 原始内容:我们利用Queue的原理,不断往里塞SKU,队列的长只有50……传进来之后,有的位置会往前移,我们能很快地在一秒内知道,排在前面的SKU肯定是访问次数最多的,也是每一个阶段内应用存储访问最多的数据,如果是秒杀商品,在500万的请求中会有10~20万,它大部分的请求肯定在这块就出去了,不会穿透进来。