Redis hash tag进行分槽导致的问题

针对RedisCluster中因分槽导致的数据不均衡问题,本文详细介绍了分析内存占用、调整分槽策略的方法,以及如何解决由此引发的Redis服务异常。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

我们已经对redis cluster中的key进行了一定的分槽,但是导致了redis节点数据的不均匀分布,三个节点数据量大小对比:5:1:1,但更加恐怖的是内存使用对比,在最多的一个进程中占用超过900M,而最少的一个进程仅60M。
 
对比redis的dump文件,是其他两个的20倍
 
-rw-r--r--. 1 root root  14448246 8月  19 18:45 dump.6388.rdb
-rw-r--r--. 1 root root 279497287 8月  19 18:38 dump.6389.rdb
-rw-r--r--. 1 root root  14199864 8月  19 18:35 dump.6390.rdb
 
 

 Redis启动内存配置

 
可以参考知乎上的回答: https://www.zhihu.com/question/31102463
 
通过redis的config get *命令,可以查看redis配置中所有字段,其中可以看到。
 
 13) "maxmemory"
 14) "0"
 15) "maxmemory-samples"
 16) "5"
113) "maxmemory-policy"
114) "noeviction"
 
 
可以在redis.conf配置文件中,设置maxmemory用于表示redis的读/写最大内存,如果该值为0则表示没有限制;
 
maxmemory-policy用于设置回收策略,当内存达到maxmemory限制时,如果不进行回收,redis进程可能会挂掉,maxmemory-policy有6种方式用于回收:
 
  • volatile-lru:(默认值)从已设置过期时间的数据集(server.db[i].expires)中挑选最近最少使用的数据淘汰
  • volatile-random:从已设置过期时间的数据集(server.db[i].expires)中任意选择数据淘汰
  • volatile-ttl : 从已设置过期时间的数据集(server.db[i].expires)中挑选将要过期的数据淘汰
  • allkeys-lru : 从数据集(server.db[i].dict)中挑选最近最少使用的数据淘汰
  • allkeys-random:从数据集(server.db[i].dict)中任意选择数据淘汰
  • noeviction : 禁止驱逐数据,永不过期,返回错误
 
redisObject结果中包括一个lru属性,其中记录了对象最后一次被命令程序访问时的时间,lru属性用于配合实现valatile-ttl和allkeys-lru回收策略使用。
 
在redis中lru算法是一个近似算法,默认情况下,redis会随机挑选maxmemory-samples个键,从中选取一个最近最久未使用的key进行淘汰。
 
在配置文件中可以通过maxmemory-samples的值来设置redis需要检查key的个数,但是检查的越多,耗费的时间也就越久,但是结构越精确(也就是Redis从内存中淘汰的对象未使用的时间也就越久~)。
 
 

Redis运行时内存占用

 
 
info命令中返回memory部分:
 
# Memory
used_memory:895628864
used_memory_human:854.14M
used_memory_rss:939532288
used_memory_peak:912382408
used_memory_peak_human:870.12M
used_memory_lua:36864
mem_fragmentation_ratio:1.05
mem_allocator:jemalloc-3.6.0
 
 
used_memory表示由redis分配器分配的内存,byte为单位;used_memory_human是used_memory的人类可读方式;used_memory_rss是指从操作系统的角度,返回redis已分配的内存总量(常驻集大小),与top,ps等操作系统命令返回一致。
 
如果redis中过期了一定的keys,used_memory会降低,rss不会降低(redis释放的内存,短期内不会返回给操作系统),会产生一定的内存碎片。
 
mem_fragmentation_ratio, 1.05表示内存碎片率(used_memory_rss/used_memory),稍大于1是比较合理的,说明redis没有发生内存交换,但如果内存碎片率超过1.5,就说明redis消耗了实际需要物理内存的150%,其中50%是内存碎片率;若是内存碎片率低于1的话,说明redis内存分配超出了物理内存,操作系统正在进行内存交换,内存交换会引起比较明显的响应延迟。
 
