基于Redis内核的热key统计实现方案|得物技术

一、Redis热key介绍

Redis热key问题是指单位时间内,某个特定key的访问量特别高,占用大量的CPU资源,影响其他请求并导致整体性能降低。而且,如果访问热key的命令是时间复杂度较高的命令,会使得CPU消耗变得更加严重;或者,如果访问的热key同时也是一个大key,也可能使得访问流量达到节点所在机器带宽上限。

二、Redis热key常见探测方法

突发的热点新闻、爆款商品、或者促销活动都可能导致访问热key的出现,目前,Redis官方和业界也都有不少热key探测与发现方法。

先通过一个表格整体预览一下当前存在的热key探测方案优缺点

Redis-cli的hotkeys参数

Redis自4.0起在Redis-cli中提供了hotkeys参数来方便用户进行实例级的热key分析功能,Redis-cli通过向Redis-server节点发送scan + object freq命令以遍历的方式分析Redis实例中所有key,然后返回实例中热key信息。

该方式存在以下几个问题:

  1. 使用该方案的前提条件是需要将Redis-server的淘汰策略maxmemory-policy参数设置为LFU(volatile-lfu或allkeys-lfu)
  2. 实时性差。由于需要扫描整个keyspace,实时性较差,扫描时间与key数量正相关,如果key数量比较多,耗时可能会非常长。
  3. 信息不够丰富。首先记录的访问频率是一个与访问次数的对数成比例的相关近似值,不能够很直观的看出来热key的访问频率;另外,返回的信息中也没有key的类型和热key出现的时间等。

monitor命令统计

Redis提供monitor命令可以实时抓取出Redis服务器接收到的命令,可以对抓取的数据结合一些现成的分析工具(比如Redis-faina)统计出抓取时间段内的访问热key。

该方式存在以下几个问题:

  1. 该命令在高并发的条件下,有内存增暴增的隐患,还会降低Redis的性能,只能紧急情况下短暂使用,不能长时间使用。
  2. 该方式只能统计开启monitor命令的期间访问热key情况,对于过去已经发生的访问热key无法获取,无法应对一些瞬时的突发热key等情况。

Redis节点抓包分析

Redis客户端使用TCP协议与服务端进行交互,并且通信协议采用自定义的RESP协议,可以使用libpcap库对Redis-server监听端口抓包,然后按照RESP协议解析数据,并统计抓包期间内访问的热key。

该方式存在以下几个问题:

  1. 该方式实现相对比较复杂,有一定的开发成本。
  2. 同样只能统计开启抓包期间的访问热key情况,无法获取过去的热key。
  3. 开启期间对访问Redis-server性能有一定的损耗,而且ECS一般会部署多个Redis-server,全量开启会对系统负载有一定影响,因此无法长时间开启进行实时处理。

Client/Proxy端收集

可以对客户端工具进行封装,在发送请求前进行收集采集,同时定时把收集到的数据上报到统一的服务进行聚合计算。或者,如果业务通过Proxy访问缓存的话,可以在Proxy上进行收集,其他思路与Client端收集模式一致。

目前,比如,有赞自研分布式缓存系统zanKV、京东零售开源的热key探测框架(JD-hotkey)、得物热点探测框架(Burning)都是类似这种方案,在客户端进行收集,在聚合中心worker节点上进行热key统计,统计出来的热key可以推送到客户端进行本地缓存。

该方式存在以下几个问题:

  1. 在客户端收集的方案对客户端代码有一定的侵入,而且每种语言的SDK都需要进行开发,后期开发维护成本较高。
  2. 框架比较复杂,开发成本高。由于同一个key的访问可能同时出现在多个不同的客户端或者Proxy上,因此,在单个客户端或者Proxy上是无法统计热key的,因此,该方案需要一个聚合中心计算平台,收集不同Client/Proxy上访问的key,然后计算热key信息。

下图为京东开源的热key探测框架系统架构图:

三、基于Redis内核的热key统计

从上面的分析可以看到,目前存在的一些方案,要么无法高效快速的获取实时热key信息,要么架构比较复杂或者对业务有一定的侵入,得物自建Redis设计并研发基于Redis内核的热key统计方案,可以高效的统计并记录Redis实时热key信息,同时提供热key产生与热key失效的订阅通知。

实现原理简介

