1.redis高可用介绍
redis从3.0版本开始引入了redis-cluster(集群)。
从主从-哨兵-集群可以看到redis的不断完善;主从复制是最简单的节点同步方案无法主从自动故障转移。
哨兵可以同时管理多个主从同步方案同时也可以处理主从自动故障转移,通过配置多个哨兵节点可以解决单点网络故障问题, 但是单个节点的性能压力问题无法解决。集群解决了前面两个方案的所有问题。
(1)Redis-Cluster采用无中心结构
每个节点都和其它节点通过互ping保持连接,每个节点保存整个集群的状态信息,可以通过连接任意节点读取或者写入数据
(甚至是没有数据的空节点)。
(2)只有当集群中的大多数节点同时fail整个集群才fail
一般情况下是集群当中超过一半以上的节点fail的时候,集群才会fail
(3)整个集群有16384个slot
当需要在 Redis 集群中放置一个key-value 时,根据 CRC16(key) mod 16384的值,决定将一个key放到哪个桶中。
读取一个key时也是相同的算法。
(4)当主节点fail时从节点会升级为主节点
fail的主节点online之后自动变成了从节点
Redis集群中内置了 16384 个哈希槽,当需要在 Redis 集群中放置一个 key-value 时,redis 先对key 使用 crc16 算法算出一个结果,
然后把结果对 16384 求余数,这样每个 key 都会对应一个编号在 0-16383 之间的哈希槽,
redis 会根据节点数量大致均等的将哈希槽映射到不同的节点。
2.什么是哈希槽?
Redis 集群没有使用一致性hash, 而是引入了哈希槽的概念。
Redis 集群有16384个哈希槽,每个key通过CRC16校验后对16384取模来决定放置哪个槽.集群的每个节点负责一部分hash槽。
这种结构很容易添加或者删除节点,并且无论是添加删除或者修改某一个节点,都不会造成集群不可用的状态。
使用哈希槽的好处就在于可以方便的添加或移除节点。
当需要增加节点时,只需要把其他节点的某些哈希槽挪到新节点就可以了;
当需要移除节点时,只需要把移除节点上的哈希槽挪到其他节点就行了;
在这一点上,我们以后新增或移除节点的时候不用先停掉所有的 redis 服务。
"用了哈希槽的概念,而没有用一致性哈希算法,不都是哈希么?这样做的原因是为什么呢?
"
Redis Cluster是自己做的crc16的简单hash算法,没有用一致性hash。
Redis的作者认为它的crc16(key) mod 16384的效果已经不错了,
虽然没有一致性hash灵活,但实现很简单,节点增删时处理起来也很方便。
"为了动态增删节点的时候,不至于丢失数据么?
"
节点增删时不丢失数据和hash算法没什么关系,不丢失数据要求的是一份数据有多个副本。
“还有集群总共有2的14次方,16384个哈希槽,那么每一个哈希槽中存的key 和 value是什么?
”
当你往Redis Cluster中加入一个Key时,会根据crc16(key) mod 16384计算这个key应该分布到哪个hash slot中,
一个hash slot中会有很多key和value。你可以理解成表的分区,使用单节点时的redis时只有一个表,所有的key都放在这个表里;
改用Redis Cluster以后会自动为你生成16384个分区表,你insert数据时会根据上面的简单算法来决定你的key应该存在哪个分区,
每个分区里有很多key。
3.其他知识
集群:是一个提供多个Redis(分布式)节点间共享数据的程序集
集群部署:Redis 集群的键空间被分割为 16384 hash个槽(slot), 集群的最大节点数量也是 16384 个
关系:cluster>node>slot>key
分片
:
Redis Cluster在设计中没有使用一致性哈希(Consistency Hashing),而是使用数据分片引入哈希槽(hash slot)来实现;
一个 Redis Cluster包含16384(0~16383)个哈希槽,存储在Redis Cluster中的所有键都会被映射到这些slot中,
集群中的每个键都属于这16384个哈希槽中的一个,集群使用公式slot=CRC16(key)/16384来计算key属于哪个槽,
其中CRC16(key)语句用于计算key的CRC16 校验和。
按照槽来进行分片,通过为每个节点指派不同数量的槽,可以控制不同节点负责的数据量和请求数.
当前集群有3个节点,槽默认是平均分的:
节点 A (6381)包含 0 到 5499号哈希槽.
节点 B (6382)包含5500 到 10999 号哈希槽.
节点 C (6383)包含11000 到 16383号哈希槽.
这种结构很容易添加或者删除节点. 比如如果我想新添加个节点D, 我需要从节点 A, B, C中得部分槽到D上.
如果我想移除节点A,需要将A中得槽移到B和C节点上,然后将没有任何槽的A节点从集群中移除即可.
由于从一个节点将哈希槽移动到另一个节点并不会停止服务,
所以无论添加删除或者改变某个节点的哈希槽的数量都不会造成集群不可用的状态.
数据迁移
:
数据迁移可以理解为slot(槽)和key的迁移,这个功能很重要,极大地方便了集群做线性扩展,以及实现平滑的扩容或缩容。
现在要将Master A节点中编号为1、2、3的slot迁移到Master B节点中,
在slot迁移的中间状态下,slot 1、2、3在Master A节点的状态表现为MIGRATING(迁移),
在Master B节点的状态表现为IMPORTING(入口)。
此时并不刷新node的映射关系
IMPORTING状态
被迁移slot 在目标Master B节点中出现的一种状态,
准备迁移slot从Mater A到Master B的时候,被迁移slot的状态首先变为IMPORTING状态。
键空间迁移
:
键空间迁移是指当满足了slot迁移前提的情况下,通过相关命令将slot 1、2、3中的键空间从Master A节点转移到Master B节点。
此时刷新node的映射关系。
复制&高可用
:
集群的节点内置了复制和高可用特性。
特点:
1、节点自动发现
2、slave->master 选举,集群容错
3、Hot resharding:在线分片
4、基于配置(nodes-port.conf)的集群管理
5、客户端与redis节点直连、不需要中间proxy层.
6、所有的redis节点彼此互联(PING-PONG机制),内部使用二进制协议优化传输速度和带宽.
4.高可用redis cluster集群的具体实现过程如下:
(1)在server1(master)上面进行设置
overcommit_memory是什么?
overcommit_memory是一个内核对内存分配的一种策略。 具体可见/proc/sys/vm/overcommit_memory下的值
overcommit_memory有什么作用?
overcommit_memory取值又三种分别为0, 1, 2
overcommit_memory=0, 表示内核将检查是否有足够的可用内存供应用进程使用;
如果有足够的可用内存,内存申请允许;否则,内存申请失败,并把错误返回给应用进程。
overcommit_memory=1, 表示内核允许分配所有的物理内存,而不管当前的内存状态如何。
overcommit_memory=2, 表示内核允许分配超过所有物理内存和交换空间总和的内存
我将值设置为1
(2)在server1上创建 6个Redis 节点
先把默认开启的6379停掉:
首先在 server1 机器上 /usr/local/目录下创建 rediscluster 目录;
在 rediscluster 目录下,创建名为7001、7002、7003、7004、7005、7006的目录
进入7001目录,编写redis.conf文件
开启7001节点,发现直接占用我们的终端
port 7001 //端口7001,7002,7003,7004,7005,7006
cluster-enabled yes //开启集群
cluster-config-file nodes.conf //集群的配置,配置文件首次启动自动生成 7001,7002,7003,7004,7005,7006
cluster-node-timeout 5000 //请求超时 默认5秒,可自行设置
appendonly yes //aof日志开启 有需要就开启,它会每次写操作都记录一条日志
同理配置其他5个节点,并且开启服务
:
最终可以查看6个节点全部开启
(3)在server1上创建rediscluster集群
注意:要指定一主一从
测试:集群中三个master,三个slave,数据完全同步
三个master分别为:server1、server2、server3
server2的slave是server5
(4)接下来测试集群的高可用
登陆节点2(master节点之一),shutdown
查看集群的状况,发现server2的slave节点server5自动变为新的master了
然后将server5也down掉
再次查看发现只有两个master了
检查集群中的哈希槽已经不能用了,集群已经down了。
数据存储位置:
重启server2、5
:
再次恢复可用
:
当集群当中的一半以上的master都down掉以后,集群也会down掉了
5.增加新的节点
将7007节点添加进去,必须指定一个老的节点:
给7007主节点添加一个7008从节点
:
因为上述添加的没有哈希草,现在从新分配一下:
指定分配300个哈希草:
若想平均分配哈希草: