乐趣区

关于redis:聊聊Redis的数据热点问题

  前两天,咱们应用的某云厂商服务挂了,而且一挂就是挂大半天,咱们的服务强依赖于他们,所以咱们也跟着一起挂。然而咱们却无能为力,只能等他们复原。事变起因中听他们提到 Redis 有个热 key,正好我在上家公司负责过部门 Redis 集群,也解决过很多起 Redis 数据热点的问题,接下来就一起聊聊什么是 Redis 热点?Redis 热点问题为什么会极大地影响整个集群的性能?如何防止 Redis 数据热点?热点问题如何排查?热点问题如何解决?

什么是 Redis 热点?

  我曾在我过往的博文中屡次提到了 局部性 一词(对于局部性能够看下我之前的博文 局部性原理),数据热点就是数据拜访局部性的体现,具体表现就是 Redis 中某个 Key 的拜访频次远大于其余残余的 Key,咱们也有一句俗语来形容这种景象 旱的旱死,涝的涝死

  为什么 Redis 会有热点问题?这就得从 Redis 的原理说起了。家喻户晓,Redis 中存储的是 K - V 数据,在集群模式下,Redis 会将所有数据按 Key 的 CRC64 值调配到 16384 个数据槽 (slot) 中,并将这 16384 个数据槽调配到集群中各个机器上,尽可能实现数据在各个机器上的平均存储。但平均存储并不意味着平均拜访,有时候某个 Key 的申请会占到总申请的很大一部分,这就会导致申请集中在某个 Redis 实例上,将该 Redis 实例的承载能力耗尽,所有存储在这个实例上的其余数据也就无奈失常拜访了,这就意味着所有依赖于这些数据的服务都会出问题。

  这里的出问题并不是说 Redis 会间接宕机,家喻户晓 Redis 的外围流程是单线程模式,这就意味着 Redis 是串行解决所有申请的,当申请过多时,申请就会拥挤起来,从应用层的视角来看,就是申请 Redis 的耗时会特地特地高。因为应用层应用 Redis 都是作为缓存,都是同步申请,所以会间接导致应用层的申请解决也会特地耗时,从而导致应用层申请也逐步拥挤,最终整体不可用。

  咱们来举个简略的例子,置信大家都在微博上吃过瓜,当有大瓜呈现时,微博上会迅速涌入一批用户检索相干信息,疯狂拜访同一份微博(数据),这种状况下这份数据就是热点数据,如果数据太“热”最终会导致微博挂掉,实际上微博挂掉的状况曾经呈现很屡次了,不是因为微博技术不行,而是因为热点问题太可怕。

Redis 热点是如何拖垮其余服务的?

  Redis 的热点并不仅仅会导致单个服务异样,而是会导致所有依赖于此 Redis 集群的所有服务异样。上图中 Server2、Server、Server3 频繁拜访 XXX_KEY,导致 RedisServer2 实例不可用,因为 Server4 依赖于 RedisServer2 上的 Key7,即使是 RedisServer1 3 4 5 都失常服务,Server4 也无奈对外提供失常的服务。

  是不是有人会问 RedisServer2 挂了,不能把它下掉,换一个新的机器下来吗?其实在 Redis 集群模式下,某个实例宕机 Redis 集群会主动将其替换。但当初的状况是,即使是替换了新实例,大量的申请也会一下子涌进来将其压挂。所以面对 Redis 热点问题,重启之类的伎俩是有效的,只能从申请端解决问题。

  其实这就是一个很显著的 木桶模型,一个木桶所能装水的多少取决于木桶上最短的那块木板,当利用应用 Redis 集群时,Redis 集群的性能下限并不齐全等于单实例下限乘以实例个数。但当 Redis 集群中任一实例有问题,下层感知到的就是整个 Redis 集群有问题。

Redis 热点如何防止?

  上文也说到,热点问题其实是局部性问题,而局部性问题的防止其实十分难,任何分布式系统简直都会受局部性的影响。面对这种问题,说实话没有相对能够防止的形式,只能提前通过剖析数据的个性,做好相应的措施。说白了就是靠教训,不晓得大家有啥其余好的思路,能够在评论区探讨下。

