.markdown-body{word-break:break-word;line-height:1.75;font-weight:400;font-size:15px;overflow-x:hidden;color:#333}.markdown-body h1,.markdown-body h2,.markdown-body h3,.markdown-body h4,.markdown-body h5,.markdown-body h6{line-height:1.5;margin-top:35px;margin-bottom:10px;padding-bottom:5px}.markdown-body h1{font-size:30px;margin-bottom:5px}.markdown-body h2{padding-bottom:12px;font-size:24px;border-bottom:1px solid #ececec}.markdown-body h3{font-size:18px;padding-bottom:0}.markdown-body h4{font-size:16px}.markdown-body h5{font-size:15px}.markdown-body h6{margin-top:5px}.markdown-body p{line-height:inherit;margin-top:22px;margin-bottom:22px}.markdown-body img{max-width:100%}.markdown-body hr{border:none;border-top:1px solid #ddd;margin-top:32px;margin-bottom:32px}.markdown-body code{word-break:break-word;border-radius:2px;overflow-x:auto;background-color:#fff5f5;color:#ff502c;font-size:.87em;padding:.065em .4em}.markdown-body code,.markdown-body pre{font-family:Menlo,Monaco,Consolas,Courier New,monospace}.markdown-body pre{overflow:auto;position:relative;line-height:1.75}.markdown-body pre>code{font-size:12px;padding:15px 12px;margin:0;word-break:normal;display:block;overflow-x:auto;color:#333;background:#f8f8f8}.markdown-body a{text-decoration:none;color:#0269c8;border-bottom:1px solid #d1e9ff}.markdown-body a:active,.markdown-body a:hover{color:#275b8c}.markdown-body table{display:inline-block!important;font-size:12px;width:auto;max-width:100%;overflow:auto;border:1px solid #f6f6f6}.markdown-body thead{background:#f6f6f6;color:#000;text-align:left}.markdown-body tr:nth-child(2n){background-color:#fcfcfc}.markdown-body td,.markdown-body th{padding:12px 7px;line-height:24px}.markdown-body td{min-width:120px}.markdown-body blockquote{color:#666;padding:1px 23px;margin:22px 0;border-left:4px solid #cbcbcb;background-color:#f8f8f8}.markdown-body blockquote:after{display:block;content:""}.markdown-body blockquote>p{margin:10px 0}.markdown-body ol,.markdown-body ul{padding-left:28px}.markdown-body ol li,.markdown-body ul li{margin-bottom:0;list-style:inherit}.markdown-body ol li .task-list-item,.markdown-body ul li .task-list-item{list-style:none}.markdown-body ol li .task-list-item ol,.markdown-body ol li .task-list-item ul,.markdown-body ul li .task-list-item ol,.markdown-body ul li .task-list-item ul{margin-top:0}.markdown-body ol ol,.markdown-body ol ul,.markdown-body ul ol,.markdown-body ul ul{margin-top:3px}.markdown-body ol li{padding-left:6px}.markdown-body .contains-task-list{padding-left:0}.markdown-body .task-list-item{list-style:none}@media (max-width:720px){.markdown-body h1{font-size:24px}.markdown-body h2{font-size:20px}.markdown-body h3{font-size:18px}}
大家好,我是南橘,从接触java到现在也有差不多两年时间了,两年时间,从一名连java有几种数据结构都不懂超级小白,到现在懂了一点点的进阶小白,学到了不少的东西。知识越分享越值钱,我这段时间总结(包括从别的大佬那边学习,引用)了一些平常学习和面试中的重点(自我认为),希望给大家带来一些帮助 这篇文章的出现,首先要感谢一个人三太子敖丙 ,就是他的文章让我发现,原来Redis的知识如此的多姿多彩。恩恩,他的文章,我是期期都看
这是这篇文章的思维导图,因为用的是免费版的软件,所以有不少水印,如果需要原始版本的话,可以加我的微信:
有需要的同学可以加我的公众号,以后的最新的文章第一时间都在里面,也可以找我要思维导图
Redis篇,因为时间和篇幅的原因,并没有一次性写完,于是乎,分成了上下两篇,没有看过上半部分的小伙伴可以去看一下~
这一次,从Redis最为人津津乐道(面试也经常常问)的缓存三崩坏来说起
顾名思义,大家应该都见过雪崩,南橘我更是远远地亲眼见过,那场景,颇有种天崩地裂的感觉,而对于数据库来说,缓存雪崩,也说得上是一种天崩地裂了。 同一时间Redis缓存大面积失效,那一瞬间Redis跟不存在一样,这个时候数据直接请求到数据库。你想想,缓存的意义就是减少DB,如果缓存没有了,大量的请求还不直接打爆数据库?
缓存雪崩如何出现的?
解决办法:
有一个Key非常热点,在不停扛着大并发,大并发集中对这一点进行访问,当这个Key失效的瞬间、大量并发击穿缓存,直接访问数据库。
其实缓存击穿,真的算不上什么特别大的问题,毕竟不是每个公司都在同一个Key上都有那么大的热点,只需要设置好过期时间,稳定好Redis集群,缓存击穿不难避免。
解决办法:
在我的经验来看,设置互斥锁显然没有必要,一个热点永不过期就能解决的问题,为什么还要用到锁?这不是平白增加复杂度吗?也许在特殊场景能看到,但是对于我这个小白来说,仅仅能在各位大牛的博客里看到这个观点。
从名字上来看,缓存击穿和缓存穿透很像,实际上页比较像,但是既然区分了出来,自然有一些不同的地方
缓存穿透的概念很简单,用户想要查询一个数据,发现redis内存数据库没有,也就是缓存没有命中,于是向持久层数据库查询。发现也没有,于是本次查询失败。当用户很多的时候,缓存都没有命中,于是都去请求了持久层数据库。这会给持久层数据库造成很大的压力,这时候就相当于出现了缓存穿透。
但是,缓存穿透真正要防止的是黑客。
如果一个黑客每次故意查询一个在缓存内必然不存在的数据,导致每次请求都要去存储层去查询,这样缓存就失去了意义。如果在大流量下数据库可能挂掉,这也是缓存击穿。 解决办法:
利用布隆过滤器来防止缓存击穿,主要是通过将已存在的缓存放到布隆过滤器中,当黑客访问不存在的缓存时迅速返回避免缓存及DB挂掉。
布隆过滤器本质上布隆过滤器是一种数据结构,比较巧妙的概率型数据结构(probabilistic data structure),特点是高效地插入和查询,可以用来告诉你 “某样东西一定不存在或者可能存在”。
布隆过滤器是由一个很长的bit数组和一系列哈希函数组成的。
数组的每个元素都只占1bit空间,并且每个元素只能为0或1。
布隆过滤器拥有k个哈希函数,当一个元素加入布隆过滤器时,会使用k个哈希函数对其进行k次计算,得到k个哈希值,并且根据得到的哈希值,在位数组中把对应下标的值置位1。
判断某个数是否在布隆过滤器中,就对该元素进行k次哈希计算,得到的值在位数组中判断每个元素是否都为1,如果每个元素都为1,就说明这个值在布隆过滤器中。
当插入的元素越来越多时,当一个不在布隆过滤器中的元素,经过同样规则的哈希计算之后,得到的值在位数组中查询,有可能这些位置因为其他的元素先被置1了。
所以布隆过滤器存在误判的情况,但是如果布隆过滤器判断某个元素不在布隆过滤器中,那么这个值就一定不在。
通过这个方法,就可以有效的防止黑客导致的缓存穿透了。
其实不是很传统,只是我感觉所有的集群都有主从模式orz
主从模式的一个作用是备份数据,这样当一个节点损坏(指不可恢复的硬件损坏)时,数据因为有备份,可以方便恢复。 另一个作用是负载均衡,所有客户端都访问一个节点肯定会影响Redis工作效率,有了主从以后,查询操作就可以通过查询从节点来完成。
在主从模式中,一个Master可以有多个Slaves,默认配置下,master节点可以进行读和写,slave节点只能进行读操作,无法进行写操作。
如果修改默认配置,可以让slave进行写,但是这毫无意义,因为写入的数据不会同步给其他slave,同时,master节点如果修改了,slave上的数据回马上被覆盖。
slave节点挂了不影响其他slave节点的读和master节点的读和写,重新启动后会将数据从master节点同步过来。master节点挂了以后,不影响slave节点的读,Redis将不再提供写服务,master节点启动后Redis将重新对外提供写服务。
所以,我们可以发现Redis的主从和Zookeeper的主从完全不一样!它竟然不会选举!
这个缺点影响是很大的,尤其是对生产环境来说,是一刻都不能停止服务的,所以一般的生产坏境是不会单单只有主从模式的。所以有了下面的sentinel模式。
哨兵模式要搭配主从模式来使用,主从不能自己选举,那我们就加一个哨兵,当sentinel发现master节点挂了以后,sentinel就会从slave中重新选举一个master。
哨兵的作用就是监控Redis系统的运行状况。它的功能包括以下两个。
(1)监控主服务器和从服务器是否正常运行。
(2)主服务器出现故障时自动将从服务器转换为主服务器。
这不就皆大欢喜了吗?
哨兵的工作方式:
当有足够数量的 Sentinel(哨兵)进程(大于等于配置文件指定的值)在指定的时间范围内确认Master主服务器进入了主观下线状态(SDOWN), 则Master主服务器会被标记为客观下线(ODOWN)
当Master主服务器被 Sentinel(哨兵)进程标记为客观下线(ODOWN)时,Sentinel(哨兵)进程向下线的 Master主服务器的所有 Slave从服务器发送 INFO 命令的频率会从 10 秒一次改为每秒一次。
sentinel模式基本可以满足一般生产的需求,具备高可用性。但是当数据量过大到一台服务器存放不下的情况时,主从模式或sentinel模式就不能满足需求了,这个时候需要对存储的数据进行分片,将数据存储到多个Redis实例中,这就是cluster模式。
cluster的出现是为了解决单机Redis容量有限的问题,将Redis的数据根据一定的规则分配到多台机器。
Redis-Cluster采用无中心结构,它的特点如下:
cluster可以说是sentinel和主从模式的结合体,通过cluster可以实现主从和master重选功能,所以如果配置三个副本三个分片的话,就需九六个Redis实例。 因为Redis的数据是根据一定规则分配到cluster的不同机器的,当数据量过大时,可以新增机器进行扩容,这种模式适合数据量巨大的缓存要求,当数据量不是很大使用sentinel即可。
引用一张大佬的图片来直观展现一下什么是 Redis-Cluster
每个请求访问Redis-Cluster集群的时候,都会进行一个路由,路由可以通过Hash(也可以用别的)来进行随机分片,但是如果完全hash的话很可能导致分片们旱的旱死,涝的涝死。,所以,提出了**一致性哈希(自动缓存迁移)+虚拟节点(自动负载均衡)**的方法来解决问题
具体内容大家可以看看这篇文章,写的比较详细,看的也很过瘾
www.jianshu.com/p/49c9e03ee… 关于redis的几件小事(十)redis cluster模式
一致性哈希的原理 :将所有master node落在一个圆环上面,然后,有一个key过来之后。同样就是hash值,然后会用hash值在圆环对应的各个点上(每个点都有一个hash值)去对比,看hash值落在那个位置,落在圆环上面以后,就会顺时针旋转去寻找距离自己最近的一个节点,数据的存储于读取都在该节点进行。 一致性哈希的优势 :保证了任何一个master宕机,只会影响之前在那个master上面的数据,因为照着顺时针走,全部在之前的master上面找不到了,master也宕机了,就会继续顺着顺时针走到下一个master节点去。这样就只会有一部分数据丢失。
既然Redis能储存数据,自然也就要删除多余的数据,不然,空间都被占满了,新的内容放在哪里?聪明的程序员提出了三个办法解决Redis的内存问题。
创建一个定时器,当key设置有过期时间,且过期时间到达时,由定时器任务立即执行对键的删除操作,默认100ms就随机抽一些key判断是否过期,过期的话就删除,用处理器性能换取存储空间(拿时间换空间)
当Redis中的数据到了过期时间,我们先不做处理。等下次访问该数据时进行一次判断,如果未过期,就正常返回,如果发现数据已过期,立刻删除,然后返回不存在,用存储空间换取处理器性能(拿空间换时间)
不知道大家不知道发现了没有,大部分的算法,不是时间换空间,就是空间换时间。刚刚发现这个秘密的我简直惊呆了,这就是人类的终极奥秘之一了,只要我们知道这个诀窍,就能解决大部分的问题。
在Redis的redis.config文件中还可通过搜索maxmemory-policy来设置淘汰机制
noeviction:当内存使用达到阈值的时候,所有引起申请内存的命令会报错。
allkeys-lru:在主键空间中,优先移除最近未使用的key。
volatile-lru:在设置了过期时间的键空间中,优先移除最近未使用的key。
allkeys-random:在主键空间中,随机移除某个key。
volatile-random:在设置了过期时间的键空间中,随机移除某个key。
volatile-ttl:在设置了过期时间的键空间中,具有更早过期时间的key优先移除。
Redis篇写完了,感觉Redis真的是有好多内容啊,之前觉得自己貌似全都掌握了一样,回过头来,发现还是有很多不懂~很开心能在这里给大家分享我的收获,我知道我的技术栈比起各位响当当的大佬还是有差距,但是人不努力怎么知道自己不可以?希望大家能喜欢我的文章,也希望这篇文章能帮到大家。 同时需要思维导图的话,可以联系我,毕竟知识越分享越香!