架构师之路-redis集群解析

2022年01月16日 阅读数:1
这篇文章主要向大家介绍架构师之路-redis集群解析,主要内容包括基础应用、实用技巧、原理机制等方面,希望对大家有所帮助。

引子

 上篇《架构师之路-https底层原理》里我提到了上面的总体视图,文章也介绍了想要真正能在工做中及时正确解决问题的基本功:原理理解透彻。今天以redis集群解析为例介绍一个及时敏锐的发现问题的基本功:深刻分析。mysql

我认为达到深刻分析有三个步骤:面试

第一步,深刻理解redis

第二步,学以至用算法

第三步,千人千问sql

第一步redis集群各类原理介绍的人也不少;第二步不少人实际项目中大概也对redis集群不陌生;因此本文主要讲第三步:千人千问。数据库

 

提出问题后端

"redis集群使用时有什么注意事项?"这是以前有段时间我面试喜欢问的一个问题。个人一个观点是做为redis集群的使用方而不是开发者首先要作的是用好。经过这个问题肯定候选人用好了,再去挖掘他是经过了解了怎么用好的。因此我一般不会一开始就问一些中间件的原理,而是先从使用者的角度提出问题。缓存

下面列举了6条表明性的回答:服务器

1>防止集中失效网络

2>单线程执行,注意不要卡住

3>注意客户端和服务端的版本匹配

4>分片要保持流量均匀

5>注意超时时间配置

6>当内存缓存用,推荐删除代替更新

每条问题前面加上个为何,就引出了6条新的问题。

 

解决问题

Q1:为何要防止缓存集中失效?

A:缓存穿透、缓存集中失效和缓存雪崩并称为缓存世界的三大问题。先来总结理解一下这三个概念。这三个概念都是创建在缓存的一大做用就是对后端存储,好比mysql的保护。缓存没有保护住mysql,一个或一些到mysql了,那就是穿透;一个时间点缓存数据没有了,打到mysql了就是集中失效;缓存彻底丧失了保护mysql的能力,请求全打到mysql了,就是雪崩。

因此防止缓存集中失效是对后端存储的保护。

Q2:为何单线程执行,注意不要卡住?

A:卡住换个专业点的词就是阻塞嘛。什么叫阻塞呢,一辆小轿车A在单行道跑,遇到前面一辆车B停了,那A就被阻塞了。若是A和B都在高速单行道上跑,A开了160迈、B开了140迈。就算高速的容许最高速度是120迈(咱就当路过的是没有摄像头的路段,这俩车肆无忌惮),那A是否是仍是被B给阻塞了呢?因此卡住形成的最直接影响就是快的快不起来,由于单线程不能绕行嘛。

有人说不是能够多开几个redis嘛。是滴,可是客户端分请求使用的是crc16,根本不会先探测哪一个服务端比较空闲呀。因此后面来的总会被阻塞。

注意不要卡住还有个你们更常听到的名字:“避免大key问题”。其实我刚听到这个名字的时候是以为很奇怪的。由于避免大key其实是要避免key所对应的value不要太大。我以前一直以为这个名字取的不对。那应该叫“避免大value问题”。后来想一想这确实是正宗的中国话。好比张三的媳妇,人家都怎样叫呢?通常都是张三媳妇、张三家的。由于他家主要是张三出来抛头露面。那redis取值也同样,通常是先知道key,从key取value。用这个key取出来的数据大,就是大key问题啦。

Q3:若是不注意客户端和服务端版本匹配会引起什么问题?

A:先来思考客户端作了什么事情。我理解它就作了两件事:第一是使用RESP(Redis自定义的序列化协议)传输客户端命令并返回结果。第二是为了作第一件事,由于Redis集群是直连服务端模式,因此计算命令要落在哪一个节点、哪一个哈希槽上也是客户端来作的,我就称为选节点吧。

其实要回答客户端和服务端不匹配会引起什么问题,正规的方法应该是查看客户端版本升级都作过什么更新。

通常升级会作的是客户端依赖的jar包变了。这个可能会引发程序启动错误,可是这个每每启动成功了就不会再有问题,和服务端版本没有直接关系。

十年前还在用memcache的时候,发生过一次升级客户端版本,由于算法发生了变化,因此致使缓存所有不命中的问题。Redis最近的算法一直是crc16。若是不存在分布式算法不兼容问题的话,下一个要考虑的是大迭代是Redis3.0版本,支持了集群,集群模式是必需要匹配的。

Q4:为何分片要保持流量均匀?

