缓存是Redis最常见的用途,一般用来保证系统的高性能与高并发,因为缓存是放在内存的,而数据库的数据需要经过磁盘文件,当然mysql也支持一部分缓存,内存读写的并发量一定是比磁盘读写高的。
主要使用file event handler,一个单线程的文件事件处理器。监听多个socket,根据socket上的事件类型选择对应的处理器来处理。包括四个部分:多个socket,IO多路复用程序,文件事件分派器,事件处理器(连接应答,命令请求,命令回复处理),其中为了防止事件并发引起的问题,文件事件分派器会将产生的事件放入队列中排队。由于是纯内存操作、IO多路复用程序是NIO的、底层使用C语言、没有多线程的竞争问题等优点,Redis的效率很高。在6.0版本后引入了多线程,用来处理网络数据的读写与协议解析。
定期删除+惰性删除
定期删除: 指的是Redis每隔一定的时间(默认100ms,可重新配置)随机选择一些设置了过期时间的key,检查并决定是否删除。
惰性删除:每次现在获取的时候,都会检查是否过期。
存在一个极端情况,当定期删除没能选中某些数据,而这些数据也未被使用也就是不能惰性删除,那么会导致数据会越来越多,导致内存耗尽。
主要提供几种
主要依靠主从架构:和其他主从一样,就是一个节点负责写,其他节点负责读。
当从节点第一次启动并连接主节点,会启动一次全量复制。复制的方式是由主节点生成一份RDB文件(类似镜像快照),同时将新的写入命令缓存。从节点收到RDB之后,先将它写入磁盘,再加载到内存。然后主节点将新写入的缓存命令发送给slave,继续同步这些数据。
上述题到的主从复制核心原理,会发生网络不佳的情况,那么就会出现部分命令丢失的情况,这时候就需要用到断点续传。主要由主节点维护一个内存中的backlog,主从节点都会保存一个偏移量和id,其中偏移量是保存在backlog中,这样断开重连后还能重新开始传,id的话主要是用来定位主节点的。因为用ip来定位是不可靠的。
主节点在内存中直接创建RDB,在配置文件的repl-diskless-sync配置项设置为yes就可以了。
只有主节点才可以处理过期的key,并将淘汰命令同步到从节点。
主从节点会相互发送心跳信息,确认是否活着。
主要由哨兵来实现,哨兵有集群监控、消息通知、故障转移、配置中心的功能。并不保证数据的零丢失。
哨兵至少需要3个实例,不保证数据完全不丢失,其中数据丢失主要发生在两种情况,一种是异步复制导致的数据丢失,另一种是脑裂导致的数据丢失(出现了两个master)。解决方法就是配置min-slaves-max-lag和min-slaves-to-write去尽量避免问题。
sdown是主观宕机的,就一个哨兵如果自己觉得一个master宕机了,那么就是主观宕机。
odown是客观宕机,如果quorum数量的哨兵都觉得一个master宕机了,那么就是客观宕机。
主要通过pub/sub实现,去互相交换信息对master的监控配置等。
首先按照从节点的优先级排序,然后按照从节点的复制偏移量。总而言之就是选择留有尽可能多的数据的从节点。
每次一个哨兵要做主备切换,首先需要quorum数量的哨兵认为down,然后选举出一个哨兵来切换,同时得到主哨兵的授权。
主要有两种方式,RDB和AOF
RDB持久化机制,是对Redis中的数据执行周期性的持久化。
RDB会生成多个数据文件,可以用来做备份。
RDB的性能很高,因为复制操作是由一个线程完成的。
由RDB恢复Redis进程更快。
但是RDB可能会丢失数据在故障情况下。
当RDB足够大的时候,会一定程度导致服务暂停。
把每条写入命令存入日志,通过回放日志来重新建立。
数据更安全,丢失的数据不会很多。
没有磁盘寻址的开销,性能高。
日志文件过大的时候,后台会重写,但不会影响客户端的重写,因为有压缩。
AOF的可读性较强,即使被删库也可恢复。
缺点是容量过大。
成年人才做选择,可以都开启。
在集群架构下,每个Redis会开启两个端口6379和16379,其中16379是用来节点间通信的,主要用总线的模式来进行,一般使用的是gossip协议,自动将数据进行分片,每个master上放一部分数据,提供内置的高可用支持,部分master不可用时可以继续工作。
分为集中式、Gossip协议两种。
集中式的原理类似与大数据里的storm,主要用zookeeper来实现。
Gossip协议则是一种达到分布式共识的传输协议。
对于key先计算hash值,然后对节点数取模。一旦某个master宕机,都会基于最新的剩余master节点去取模,尝试去取数据。导致大部分请求过来,无法拿到新的缓存。
将整个hash值空间组织成一个虚拟的圆环,整个空间按顺时针方向组织,下一步将各个master节点(使用ip和主机名)进行hash。从而确定位置。
如果一个节点挂了,受影响的只有一前面的那个节点。但是在节点太少时,容易因为节点分部不均匀而造成缓存热点的问题。所以引入了虚拟节点机制,即对每一个节点计算多个hash,每个计算结果位置都放置一个虚拟节点。
Redis cluster 有固定的 16384 个 hash slot,对每个 key 计算 CRC16 值,然后对 16384 取模,可以获取 key 对应的 hash slot。
Redis cluster 中每个 master 都会持有部分 slot,比如有 3 个 master,那么可能每个 master 持有 5000 多个 hash slot。hash slot 让 node 的增加和移除很简单,增加一个 master,就将其他 master 的 hash slot 移动部分过去,减少一个 master,就将它的 hash slot 移动到其他 master 上去。移动 hash slot 的成本是非常低的。客户端的 api,可以对指定的数据,让他们走同一个 hash slot,通过 hash tag 来实现。
任何一台机器宕机,另外两个节点,不影响的。因为 key 找的是 hash slot,不是机器。
可以通过zookeeper实现分布式锁,确保同一时间只能有一个实例在操作某个key。
CAS的话是通过时间戳来作为版本号,这样可以有效避免ABA问题。