目录
1、怎么才能够突破单机主从架构瓶颈,让redis支撑海量数据?
redis中分布式数据存储的算法
什么是redis的雪崩和穿透?
如何保证缓存与数据库的双写一致性?
使用cache aside pattern
redis的并发竞争问题是什么?如何解决这个问题?了解Redis事务的CAS方案吗?
1、怎么才能够突破单机主从架构瓶颈,让redis支撑海量数据?
redis cluster,主要是针对海量数据+高并发+高可用的场景
redis cluster介绍
redis cluster
(1)自动将数据进行分片,每个master上放一部分数据
(2)提供内置的高可用支持,部分master不可用时,还是可以继续工作的
在redis cluster架构下,每个redis要放开两个端口号,比如一个是6379,另外一个就是加10000的端口号,比如16379
16379端口号是用来进行节点间通信的,也就是cluster bus的东西,集群总线。cluster bus的通信,用来进行故障检测,配置更新,故障转移授权
redis中分布式数据存储的算法
hash取余
在扩容的时候会导致缓存无法命中,需要全部重新进行hash取余。例如3台-->4台,就会有3/4=75%的无法命中。如0,1,2,3,4,5,6,7,8,9,10,11,12,其中扩容之后只有1,2,3能够命中
一致性hash算法(memcached) -> redis cluster,hash slot算法
一致性hash
1、hash值是一个非负整数,将非负整数的值范围做成一个圆环范围
2、对集群上的节点某个属性(比如节点名)求hash值,放到环上
3、对数据key求hash值,也放到环上,按顺时针方向找到离它最近的节点,放到它上面
一致性hash+虚拟节点
由于一致性hash导致加入的新节点无法均衡分摊其他节点的压力所以对于放入的节点创建其对应的虚拟节点,然后均匀的放入到里面。
例如下面的:将n0节点创建出多个虚拟节点然后放入到里面
即使使用了虚拟节点,在节点逐渐增多的时候还是容易出现虚拟节点分布密集,导致hash倾斜。
redis cluster的hash slot(hash槽)算法
redis cluster有固定的16384个hash slot(类似于一致性hash的虚拟节点),对每个key计算CRC16值,然后对16384个hash slot取模,可以获取key对应的hash slot
redis cluster中每个master都会持有部分slot,比如有3个master,那么可能每个master持有5000多个hash slot
每增加一个master,就将其他master的hash slot移动部分过去,减少一个master,就将它的hash slot移动到其他master上去
数据迁移可以理解为slot(槽)和value的迁移,由于redis 是走的内存,所以移动数据迁移的成本是非常低的
什么是redis的雪崩和穿透?
缓存雪崩发生的现象:redis挂了之后,请求全部进入到数据库,最后导致数据库挂掉,挂掉之后整个系统挂掉。
缓存雪崩的事前事中事后的解决方案
事前:redis高可用,使用redis cluster,避免全盘崩溃
事中:hystrix限流&降级,避免MySQL挂掉
事后:redis持久化,快速恢复缓存数据
缓存穿透的现象:有人恶意攻击,发送大量的请求不存在的id,然后缓存没查到全部走数据库。然而数据库没有,它继续循环请求,导致数据库崩溃。
缓存穿透的解决方法:只要在数据库没查到的id,就写一个空值到缓存里去(set -1 unknown)
如何保证缓存与数据库的双写一致性?
使用cache aside pattern
1、Cache Aside Pattern
(1)读的时候,先读缓存,缓存没有,再读数据库,然后取出数据后放入缓存,同时返回响应
(2)更新的时候,先删除缓存,然后再更新数据库
2、为什么是删除缓存,而不是更新缓存呢?
如果是更新缓存的话,当写入数据库写数据失败之后,而缓存数据是更新后的数据,这样就会出现数据不一致问题。
redis的并发竞争问题是什么?如何解决这个问题?了解Redis事务的CAS方案吗?
在高并发的情况下,对某个数据进行更新操作的时候,第一个线程首先删除了redis数据,然后在更新数据库的时候,第二个线程来了,他发现redis 没有数据,就到mysql 中查找,拿到旧的数据。这个时候第一个线程恰好在第一个线程拿到旧的数据之后更新完毕,然后写入到redis中,而第二个线程拿到旧的数据也写入到redis中,这个时候redis中新的数据被旧的数据所覆盖。
上面的解决办法:mysql中写数据的时候,必须保持时间戳,从mysql中查出来时候,与redis 中已有数据的时间戳进行比较,类似于CAS比较。
对于redis的数据高并发下的数据同步:多个客户端来共同修改redis中的某个数据,这个时候需要使用分布式锁,通过代码实现,主要是针对某一笔数据的流水号加锁,防止多个线程写入这个数据。