基于内核的Redis热key统计方案在Redis-server端实现,包含热key统计模块和热key通知模块两部分,另外提供热key日志记录查询与重置命令。

热key统计模块基于LRU队列实现统计key每秒内访问次数,当访问次数达到设置的热key阈值时,被判定为热key,热key加入热key队列用于提供实时查询。

基于内核的Redis热key统计方案提供热key订阅与主动通知功能,提供读热key、写热key、热key失效三个订阅通道channel,可用于Client/Proxy订阅热key消息,当key被判定为热key时,Redis-server主动向对应的消息通道广播热key消息。

实现原理图如下所示:

实现流程图

热key统计

为了能够高效进行热key统计,并且不消耗过多内存资源,在Redis中使用一个固定大小的LRU队列(大小可配置)来进行热key统计,记录数据结构采用了非常紧凑的格式设计,每个key的统计操作都是O(1)时间复杂度,保证高效统计的同时,统计工作消耗的内存资源不会随着Redis中存储的key数量增长而增长。

LRU队列中用于统计key访问记录的数据结构如下:

#define HOTKEY_NOTIFIED_BIT 1
#define ACCESS_COUNT_BITS 16
#define ACCESS_TIME_BITS 46typedef struct hotkeyRecord {uint64_t notified:HOTKEY_NOTIFIED_BIT;      // 热key是否通知或记录日志uint64_t same_period:HOTKEY_NOTIFIED_BIT;   // 每秒一个统计周期,同一个key每秒最多发送一次热key通知uint64_t count:ACCESS_COUNT_BITS;           // 热key计数uint64_t access_time:ACCESS_TIME_BITS;      // 热key计数记录起始时间,单位:毫秒
} hotkeyRecord;

热key统计默认以每秒一个周期,统计每个key在每秒时间内的访问次数,当每秒访问次数达到一定的阈值(阈值大小可配置)时,认定为是热key;同时,同一个时间周期内(即同一秒内)同一个key只记录一次热key,连续多次的不同时间周期内,同一个key连续出现热key现象会多次记录,同时,记录热key出现的时间与访问次数。

热key统计区分读热key与写热key,方便业务进行缓存或者其他相关处理。

被判定为热key的记录,会加入热key队列记录日志,可供查询,管控平台通过查询热key日志队列可以展示Redis-server节点实时热key信息;热key日志记录包括热key出现的时间、访问次数、key类型、读操作还是写操作等信息。

热key日志队列记录数据结构如下所示:

#define HOTKEY_NOTIFIED_BIT 1
#define ACCESS_COUNT_BITS 16
#define LOG_TIME_BITS 46typedef struct hotkeyLogEntry {uint64_t notified:HOTKEY_NOTIFIED_BIT;uint64_t access_count:ACCESS_COUNT_BITS; // 热key计数uint64_t access_time:LOG_TIME_BITS;   // 热key计数记录起始时间,单位:毫秒unsigned type;void *key;
} hotkeyLogEntry;

热key通知

基于内核的Redis热key统计方案支持订阅模块与热key主动通知功能。

Redis-server提供读热key、写热key、热key失效三个订阅通道channel,可用于Client或者Proxy订阅热key相关消息;当出现读写热key时,Redis-server主动向对应的订阅通道广播热key消息;当一个热key出现写操作时,会向热key失效订阅通道广播key失效消息。

热key类型定义数据结构如下所示:

/* hotkey type */
#define READ_HOTKEY_NOTIFY 0
#define READ_HOTKEY_INVALID 1
#define WRITE_HOTKEY_NOTIFY 2

热key记录查询与重置命令

除了通过订阅通道主动通知外,Redis-server提供热key日志记录查询与重置命令,可供平台查询进行展示或者操作。

读命令热key查询与重置

可以查询指定长度的日志、或者从指定位置查询指定长度的日志:

// 查询读热 key 日志长度
readHotkeyLog len
// 重置清空读热 key 日志
readHotkeyLog reset
// 查询读热 key 日志
readHotkeyLog get                   // 查询默认长度,从日志队列头部开始查询数据
readHotkeyLog get [len]             // 查询指定长度,从日志队列头部开始查询数据
readHotkeyLog get [index] [len]     // 从指定 index 开始查询指定长度

写命令热key查询与重置

可以查询指定长度的日志、或者从指定位置查询指定长度的日志:

// 查询写热 key 日志长度
writeHotkeyLog len
// 重置清空写热 key 日志
writeHotkeyLog reset
// 查询写热 key 日志
writeHotkeyLog get                   // 查询默认长度,从日志队列头部开始查询数据
writeHotkeyLog get [len]             // 查询指定长度,从日志队列头部开始查询数据
writeHotkeyLog get [index] [len]     // 从指定 index 开始查询指定长度

四、总结

Redis热key是在Redis使用过程中一个比较常见的现象,同时,热key的实时探测与解决一直是业界的一个难点问题。得物自建Redis结合当前各种热key探测方案的优缺点,实现基于Redis内核的高性能实时热key统计方案。该方案具备如下优点:

  • 实时性强:可实时统计热key信息,统计粒度为每秒
  • 热key信息详细:热key信息包含热key出现的时间、访问次数、key类型、读操作或写操作等信息
  • 支持订阅与查询:支持读热key、写热key、热key失效三种类型通知,可查询热key日志记录

往期回顾

1.解析Go切片:为何按值传递时会发生改变?|得物技术

2.得物彩虹桥架构演进之路-负载均衡篇

3.得物精准测试平台设计与实现

4.基于IM场景下的Wasm初探:提升Web应用性能|得物技术

5.Java性能测试利器:JMH入门与实践|得物技术

文 / Miro

关注得物技术,每周一、三更新技术干货

要是觉得文章对你有帮助的话,欢迎评论转发点赞~

未经得物技术许可严禁转载,否则依法追究法律责任。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/887541.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

鸿蒙安全控件之位置控件简介

位置控件使用直观且易懂的通用标识,让用户明确地知道这是一个获取位置信息的按钮。这满足了授权场景需要匹配用户真实意图的需求。只有当用户主观愿意,并且明确了解使用场景后点击位置控件,应用才会获得临时的授权,获取位置信息并…

鸿蒙主流路由详解

鸿蒙主流路由详解 Navigation Navigation更适合于一次开发,多端部署,也是官方主流推荐的一种路由控制方式,但是,使用起来入侵耦合度高,所以,一般会使用HMRouter,这也是官方主流推荐的路由 Navigation官网地址 个人源码地址 路由跳转 第一步-定义路由栈 Provide(PageInfo) pag…

spring boot有那些优势?

Spring Boot 作为 Spring 框架的一个扩展,旨在简化新 Spring 应用程序的初始搭建以及开发过程。它通过提供一系列默认配置来快速启动基于 Spring 的应用,并且减少了大量的样板代码和配置工作。以下是使用 Spring Boot 的一些主要优势: 简化配…

Jackson库中JsonInclude的使用

简介 JsonInclude是 Jackson 库(Java 中用于处理 JSON 数据的流行库)中的一个注解。它用于控制在序列化 Java 对象为 JSON 时,哪些属性应该被包含在 JSON 输出中。这个注解提供了多种策略来决定属性的包含与否,帮助减少不必要的数…

JavaFX:简介、使用场景、常见问题及对比其他框架分析

1. JavaFX 简介 1.1 什么是 JavaFX? JavaFX 是一个基于 Java 的 GUI 工具包,支持创建桌面和互联网应用。它通过 Scene Graph(场景图)模型渲染 UI 元素,并采用声明式编程风格。自 JDK 11 起,JavaFX 被移除…

88页精品PPT | 某电信集团大数据平台建设方案技术交流

这份PPT文档是关于某电信集团大数据平台建设的技术交流方案,内容涵盖了现状分析、规划思路、产品设计、成功案例以及干货附录等多个部分。文档详细介绍了集团大数据平台的建设背景、技术特点、面临的挑战和痛点,以及具体的技术架构和实施策略。还包括了数…

Java设计模式笔记(一)

Java设计模式笔记(一) (23种设计模式由于篇幅较大分为两篇展示) 一、设计模式介绍 1、设计模式的目的 让程序具有更好的: 代码重用性可读性可扩展性可靠性高内聚,低耦合 2、设计模式的七大原则 单一职…

在使用PCA算法进行数据压缩降维时,如何确定最佳维度是一个关键问题?

一、PCA算法的基本原理 PCA算法的核心思想是通过正交变换,将一组可能相关的变量转换成一组线性不相关的变量,称为主成分。这组主成分能够以最小的信息损失来尽可能多地保留原始数据集的变异性。具体来说,PCA算法包括以下几个步骤&#xff1a…

