一、单机模式
1、优点
- 部署简单,0成本。
- 成本低,没有备用节点,不需要其他的开支。
- 高性能,单机不需要同步数据,数据天然一致性。
2、缺点
- 可靠性保证不是很好,单节点有宕机的风险。
- 单机高性能受限于CPU的处理能力,redis是单线程的。
单机模式选择需要根据自己的业务场景去选择,如果需要很高的性能、可靠性,单机就不太合适了。
二、主从模式
- 即:主从复制,是指将一台Redis服务器的数据,复制到其他的Redis服务器;
- 前者称为主节点(master),后者称为从节点(slave);
- 数据的复制是单向的,只能由主节点到从节点。
- 主从模式配置很简单,只需要在从节点配置主节点的ip和端口号即可。
slaveof <masterip> <masterport># 例如# slaveof 192.168.1.214 6379
5. 主从模式在很多系统设计时都会考虑,一个master挂在多个slave节点,当master服务宕机,会选举产生一个新的master节点,从而保证服务的高可用性。
优点:
- 一旦 主节点宕机,从节点 作为 主节点 的 备份 可以随时顶上来;
- 扩展 主节点 的 读能力,分担主节点读压力;
- 高可用基石:除了上述作用以外,主从复制还是哨兵模式和集群模式能够实施的基础,因此说主从复制是Redis高可用的基石。
缺点
- master和slave的数据都是一样的,有数据冗余问题;(为了高可用性和高性能,是允许有冗余存在的)
- 一旦 主节点宕机,从节点 晋升成 主节点,同时需要修改 应用方 的 主节点地址,还需要命令所有 从节点 去 复制 新的主节点,整个过程需要 人工干预。
- 主节点 的 写能力 受到 单机的限制;
- 主节点 的 存储能力 受到 单机的限制;
- Redis不具备自动容错和恢复功能,主机从机的宕机都会导致前端部分读写请求失败,需要等待机器重启或者手动切换前端的IP才能恢复
- 主机宕机,宕机前有部分数据未能及时同步到从机,切换IP后还会引入数据不一致的问题,降低了系统的可用性
- Redis的主从复制采用全量复制,复制过程中主机会fork出一个子进程对内存做一份快照,并将子进程的内存快照保存为文件发送给从机,这一过程需要确保主机有足够多的空余内存。若快照文件较大,对集群的服务能力会产生较大的影响,而且复制过程是在从机新加入集群或者从机和主机网络断开重连时都会进行,也就是网络波动都会造成主机和从机间的一次全量的数据复制,这对实际的系统运营造成了不小的麻烦
三、哨兵模式
刚刚提到了,主从模式,当主节点宕机之后,从节点是可以作为主节点顶上来,继续提供服务的。但是有一个问题,主节点的IP已经变动了,此时应用服务还是拿着原主节点的地址去访问,这很显然是会有问题的。于是,引入了哨兵模式。
在主从的基础上,哨兵实现了自动化的故障恢复
如上图,哨兵模式由两部分组成,哨兵节点和数据节点:
- 哨兵节点:由一个或多个哨兵节点组成,哨兵节点是特殊的redis节点,不存储数据;
- 数据节点:主节点和从节点都是数据节点。
访问redis集群的数据都是通过哨兵集群的,哨兵监控整个redis集群。一旦发现redis集群出现了问题,比如刚刚说的主节点挂了,从节点会顶上来。但是主节点地址变了,这时候应用服务无感知,也不用更改访问地址,因为哨兵才是和应用服务做交互的。
哨兵很好的解决了故障转移,在高可用方面又上升了一个台阶,除此外还有一些其他功能:主节点存活检测、主从运行情况检测、主从切换。
Redis的Sentinel最小配置是 一主一从。
优点:
- 哨兵模式是基于主从模式的,所有主从的优点,哨兵模式都具有
- 主从可以自动切换,系统更健壮,可用性更高
- Sentinel 会不断的检查 主服务器 和 从服务器 是否正常运行。当被监控的某个 Redis 服务器出现问题,Sentinel 通过API脚本向管理员或者其他的应用程序发送通知。
缺点:
- Redis较难支持在线扩容,对于集群,容量达到上限时在线扩容会变得很复杂。
- 主从模式,切换需要时间,容易丢数据(重新选举出master需要时间)
- 没有解决 master 写的压力
四、集群模式
主从不能解决故障自动恢复问题,哨兵已经可以解决故障自动恢复了,那到底为啥还要集群模式呢?
主从和哨兵都还有另外一些问题没有解决,单个节点的存储能力是有上限,访问能力是有上限的。
哨兵模式虽然基本已经可以实现高可用,读写分离 ,但是在这种模式下每台 Redis 服务器都存储相同的数据,很浪费内存,所以在redis3.0上加入了 Cluster 集群模式,实现了 Redis 的分布式存储,也就是说每台 Redis 节点上存储不同的内容
Redis Cluster 集群模式具有 高可用、可扩展性、分布式、容错等特性。
原理:
通过数据分片的方式来进行数据共享问题,同时提供数据复制和故障转移功能。
之前的两种模式数据都是在一个节点上的,单个节点存储是存在上限的。集群模式就是把数据进行分片存储,当一个分片数据达到上限的时候,就分成多个分片。
背景:
Redis的官方多机部署方案,Redis Cluster。一组Redis Cluster是由多个Redis实例组成,官方推荐我们使用6实例,其中3个为主节点,3个为从结点。一旦有主节点发生故障的时候,Redis Cluster可以选举出对应的从结点成为新的主节点,继续对外服务,从而保证服务的高可用性。
那么对于客户端来说,知道对应的key是要路由到哪一个节点呢?原来,Redis Cluster 把所有的数据划分为16384个不同的槽位,可以根据机器的性能把不同的槽位分配给不同的Redis实例,对于Redis实例来说,他们只会存储部分的Redis数据,当然,槽的数据是可以迁移的,不同的实例之间,可以通过一定的协议,进行数据迁移。
Cluster 模式的原理:
其实现原理就是一致性 Hash。Redis Cluster 中有一个 16384 长度的槽的概念,他们的编号为 0、1、2、3 …… 16382、16383。这个槽是一个虚拟的槽,并不是真正存在的。正常工作的时候,Redis Cluster 中的每个 Master 节点都会负责一部分的槽,当有某个 key 被映射到某个 Master 负责的槽,那么这个 Master 负责为这个 key 提供服务。
至于哪个 Master 节点负责哪个槽,这是可以由用户指定的,也可以在初始化的时候自动生成(redis-trib.rb脚本)。这里值得一提的是,在 Redis Cluster 中,只有 Master 才拥有槽的所有权,如果是某个 Master 的 slave,这个slave只负责槽的使用,但是没有所有权。
Cluster 的分片机制:
Redis Cluster采用虚拟哈希槽分区而非一致性hash算法,为了使得集群能够水平扩展,首要解决的问题就是如何将整个数据集按照一定的规则分配到多个节点上。对于客户端请求的 key,根据公式 HASH_SLOT=CRC16(key) mod 16384,计算出映射到哪个分片上。而对于 CRC16 算法产生的 hash 值会有 16bit,可以产生 2^16-=65536 个值。
Redis 集群提供了灵活的节点扩容和收缩方案。在不影响集群对外服务的情况下,可以为集群添加节点进行扩容也可以下线部分节点进行缩容。可以说,槽是 Redis 集群管理数据的基本单位,集群伸缩就是槽和数据在节点之间的移动。
客户端如何路由?
既然 Redis 集群中的数据是分片存储的,那我们该如何知道某个 key 存在哪个节点上呢?即我们需要一个查询路由,该路由根据给定的 key,返回存储该键值的机器地址。
常规的实现方式便是采用如下图所示的代理方案,即采用一个中央节点(比如HDFS中的NameNode)来管理所有的元数据,但是这样的方案带来的最大问题就是代理节点很容易成为访问的瓶颈,当读写并发量高的时候,代理节点会严重的拖慢整个系统的性能。
Redis 并没有选择使用代理,而是客户端直接连接每个节点。Redis 的每个节点中都存储着整个集群的状态,集群状态中一个重要的信息就是每个桶的负责节点。在具体的实现中,Redis 用一个大小固定为 CLUSTER_SLOTS 的 clusterNode 数组 slots 来保存每个桶的负责节点。
方案说明:
- 通过哈希的方式,将数据分片,每个节点均分存储一定哈希槽(哈希值)区间的数据,默认分配了16384 个槽位
- 每份数据分片会存储在多个互为主从的多节点上
- 数据写入先写主节点,再同步到从节点(支持配置为阻塞同步)
- 同一分片多个节点间的数据不保持一致性
- 读取数据时,当客户端操作的key没有分配在该节点上时,redis会返回转向指令,指向正确的节点
- 扩容时时需要需要把旧节点的数据迁移一部分到新节点
- 在 redis cluster 架构下,每个 redis 要放开两个端口号,比如一个是 6379,另外一个就是 加1w 的端口号,比如 16379。
- 16379 端口号是用来进行节点间通信的,也就是 cluster bus 的东西,cluster bus 的通信,用来进行故障检测、配置更新、故障转移授权。cluster bus 用了另外一种二进制的协议,gossip 协议,用于节点间进行高效的数据交换,占用更少的网络带宽和处理时间。
分布式寻址算法:
- hash 算法(大量缓存重建)
- 一致性 hash 算法(自动缓存迁移)+ 虚拟节点(自动负载均衡)
- redis cluster 的 hash slot 算法
优点:
- 无中心架构,支持动态扩容,对业务透明
- 具备Sentinel的监控和自动Failover(故障转移)能力
- 客户端不需要连接集群所有节点,连接集群中任何一个可用节点即可
- 高性能,客户端直连redis服务,免去了proxy代理的损耗
缺点:
- 运维也很复杂,数据迁移需要人工干预
- 只能使用0号数据库
- 不支持批量操作(pipeline管道操作)
- 分布式逻辑和存储模块耦合等