Redis初时~集群模式
Redis的集群模式是在Redis3.0模式以后所实行的高可用模式。虽然大部分公司还都在用3.0以下的模式,但是随着发展我们会慢慢的接触到3.0以上的形式。在这里我们先简单的介绍下集群的模式,方便我们后期来用。
Redis的集群介绍
Redis的集群是一个提供多个Redis节点之间数据共享的程序集。但是Redis集群并不支持处理多个keys的命令,因为这需要在不同的节点移动数据,在高负载的情况下可能导致不可预料的错误。Redis集群通过分区来提供一定程度的可用性,这样情况的优势在于,
- 能自动的分割数据到不同的节点上。
- 整个集群的部分节点失败或者不可达的情况下能继续处理命令。
Redis集群的数据分片
Redis的集群没有使用一致性的hash,而是引入了哈希槽的概念。哈希槽就是在Redis中使用CRC16检验后对16384进行取模 来决定放置在哪个槽。Redis中一共有16384个槽 ,所以在取模的时候我们会对16384进行操作。集群中有N个机器,那么16384节点会平分这些槽。这样就很容易方便我们方便我们操作机器的增加和删除,并且不影响我们集群的状态。
Redis集群的主从复制模型
前面的文章中我们介绍的Redis中的复制功能。在集群中,我们也是用了相关的操作,为了防止在部分节点失败的或者无法通信的情况下集群仍然可用。所以我们在集群中使用了主从复制模型,每个节点都会有N-1个复制品。当主节点失败的时候,从节点会直接代替旧的主节点成为新的主节点。
Redis的一致性保证
Redis 并不能保证数据的强一致性,这在操作中容易出现丢失的写操作。为什么会出现这种情况呢,是因为Redis的集群采取的异步复制的方式。写操作的过程中
- 客户端向主节点写入一条命令。
- 主节点master向客户端回复一条命令状态
- 主节点将写操作复制给他的从节点
主节点对命令的复制工作发生在返回命令回复之后,因为如果每次请求命令都需要等待复制操作完成的情况下,那么主节点处理命令的请求速度回极大地降低,所以我们必须在性能和一致性操作做出权衡。 另外出现数据丢失的情况是 集群出现了网络分区,并且一个客户端与至少一个主节点在内的少数实例被孤立。
错误的分区那么相当于主节点就会出现问题,虽然在这期间仍然能像某个出现问题的主节点上继续写入数据,但是在大的分区那里从节点会被选举为新的主节点,这样在选举期间造成的数据写入到旧的数据master上,就会数据丢失了。所以我们在配置集群的时候 节点的超时时间配置(node timeout)就是十分重要了。
集群的重新分片
在上面我们也说过,我们在集群中可以方便的增加节点和删除节点,但是有个问题就是我们需要进行重新进行分片。在Redis中我们的分片操作并不影响我们系统的运行,我们可以使用
./redis-trib.rb reshard 127.0.0.1:7000 数据进行分片
我们知道如果集群已经稳定的运行了一段时间,那么在我们想移动的槽里面一般都会存在数据的,所以我们在移动的时候也得知道移动的哈希槽数量之外 ,还的知道分片的目标地址。
$ redis-cli -p 7000 cluster nodes | grep myself
87a3a3236747727124449322d633e1c3db5421b1 :0 myself,master - 0 0 0 connected 0-5460
其中目标节点是87a3a3236747727124449322d633e1c3db5421b1,现在需要指定从哪些节点来移动keys到目标节点 我输入的是all ,这样就会从其他每个master上取一些哈希槽。
最后确认后你将会看到每个redis-trib移动的槽的信息,每个key的移动的信息也会打印出来 在重新分片的过程中,你的例子程序是不会受到影响的,你可以停止或者重新启动多次。
Redis集群的目标
Redis的集群在3.0版本以后增加了,为什么会专门在Redis中实现集群的方式呢,在这里我们看到的是Redis为了提高高可用的性能所做的努力。
- 集群目标是在1000个节点的时候仍然能表现的很好,并且有很好的扩展性。
- 没有合并的操作,这样在Redi的数据模型上大数据值也能表现的很好。
- 写入安全,尝试让大多数节点相连的客户端写入操作都能保证的安全的写入,虽然现在还会有小部分写入丢失。
- 可用性,在绝大多数节点是可达的情况下,对于不可达的主节点在有一个从节点可达的情况下,Redis集群仍能进行分区操作。
Redis 集群中客户端与服务端
Redis中节点负责存储数据、记录集群的状态。集群节点同样能自动发现其他节点,检测出没有正常工作的节点,并且在节点中 选出主节点,那么为了这些操作,Redis之间的节点是通过TCP链接和一个二进制链接简历通讯,每一个节点都活通过集群链接与集群上的其他节点链接起来,并且通过使用一个gossip协议来传播集群的信息。这样发现新的节点、通过网络ping, 特定情况发生时发送集群消息。 由于集群节点不能代理 请求,所以客户端在接收到重定向错误的时会将命令重定向其他节点。客户端是可以自由的像集群中任意节点发送请求。也可以在需要的时候重定向到其他节点来保证命令的执行效率。
安全写入
Redis集群之间节点采用了异步的冗余备份。所以偶尔在分区的时候会存在时间段容易丢失数据。但是就如我们上面所说的两种情况会导致数据的丢失。总结情况如下:
- 写入操作能到达一个节点上,当回复节点时主节点宕机了,然而数据还没有同步到从节点,那么该写入就已经丢失,从节点被提为主节点。
- 因为分区使一个主节点不可达。
- 故障转移导致主节点的从节点升为主节点
- 过一段时间后主节点再次可达
- 一个没有更新路由表的客户端或许会在集群把主节点变成从节点。导致写入失败。
所以我们在这是node_timeout的时候需要慎重,容易导致数据丢失的问题
为什么有的单机操作使用的命令在集群 中不可使用
Redis集群在设计的时候是避免在多个节点中存在同个键值对的冲突版本。Redis中的数据模型不允许这么做,有时候值特别大,那么我们在列表或者排序号的集合中就会有大量的元素,传输和合并就会有性能瓶颈。
TIM截图20180405235154.jpg