【问题标题】:Redis cluster live reshard failureRedis 集群实时重新分片失败
【发布时间】:2018-10-31 09:41:12
【问题描述】:

我们在生产环境中广泛使用 redis-cluster。我们目前有一个 30 个节点的集群(15 个主节点,15 个从节点) 我们正在尝试增加集群,因为我们已经创建了新服务器并将它们加入到集群中。到目前为止一切都很好。

下一步 - 我们正在尝试将插槽重新分配给新的主节点。我们使用redis-trib reshard 命令编写了一个执行此操作的脚本。

但是 - 迁移中途失败(但距离开始不远)并出现以下错误: [ERR] Calling MIGRATE: ERR Target instance replied with error: BUSYKEY Target key name already exists.

这种情况偶尔会发生,有时它会在失败之前设法移动一些插槽,有时它会在第一个插槽上失败。 每个此类故障都需要手动修复操作,这使得重新分片操作非常难以管理。

除了停机迁移之外,我们还没有找到任何具体的例子,也没有任何关于如何防止这种情况的想法。我们正在努力避免。

版本:
redis 服务器 4.0.2
redis trib 3.3.3(在此问题后从 4.0.2 降级:redis cluster reshard [ERR] Calling MIGRATE: ERR Syntax error

我们的下一步是升级到最新的 redis (4.0.11),尽管我们在此问题的发行说明中没有发现任何迹象。

希望听到我们做错了什么以及如何解决它,或者 redis-cluster 不是为实时重新分片而构建的?

谢谢

【问题讨论】:

    标签: redis redis-cluster


    【解决方案1】:

    我在为我们自己的项目使用 redis-clustering 支持时遇到了类似的问题。我发现redis-trib reshard 命令有问题。如果没有密钥存储在从一个主节点迁移到另一个主节点的插槽中,它就可以正常工作。

    但是 redis-5(仍在开发中,还不稳定)有它自己的 我认为重新分片命令没有问题的“redis-cli”。只有 5 的低版本才会发生这种情况。

    如果您查看 redis 的官方文档,例如 redis reconfigurationredis cluster resharding,您会发现他们在内部为重新分片所做的工作。

    所以我通过运行 bash 脚本而不是运行 redis-trib reshard 命令来完成这些任务,从而解决了这个问题。

    假设你想将一些槽从一个主节点重新分片到另一个主节点。我们将拥有哈希槽当前所有权的节点称为源节点,我们要迁移到的节点称为目标节点

    对每个插槽执行以下步骤:

    请记住,根据 redis 官方文档,这些步骤的顺序在这里很重要。

    1. 发送CLUSTER SETSLOT <slot> IMPORTING <source-node-id>目标节点,将slot设置为importing状态。
    2. 源节点发送CLUSTER SETSLOT <slot> MIGRATING <destination-node-id>,将设置为正在迁移状态。
    3. 使用CLUSTER GETKEYSINSLOT 命令从源节点 获取密钥,并使用以下MIGRATE 命令将它们移动到目标节点

      MIGRATE target_host target_port key target_database_id timeout

      在 Redis Cluster 中不需要指定除 0 以外的数据库,但MIGRATE 是通用命令,可用于不涉及 Redis Cluster 的其他任务。

    4. 当迁移过程最终完成时,在源节点目标节点中都使用CLUSTER SETSLOT <slot> NODE <destination-node-id>,以便再次将槽设置为其正常状态。相同的命令通常会发送到所有其他节点,以避免等待新配置在集群中自然传播。

    这里还提供了一个简单的示例 bash 脚本:

    源 IP:172.17.0.5。源ID:1f70a5107e0042a7d33a9efaf88dbdfecd78076a

    目标 IP:172.17.0.4。目的地ID:7e428bae84697a3882ecad19bd0d13ac7ee97d02

    另一个主ip:172.17.0.7

    for i in `seq 0 5460`; do
        redis-cli -c -h 172.17.0.4 cluster setslot ${i} importing 1f70a5107e0042a7d33a9efaf88dbdfecd78076a
        redis-cli -c -h 172.17.0.5 cluster setslot ${i} migrating 7e428bae84697a3882ecad19bd0d13ac7ee97d02
        while true; do
            key=`redis-cli -c -h 172.17.0.5 cluster getkeysinslot ${i} 1`
            if [ "" = "$key" ]; then
                echo "there are no key in this slot ${i}"
                break
            fi
            redis-cli -h 172.17.0.5 migrate 172.17.0.4 6379 ${key} 0 5000
        done
        redis-cli -c -h 172.17.0.5 cluster setslot ${i} node 7e428bae84697a3882ecad19bd0d13ac7ee97d02
        redis-cli -c -h 172.17.0.4 cluster setslot ${i} node 7e428bae84697a3882ecad19bd0d13ac7ee97d02
        redis-cli -c -h 172.17.0.7 cluster setslot ${i} node 7e428bae84697a3882ecad19bd0d13ac7ee97d02
    done
    

    【讨论】:

    • 这也发生在 redis 5 的情况下,通过 redis-cli 命令将一些插槽迁移到新的主节点并且源节点在进程中失败
    • 我实际上不能自信地说这不会发生在 redis 5 的情况下,但是我在 redis 4 对项目 github.com/kubedb 的支持期间遇到并解决了 redis 4 的这种方式。
    • 好的,只是为了帮助别人而添加的
    • 回答完整的细节,以确定问题的出处和位置。谢谢
    猜你喜欢
    • 1970-01-01
    • 2015-11-12
    • 2022-10-24
    • 2015-06-19
    • 2020-03-26
    • 2011-01-09
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多