引子

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

我认为达到深入分析有三个步骤:

第一步,深入理解

第二步,学以致用

第三步,千人千问

第一步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个,我就写这个。

推荐阅读

架构师之路-redis集群解析的更多相关文章

  1. 【架构师之路】集群/分布式环境下5种session处理策略

    [架构师之路]集群/分布式环境下5种session处理策略   转自:http://www.cnblogs.com/jhli/p/6557929.html 在搭建完集群环境后,不得不考虑的一个问题就是 ...

  2. Couchbase集群和Redis集群解析

    Couchbase集群和Redis集群解析 首先,关于一些数据库或者是缓存的集群有两种结构,一种是Cluster;一种是master-salve. 关于缓存系统一般使用的就是Redis,Redis是开 ...

  3. linux运维、架构之路-redis集群

    一.介绍            redis cluster 3.0之后的功能,至少需要3(Master)+3(Slave)才能建立集群,是无中心的分布式存储架构,可以在多个节点之间进行数据共享,解决了 ...

  4. (转)高性能网站架构之缓存篇—Redis集群搭建

    看过 高性能网站架构之缓存篇--Redis安装配置和高性能网站架构之缓存篇--Redis使用配置端口转发 这两篇文章的,相信你已经对redis有一定的了解,并能够安装上,进行简单的使用了,但是在咱们的 ...

  5. (转)高性能网站架构之缓存篇—Redis集群增删节点

    标签: 高性能架构集群缓存redis 上一篇文章,我们搭建了Redis-cluster集群,这篇博客跟大家讲一下如何在一个运行的集群上增加节点或者删除节点. Redis集群添加节点 首先我们要新建立一 ...

  6. windows下rabbitmq(架构师必备神器)集群搭建

    准备2台机器,例如:computera: 10.0.0.151   computerb:10.0.0.234  都安装erlang环境和rabbitmq服务,注意otp环境和rabbitmq服务必须版 ...

  7. Java企业级电商项目架构演进之路 Tomcat集群与Redis分布式

    史诗级Java/JavaWeb学习资源免费分享 欢迎关注我的微信公众号:"Java面试通关手册"(坚持原创,分享各种Java学习资源,面试题,优质文章,以及企业级Java实战项目回 ...

  8. 【原创】那些年用过的Redis集群架构(含面试解析)

    引言 今天是2019年2月12号,也就是大年初八,我接到了高中同学刘有码面试失利的消息. 他面试的时候,身份是某知名公司的小码农一枚,却因为不懂自己生产上Redis是如何部署的,导致面试失败! 人间惨 ...

  9. 【转】那些年用过的Redis集群架构(含面试解析)

    引言 今天是2019年2月12号,也就是大年初八,我接到了高中同学刘有码面试失利的消息. 他面试的时候,身份是某知名公司的小码农一枚,却因为不懂自己生产上Redis是如何部署的,导致面试失败! 人间惨 ...

随机推荐

  1. 一文看懂String类中的常用方法

    1.int length(): 返回字符串的长度: return value.length 2.char charAt(int index): 返回某索引处的字符return value[index] ...

  2. 动态查看及加载PHP扩展

    在编译并完成 php.ini 的配置之后,我们就成功的安装了一个 PHP 的扩展.不过, PHP 也为我们提供了两个在动态运行期间可以查看扩展状态以及加载未在 php.ini 中进行配置的扩展的函数. ...

  3. jquery播放视频事件

    $('video').trigger('play'); $('video').trigger('pause'); 判断video播放器的播放状态,并进行切换播放,需要这样 let video = $( ...

  4. CF1556E-Equilibrium【栈,树状数组】

    正题 题目连接:https://codeforces.com/contest/1556/problem/E 题目大意 两个长度为\(n\)的序列\(a,b\),\(q\)次询问一个区间\([l,r]\ ...

  5. Redis高可用解决方案:哨兵(Sentinel)

    哨兵是Redis的高可用解决方案:由多个哨兵组成的系统监视主从服务器,可以将下线的主服务器属下的某个从服 务器升级为新的主服务器,继续保障运行. 启动并初始化Sentinel redis-sentin ...

  6. 解决Vue项目打包之后放到nginx下刷新就报错404的问题

    最近跟着某机构的教学视频敲了一遍vue项目,但是在windows环境下部署的时候就懵逼了放到nginx下正常跑没问题,但是刷新之后就报404错误 前端项目构建vue 脚手架版本 是@vue/cli 4 ...

  7. Vue使用axios post方法发送json数据报415Unsupported Media Type

    1.Vue使用axios post方法发送json数据 <template> <el-aside> <el-form ref="form" :mode ...

  8. T-SQL——关于表数据的复制插入

    目录 0. 复制表中一列插入到另外一列 1. 复制表结构和数据到自动创建的一张新表中--select into 2. 复制表中一些字段值插入到另外一张表中--insert into 3. 将存储过过程 ...

  9. SpringCloud升级之路2020.0.x版-25.OpenFeign简介与使用

    本系列代码地址:https://github.com/JoJoTec/spring-cloud-parent OpenFeign 的由来和实现思路 在微服务系统中,我们经常会进行 RPC 调用.在 S ...

  10. ES5新增方法--查找方法--forEach(),filter(),some()区别

    1.forEach方法 迭代(遍历)数组 var arr = [1, 2, 3]; var sum = 0; arr.forEach(function (value, index, array) { ...