除非你能够保证你的机器总是有一半的空闲内存,否则别使用快照方式持久化数据或者通过执行BGREWRITEAOF压缩aof文件。 redis在执行bgsave时,会进行一次fork,fork后的进程负责将内存中的数据写入磁盘,由于fork采用Copy-On-Write,两个redis进程共享内存中的数据。redis如果有数据更新,则会将对应的共享内存页创建一份副本再更新,当更新操作足够频繁时,共享的内存空间会迅速地副本化,导致物理内存被耗光,系统被迫动用交换空间,从而导致redis服务极不稳定,整个系统堵塞在磁盘io上。
 
而切分slot的结果是导致了其中数据量比较大的节点占用内存是其他两个节点的10倍。
 
关于redis内部的内存优化,可以参考: http://www.infoq.com/cn/articles/tq-redis-memory-usage-optimization-storage
 
 

Redis中的key内存估算

 
除了通过redis info命令宏观地查看其中的所有keys占用内存,以及系统分配内容,还可以借助外部工具来查看
 
 
通过安装该工具来对redis的内存进行分析:
 

1.分析单个key:

 
redis-memory-for-key -s 192.168.1.137 -p 6389 {prod}_brand
Key                    "{prod}_brand"
Bytes                  443636.0
Type                   hash
Encoding                   hashtable
Number of Elements             550
Length of Largest Element          1479
 
 
此时,会输出该key的一些基本信息,type,encoding等,其中我们比较关心的是bytes字段。
 
经过分析发现,对于redis中的值,该分析过程输出的bytes(容量)会比该值(本身的字符串bytes[].length)本身要大,这其中可能要考虑到redis的管理成本,通过infoQ那篇文章也能看到端倪。
 

2.分析整个dump文件,产生memory报告

 
很可惜,我们需要的memory report并没有生成出来,报错了...
 