A:要提分片先来回忆一下redis集群的发展史,从单机版到主从版,后来有了你们可能很耳熟的哨兵模式。哨兵模式就是给主从增长一个监控,发现主节点挂了自动把从节点升级为主节点,有了故障自动迁移的功能。可是直到哨兵时代都只有一个主节点,也就是处理写请求的节点,不能称之为真正的集群。这也是很无奈的事情,一旦多个节点写一份数据,就涉及到数据一致性的问题。

一个蜂巢只能有一个蜂后,多出来一个,蜜蜂们就不会正常提供采蜜服务了,都打架去了。可是分红两个蜂巢呢?秩序就会恢复。因此如今的集群基本都是分片的原理。以前主从和哨兵的经验不能废弃,加上分片。redis集群就是将一个完整服务数据分红几份,每份都带着从节点,故障时可自动转移的一个总体。以前在《Redis集群搭建采坑总结》里讲过,1个节点的集群会有问题,最少须要3主3从也就是6个redis进程。3个主方便在1个挂掉以后从新选主。

梳理了这个以后,分片保持流量均匀这件事也很容易了。就是Q2的问题,均匀更不容易阻塞嘛。

Q5:为何要注意超时时间配置?

A:提到redis的key的过时时间,首先想到的是redis的术语中,带过时时间的key又叫volatile key,就是不稳定key。怎么不稳定呢?就至关key这个对象有value和过时时间2个属性。过时时间这个属性1s改变一次(redis领域内时间都是以秒为单位),一直在变,固然不稳定。

若是把过时时间理解为key的一个属性,那也很好理解:对其进行del、set命令时过时时间也会删除;rename会把过时时间传给新的key;incr、lpush、hset等命令改变的是key的存储容器,没有改变key这个对象自己因此不会影响过时时间。

值得注意的是persist命令就是持久化保存的意思,将不稳定变成稳定,过时时间也自动删除了。

Redis在服务端有过时策略,可是对客户端是不感知的。客户端访问过时的就是一个表现,访问不到了。实际上服务端是有两种策略配合使用,一个是惰性删除,就是访问的时候发现过时了,就直接删除了;另外一个策略会按期去删除,这个是为了防止一个过时的key老是不被访问到,还占着资源不释放。

Q6:为何当内存缓存用,推荐删除代替更新?

A:通常你们出于数据一致性的考虑,会选择删除代替更新。这都是基于更新必定要更新数据库的固有思路。并发场景下,A的值1先被更新到数据库再更新缓存时,又来了一个更新请求把A的值更新为2。若是这时候执行更新为1的服务器性能很差或者网络传输速度比更新为2的慢,致使2在数据库是最新值,而设置为1的后更新了缓存。缓存就和数据库不一致了。

但只是记住删除代替更新不太够。若是先删除缓存再更新数据库,其余请求可能会把数据库老的值再加载到缓存中。记得以前有人介绍缓存还有三大种模式:Cache-Aside、Read-Through/Write-Through、Write-Behind。

Cache-Aside就是先更新数据库再删除缓存数据,能够避免上面提到的持续脏读的问题,顶多就是更新数据库的那一小段时间有更新延迟可见。咱们给Cache-Aside起个中文名,叫经典模式。

Read-Through/Write-Through就是数据以缓存为准,数据库的操做是缓存发起的。Read-Through是在读数据时发现缓存过时了,那缓存本身去数据库加载新的数据,读数据仍是读取缓存值。Write-Through写数据时调用方只负责写缓存,缓存本身去同步更新数据库。Read-Through/Write-Through通常配合使用。

Write-Behind和Write-Through的区别是虽然都是是写数据时调用方只负责写缓存,可是Write-Behind缓存本身去异步更新数据库。

由于Read-Through/Write-Through、Write-Behind都是以缓存为准,缓存不可靠,因此仍是推荐经典模式。

 

后记

一些朋友问我一边上班一边写文章哪有那么多时间呀。细心的朋友可能会发现个人文章通常是周末或者周一,再不就是节假日或者哪天失眠了发出来。由于内容都是非上班时间写的,可是每次下笔腹稿都是提早打好的。我的意见哈,做为架构师,不少人都会造成随时随地为工做思考和总结的习惯。因此不少人看着下班很早,人家回家路上,晒太阳的时候……未必没在想工做的事情。

架构师三件占时间的事:会议、评审和演讲。对应有三大难:提出有水平的问题、作出有水平的总结和建议、作出有水平的回答。因此天天有不少的腹稿要打。腹稿按照必定的框架结构整理就是文章。

若是你们都架构师的三大难有兴趣,我能够举一些具体的示例和解决方法。你们投票吧,若是在看超过10个,我就写这个。

 

推荐阅读