BAT经典面试题之redis的热KEY问题怎么解决

讲了几天的数据库系列的文章,大家一定看烦了,其实还没讲完。。。(以下省略一万字)。
今天我们换换口味,来写redis方面的内容,谈谈热key问题如何解决。
其实热key问题说来也很简单,就是瞬间有几十万的请求去访问redis上某个固定的key,从而压垮缓存服务的情情况。
其实生活中也是有不少这样的例子。比如XX明星结婚。那么关于XX明星的Key就会瞬间增大,就会出现热数据问题。
ps:hot key和big key问题,大家一定要有所了解。
本文预计分为如下几个部分

  • 热key问题
  • 如何发现
  • 业内方案

正文

热Key问题

上面提到,所谓热key问题就是,突然有几十万的请求去访问redis上的某个特定key。那么,这样会造成流量过于集中,达到物理网卡上限,从而导致这台redis的服务器宕机。
那接下来这个key的请求,就会直接怼到你的数据库上,导致你的服务不可用。

怎么发现热key

方法一:凭借业务经验,进行预估哪些是热key
其实这个方法还是挺有可行性的。比如某商品在做秒杀,那这个商品的key就可以判断出是热key。缺点很明显,并非所有业务都能预估出哪些key是热key。
方法二:在客户端进行收集
这个方式就是在操作redis之前,加入一行代码进行数据统计。那么这个数据统计的方式有很多种,也可以是给外部的通讯系统发送一个通知信息。缺点就是对客户端代码造成入侵。
方法三:在Proxy层做收集
有些集群架构是下面这样的,Proxy可以是Twemproxy,是统一的入口。可以在Proxy层做收集上报,但是缺点很明显,并非所有的redis集群架构都有proxy。

BAT经典面试题之redis的热KEY问题怎么解决
方法四:用redis自带命令
(1)monitor命令,该命令可以实时抓取出redis服务器接收到的命令,然后写代码统计出热key是啥。当然,也有现成的分析工具可以给你使用,比如 redis-faina。但是该命令在高并发的条件下,有内存增暴增的隐患,还会降低redis的性能。
(2)hotkeys参数,redis 4.0.3提供了redis-cli的热点key发现功能,执行redis-cli时加上–hotkeys选项即可。但是该参数在执行的时候,如果key比较多,执行起来比较慢。
方法五:自己抓包评估
Redis客户端使用TCP协议与服务端进行交互,通信协议采用的是RESP。自己写程序监听端口,按照RESP协议规则解析数据,进行分析。缺点就是开发成本高,维护困难,有丢包可能性。

以上五种方案,各有优缺点。根据自己业务场景进行抉择即可。那么发现热key后,如何解决呢?

如何解决

目前业内的方案有两种
(1)利用二级缓存
比如利用 ehcache,或者一个 HashMap都可以。在你发现热key以后,把热key加载到系统的JVM中。
针对这种热key请求,会直接从jvm中取,而不会走到redis层。
假设此时有十万个针对同一个key的请求过来,如果没有本地缓存,这十万个请求就直接怼到同一台redis上了。
现在假设,你的应用层有50台机器,OK,你也有jvm缓存了。这十万个请求平均分散开来,每个机器有2000个请求,会从JVM中取到value值,然后返回数据。避免了十万个请求怼到同一台redis上的情形。
(2)备份热key
这个方案也很简单。不要让key走到同一台redis上不就行了。我们把这个key,在多个redis上都存一份不就好了。接下来,有热key请求进来的时候,我们就在有备份的redis上随机选取一台,进行访问取值,返回数据。
假设redis的集群数量为N,步骤如下图所示

BAT经典面试题之redis的热KEY问题怎么解决
注:不一定是2N,你想取3N,4N都可以,看要求。
伪代码如下
<span class="hljs-title">const <span class="hljs-type">M = <span class="hljs-type">N * <span class="hljs-number">2
//&#x751F;&#x6210;&#x968F;&#x673A;&#x6570;
<span class="hljs-title">random = <span class="hljs-type">GenRandom(<span class="hljs-number">0, <span class="hljs-type">M)
//&#x6784;&#x9020;&#x5907;&#x4EFD;&#x65B0;key
<span class="hljs-title">bakHotKey = hotKey + &#x201C;_&#x201D; + random
<span class="hljs-class"><span class="hljs-keyword">data = redis.<span class="hljs-type">GET(<span class="hljs-title">bakHotKey)
<span class="hljs-title">if <span class="hljs-class"><span class="hljs-keyword">data == <span class="hljs-type">NULL {
    <span class="hljs-title">data = <span class="hljs-type">GetFromDB()
    <span class="hljs-title">redis.<span class="hljs-type">SET(<span class="hljs-title">bakHotKey, <span class="hljs-title">expireTime + <span class="hljs-type">GenRandom(0,5))
}
</span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span>

业内方案

OK,其实看完上面的内容,大家可能会有一个疑问。

烟哥,有办法在项目运行过程中,自动发现热key,然后程序自动处理么?

嗯,好问题,那我们来讲讲业内怎么做的。其实只有两步
(1)监控热key
(2)通知系统做处理
正巧,前几天有赞出了一篇《有赞透明多级缓存解决方案(TMC)》,里头也有提到热点key问题,我们刚好借此说明
(1)监控热key
在监控热key方面,有赞用的是方式二: 在客户端进行收集
在《有赞透明多级缓存解决方案(TMC)》中有一句话提到

TMC 对原生jedis包的JedisPool和Jedis类做了改造,在JedisPool初始化过程中集成TMC”热点发现”+”本地缓存”功能Hermes-SDK包的初始化逻辑。

也就说人家改写了jedis原生的jar包,加入了Hermes-SDK包。
那Hermes-SDK包用来干嘛?
OK,就是做 热点发现本地缓存
从监控的角度看,该包对于Jedis-Client的每次key值访问请求,Hermes-SDK 都会通过其通信模块将key访问事件异步上报给Hermes服务端集群,以便其根据上报数据进行”热点探测”。

当然,这只是其中一种方式,有的公司在监控方面用的是方式五: 自己抓包评估
具体是这么做的,先利用flink搭建一套流式计算系统。然后自己写一个抓包程序抓redis监听端口的数据,抓到数据后往kafka里丢。
接下来,流式计算系统消费kafka里的数据,进行数据统计即可,也能达到监控热key的目的。

(2)通知系统做处理
在这个角度,有赞用的是上面的解决方案一:利用二级缓存进行处理。
有赞在监控到热key后,Hermes服务端集群会通过各种手段通知各业务系统里的Hermes-SDK,告诉他们:”老弟,这个key是热key,记得做本地缓存。”
于是Hermes-SDK就会将该key缓存在本地,对于后面的请求。Hermes-SDK发现这个是一个热key,直接从本地中拿,而不会去访问集群。

除了这种通知方式以外。我们也可以这么做,比如你的流式计算系统监控到热key了,往zookeeper里头的某个节点里写。然后你的业务系统监听该节点,发现节点数据变化了,就代表发现热key。最后往本地缓存里写,也是可以的。

通知方式各种各样,大家可以自由发挥。本文只是提供一个思路。

总结

希望通过本文,大家明白如何处理生产上遇到的热key问题

Original: https://www.cnblogs.com/StarbucksBoy/p/14750195.html
Author: 陶朱公Boy
Title: BAT经典面试题之redis的热KEY问题怎么解决

原创文章受到原创版权保护。转载请注明出处:https://www.johngo689.com/615535/

转载文章受原作者版权保护。转载请注明原作者出处!

(0)

大家都在看

  • 从源码中理解Spring Boot自动装配原理

    SpringBoot 定义了一套接口规范,这套规范规定: SpringBoot在启动时会扫描外部引用jar包中的 META-INF/spring.factories文件,将文件中配…

    Java 2023年6月16日
    094
  • 面试官问我TCP三次握手和四次挥手,我真的是

    候选者: 面试官你好,请问面试可以开始了吗 面试官:嗯,开始吧 面试官: 今天来聊聊TCP吧,TCP的各个状态还有印象吗? 候选者:还有些许印象的,要不我就来简单说下TCP的三次握…

    Java 2023年6月9日
    068
  • 【转】虚拟机网络服务启动失败Failed to start LSB 解决方法

    场景:克隆了一个虚拟机后不能重启它的网络服务编辑IP配置文件:vi /etc/sysconfig/network-scripts/ifcfg-ens33重新修改了ip后,发现还是报…

    Java 2023年5月30日
    096
  • 约瑟夫问题

    这篇博客是我在B站看韩顺平老师的数据结构和算法的约瑟夫问题后的学习笔记,记录一下,防止忘记,也希望能帮到各位小伙伴。 问题引入:设编号为 1,2,… n 的 n 个人围…

    Java 2023年6月15日
    0112
  • sharding-jdbc教程 看这一篇就够了

    ​ Sharding-JDBC是ShardingSphere的第一个产品,也是ShardingSphere的前身。 它定位为轻量级Java框架,在Java的JDBC层提供的额外服务…

    Java 2023年6月7日
    089
  • shiro角色与权限

    shiro角色与权限 shiro在认证过程中,会判断该用户是否含有一定的权限或者角色,其中位于顶层的接口为AuthorizationInfo,其继承体系如下: Authorizat…

    Java 2023年6月7日
    098
  • 【力扣】525. 连续数组

    给定一个二进制数组 nums , 找到含有相同数量的 0 和 1 的最长连续子数组,并返回该子数组的长度。 示例 1: 输入: nums = [0,1]输出: 2说明: [0, 1…

    Java 2023年6月8日
    064
  • Neo4j在linux上的安装与Springboot的集成

    Neo4j在linux上的安装与Springboot的集成 在linux安装: 前提:安装配置好java环境 1.下载neo4j 官方社区版下载地址:https://neo4j.c…

    Java 2023年6月14日
    0157
  • Redis GEO 地理位置

    GEO指令 GEOADD GEODIST GEOPOP GEOHASH GEORADIUS GEORADIUSBYMEMBER 指令补充 删除操作 避免单集合数量过多 存储原理 G…

    Java 2023年6月6日
    077
  • 进程与线程

    进程和线程明显的界限就在于:虚拟地址空间的共享和不共享。 Linux没有进程和线程,只有Task。但是Task与Task之间是区别的,当克隆发生时,不同Task之间的最大和最小共享…

    Java 2023年5月30日
    069
  • 第五周总结-Hadoop&Sqoop学习

    学习课程中的数据清洗sql语句 sql;gutter:true; start-all.sh #启动Hadoop集群 nohup /export/server/apache-hive…

    Java 2023年6月7日
    080
  • 【设计模式系列】结构型之桥接模式(常用)

    前言 不知道大家对于设计模式是个什么样的看法,是认为没必要啊,还是觉得是那种深入到骨子里的优雅。随着工作年限的增加,对设计模式愈发熟悉的前提下,真心觉得,设计模式是真他 * 的优雅…

    Java 2023年6月7日
    0116
  • jvm:内存结构与对象内存解析

    java的跨平台性主要是因为其字节码文件可以在任何具有java虚拟机的计算机或者电子设备上运行,jvm中的字节码解析器负责将字节码文件解释成机器码运行,字节码文件.class是ja…

    Java 2023年6月7日
    088
  • 通过代码获取res里生成R.java中的值

    引用:http://my.eoe.cn/blue_rain/archive/552.html 有的时候我们生成库文件,需要在里面加入一些UI,并提供出一些xml的资源,那如何在其他…

    Java 2023年5月29日
    0102
  • 记一次Idea无法打开记录(idea升级)

    记一次Idea无法打开记录 前言,本来今天是打算升级Idea,然后体验一波的,结果升级完之后,发现无法打开idea(双击之后并没有任何打开的反应)。 原因排查,打开idea所在目录…

    Java 2023年6月5日
    065
  • SpringBoot定时任务-什么是ElasticJob?如何集成ElasticJob实现分布式任务调度?

    前文展示quartz实现基于数据库的分布式任务管理和job生命周期的控制,那在分布式场景下如何解决弹性调度、资源管控、以及作业治理等呢?针对这些功能前当当团队开发了ElasticJ…

    Java 2023年6月6日
    068
亲爱的 Coder【最近整理,可免费获取】👉 最新必读书单  | 👏 面试题下载  | 🌎 免费的AI知识星球