rdb -c memory dump.6389.rdb > memory.csv
Traceback (most recent call last):
  File "/usr/local/bin/rdb", line 9, in <module>
    load_entry_point('rdbtools==0.1.7', 'console_scripts', 'rdb')()
  File "/Library/Python/2.7/site-packages/rdbtools-0.1.7-py2.7.egg/rdbtools/cli/rdb.py", line 72, in main
    parser.parse(dump_file)
  File "/Library/Python/2.7/site-packages/rdbtools-0.1.7-py2.7.egg/rdbtools/parser.py", line 293, in parse
    self.parse_fd(open(filename, "rb"))
  File "/Library/Python/2.7/site-packages/rdbtools-0.1.7-py2.7.egg/rdbtools/parser.py", line 337, in parse_fd
    self._callback.end_database(db_number)
  File "/Library/Python/2.7/site-packages/rdbtools-0.1.7-py2.7.egg/rdbtools/memprofiler.py", line 150, in end_database
    self._stream.next_record(record)
  File "/Library/Python/2.7/site-packages/rdbtools-0.1.7-py2.7.egg/rdbtools/memprofiler.py", line 90, in next_record
    self._out.write("%d,%s,%s,%d,%s,%d,%d\n" % (record.database, record.type, encode_key(record.key),
  File "/Library/Python/2.7/site-packages/rdbtools-0.1.7-py2.7.egg/rdbtools/callbacks.py", line 91, in encode_key
    return _encode(s, quote_numbers=True)
  File "/Library/Python/2.7/site-packages/rdbtools-0.1.7-py2.7.egg/rdbtools/callbacks.py", line 88, in _encode
    return _encode_basestring_ascii(s)
  File "/Library/Python/2.7/site-packages/rdbtools-0.1.7-py2.7.egg/rdbtools/callbacks.py", line 69, in _encode_basestring_ascii
    return '"' + str(ESCAPE_ASCII.sub(replace, s)) + '"'
TypeError: expected string or buffer
 
 
 
如果dump文件比较大,会造成分析的过程比较长。
 

3.将dump文件转换成json

 
如果单独看dump文件,使用head命令时,文件属于二进制格式,并不能以可以看的方式显示:
 
REDIS0006�$DFDF3DB1-5371-4644-BC12-B784DE6C6F9AppStorepriceStock_spec_106488�28{"price":3299,"marketP�
                                                                                                      850,"stock":         fixS�
                                                                                                                             0}$86A586E8-30A3-4{"brandId":97,�F1366AppStore{prod}_base_info_25560�C�E�
               Name":"TOD'S","category@#10hannel":4
                                                    ustomsR "":0.@
editorIntro D一双美丽的高跟鞋就像 位拥有魔法 #仙女,在脚尖轻  ,点@��能让穿上它 5  5人变得更性感迷 !借助那些精@� h�� 8 z力 Y来 V自己成为镁光灯下 )焦 �吧。!gender �
  
 
但可以将其转换为json,下面就是将符合正则条件格式的key转换为json:
 
rdb --command json --key "{prod}_*" dump.6389.rdb  > temp
  
当然还有一些其他参数可以使用,比如db, type(键值类型)。
 
[{
"{prod}_base_info_25560":"{\"brandId\":97,\"brandName\":\"TOD'S\",\"categoryId\":10,\"channel\":4,\"customsRate\":0.10,\"editorIntro\":\"\u4e00\u53cc\u7f8e\u4e3d\u7684\u9ad8\u8ddf\u978b\u5c31\u50cf\u4e00\u4f4d\u62e5\u6709\u9b54\u6cd5\u7684\u4ed9\u5973\uff0c\u5728\u811a\u5c16\u8f7b\u8f7b\u4e00\u70b9\uff0c\u5c31\u80fd\u8ba9\u7a7f\u4e0a\u5b83\u7684\u7684\u5973\u4eba\u53d8\u5f97\u66f4\u6027\u611f\u8ff7\u4eba\uff01\u501f\u52a9\u90a3\u4e9b\u7cbe\u7f8e\u4ed9\u5c65\u7684\u9b54\u529b\uff0c\u6765\u8ba9\u81ea\u5df1\u6210\u4e3a\u9541\u5149\u706f\u4e0b\u7684\u7126\u70b9\u5427\u3002\",\"gender\":0,\"goodsId\":19917,\"imageSource\":\"http://pic2.zhenimg.com/upload2/45/0c/450c490c4bdb85a72eac185ab05b591e.jpg\",\"isSpecial\":0,\"isStop\":0,\"mSmall\":\"http://pic2.zhenimg.com/upload2/45/0c/m_small_450c490c4bdb85a72eac185ab05b591e.jpg\",\"marketPrice\":5600,\"price\":1680,\"productAd\":\"\",\"productCode\":\"HY XXW0LK08780G23 740A\",\"productDetail\":\"\",\"productId\":25560,\"productImage\":\"[\\\"http://pic2.zhenimg.com/upload2/45/0c/450c490c4bdb85a72eac185ab05b591e.jpg\\\",\\\"http://pic2.zhenimg.com/upload2/fa/b9/fab98f7eb6261d90884857d771f1119b.jpg\\\",\\\"http://pic2.zhenimg.com/upload2/8a/9c/8a9c5b5dea7907817eb4721a46fbec42.jpg\\\",\\\"http://pic2.zhenimg.com/upload2/14/b4/14b4c0b6ce75541fa30b364e3788f52a.jpg\\\",\\\"http://pic2.zhenimg.com/upload2/ef/b3/efb3b3b9a14b8215bdc52b33c08c5377.jpg\\\",\\\"http://pic2.zhenimg.com/upload2/43/09/4309cafb27158298add464e75d5c547e.jpg\\\",\\\"http://pic2.zhenimg.com/upload2/5e/d1/5ed141b0efb6b4e6372d6323cb715ff7.jpg\\\",\\\"http://pic2.zhenimg.com/upload2/2e/44/2e44baef1e86b86134c02ef077d40578.jpg\\\"]\",\"productName\":\"TOD'S/\u6258\u5fb7\u65af \u9ed1\u8272/\u7d2b\u7ea2\u8272 \u5c0f\u725b\u76ae \u5973\u58eb\u9ad8\u8ddf\u978b HY XXW0LK08780G23 740A\",\"providerId\":18,\"providerStorageId\":1,\"skuIds\":[\"38455\",\"38456\",\"38457\"],\"status\":0,\"urlId\":79052250}",
 
 
如果将其转换成json,原有的dump文件大概270M,json文件增长为700M左右(且我们只转换了其中的一部分)。
 
 

如何修改默认的分槽策略

 
在制定HASH Tag方案后,不可避免地使得有些slot key会集中到一台/几台服务器上,此时或许我们可以将一些占用空间较大的slot比较集中的server释放一下压力,将其slot转移至新增的服务器上。
 
在一个redis集群中,可以通过cluster info查看当前集群状态:
 
> cluster info
cluster_state:ok
cluster_slots_assigned:16384
cluster_slots_ok:16384
cluster_slots_pfail:0
cluster_slots_fail:0
cluster_known_nodes:6
cluster_size:3
cluster_current_epoch:35
cluster_my_epoch:35
cluster_stats_messages_sent:7324
cluster_stats_messages_received:7324
 
 
通过cluster nodes命令查看当前集群机器分布情况:
 
d08dc883ee4fcb90c4bb47992ee03e6474398324 192.168.1.137:6390 master - 0 1471661565059 33 connected 5641-11040
5974ed7dd81c112d9a2354a0a985995913b4702c 192.168.1.137:6389 slave ffb4db4e1ced0f91ea66cd2335f7e4eadc29fd56 0 1471661563556 35 connected
532e58842d001f8097fadc325bdb5541b788a360 192.168.1.138:6389 master - 0 1471661564058 29 connected 11041-16383
ffb4db4e1ced0f91ea66cd2335f7e4eadc29fd56 192.168.1.138:6390 myself,master - 0 0 35 connected 0-5640
c69b521a30336caf8bce078047cf9bb5f37363ee 192.168.1.137:6388 slave 532e58842d001f8097fadc325bdb5541b788a360 0 1471661564058 29 connected
aa52c7810e499d042e94e0aa4bc28c57a1da74e3 192.168.1.138:6388 slave d08dc883ee4fcb90c4bb47992ee03e6474398324 0 1471661565562 33 connected
 
 
 

技术解决

 
从技术上考虑,解决该问题的方法有几种:
 

减少redis的单个元素值大小

 
改用其他类型的解决方案,各种序列化方案的对比表现: https://github.com/eishay/jvm-serializers/wiki,体现在 序列化/反序列化的速度,以及序列化后占用空间大小。我们当前使用fastjson,可以考虑使用更加高效的protostuff来代替。
 

垂直扩展,增加单个redis服务可用内存

 
但绝不能随意加,估算出大概需要的内存量并进行合理规划
 

水平扩展,加机器

 
重新切分slot,将占用内存较大的slot单独切分出去,集群中对slot进行相关操作的命令主要有:
 
 
/集群(cluster)
CLUSTER INFO 打印集群的信息
CLUSTER NODES 列出集群当前已知的所有节点(node),以及这些节点的相关信息。
 
//节点(node)
CLUSTER MEET <ip> <port> 将 ip 和 port 所指定的节点添加到集群当中,让它成为集群的一份子。
CLUSTER FORGET <node_id> 从集群中移除 node_id 指定的节点。
CLUSTER REPLICATE <node_id> 将当前节点设置为 node_id 指定的节点的从节点。
CLUSTER SAVECONFIG 将节点的配置文件保存到硬盘里面。
 
//槽(slot)
CLUSTER ADDSLOTS <slot> [slot ...] 将一个或多个槽(slot)指派(assign)给当前节点。
CLUSTER DELSLOTS <slot> [slot ...] 移除一个或多个槽对当前节点的指派。
CLUSTER FLUSHSLOTS 移除指派给当前节点的所有槽,让当前节点变成一个没有指派任何槽的节点。
CLUSTER SETSLOT <slot> NODE <node_id> 将槽 slot 指派给 node_id 指定的节点,如果槽已经指派给另一个节点,那么先让另一个节点删除该槽>,然后再进行指派。
CLUSTER SETSLOT <slot> MIGRATING <node_id> 将本节点的槽 slot 迁移到 node_id 指定的节点中。
CLUSTER SETSLOT <slot> IMPORTING <node_id> 从 node_id 指定的节点中导入槽 slot 到本节点。
CLUSTER SETSLOT <slot> STABLE 取消对槽 slot 的导入(import)或者迁移(migrate)。
 
//键 (key)
CLUSTER KEYSLOT <key> 计算键 key 应该被放置在哪个槽上。
CLUSTER COUNTKEYSINSLOT <slot> 返回槽 slot 目前包含的键值对数量。
CLUSTER GETKEYSINSLOT <slot> <count> 返回 count 个 slot 槽中的键。
 
 
 
通过cluster keyslot和countkeysinslot查看集中的slot占用的总数量:
 
> cluster keyslot {prod}
(integer) 811
> cluster countkeysinslot 811
(integer) 361528
 
 
将指定的keyslot迁移到对应的节点上去:
 
cluster setslot 4781 migrating d08dc883ee4fcb90c4bb47992ee03e6474398324
  
此时节点的状态已经改变:
 
cluster nodes
d08dc883ee4fcb90c4bb47992ee03e6474398324 192.168.1.137:6390 master - 0 1471663968706 33 connected 5641-11040
5974ed7dd81c112d9a2354a0a985995913b4702c 192.168.1.137:6389 slave ffb4db4e1ced0f91ea66cd2335f7e4eadc29fd56 0 1471663969206 35 connected
532e58842d001f8097fadc325bdb5541b788a360 192.168.1.138:6389 master - 0 1471663968706 29 connected 11041-16383
ffb4db4e1ced0f91ea66cd2335f7e4eadc29fd56 192.168.1.138:6390 myself,master - 0 0 35 connected 0-5640 [4781->-d08dc883ee4fcb90c4bb47992ee03e6474398324]
c69b521a30336caf8bce078047cf9bb5f37363ee 192.168.1.137:6388 slave 532e58842d001f8097fadc325bdb5541b788a360 0 1471663970709 29 connected
aa52c7810e499d042e94e0aa4bc28c57a1da74e3 192.168.1.138:6388 slave d08dc883ee4fcb90c4bb47992ee03e6474398324 0 1471663970209 33 connected
 
 
此种方法是否有效也亟待在生产环境中试验。
 

由分槽内存占用过大导致的另一个问题
 
我们在由于内存占用过高导致的进程down掉的redis节点上,执行批量删除操作时,提示下面的错误:
 
> redis-cli -c -p 6390 keys "\{prod\}*" | xargs redis-cli -c -p 6390 del
 
(error) MISCONF Redis is configured to save RDB snapshots, but is currently not able to persist on disk. Commands that may modify the data set are disabled. Please check Redis logs for details about the error.
(error) MISCONF Redis is configured to save RDB snapshots, but is currently not able to persist on disk. Commands that may modify the data set are disabled. Please check Redis logs for details about the error.
(error) MISCONF Redis is configured to save RDB snapshots, but is currently not able to persist on disk. Commands that may modify the data set are disabled. Please check Redis logs for details about the error.
(error) MISCONF Redis is configured to save RDB snapshots, but is currently not able to persist on disk. Commands that may modify the data set are disabled. Please check Redis logs for details about the error.
(error) MISCONF Redis is configured to save RDB snapshots, but is currently not able to persist on disk. Commands that may modify the data set are disabled. Please check Redis logs for details about the error.
(error) MISCONF Redis is configured to save RDB snapshots, but is currently not able to persist on disk. Commands that may modify the data set are disabled. Please check Redis logs for details about the error.
(error) MISCONF Redis is configured to save RDB snapshots, but is currently not able to persist on disk. Commands that may modify the data set are disabled. Please check Redis logs for details about the error.
(error) MISCONF Redis is configured to save RDB snapshots, but is currently not able to persist on disk. Commands that may modify the data set are disabled. Please check Redis logs for details about the error.
(error) MISCONF Redis is configured to save RDB snapshots, but is currently not able to persist on disk. Commands that may modify the data set are disabled. Please check Redis logs for details about the error.
  
经过一番查询,找出问题所在,是由于redis意外挂掉导致快照停止导致的,查看redis_last_bgsave_status为err而不是ok,通过状态可以证实这一点,需要关闭属性 stop-writes-on-bgsave-error ,注意要关闭master节点上的该属性而不是 slave节点上的,并在master节点上执行删除操作。
 
config set stop-writes-on-bgsave-error no
 
 
记得在执行完成后,将其重置为yes,如果conf文件中没有设置,则下次重启后仍然会设置为默认值yes。 
<think>嗯,用户问的是Redis中哈希的作用、原理和片机制。这是个很具体的技术问题,我需要整合站内引用信息来解答。从引用看,用户提供的材料质量不错,都是关于Redis片技术的核心资料。用户可能正在学习Redis集群架构,或者是系统架构师在评估技术方案。这类问题通常出现在布式系统设计场景中,他需要理解片机制如何解决数据问题。从提问方式看,用户具备一定技术基础,但可能对具体实现细节不够清晰。最关键的引用是[2]明确指出RedisCluster采用16384个位而非一致性哈希。这点要和引用[1][3]的哈希求余算法对比解释。引用[4]关于最小片数的故障转移限制也很有价值,可以补充在高可用设计中的注意事项。回答时要突出三个核心要点:如何解决传统哈希取模的扩容痛点(原理)、CRC16算法计算的过程(机制)、布策略(作用)。最后用架构图展示会更直观,可惜文本无法呈现。不过可以描述"假设集群"的示例场景来说明数据路由流程。的核心价值在于离了节点管理和数据定位——这是其他回答没明确点出的。传统的哈希取余算法在扩缩容时必须更新所有数据的映射关系(引用[3]),而通过虚拟层解决了这个问题。这种设计特别适合Redis这种高频扩容的KV存储。有趣的是引用[3]提到各大厂商的片算法差异,这说明Redis官方选择哈希而非一致性哈希是有意为之。这个对比点可以作为相关问题的延伸方向。</think> Redis 哈希Hash Slots)是 Redis Cluster 实现布式数据存储和片机制的核心技术,其作用、原理和片机制如下: ### **一、核心作用** 1. **数据片基础单位** 将整个数据空间划为 $2^{14}$ (16384) 个固定位(Slots),每个键值对通过计算归属到特定位。 *作用:避免数据不均,解决传统哈希取余算法在节点增删时的大规模数据迁移问题[^3]。* 2. **节点与解耦** 是逻辑概念,独立于物理节点。集群可将任意配到不同主节点,实现数据与节点关系的灵活管理。 *作用:支持动态扩缩容,节点变化时仅需迁移局部数据[^1]。* 3. **路由寻址核心** 客户端或代理通过计算键的编号,定位到负责该的主节点(或重定向至正确节点)。 *作用:实现高效的数据访问路由[^2]。* --- ### **二、片机制原理** #### **1. 配算法** 1. **键到的计算** 使用 **CRC16 算法** 计算键的哈希值(如 `CRC16("user:100")`),再对 $16384$ 取模: $$ \text{slot} = \text{CRC16}(key) \mod 16384 $$ 2. **到节点的映射** 集群启动时,管理员将 $16384$ 个配给各主节点(如 3 主节点:节点 A 管 0-5460,节点 B 管 5461-10922,节点 C 管 10923-16383)。 *配信息同步到所有节点和客户端[^2]。* #### **2. 动态扩缩容** (迁移) - **扩容**:新增节点时,从现有节点转移部到新节点。 - **缩容**:节点下线前,将其迁移至其他节点。 *迁移过程中涉及状态的变更广播,确保数据一致性[^4]。* --- ### **三、关键机制** 1. **路由重定向** 若客户端访问错误节点,节点返回 `MOVED <slot> <目标节点IP:Port>` 指令,客户端更新本地缓存并重试。 *优化方案:Smart Client 本地缓存映射表,直连正确节点[^2]。* 2. **高可用与故障转移** 每个主节点有 N 个从节点(副本)。主节点故障时,从节点通过选举接管其(需至少 $3$ 个主节点保证选举有效性[^4])。 *迁移期间集群部不可用。* 3. **多键操作限制** 跨的多键命令(如 `MGET key1 key2`)仅当所有键在同一时才支持,否则返回错误。 *解决方法*:使用哈希标签(Hash Tag)强制多键配到同一,例如键 `{user100}.name` 和 `{user100}.age`。 --- ### **四、架构图示例** ``` Redis Cluster +-----------------------+ | Slot 0-5460: Node A |-----> [Slave A1, Slave A2] +-----------------------+ | Slot 5461-10922: Node B |---> [Slave B1] +-----------------------+ | Slot 10923-16383: Node C|---> [Slave C1, Slave C2] +-----------------------+ ``` - 数据流:客户端根据 `CRC16(key) % 16384` 找到对应的节点 - 故障转移:若 Node B 宕机,Slave B1 接管其 --- ### **与替代方案的对比** | **片方案** | 优势 | 劣势 | |---------------------|-------------------------------|-------------------------------| | **哈希 (Redis Cluster)** | 动态扩缩容、数据均匀布 | 需集群模式支持,跨操作受限 | | **一致性哈希** | 节点增减影响小 | 存在数据倾斜风险 | | **哈希取余** | 实现简单 | 节点数变化需全部数据重布 | ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值