shodan(7)

声明! 学习视频来自B站up主 泷羽sec 有兴趣的师傅可以关注一下,如涉及侵权马上删除文章,笔记只是方便各位师傅的学习和探讨,文章所提到的网站以及内容,只做学习交流,其他均与本人以及泷羽sec团队无关&#…

三维地形图计算软件(三)-原基于PYQT5+pyqtgraph旧代码

最先入手设计三维地形图及平基挖填方计算软件时,地形图的显示方案是:三维视图基于pyqtgraph.opengl显示和二维视图基于pyqtgraph的PlotWidget来显示地形地貌,作到一半时就发现,地形点过多时,将会造成系统卡顿(加载时主…

从入门到精通数据结构----四大排序(上)

目录 首言: 1. 插入排序 1.1 直接插入排序 1.2 希尔排序 2. 选择排序 2.1 直接选择排序 2.2 堆排序 3. 交换排序 3.1 冒泡排序 3.2 快排 结尾: 首言: 本篇文章主要介绍常见的四大排序:交换排序、选择排序、插入排序、归并排…

集合Queue、Deque、LinkedList、ArrayDeque、PriorityQueue详解

1、 Queue与Deque的区别 在研究java集合源码的时候,发现了一个很少用但是很有趣的点:Queue以及Deque; 平常在写leetcode经常用LinkedList向上转型Deque作为栈或者队列使用,但是一直都不知道Queue的作用,于是就直接官方…

Qwen2.5-7B大模型微调记录

Qwen2.5-7B大模型微调记录 研究需要,需要搞一个大模型出来,没有太多的时间自己训练,准备用现成的开源大模型,然后结合研究方向进行微调 前前后后折腾大半个月,总算做完了第一个微调的大模型,模型基于阿里…

Spring Boot 开发环境搭建及示例应用

文章目录 1. 准备开发工具安装 JDK安装 IDE安装 Maven 2. 创建 Spring Boot 项目使用 Spring Initializr 创建项目导入项目到 IDE 3. 编写代码主类创建控制器创建实体类创建仓库接口创建服务类创建控制器 4. 配置文件5. 运行应用程序6. 测试应用程序7. 调试与优化8. 部署应用 1…

CentOS Docker 安装

CentOS Docker 安装 1. 简介 CentOS 是一个基于 Red Hat Enterprise Linux (RHEL) 的开源操作系统,广泛用于服务器环境。Docker 是一个开源的应用容器引擎,它允许开发者打包他们的应用以及依赖包到一个可移植的容器中,然后发布到任何流行的…

docker 的各种操作

Docker pull拉取镜像报错“Error response from daemon: Get "https://registry-1.docker.io/v2”解决办法: 解决方法:将 /etc/docker/daemon.json 中的"registry-mirrors"的内容换成如下内容 { "registry-mirrors": [ "…

在xml的sql的子查询中使用row_number over之后再在mapper的接口层传入Page对象实现分页功能,出现Bug

1.报错信息复现&#xff1a; Mapper接口&#xff1a; List<UserInfo> queryUserPage(Param(“vo”) UserQury query,Page<UserInfo> page); UserQury 类中的状态字段&#xff1a; ApiModelproperty(“状态”) private String status; Xml中sql如下&#xff1…

动态规划之背包问题

0/1背包问题 1.二维数组解法 题目描述&#xff1a;有一个容量为m的背包&#xff0c;还有n个物品&#xff0c;他们的重量分别为w1、w2、w3.....wn&#xff0c;他们的价值分别为v1、v2、v3......vn。每个物品只能使用一次&#xff0c;求可以放进背包物品的最大价值。 输入样例…

蓝桥杯模拟题不知名题目

题目:p是一个质数&#xff0c;但p是n的约数。将p称为是n的质因数。求2024最大质因数。 #include<iostream> #include<algorithm> using namespace std; bool fun(int x) {for(int i 2 ; i * i < x ; i){if(x % i 0)return false;}return true; } int main() …

JavaFX 表格组件详解及案例

1. 表格组件简介 TableView&#xff1a;用于显示数据的二维表格&#xff0c;支持列排序、选择、编辑等功能。TreeTableView&#xff1a;类似于 TableView&#xff0c;但支持分层数据展示&#xff0c;适合树形结构的数据。 2. TableView 的常用方法 2.1 构造方法 TableView()…