redis中集群
Redis集群:
Redis单机版主要有以下几个缺点:
- 不能够保证数据的可靠性,服务器全部部署在一台服务器上面,一旦服务器宕机整个redis的服务都不再可用
- 性能瓶颈的问题,内存的容量有限,在处理的能力上有一定的缺失
1. Redis的主从模式:
Redis单机版通过RDB与AOF的持久化的机制将数据持久化到相应的硬盘上,但是数据的存储都是在一台服务器上的,并且读写都在同一台服务器,如果硬盘出现了问题,则会导致数据的不可用,为了避免这个问题,Redis提供了复制的功能即在master数据库中的数据更新以后,自动将更新的数据同步到slave数据库上面,这就是主从模式的Redis集群。
Redis中主从配置策略的详细解释:
采用远程的阿里云服务器进行配置:
(1)只需要配置从库并不需要配置主库:
# 查看库的一些默认的信息:
127.0.0.1:6879> info replication
# Replication
role:master # 角色
connected_slaves:0 # 当前无从机
master_replid:e5fe646e9cf014e76374f443cada3f4f0a4b69f3
master_replid2:0000000000000000000000000000000000000000
master_repl_offset:0
second_repl_offset:-1
repl_backlog_active:0
repl_backlog_size:1048576
repl_backlog_first_byte_offset:0
repl_backlog_histlen:0
(2)首先打开四个窗口:
(3)搭载相应的伪集群:
进入到redis的配置文件位置copy两个配置文件:redis80.conf与redis81.conf按照如下进行配置:
1. port # 端口位置 port 6879
2. pid #pid文件 配置如下:pidfile /var/run/redis_6879.pid
3. log #日志文件名 redis.conf配置文件中有 logfile的配置 例如配置如下 logfile "6879.log"
4. dump.rdb #rdb文件名 配置如下:dbfilename dump6879.rdb
(4)修改完毕以后启动三个服务,三个服务会部署在同一个服务器的不同的端口位置:
(5)主从模式的配置策略:
配置一主二从:两个从机认老大:
slavof host port # slavof 0.0.0.0 6897 (host在真实的情况下需要多台云服务器)
操作:
主机可以设置值,可以写,但是从机只能是读,主机中所有的数据都会自动被从机进行保存:
从机写不可以:
主从复制的原理:
1.slave启动后会成功的连接到master后会发送一个sync命令
2.master接收到命令以后,启动后台的存盘进程,同时收集所有接收到的用于修改数据集的命令,在后台进程执行完毕以后,master将传送整个数据文件到达slave中,并完成一次性的同步。
全量的复制:slave服务在接收到数据库文件数据以后,将其存盘并加载到内存当中
增量的复制:Master继续将心的所有收集到的修改命令一次传递给slave,完成同步。
优点:
- 高可靠性,在master数据库出现故障以后,可以切换到slave数据库
- 读写分离,slave库可以扩展master库的结点的读能力,有效的应对大并发量的操作
缺点:
- 不具备自动容错和恢复的能力,主结点故障,从节点需要手动升级为主节点,且可用性较低
2.Redis中的哨兵模式:
为了解决主从模式的Redis集群所不具备自动容错和恢复能力得问题,Redis从2.6版本开始提供哨兵模式(Sentinel),哨兵模式得核心还是主从复制,不过相比于主从模式,多了一个竞选机制(多了一个哨兵集群),从所有从节点中竞选出主节点,图示:
哨兵模式是一种特殊的模式,首先redis提供了哨兵的命令,哨兵是一个独立的进程,作为进程,它会独立的运行。其原理是哨兵通过发送相应的命令,等待redis服务器的响应,从而监控运行的多个redis的实例。
这里哨兵有两个作用:
1.通过发送命令,让redis服务器返回监控其运行的状态,包括主服务器和从服务器
2.当哨兵检测到master主机宕机以后,会自动将slave切换成master,然后通过发布订阅模式通知其他的从服务器,修改其配置文件,让他们切换到相应的主机。
假设主服务器宕机,哨兵1先检测到这个结果,系统并不会马上进行failover过程,仅仅是哨兵1主观的认为主服务器不可用,这个现象成为主观下线。当后面的哨兵也检测到主服务器不可用,并且数量达到一定值时,那么哨兵之间就会进行一次投票,投票的结果由一个哨兵发起,进行failover[故障转移]操作。切换成功后,就会通过发布订阅模式,让各个哨兵把自己监控的从服务器实现切换主机,这个过程称为客观下线。
(1)实现的步骤:
1.配置哨兵的配置文件,sentinel.conf:
# 被监控名称 主机 端口 数字1代表主机挂了投票结果:
sentinel monitor myredis 0.0.0.0 6879 1
# 注意如果连接的是远程的服务器设置了redis密码就要设置密码:
sentinel auth-pass myredis + 主机密码
2.启动哨兵:
redis-sentinel liuconfig/sentinel.conf
执行显示:
1.关闭主机时,sentinel会发生心跳包使得自动选择新的从机为主机
2.选择好得从机需要输入密码以后自动变成主机
3.如果主机此时回来了只能当从机的手下
哨兵模式当中的细节点:
1.首先聊一聊redis集群当中的高可用:
redis集群中高可用的评判标准使,例如可用性达到99.9%,99.99%,99.999%。按照其运行的时间来看,服务允许不可用的时间的计算公式为:
服务允许不可用的时间 = 总的运行时间 * (1 - 可用性)
redis哨兵模式高可用的两块内容:
1.哨兵集群中哨兵之间的相互的通信
2.哨兵与redis服务实例之间的通信
- 哨兵中的相互的通信:
注意哨兵之间的通信结构肩负着Redis集群高可用的重任,通信包含以下的信息:
1.主节点的运行状态
2.主节点的主机名以及主节点的端口信息
3.主观下线的时常与客观下线的时常
4.从节点信息以及故障转移的状态等等
既可以保证哨兵之间可以定期交换主节点的运行时状态数据,又可以保证主机点的选举以及故障的转移的相关的操作顺利进行。哨兵之间转移的信息如下:
- 哨兵与redis服务实例之间的通信:
主节点的相应数据有以下几种:
1.PONG:判定主节点正常,无需向其他哨兵确认主节点状态
2.LOADING:主节点正在载入,会周期性向主节点发送诊断信息,如果主节点为PONG则无需其他操作
3.MASTERDOWN:主节点下线,这里有SDOWN(Subjectively Down)和ODOWN(Objectively Down),即主观下线和客观下线如果发现下线,当前哨兵会与其他哨兵通信,对主节点状态作最终判定,以及故障转移操作。如果Redis主节点无响应,主节点会标识自身为BUSY。
哨兵模式的优缺点:
优点:
- 哨兵模式是基于主从模式的,可以解决主从模式中master故障不可自动切换新结点的问题
缺点:
- 浪费资源,集群中所有的结点都是保存的全量的数据信息,数据量过大以后,主从同步会严重影响相应的性能
- redis主机宕机以后,投票选举结束之前,谁也不知道主机和从机是谁,此时的redis也会开启保护机制,禁止写操作,直到选举出新的redis主机。
- 只有一个master库执行写请求,写操作会受到单机性能瓶颈的影响。
3. Redis当中的自研模式:
哨兵模式虽然解决了主从模式存在的一些问题,但是其中也存在一定的弊端问题,比如数据在每一个redis实例中都是全量存储,极大的浪费了资源,为了解决这个问题,redis提供了redis cluster模式,实现了数据的分片存储,但是redis提供redis cluster之前很多公司为了解决哨兵模式存在问题,分别自行研发redis集群方案。
客户端分片:
客户端分片是把分片的逻辑放到redis客户端来实现,通过redis客户端预先定义好的路由规则(使用哈希算法),把对key的访问转发到不同的redis实例当中,查询数据时候把返回结果汇集。如下:
优缺点:
优点:
redis实例彼此独立,相互无关联,每一个redis实例像单个服务器一样进行运行,非常容易进行线性的扩展,系统的灵活性很强。
缺点:
(1)客户端sharding不支持动态的增删结点,服务端redis实例群拓扑结构有变化的时候,每一个客户端都需要更新调整。
(2)运维的成本较高,例如:java项目与PHP项目公用一套redis集群,路由分片逻辑需要写两套逻辑,以后需要维护的也是两套逻辑。
代理分片
客户端分片的最大问题就是服务端Redis实例群拓扑结构有变化时,每一个客户端都需要进行更新。为了解决这个问题,代理分片出现了,代理分片将客户端分片模块单独分了出来,作为Redis客户端和服务端的桥梁:
解决了服务端Redis实例群拓扑结构有变化时,每一个客户端都需要更新的调整的问题。缺点是由于Redis客户端每一个请求都经过代理才能到达Redis服务器,这个过程会造成性能的损失。
代理分片:
客户端分片的最大问题就是服务端Redis实例群拓扑结构有变化时,每一个客户端都需要进行更新。为了解决这个问题,代理分片出现了,代理分片将客户端分片模块单独分了出来,作为Redis客户端和服务端的桥梁
解决了服务端Redis实例群拓扑结构有变化时,每一个客户端都需要更新的调整的问题。缺点是由于Redis客户端每一个请求都经过代理才能到达Redis服务器,这个过程会造成性能的损失。
4.redis的cluster模式:
Redis Cluster是Redis作者自己提供的集群方案,集群中由一堆结点组成,每一个结点都和集群中的其他结点相连。对于Redis来说Redis的集群主要是将数据进行分片,类似于数据库通常的分库策略
解决方案如下:
1.哈希取余的解决方案:
针对redis来说1亿条数据,一般是1亿个key与value,我们把他们分别存储在N个结点上,例如:N = 3,然后用户每次读写操作根据节点N使用公式:
hash(key) % N
计算出相应的hash值,用来决定数据映射到哪一个节点上面。
优点:
- 简单粗暴,只要提前预估好数据量,然后规划好相应的节点,例如:3台,30台,300台节点,就能保证未来一段时间内的数据支撑。
缺点:
- 节点扩容的时候会成为大麻烦,因为每一次节点数量有变动时候数据节点映射关系都需要进行重新的计算,会导致数据的重新迁移。例如:原先是3台,后面需要增到8台,需要把所有的历史数按照 hash(key) % 8 重新洗牌一遍,非常的麻烦。
2.一致性hash环的方案:
步骤一:
就是对于key计算出一个hash值,然后对于2的32次方进行取模,也就是值得范围在[0-2^32-1],一致性哈希将其范围抽象构成一个圆环,使用CRC16算法计算出来得哈希值会落到环的某一个地方。
步骤二:
同时将Redis集群中各个节点映射到环上的某一个位置根据IP地址进行映射,例如redis有四台服务器:
路由规则:
路由规则包括 set(x) 与 get(x)
当需要存储一个key与value时候,可以首先计算key所对应的hash值,这个hash值必然对应于一致性hash环上的某一个位置,然后沿着这个值按照顺时针找到第一个节点,并将该键值存储在该节点上面。例如下图:
优点:
- 与hash取余相比,容错性和扩展性更加灵活,,例如NodeC节点瘫痪只会影响到NodeB和NodeC之间区域的数据,影响面较小,再例如增加一个节点NodeX在NodeA与NodeB之间,只会影响到NodeA与NodeX之间的数据
缺点:
- 会导致数据倾斜的现象发生,如果一致性hash环上面的节点数量太少就会造成该现象:
3.采用哈希槽解决redis集群问题
Redis集群当中内置了16384个哈希槽,当需要在redis集群中放置一个key-value时候,redis先对key使用crc16算法算出一个结果,然后把结果对16384求余,这样每一个key都会对应一个编号在0-16384之间,redis会根据节点数量大致均等的将哈希槽映射到不同的节点上面。
- 把哈希槽均匀分段,分配给redis节点
redis节点1,负责存储5461个哈希槽的数据,编号0号至5460号哈希槽
redis节点2,负责存储5462个哈希槽的数据,编号5461号至10922号哈希槽
redis节点3,负责存储5461个哈希槽的数据,编号10923号至16383号哈希槽 - 计算每条数据的slot空间位置
- 将数据key进行哈希取值,映射已经固定大小的hash slot空间上
使用哈希槽的好处就在于可以方便的添加或移除节点。
当需要增加节点时,只需要把其他节点的某些哈希槽挪到新节点就可以了;
当需要移除节点时,只需要把移除节点上的哈希槽挪到其他节点就行了;
在这一点上,我们以后新增或移除节点的时候不用先停掉所有的 redis 服务
redis哈希槽分区的特点:
1)解耦数据和节点之间的关系,例如:数据的读写只要计算出槽号就可以,节点的扩容和收缩只要重新均衡分配槽区间即可;故简化了节点扩容和收缩难度
2)节点自身维护槽的映射关系,不需要客户端(spring)或者代理服务维护槽分区和数据
3)支持节点、槽、键之间的映射查询,用于数据路由、在线伸缩等场景