热点问题如何排查?

  Redis 的热点的问题其实算是很好查的,就是靠监控数据,监控 Redis 各个实例的 CPU 使用率、QPS 数据,如果你看到 redis 集群中某些实例负载和 QPS 特地高,但其余实例负载很低,不必问必定是呈现热点问题了,接下来你须要做的就是找出具体的热点 key,并且找出数据拜访的起源。

  找出热点 Key 其实也很简略,抓局部拜访日志,而后统计下很容易就看进去了。但比拟难的是找出数据拜访的起源,像我之前所在的公司,同一个 Redis 集群是被很多业务所共享的,但 Redis 的拜访并为被纳入到全链路监控的数据中,所以找出拜访起源最间接的形式就是在群外面问,听起挺原始的,但也没有其余办法。

热点问题如何解决?

  尽管解决问题最好的形式是防止问题的产生,但我方才也说了,Redis 热点其实很难防止,任何业务中热点肯定有,但不肯定会造成劫难而已 。热点的发现不肯定非得是事变引出的,咱们也能够在日常工作中定期巡检,一有发现热点的苗头,间接将其扼杀。
对于发现热点后如何解决,我这里提供两个我的解决思路,大家能够探讨下:

应用层 Cache

  罕用的实现形式就是在利用里实现本地缓存(LocalCache),就相当于是对 Redis 数据又加了一层 Cache,对于那些十分热的热点数据,应用层有极大的概率能在本地缓存中找到数据,只有极小局部 LocalCache 数据过期时的申请会漏到上面,这样热点数据的申请在应用层外部就能消化,从而极大缩小对 Redis 的压力。

  这种实现办法的话,仅须要数据读取端做革新,数据写入端齐全不须要革新。然而毛病的话也很显著:

  1. 须要各端自行实现,会减少应用层开发和保护老本。
  2. 会额定节约各端的存储空间。
  3. 须要针对性开发,不适宜大范畴推广。

减少数据正本

  既然热点问题是因为某个 Key 被大量拜访导致的,那咱们将这个 Key 的申请做下拆分不就行了。例如,原始的热点 Key 叫做XXX_KEY,咱们在数据写入的时候,能够用不同的 Key 反复写 10 份,比方 XXX_KEY_01, XXX_KEY_02……XXX_KEY_10, 拜访的时候在原始 Key 上随机凭接一个 1 -10 之间的后缀即可,这样就能实现数据申请的扩散,如果想让申请更扩散,能够存储更多的正本。

  这种计划的长处就是数据读取端实现老本较低(也不是齐全没有),但对数据写入端的要求就高多了。不仅要写入多份,而且还得思考数据写入后一致性的问题。这种办法要求两端都得改,貌似更麻烦了,你是不是感觉还不如第一种计划?实则不然,一般来说读取端会很多且很扩散,革新的老本会十分高,频繁变动更是不太可能,所以有些工作不得不搁置到比拟集中的端上。

  以上两种计划其实都是通过存储来换性能,次要差别点就在于由谁来做而已。前者是客户端来做,后者是服务端来做,各有优缺点。有没有可能对外提供纯正的 Redis 协定,但能够解决数据热点的问题?。鲁迅……David Wheeler 已经说过,计算机科学的如何问题都能够通过减少一层来解决,热点的问题也不例外。咱们能够在利用和 Redis 之间加一层中间层,这层中间层能够是实在的服务,比方数据对立拜访层。也能够是特制的 Redis 客户端。

  中间层能够对特定的 Key 加本地 Cache,就能够保障热点不会呈现在 Redis 上。至于对哪些 Key 加本地 Cache,中间层能够实时去剖析近期申请热点数据,自行决定。其实最简略的形式就是开个 LRU 或者 LFU 的 Cache。

  另外,像第二种减少数据正本的计划,也齐全能够由中间层去实现。当咱们发现有数据热点时,让中间层被动将热点数据复制,拦挡并改写所有对热点数据的申请,将其分散开来。当然,如果中间层更智能的化,这些齐全都能够实现自动化,从热点的发现到解决,齐全不须要人参加。


  明天的文章就到这了,大家感觉有用请点赞,喜爱请关注。对于 Redis 热点的问题,大家有啥认识或者教训能够在评论区留言探讨。

退出移动版