Redisslots迁移丢key问题排查
RedisslotsRedisslots 迁移丢迁移丢 keykey 问题排查问题排查1.1.问题问题redis slots 迁移的时候,在迁移之后 key 数量会变少.2.2.排查排查2.12.1 思考思考redis 3.x 也是比较成熟的产品了,为什么会丢 key?别人有没有遇到同样的问题?假设丢 key 了,如果 key 是因为 expire 丢失,那应该是正常,如果没有 expire 丢失,就是问题了,首先复现问题。2.22.2 复现问题复现问题0.0.准备集群准备集群造了两个节点的集群:10.0.0.10:20003 和 10.0.0.10:20004,最大可使用内存200M,并保证在测试过程中不会导致内存满等其他问题? 1 2 310.0.0.10:20004> cluster nodes 2aed426536067077179a3d23875b93b223802dea 10.0.0.10:20003 master - 0 1482132098352 6 connected 03a53320815d8b5f774810f2d41329007d60ebf4 10.0.0.10:20004 myself,master - 0 0 7 connected 0-16383key 格式:test_i, 保证所有的 key 使用同一个 slot。test_i 的 slot 为 6918,并且测试前 slot 里面没有 key.? 1 2 3 4 5 6 7 8 9 10 1110.0.0.10:20004> cluster keyslot test_i (integer) 6918 10.0.0.10:20004> cluster countkeysinslot 6918 (integer) 0 10.0.0.10:20003> cluster countkeysinslot 6918 (integer) 0# 迁移函数,配合 redis-trib fix 迁移 def migrate_from_4_to_3(slot):cmd=“cluster setslot %s migrating 2aed426536067077179a3d23875b93b223802dea“ % (slot,)12 13 14 15 16 17 18 19cli4.execute_command(cmd)cmd=“cluster setslot %s importing 03a53320815d8b5f774810f2d41329007d60ebf4“ % (slot,)cli3.execute_command(cmd)def migrate_from_3_to_4(slot):cmd=“cluster setslot %s migrating 03a53320815d8b5f774810f2d41329007d60ebf4“ % (slot,)cli3.execute_command(cmd)cmd=“cluster setslot %s importing 2aed426536067077179a3d23875b93b223802dea“ % (slot,)cli4.execute_command(cmd)1.1.非过期非过期 keykey 测试测试 ? 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 2210.0.0.10:20003> cluster countkeysinslot 6918 (integer) 0 10.0.0.10:20004> cluster countkeysinslot 6918 (integer) 0# 向 10.0.0.10:20004 写入 20000 个不带过期时间的 keyfor i in range(20000):cmd=“set test_%s %s“ % (i, i)print cmd, cli4.execute_command(cmd)10.0.0.10:20004> cluster countkeysinslot 6918 (integer) 20000# 迁移 slot 6918 migrate_from_4_to_3(6918) redis-trib fix 10.0.0.10:20004#check 10.0.0.10:20003> cluster countkeysinslot 6918 (integer) 20000 10.0.0.10:20004> cluster countkeysinslot 6918 (integer) 0结论: 20000 个 key 全部迁移,没有问题。638 棋牌 http:/www.rodlg.com2.2.部分带过期时间的部分带过期时间的 keykey 测试测试使用和上面相同的方法,测试20000 个不过期的 key,20000 个带过期时间的 key的情况。使用了test_i 的 slot=6918 和bug_i 的 slot=7910 这两个 slot 进行了测试。如果迁移的过程中没有 key 正在过期,发现迁移后 key 的数量也会减少如果有迁移的过程中有 key 正在过期,那么迁移完成后 key 的数量少于 20000,并且多次实验测试少的 key 的数量不同,有的时候少几百个,有的时候少 2000 多个。说明,如果在迁移 slot 的过程中,如果有 key 过期,那么会对那么没有过期时间的key 造成影响,导致丢失一些不过期的 key.3.3.是不是是不是 redis-tribredis-trib 的问题?的问题?redis-trib 在判断是不是迁移完成时,只判断了 getkeysinslot,当 getkeysinslot返回空时就直接认为迁移完成了,直接退出。所以在代码里面添加了 countkeysinslot,当两者同时为 0 时,在尝试判断 10 次在退出试一下。? 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24# 修改后的 redis-trib.rb . # Migrate all the keys from source to target using the MIGRATE command zerocounttime = 0 while truekeys = source.r.cluster(“getkeysinslot“,slot,o:pipeline)cntkeysinslot = source.r.cluster(“countkeysinslot“,slot)if keys.length = 0 if (ttl) setExpire(c->db,c->argv1,mstime()+ttl);signalModifiedKey(c->db,c->argv1);addReply(c,shared.ok);server.dirty+;if (sdslen(c->argv1->ptr) argv1->ptr, ttl); / add log for migrateCommand . /* Create RESTORE payload and generate the protocol to call the command. */ for (j = 0; j db,kvj);if (expireat != -1) ttl = expireat-mstime();if (ttl ptr,sdslen(kvj->ptr);serverAssertWithInfo(c,NULL,rioWriteBulkLongLong(serverLog(LL_WARNING,“prepare cmd, key:%s, ttl:%lld“, kvj->ptr, ttl);/debug log/* Emit the payload argument, that is the serialized object using* the DUMP format. */createDumpPayload(serverAssertWithInfo(c,NULL,rioWriteBulkString(sdsfree(payload.io.buffer.ptr);/* Add the REPLACE option to the RESTORE command if it was specified* as a MIGRATE option. */天地棋牌 http:/www.dadiqipaigw.cnif (replace)serverAssertWithInfo(c,NULL,rioWriteBulkString( . . /* Create RESTORE payload and generate the protocol to call the command. */ for (j = 0; j ptr); / debug logexpireat = getExpire(c->db,kvj);if (expireat != -1) ttl = expireat-mstime();if (ttl >> len(notfound) 7 >>>4 5>>> notfound 4, 3994, 3995, 3996, 3997, 3998, 3999在 redis-trib 和 source 节点都能看到缺少的 key 的日志,很明显的看到 key 被迁移了。在 target 的节点看到日志是这样的:? 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16125838:M 21 Dec 11:40:36.390 # store key ok, key:haha_399, ttl:0 125838:M 21 Dec 11:40:36.390 # store key ok, key:haha_3990, ttl:0 125838:M 21 Dec 11:40:36.426 # store key ok, key:haha_3991, ttl:0 125838:M 21 Dec 11:40:36.445 # store key ok, key:haha_3992, ttl:0 125838:M 21 Dec 11:40:36.467 # store key ok, key:haha_3993, ttl:0 125838:M 21 Dec 11:40:36.486 # store key ok, key:haha_3994, ttl:1 125838:M 21 Dec 11:40:36.505 # store key ok, key:haha_3995, ttl:14 125838:M 21 Dec 11:40:36.524 # store key ok, key:haha_3996, ttl:22 125838:M 21 Dec 11:40:36.544 # store key ok, key:haha_3997, ttl:25 125838:M 21 Dec 11:40:36.561 # store key ok, key:haha_3998, ttl:30 125838:M 21 Dec 11:40:36.580 # store key ok, key:haha_3999, ttl:32 125838:M 21 Dec 11:40:36.599 # store key ok, key:haha_4, ttl:35 125838:M 21 Dec 11:40:36.632 # store key ok, key:haha_