hotkey 是京东APP后台热数据探测框架,在上线运行的这段时间内,每天探测的 key 数量数十亿计,精准捕获了大量爬虫、刷子用户,另准确探测大量热门商品并毫秒级推送到各个服务端内存,大幅降低了热数据对数据层的查询压力,提升了应用性能。在大促期间,hotkey 的 worker 集群秒级吞吐量达到 1500 万级别
前言
hotkey 是京东APP后台热数据探测框架,历经多次高压压测和京东 618、双 11 大促考验。
示例:hotkey 是京东APP后台热数据探测框架,历经多次高压压测和京东 618、双 11 大促考验。
二、使用步骤
1.安装依赖
首先他的核心组件分为Etcd集群,client端的jar包,worker端集群,dashboard控制台
首先就是安装Etcd集群,HotKey代码等等
通过网盘分享的文件:HotKey
链接: https://pan.baidu.com/s/1gfcVk253hyOkK51ff1TwzQ?pwd=th8q 提取码: th8q
--来自百度网盘超级会员v6的分享
接下来就是修改配置了
首先打开HotKey项目
修改合适的端口数据
接下来运行Etcd
执行 etcd 脚本后,可以启动 etcd 服务,服务默认占用 2379 和 2380 端口,作用分别如下
- 2379:提供 HTTP API 服务,和 etcdctl 交互
- 2380:集群中节点间通讯
接下来先运行
写HotKey需要的数据库
create database hotkey_db;
use hotkey_db;
DROP TABLE IF EXISTS `hk_change_log`;
CREATE TABLE `hk_change_log` (
`id` int(11) NOT NULL AUTO_INCREMENT COMMENT '主键',
`biz_id` varchar(128) CHARACTER SET utf8 COLLATE utf8_bin NOT NULL COMMENT '业务key',
`biz_type` int(11) NOT NULL COMMENT '业务类型:1规则变更;2worker变更',
`from_str` varchar(1024) CHARACTER SET utf8 COLLATE utf8_bin NOT NULL DEFAULT '' COMMENT '原始值',
`to_str` varchar(1024) CHARACTER SET utf8 COLLATE utf8_bin NOT NULL DEFAULT '' COMMENT '目标值',
`app_name` varchar(32) CHARACTER SET utf8 COLLATE utf8_bin NOT NULL DEFAULT '' COMMENT '数据所属APP',
`update_user` varchar(32) CHARACTER SET utf8 COLLATE utf8_bin NOT NULL DEFAULT '' COMMENT '修改人',
`create_time` datetime(0) NOT NULL ON UPDATE CURRENT_TIMESTAMP(0) COMMENT '创建时间',
`uuid` varchar(128) CHARACTER SET utf8 COLLATE utf8_bin NOT NULL COMMENT '防重ID',
PRIMARY KEY (`id`) USING BTREE,
UNIQUE INDEX `uniq_uuid`(`uuid`) USING BTREE COMMENT '防重索引'
) ENGINE = InnoDB AUTO_INCREMENT = 29 CHARACTER SET = utf8 COLLATE = utf8_bin ROW_FORMAT = Compact;
DROP TABLE IF EXISTS `hk_user`;
CREATE TABLE `hk_user` (
`id` int(11) NOT NULL AUTO_INCREMENT COMMENT 'id',
`nick_name` varchar(32) CHARACTER SET utf8 COLLATE utf8_bin NOT NULL DEFAULT '' COMMENT '昵称',
`user_name` varchar(32) CHARACTER SET utf8 COLLATE utf8_bin NOT NULL DEFAULT '' COMMENT '用户名',
`pwd` varchar(64) CHARACTER SET utf8 COLLATE utf8_bin NOT NULL DEFAULT '' COMMENT '密码',
`phone` varchar(16) CHARACTER SET utf8 COLLATE utf8_bin NOT NULL DEFAULT '' COMMENT '手机号',
`role` varchar(16) CHARACTER SET utf8 COLLATE utf8_bin NOT NULL DEFAULT '' COMMENT '角色:ADMIN-超管,APPADMIN-app管理员,APPUSER-app用户',
`app_name` varchar(64) CHARACTER SET utf8 COLLATE utf8_bin NOT NULL DEFAULT '' COMMENT '所属appName',
`create_time` datetime(0) NOT NULL ON UPDATE CURRENT_TIMESTAMP(0) COMMENT '创建时间',
`state` int(11) NOT NULL DEFAULT 1 COMMENT '状态:1可用;0冻结',
PRIMARY KEY (`id`) USING BTREE,
UNIQUE INDEX `uniq_userName`(`user_name`) USING BTREE COMMENT '账号唯一索引'
) ENGINE = InnoDB AUTO_INCREMENT = 2 CHARACTER SET = utf8 COLLATE = utf8_bin ROW_FORMAT = Compact;
-- pwd: 123456
INSERT INTO `hk_user` VALUES (2, 'admin', 'admin', 'e10adc3949ba59abbe56e057f20f883e', '1888888', 'ADMIN', '', '2020-07-28 14:01:03', 1);
DROP TABLE IF EXISTS `hk_key_record`;
CREATE TABLE `hk_key_record` (
`id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT '主键',
`key_name` varchar(128) CHARACTER SET utf8 COLLATE utf8_bin NOT NULL DEFAULT '' COMMENT 'key',
`app_name` varchar(64) CHARACTER SET utf8 COLLATE utf8_bin NOT NULL DEFAULT '' COMMENT '所属appName',
`val` varchar(2048) CHARACTER SET utf8 COLLATE utf8_bin NOT NULL DEFAULT '' COMMENT 'value',
`duration` int(11) NOT NULL DEFAULT 60 COMMENT '缓存时间',
`source` varchar(32) CHARACTER SET utf8 COLLATE utf8_bin NOT NULL DEFAULT '' COMMENT '来源',
`type` int(11) NOT NULL DEFAULT 1 COMMENT '记录类型:1put;2del; -1unkonw',
`create_time` datetime(0) NOT NULL ON UPDATE CURRENT_TIMESTAMP(0) COMMENT '创建时间',
`uuid` varchar(255) CHARACTER SET utf8 COLLATE utf8_bin NOT NULL DEFAULT '' COMMENT '防重ID',
`rule` varchar(64) CHARACTER SET utf8 COLLATE utf8_bin NOT NULL DEFAULT '''' COMMENT '规则',
PRIMARY KEY (`id`) USING BTREE,
UNIQUE INDEX `uniq_key`(`uuid`) USING BTREE COMMENT '唯一索引'
) ENGINE = InnoDB AUTO_INCREMENT = 3 CHARACTER SET = utf8 COLLATE = utf8_bin ROW_FORMAT = Compact;
DROP TABLE IF EXISTS `hk_key_timely`;
CREATE TABLE `hk_key_timely` (
`id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT '主键',
`key_name` varchar(128) CHARACTER SET utf8 COLLATE utf8_bin NOT NULL DEFAULT '' COMMENT 'key',
`val` varchar(2048) CHARACTER SET utf8 COLLATE utf8_bin NOT NULL DEFAULT '' COMMENT 'value',
`uuid` varchar(128) CHARACTER SET utf8 COLLATE utf8_bin NOT NULL DEFAULT '' COMMENT '防重ID',
`app_name` varchar(64) CHARACTER SET utf8 COLLATE utf8_bin NOT NULL DEFAULT '' COMMENT '所属appName',
`duration` int(11) NOT NULL DEFAULT 0 COMMENT '缓存时间',
`create_time` datetime(0) NOT NULL ON UPDATE CURRENT_TIMESTAMP(0) COMMENT '创建时间',
PRIMARY KEY (`id`) USING BTREE,
UNIQUE INDEX `uniq_key`(`uuid`) USING BTREE COMMENT '唯一索引'
) ENGINE = InnoDB AUTO_INCREMENT = 8 CHARACTER SET = utf8 COLLATE = utf8_bin ROW_FORMAT = Compact;
CREATE TABLE `hk_statistics` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`key_name` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin NOT NULL COMMENT 'keyName',
`count` int(11) NOT NULL COMMENT '计数',
`app` varchar(30) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin NULL DEFAULT NULL COMMENT 'app',
`days` int(11) NOT NULL COMMENT '天数',
`hours` bigint(11) NOT NULL COMMENT '小时数',
`minutes` bigint(11) NOT NULL DEFAULT 0 COMMENT '分钟数',
`biz_type` int(2) NOT NULL COMMENT '业务类型',
`rule` varchar(180) NOT NULL COMMENT '所属规则',
`uuid` varchar(180) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin NOT NULL COMMENT '防重ID',
`create_time` datetime(0) NOT NULL COMMENT '创建时间',
PRIMARY KEY (`id`) USING BTREE,
UNIQUE INDEX `uniq_uuid`(`uuid`) USING BTREE COMMENT '防重唯一索引'
) ENGINE = InnoDB AUTO_INCREMENT = 1 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_bin ROW_FORMAT = Compact;
CREATE TABLE `hk_rules` (
`id` int(11) NOT NULL AUTO_INCREMENT COMMENT '主键',
`rules` varchar(5000) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin NOT NULL COMMENT '规则JSON',
`app` varchar(30) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin NOT NULL DEFAULT '' COMMENT '所属APP',
`update_user` varchar(30) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin NOT NULL DEFAULT '' COMMENT '修改人',
`update_time` datetime(0) NOT NULL ON UPDATE CURRENT_TIMESTAMP(0) COMMENT '修改时间',
`version` int(11) NOT NULL DEFAULT 0 COMMENT '版本号',
PRIMARY KEY (`id`) USING BTREE,
UNIQUE INDEX `uniq_app`(`app`) USING BTREE COMMENT '防重索引'
) ENGINE = InnoDB AUTO_INCREMENT = 15 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_bin ROW_FORMAT = Compact;
CREATE TABLE `hk_summary` (
`id` int(11) NOT NULL AUTO_INCREMENT COMMENT '主键',
`index_name` varchar(32) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin NOT NULL DEFAULT '' COMMENT '指标名称',
`rule` varchar(32) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin NOT NULL DEFAULT '' COMMENT '规则',
`app` varchar(32) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin NOT NULL DEFAULT '' COMMENT 'app',
`index_val1` int(11) NOT NULL DEFAULT 0 COMMENT '指标值1',
`index_val2` int(11) NOT NULL DEFAULT 0 COMMENT '指标值2',
`index_val3` decimal(10, 2) NOT NULL DEFAULT 0.00 COMMENT '指标值3',
`days` int(11) NOT NULL DEFAULT 0 COMMENT '天数',
`hours` int(11) NOT NULL DEFAULT 0 COMMENT '小时数',
`minutes` bigint(11) NOT NULL DEFAULT 0 COMMENT '分钟数',
`seconds` bigint(11) NOT NULL DEFAULT 0 COMMENT '秒数',
`biz_type` tinyint(2) NOT NULL DEFAULT 0 COMMENT '类型',
`uuid` varchar(128) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin NOT NULL DEFAULT '' COMMENT '防重ID',
`create_time` datetime(0) NOT NULL COMMENT '创建时间',
`update_time` datetime(0) NULL DEFAULT NULL ON UPDATE CURRENT_TIMESTAMP(0) COMMENT '修改时间',
PRIMARY KEY (`id`) USING BTREE,
UNIQUE INDEX `uniq_uuid`(`uuid`) USING BTREE COMMENT '防重索引',
INDEX `idx_apprule`(`app`, `rule`) USING BTREE COMMENT '查询索引',
INDEX `ix_ct`(`create_time`) USING BTREE COMMENT '时间索引'
) ENGINE = InnoDB AUTO_INCREMENT = 18 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_bin COMMENT = '汇总表' ROW_FORMAT = Compact;
/* 请确认以下SQL符合您的变更需求,务必确认无误后再提交执行 */
CREATE TABLE `biz_access_token` (
`id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT '主键',
`token` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL DEFAULT '' COMMENT 'token',
`flag` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL DEFAULT '' COMMENT 'flag',
`CREATED_BY` varchar(128) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL COMMENT '创建人',
`CREATED_TIME` datetime NULL ON UPDATE CURRENT_TIMESTAMP COMMENT '创建时间',
`UPDATED_BY` varchar(128) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL COMMENT '修改人',
`UPDATED_TIME` datetime NULL ON UPDATE CURRENT_TIMESTAMP COMMENT '修改时间',
PRIMARY KEY (`id`)
) ENGINE = InnoDB AUTO_INCREMENT = 1 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_bin COMMENT = '咚咚token表' ROW_FORMAT = Compact;
再运行
http://localhost:8121/此时就可以看到界面了
输入管理员的账号密码(admin,123456)后,即可成功登录:
初次使用时需要先添加 APP。建议先在用户管理菜单中,添加一个新用户,设置昵称为 APP 名称、并填写所属 APP,如 XXX,密码此处就设置为 123456。之后就可以登录这个新建的用户来给应用设置规则了 (当然也可以使用 admin 账户添加),而且系统会自动创建一个 APP
随后,在规则配置中,选择对应的 APP,新增对应的热点探测规则:
[
{
"duration":600,
"key":"bank_detail_",
"prefix":true,
"interval":5,
"threshold":10,
"desc":"热门题库缓存"
}
]
接下来配置一组规则,如上所示,请修改为自己的就可以
此时在自己的项目中创建lab目录,然后引入上面百度网盘的jar包
自己的项目中引入maven
<dependency>
<artifactId>hotkey-client</artifactId>
<groupId>com.jd.platform.hotkey</groupId>
<version>0.0.4-SNAPSHOT</version>
<scope>system</scope>
<systemPath>${project.basedir}/lib/hotkey-client-0.0.4-SNAPSHOT.jar</systemPath>
</dependency>
添加配置类
@Configuration
@ConfigurationProperties(prefix = "hotkey")
@Data
public class HotKeyConfig {
/**
* Etcd 服务器完整地址
*/
private String etcdServer = "http://127.0.0.1:2379";
/**
* 应用名称
*/
private String appName = "app";
/**
* 本地缓存最大数量
*/
private int caffeineSize = 10000;
/**
* 批量推送 key 的间隔时间
*/
private long pushPeriod = 1000L;
/**
* 初始化 hotkey
*/
@Bean
public void initHotkey() {
ClientStarter.Builder builder = new ClientStarter.Builder();
ClientStarter starter = builder.setAppName(appName)
.setCaffeineSize(caffeineSize)
.setPushPeriod(pushPeriod)
.setEtcdServer(etcdServer)
.build();
starter.startPipeline();
}
}
添加application.yml配置
# 热 key 探测
hotkey:
app-name: mianshiya
caffeine-size: 10000
push-period: 1000
etcd-server: http://localhost:2379
2.运行项目
方法介绍
1)boolean isHotKey(String key)1685493154377109506_0.5237384609427116
该方法会返回该 key 是否是热 key,如果是返回 true,如果不是返回 false,并且会将 key 上报到探测集群进行数量计算。该方法通常用于判断只需要判断 key 是否热、不需要缓存 value 的场景,如刷子用户、接口访问频率等。
2)Object get(String key)
该方法返回该 key 本地缓存的 value 值,可用于判断是热 key 后,再去获取本地缓存的 value 值,通常用于 redis 热 key 缓存。1685493154377109506_0.4639330640606676
3)void smartSet(String key, Object value)
方法给热 key 赋值 value,如果是热 key,该方法才会赋值,非热 key,什么也不做
4)Object getValue(String key)1685493154377109506_0.9883136813690505
该方法是一个整合方法,相当于 isHotKey 和 get 两个方法的整合,该方法直接返回本地缓存的 value。 如果是热 key,则存在两种情况
- 是返回 value
- 是返回 null
返回 null 是因为尚未给它 set 真正的 value,返回非 null 说明已经调用过 set 方法了,本地缓存 value 有值了。 如果不是热 key,则返回 null,并且将 key 上报到探测集群进行数量探测。
在需要的地方添加热key
//生成热key
String key = "bank_detail_"+id;
//如果是热key
if(JdHotKeyStore.isHotKey(key)){
Object cacheQuestionBankVo = JdHotKeyStore.get(key);
if(cacheQuestionBankVo != null){
return ResultUtils.success((QuestionBankVO) cacheQuestionBankVo);
}
}
在需要返回的数据上添加
//设置本地缓存
JdHotKeyStore.smartSet(key,questionBankVO);
此时如果按照上面的配置的规则执行之后就会出现下面的热点配置