Redis报错:CROSSSLOT Keys in request don‘t hash to the same slot的解决方案

最近,项目上线的时候,出现了一个Redis的报错:CROSSSLOT Keys in request don't hash to the same slot,这个在内网环境下无法复现,因为正式环境的Redis是cluster集群模式,而我们内网环境是单机模式。(后面我在内网也部署了一个Redis集群,具体见我这一篇文章 《使用Docker搭建Redis Cluster集群》

Redis集群的slot概念

Redis的插槽(Slot)是用于实现集群分片(Cluster Sharding)的一种机制。Redis集群至少需要三个结点,每个结点处理一部分数据。那么怎样分配这些数据到各个结点呢?Redis Cluster 采用的是虚拟槽分区算法,其中提到了槽(Slot)的概念。这个槽是用来存放缓存信息的单位,在 Redis 中将存储空间分成了 16384 2 14 {2}^{14} 214)个槽,也就是说 Redis Cluster 槽的范围是 0 -16383。

在存储数据的时候,集群会对 Key 进行 CRC16 校验并对 16384 取模:

slot = CRC16(key) % 16384

得到的结果就是 Key-Value 所放入的槽,从而实现自动分割数据到不同的节点上

在这里插入图片描述

为什么会是16384个插槽呢?Redis作者是这么说的:传送门

什么情况下会报这个错

在集群模式下,所有涉及到多个 key的Redis指令,都要求所有的 key处于同一个 slot,如果 slot不同,哪怕实际上这些 slot都在同一个结点上,也会报这个错:

CROSSSLOT Keys in request don't hash to the same slot

例如以下这些操作:

SUNIONSTORE destination key [key ...]
 SDIFF key [key ...]
 EVAL script numkeys key [key ...] arg [arg ...]
 DEL key [key ...]

只要看到格式中有 key [key ...]这样的操作,在集群中,都必须保证所有 key在同一个 slot

禁止不同的slot操作,大概有以下原因:

  1. 性能考虑:允许跨槽操作将需要在不同节点之间进行复杂的协调和网络通信,这可能会显著降低操作的性能。Redis设计为高性能的存储系统,这种设计选择有助于保持操作的速度和效率。
  2. 简化分布式环境下的操作:通过限制操作仅在相同槽的键上执行,Redis Cluster简化了分布式环境下的数据管理。这样做减少了数据一致性和同步问题的复杂度,使得集群管理更为简单。
  3. 提高可扩展性和可靠性:这种设计允许Redis Cluster在节点失败或网络分区发生时更容易地进行数据迁移和故障转移。如果允许跨槽操作,这将增加数据迁移和恢复的复杂性,可能会影响到整个系统的可靠性。
  4. 分区的自治性:将数据划分到不同的槽中,并限制跨槽操作,有助于保证每个分区的自治性。这意味着每个节点可以独立处理其槽内的操作,从而减少了节点之间的依赖性。

要如何解决这个问题

既然Redis集群不允许跨slot的操作,那我们只要让key强制分配到同一个Slot就行了。

上面说了,正常情况下,slot = CRC16(key)%16384,这里是对整个key进行CRC16。

Redis提供了一种Hash Tag的功能,在key中使用{}括起key中的一部分,在进行 CRC 16 (key) % 16384 的过程中,只会对{}内的字符串计算。

例如,{rank:level}:1,{rank:level}:2这两个key就会分配都同一个slot,因为计算哈希的时候,都使用了 {}中的那一部分:rank:level,所以分配出来的 slot就是一样的。

值得注意的是,这里的 {}可以放在key的任意位置,例如 all{rank:level},all{rank:level}:1也都是一样的。

另外,如果有多个 {}的话,只有第一个 {}生效,例如 {rank:level}:1:{2},用来计算哈希的只是第一个 {}里面的 rank:level

参考资料

  • 11
    点赞
  • 15
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
### 回答1: "missing keys in state_dict" 的意思是模型的状态字典中缺少某些键。这通常是因为加载的预训练模型与当前模型的结构不匹配,或者是因为模型的状态字典被修改了。要解决这个问题,可以检查模型的结构是否与预训练模型相同,并确保状态字典中包含所有必要的键。如果需要,可以手动添加缺失的键或重新训练模型。 ### 回答2: 在PyTorch中,state_dict是一个Python字典对象,它保存了模型的所有参数和持久性缓存。当我们需要加载模型时,可以使用state_dict来恢复模型的参数。但是,有时候我们会遇到missing keys in state_dict的错误。 这个错误的原因通常有两种: 1. 加载模型时使用了错误的state_dict。解决这个问题的方法是确保使用的state_dict与模型结构相对应,即使模型架构有轻微的修改也需要注意。 2. 某些层没有被正确地初始化。如果我们使用了新的模型结构,但是没有正确地初始化某些层,那么加载模型时就会出现missing keys in state_dict的错误。解决这个问题的方法是用正确的权重数据初始化缺失的层。 一个比较常见的例子是使用预训练的模型进行fine-tuning。在fine-tuning时,我们通常会冻结预训练的某些层以防止参数过多而导致的过拟合。在这种情况下,我们只需要加载预训练的模型的state_dict中与被冻结的层无关的参数,然后再用正确的初始化方法初始化冻结的层。 总之,missing keys in state_dict错误通常是由于state_dict的错误或模型参数初始化不正确等原因引起的。通过正确地加载state_dict并正确地初始化所有缺失的层,可以解决这个问题。 ### 回答3: state_dict是PyTorch中保存和加载模型参数的一种机制。当我们训练一个深度学习模型时,通常会使用优化器对模型参数进行更新,而state_dict用于保存这些参数的值。当我们需要重新加载模型时,可以使用state_dict将前一次训练的参数重新加载进去。 但是有时候我们可能会遇到missing keys in state_dict的问题。这是因为模型的参数发生了变化,导致我们保存的state_dict中的键值对已经过时了,不能再用于加载模型参数。这种情况通常出现在以下几种情况中: 1.修改模型结构:在训练过程中,如果我们修改了模型的结构,比如添加或删除了一些层,原来保存的state_dict中的键值对就无法匹配新的模型结构了。 2.修改参数名称:有时候我们在训练模型时会更改参数的名称,比如将“fc.weight”改为“classifier.weight”,如果我们在加载模型时使用了原来的参数名称,就会出现missing keys的错误。 3.版本不兼容:有时候PyTorch的版本更新可能会导致state_dict的格式发生变化,若在不同版本间使用state_dict则会出现这个问题。 针对这个问题,我们可以有几种解决方案。一种方法是在新模型中手动添加缺失的键值对,这需要我们根据之前保存的state_dict的键值对手动添加缺失的参数。具体可以参考以下代码: ``` for k, v in state_dict.items(): if k not in new_model.state_dict(): print("key {} is missing in the new model".format(k)) else: new_model.state_dict()[k].copy_(v) ``` 另一种方法是使用torch.load方法的strict参数,它可以在加载模型时检查state_dict的键值对是否完全匹配,如果不匹配,则会抛出异常。我们可以将strict设置为False,这样就可以忽略掉一些缺失的键值对。具体代码如下: ``` state_dict = torch.load("model.pt", map_location=torch.device('cpu')) new_model.load_state_dict(state_dict, strict=False) ``` 此外,如果我们希望在修改模型结构时能够保留之前训练的参数,可以使用nn.Module的register_backward_hook方法来实现,在此不再赘述。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值