深入浅出百亿请求高可用Redis(codis)分布式集群揭秘
主要由dashboard按批次触发直到所有的key都迁移ok,迁移的过程,slot上的key可能存在2种情况,一种在新的redis实例上A,一种在旧的redis实例上B,所以对于有迁移状态的slot,所有向这个slot发送的命令都通过在redis中定制的命令SLOTSMGRT-EXEC-WRAPPER来处理,该命令是基于3.2的分支新增的,该命令主要做这几个事情,1)判断key是否存在,如果存在,但不在迁移批次,则直接对key调用真实方法,如果存在,但在迁移批次,则允许读操作,不允许写操作,2)如果key不存大,则key可能已经被迁移到新实例,也可能key不存在,则通知proxy前往新的实例进行操作 迁移性能 Codis的迁移其实之前2.x版本的迁移性能并不高,3.x之前性能提升了非常之大,千万级别的zset结构迁移只需要10多秒,而在原来的模式需要50多秒,具体原因在于 迁移性能数据 6.2 迁移异常处理 另外,看到这里,不知道大家有没有什么问题,不过这里我准备了一些问题,来看看codis是如何来处理的,特别在网络环境复杂,不稳定的情况下怎么操作。 问题一,把大key拆分成小批次进行迁移,如果批次迁移失败,超时,怎么做? 我们知道分布场景下网络调用有三态,成功,失败,超时,对于失败还好一点,超时的情况,我们能否盲目进行重试,这里显然不行,通常对于数据层面的重试,我们需要保证一个非常重要的原则,幂等性,但是在redis结构中除了zset,set,hash,string结构重试理论不会受影响,对于list怎么办?所以codis用了一种比较暴力的方式,批次迁移成功重试时,会先带上一个del命令,让目标结点先将key删掉,再进行重试。 问题二,带过期时间key迁移过程中,先在目标结点上设置过期时间再传数据,还是先传数据在最后再设置过期时间? 先看一下在目标结点上设置过期时间再传数据的问题:传输一半B机器的key过期,后续key就没有过期时间。不符合我们的期望 再看一下先传数据在最后再设置过期时间的问题:如果传输一半Acrash重启,而此时key过期,则数据落在B机器上成僵尸数据,也不符合我们的期望。那codis如何来做呢? 为了保证迁移过程中的分片在迁移异常时能自动销毁,所以每次分片传输的时候,都重置一下key过期时间为90秒(大于超时时间30秒),在key迁移完成之后再重置为真实的过期时间,这样即使迁移过程中Acrash,key过期或者其他的异常,分片数据也只会在目标结点上存活90秒就销毁。 问题三,迁移过程中Acrash, 此时对应分片的数据一半在A,一半在B,怎么办了? 常在河边走,哪有不挨刀,我们就碰到过codis的一个因expire迁移实现不当造成的血案,不过幸好发生在测试环境,此时千万千万不要拉起A,因为A上可能有旧数据,此时会导致已经迁移完成的key重新迁移,造成B的数据丢失,正确的姿势是A的备机顶上去,继续迁移,因为A的备机虽然是异步复制,但基本接近于A的全量数据,所以问题不太大。不过所有的迁移过程中,都最好把数据和分片信息备份,以防数据丢失。此时也千万千万不能反向将B的数据迁移回A,因为B上可能残留有部分迁移的数据,会覆盖掉A的全量数据。 问题四,为了性能问题,可否A不做备机,不开启AOF和RDB。 这个也是万万不可,因为A如果crash之后,被织云拉起,则相当于一个空实例,会清掉备机的数据,造成数据丢失。 七、Codis相关数据 其中压测环境:压测服务器(v4-8-100)+proxy(v4-8-100) + redis( B5(4 -32-100) ) 从上图中可以看出,当单次获取的数据量越来越大时,proxy的性能下降会非常快,例如ZRANGE_500的直连的性能是proxy的2倍 八、运维手册及避坑指南 操作注意项: 8.1 主从切换: 每次主从切换之后,都确认一下被切的主或者备机上的conf文件都已经rewriteok。 grep "Generatedby CONFIG REWRITE" -C 10 {redis_conf路径}/*.conf 8.2 迁移数据:关键操作前,备份数据,若涉及切片信息,备份切片信息 A迁移B时间过长的命令查看:连上Acodisserver,命令行中执行slotsmgrt-async-status查看正在迁移的分片信息(尤其是大key),做到心中有数。千万级别的key约20秒左右可以迁移完成 8.3 异常处理:redis宕机后重启,重启之后加载key快加载完时,页面上报error 8.4 客户端出现大量超时 8.5 fork耗时高 8.6 AOF持久化细节 (编辑:晋中站长网) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |