剖析JD-hotkey,我们能从中学到什么

hotkey作为开源的京东APP后台热数据探测框架,历经多次高压压测和2020年京东618、双11大促考验。据有极高的性能,下面我们就看看从源码中,我们可以学习到哪些优秀的思想。

1. 发布/订阅模型

Client端使用发布/订阅模式的实现 EventBus 组件,将规则,worker和热key 等信息变动的的监听和实际处理逻辑进行解耦。事件的生产者和消费者彼此独立,只需发布或订阅事件即可,不需要复杂的接口调用或回调机制,据有一定的清晰度跟灵活性。并且事件使用异步处理,提升了程序的响应性能。

2. 队列缓冲

以热key的上报流程为例,整体流程如下:

  • 客户端上报 热key 的netty事件
  • worker监听到对应的事件后,将热key信息 放到 QUEUE 阻塞队列里面
  • KeyConsumer 死循环 从 QUEUE 获取数据,进行热key计算。如果统计满足规则阈值,放入 hotKeyStoreQueue 阻塞队列
  • AppServerPusher 死循环 从 hotKeyStoreQueue 获取数据,推送到客户端

可以看到每两个步骤之间都使用了生产-消费模式。并且往队列里面放东西 就结束了,没有做实际复杂的逻辑,work线程又可以接着去进行处理新来的neety IO事件,解放了work线程 ,否则work线程 可能会被被热度计算过程捆绑 导致无法及时处理新来的IO事件。

同时用一个 BlockingQueue 作为任务的缓冲区,通过缓冲区实现客户端上报热key的流量控制。当队列满时,新的任务需要等待,无法直接执行。

复制代码
RocketMQ 5.0 的任意延时消息,也是用了相同的思想进行涉及的, 所以在同一时刻延时消息过多的时候, 会因为队列处理不及时, 导致延时消息延迟执行。 
同样的还有nacos 2.x 版本的事件机制实现。

3. 双map处理累计上报数据并发问题

读写容器分离的思想。避免加锁阻塞分支执行。具体代码细节可以查看:juejin.cn/post/735345...

4. 内存优化热度统计

使用循环数组队列 计算key的热度统计,具体实现可以参考:com.jd.platform.hotkey.worker.tool.SlidingWindow。

主要优势有以下几点:

scss 复制代码
空间复用: 循环数组队列的一个主要优势在于它可以复用空间。当队列的前端元素被移除时,空间不会被浪费;而是可以用于以后在队列后端添加的新元素。

性能: 循环数组队列在入队(enqueue)和出队(dequeue)操作上都提供了常数时间复杂度(O(1)),因为不需要移动其他元素,通常只涉及修改头部和尾部指针以及对数组下标进行模运算。

内存局部性: 由于循环数组队列在数组中连续存储元素,可以充分利用缓存和内存的局部性原理。

预分配: 明确窗口队列大小上限,在数组初始化时,预分配固定大小的空间可以消除队列运行时动态扩容的开销。
相关推荐
codeGoogle6 小时前
自研 IM 还是选择第三方 SDK?企业开发者应该如何权衡?
前端·后端·程序员
DLYSB_9 小时前
API 网关流量洪峰与突发 CC 攻击:我用 Go 写了个“现场物理防御哨兵”,把故障响应压缩到秒级
开发语言·后端·golang·报警灯
markinmarkin9 小时前
Spring 中Bean 的作用域有哪些?
java·后端·spring
橙子家10 小时前
使用方法 ToDictionary() 来优化查询时间复杂度:O(N*M) -> O(1*M)【C# 基础】
后端
IT_陈寒11 小时前
我又被JavaScript的隐式类型转换坑了
前端·人工智能·后端
用户83562907805111 小时前
Python Word 转 PDF 和 PDF 转 Word 指南
后端·python
用户83562907805111 小时前
如何使用 Python 加密和保护 Word 文档
后端·python
他们叫我秃子12 小时前
前端开发转 Go 全栈(五):终于遇到熟人了,Go 的闭包和高阶函数原来这么像 JavaScript
前端·后端·go
SomeB1oody12 小时前
【RustyML入门】2.6. 线性判别分析
开发语言·后端·机器学习·rust·教程
妙码生花12 小时前
从 PHP 到 AI + Golang,程序员自救转型手记(五十七):AI时代对组件封装的新理解、agInput 统一入口,动态表单预备
前端·后端·go