当前位置: 首页 > 科技观察

Redis集群的几种实现方法

时间:2023-03-18 22:45:33 科技观察

在业务场景中,如果要有所准备,最好使用集群。如果没有集群,至少要用master-slave。让从库接管,服务才能继续。否则master需要经过数据恢复和重启的过程,可能耗时较长,影响线上业务的持续服务。在了解Redis集群的实现之前,需要先了解redis的主从复制。在理解主从复制之前,首先要理解分布式系统的理论基石,CAP原理。CAPCAP是分布式存储的理论基石。C:一致性;答:可用性;P:分区公差;原理:当网络分区发生时,很难兼顾一致性和可用性。Redis满足可用性(AP);保证最终的一致性。Redis保证“最终一致性”,从节点会努力追赶主节点,最终从节点的状态会和主节点的状态一致。如果断网,主从节点的数据会出现很多不一致的情况。一旦网络恢复,从节点将使用各种策略追上滞后的数据,并继续尽力保持与主节点的一致性。关于同步主从同步Redis同步支持主从同步和从从同步。从库同步功能是Redis后续版本增加的功能,目的是减轻主库的同步负担。下面为了描述方便,统一理解为主从同步。增量同步同步是指令流。在同步指令流的同时,从节点反馈自己的偏移量。redis的copymemorybuffer是一个定长的环形数组;如果内存已满,则从头开始覆盖之前的内容。快照同步可以防止网络不好时主从无法及时同步。导致指令覆盖,非常耗资源的同步,在master节点调用一次bgsave,将当前内存中的数据全部快照到磁盘。然后将所有内容同步到从节点。从从节点接收到文件后,会立即进行一次满载,然后通知主节点同步缓冲区。如果复制的缓冲区大小太小,会导致快照同步死循环;请务必配置合适的缓冲区大小。无盘复制Redis2.8.18版本支持无盘复制。所谓无盘复制,就是主服务器直接将快照内容通过socket发送给从节点。生成快照是一个遍历过程。主节点会遍历内存,一次性将序列化后的内容发送给从节点。从节点还是和之前一样,将接收到的内容存储在一个磁盘文件中,然后一口气加载。wait命令只有在redis3.0之后才有。命令waitnt表示在t时间内等待n个节点的同步。如果t=0,则发生网络分区,redis将失去可用性。sentinel集群可以把redissentinel集群看成一个zookeeper集群,一般由3-5个节点组成。Redis主从采用异步复制,这意味着当主节点挂掉时,从节点可能收不到所有的同步消息。这部分未同步的消息丢失了。如果主从延迟特别大,可能丢失的数据特别多。Sentinel不能保证消息完全不丢失,但是会尽量保证消息丢失的少。它有两个选项来限制过多的主从延迟。min-slaves-to-write1min-slaves-max-lag10第一个参数表示master节点必须至少有一个slave节点在进行正常的复制,否则外部写服务会停止,失去可用性。sentinel默认端口为26379,如果master节点挂掉,所有连接都会断开,重新连接新的master节点。所有的更新操作都会报错并捕获一个readOnlyError。主从切换后,之前的主库降级为从库,所有修改的指令都会抛出ReadonlyError。如果没有修改指令,虽然不会切换连接,但是数据不会被破坏,所以不切换也没关系。Codis集群单实例redis只使用一个CPU,无法完成海量数据的存储和管理。Codis是redis集群解决方案之一,由原peapod团队开发。项目负责人刘奇还开发了分布式数据库TiDB。使用go语言,是一个代理中间件;它使用redis协议进行外部服务。分片原则默认为1024个槽位,可以调整。建议调整为2048、4096。slot计算方式:key->crc32获取hash值->hash%1024=slot,内存中会维护slot与redis实例的关系。不同codis实例直接槽关系使用zk和etcd同步存储槽关系,实现共享槽关系配置。扩展codis对redis进行了改造,增加了slotsscan命令,可以遍历指定slot下的所有key。当codis收到正在迁移的key后,会强制迁移,然后向新的实例发送请求。缺点不是真子单键不易太大不支持事物增加代理层网络开销需要维护zk集群优势自动槽均衡有良好的后台管理系统,qps曲线,槽状态,哪个实例slot分配给等Redis集群clusterRedisCluster是Redis的子类,是Redis作者自己提供的Redis集群解决方案。与Codis不同,它是去中心化的。每个节点负责不同的数据,Redis集群节点使用Gossip协议广播自己的状态和对整个集群的感知变化。例如,如果一个节点发现一个节点断开连接(PFail),它会向整个集群广播这个信息,其他节点也能收到这个断开连接的信息。如果一个节点收到某个节点已经达到集群多数的数量(PFailCount),它可以将该节点标记为确认下线状态(Fail),然后向整个集群广播以强制其他节点也下线接收PFail计数。节点已经下线的事实,立即执行丢失节点的主从切换。默认有16384个slot,客户端会存储一个slot的配置信息。槽位定位key->crc16得到hash值->hash%16384=slot通过在key字符串中嵌入一个tag;钥匙所在的插槽可以强制使用;当槽被迁移时,对旧槽的请求将返回一个MOVED命令,后面跟着一个目标节点地址。客户端收到MOVED命令后,立即更正本地slot映射表。第二条asking命令与moved不同,它是用来临时纠正slot的。如果当前slot正在迁移,则命令首先发送给slot所在的旧节点。如果旧节点有数据,则直接返回结果。如果它不存在,那么它可能不存在或者它可能正在目标节点上迁移。所以老节点会通知客户端去新节点尝试获取数据,看看新节点有没有。此时会向客户端返回一个请求错误,其中包含目标节点的地址。客户端收到这个询问错误后,会去目标节点尝试。客户端不会刷新slot映射表,因为它只是暂时修正命令的slot信息,不影响后续命令。为了防止连续跳转,rt太高,客户端设置重试次数。一次迁移一个插槽没有非常友好的用户界面。大致流程如下:从源节点获取内容-》保存到目标节点-》从源节点删除内容,整个过程是同步的,会造成阻塞。集群变化感知当服务器节点发生变化时,应立即通知客户端实时刷新其节点关系表。客户如何收到通知?这里有两种情况:目标节点挂掉了,客户端会抛出ConnectionError,然后会随机挑一个节点重试,重试的节点会把目标槽分配到的新节点地址通知给移动错误。运维手动修改集群信息,将master切换到其他节点,将老master从集群中移除。此时在老节点上敲的命令会收到ClusterDown错误,提示当前节点所在的集群不可用(当前节点已经被隔离,不再属于之前的集群)。这个时候client会关闭所有连接,清空slot映射关系表,然后向上层抛出错误。当下一条指令到来时,它会再次尝试初始化节点信息。容错性每个主节点设置多个从节点。主节点挂掉后,提升其中一个从节点。如果没有slave节点可用,可以设置cluster-require-full-coverage允许一些错误,其他节点正常对外服务。网络抖动设置主从切换slack系数和cluster-node-timeout,防止网络抖动导致主从频繁切换。