JD-hotkey框架处理Redis热key方案

1,244 阅读5分钟

“开启掘金成长之旅!这是我参与「掘金日新计划 · 2 月更文挑战」的第 1 天,点击查看活动详情

一、简介

京东hotkey是⼀套通⽤轻量级热key探测框架,它很轻量级,既不改redis源码也不改redis的客户端jar包,当然,它与redis没⼀点关系,完全不依赖redis。它是⼀个独⽴的系统,部署后,在server代码⾥引⼊jar,之后就像使⽤⼀个本地的HashMap⼀样来使⽤它即可。

hotkey有着强悍的性能表现,⼀台8核8G的机器,在承担该框架热key探测计算任务时(即worker服务),每秒可以处理来⾃于数千台服务器发来的⾼达16万个的待测key,8核单机吞吐量在16万,16核机器每秒可达30万以上探测量,当然前提是cpu很稳定。⾼性能代表了低成本,所以我们就可以仅仅采⽤10台机器,即可完成每秒近300万次的key探测任务,⼀旦找到了热key,那该数据的访问耗时就和redis不在⼀个数量级了。

image.png

二、hotkey框架的主要组成部分

2.1、etcd端

etcd作为⼀个⾼性能的配置中⼼,可以以极⼩的资源占⽤,提供⾼效的监听订阅服务。主要⽤于存放规则配置,各worker的ip地址,以及探测出的热key、⼿⼯添加的热key等。

2.2、dashboard

控制台是⼀个带可视化界⾯的Java程序,也是连接到etcd,之后在控制台设置各个APP的key规则,譬如2秒出现20次算热key。然后当worker探测出来热key后,会将key发往etcd,dashboard也会监听热key信息,进⾏⼊库保存记录。同时,dashboard也可以⼿⼯添加、删除热key,供各个client端监听。

2.3、worker

worker端是⼀个独⽴部署的Java程序,启动后会连接etcd,并定期上报⾃⼰的ip信息,供client端获取地址并进⾏⻓连接。之后,主要就是对各个client发来的待测key进⾏累加计算,当达到etcd⾥设定的rule阈值后,将热key推送各个client。

2.4、client

就是在服务中添加的引⽤jar,引⼊后,就可以以便捷的⽅式去判断某key是否热key。同时,该jar完成了key上报、监听etcd⾥的rule变化、worker信息变化、热key变化,对热key进⾏本地caffeine缓存等。

三、hotkey安装和使用

jd-hotkey源码下载地址:gitee.com/jd-platform…

3.1、安装etcd

在etcd下载页面下载对应操作系统的etcd,github.com/etcd-io/etc… 使用3.4.x以上。

安装完成后启动命令(单机): nohup /tmp/etcd-download-test/etcd --listen-client-urls 'http://0.0.0.0:2379' --advertise-client-urls 'http://0.0.0.0:2379' 2>&1 &

查看节点状态:/tmp/etcd-download-test/etcdctl --write-out=table --endpoints=localhost:2379 endpoint status

image.png

3.2、启动worker

下载并编译好代码,将worker打包为jar,启动即可。

命令:nohup java -jar worker-0.0.4-SNAPSHOT.jar --etcd.server=localhost:2379 --thread.count=8 2>&1 &

3.3、部署dashboard项目

下载并编译好dashboard项目,创建数据库并导入resource下db.sql文件。 配置一下application.yml里的数据库相关和etcdServer地址。

启动dashboard项目,访问ip:8081,即可看到界面

⽤户名/密码:admin/123456

image.png

新增规则:

image.png

如图就是一组规则,譬如其中test开头的热key的规则就是interval-5秒内出现了threshold-50次就认为它是热key,它就会被推送到jvm内存中,并缓存60秒,prefix-true代表前缀匹配。那么在应用中,就可以把一组key,都用test开头,用来探测。

3.4、client端使用

引入client的pom依赖:

<dependency>
<groupId>com.jd.platform.hotkey</groupId>
<artifactId>hotkey-client</artifactId>
<version>${hotkey.version}</version>
</dependency>

hotkey相关配置

hotkey:
app-name: careerplan-redis
# etcd服务器地址,集群⽤逗号分隔
etcd-server: http://ip:2379
# 设置本地缓存最⼤数量,默认5万
caffeine-size: 50000
# 批量推送key的间隔时间,默认500ms,该值越⼩,上报热key越频繁,相应越及时,建议根据实
际情况调整
# 如单机每秒qps10个,那么0.5秒上报⼀次即可,否则是空跑。该值最⼩为1,即1ms上报⼀次。
push-period: 500

初始化hotkey

@PostConstruct

public void initHotkey() {

    ClientStarter.Builder builder = new ClientStarter.Builder();
    ClientStarter starter = builder.setAppName("appName").setEtcdServer("http://ip:2379,http://ip:2379,http://ip:2379").build();
    starter.startPipeline();
}
...

hotkey主要方法有:

boolean JdHotKeyStore.isHotKey(String key)

Object JdHotKeyStore.get(String key)

void JdHotKeyStore.smartSet(String key, Object value)

Object JdHotKeyStore.getValue(String key)

1 boolean isHotKey(String key) ,该方法会返回该key是否是热key,如果是返回true,如果不是返回false,并且会将key上报到探测集群进行数量计算。该方法通常用于判断只需要判断key是否热、不需要缓存value的场景,如刷子用户、接口访问频率等。

2 Object get(String key),该方法返回该key本地缓存的value值,可用于判断是热key后,再去获取本地缓存的value值,通常用于redis热key缓存

3 void smartSet(String key, Object value),方法给热key赋值value,如果是热key,该方法才会赋值,非热key,什么也不做

4 Object getValue(String key),该方法是一个整合方法,相当于isHotKey和get两个方法的整合,该方法直接返回本地缓存的value。 如果是热key,则存在两种情况,1是返回value,2是返回null。返回null是因为尚未给它set真正的value,返回非null说明已经调用过set方法了,本地缓存value有值了。 如果不是热key,则返回null,并且将key上报到探测集群进行数量探测。

检测出的实时热点:

image.png