Redis: 集群测试和集群原理

集群测试

1 ) SET/GET 命令

  • 测试 set 和 get 因为其他命令也基本相似,

  • 我们在 101 节点上尝试连接 103 $ /usr/local/redis/bin/redis-cli -c -a 123456 -h 192.168.10.103 -p 6376

  • 我们在插入或读取一个 key的时候,会对这个key做一个hash运算,运算完以后会得到对应槽的索引值

  • 之后,就会把key插入槽里,当执行 $ set username zhangsan,username 这个key就会被hash运算

    conf 复制代码
    - > Reddirecte to slot [14315] located at 192.168.10.103:6375
  • 可见 username 的 槽是 14315,在 103:6375 这个实例上

  • 并且,我现在如果执行 set 的时候主机是 6376,命令行会重定向到 6375,这是内部的一个转向

  • 这是它内部在做的一个转向操作,之后,执行 $ set age 18 这个 age 运算完后插入 741槽

  • 这里又有了一个转向,741 这个槽在 6371的实例范围之内, 这些范围在 $ cluster nodes 返回可见

  • 执行 $ set address sh 发现并没有做转向,原因肯定是 address 运算之后,在 6371 实例槽的范围之内

  • 注意,get 也一样,会转向, 不再演示

2 ) 开启从节点只读模式

  • 关于从节点的只读模式,通过上面的例子,可以看出,所有的操作都是转发到主节点上去的
  • 目前从节点只起到备份容灾的角色,而非读的角色分担压力,目前还没有开启从节点的读功能
  • 我现在要释放压力,把读的压力给从节点,我只需要在从节点中执行一个 $ READONLY 命令即可
  • 注意,这个 $ READONLY 命令只支持自己主节点的key的范围
    • 就是如果获取的 key 不在这个从节点复制的主节点中
    • 它是没有办法给你直接返回的,它还是会去做转发,这是必然的

单节点和集群模式的性能测试

  • 我们对性能进行一个测试,通过 Redis 自带的 redis-benchmark 命令
  • Redis 是通过同时执行多个命令实现的
  • 把集群和单机分别执行一百万的get和set,看一下谁的性能更高,其实单机的性能是比较高的
  • 在集群环境测试的时候,get/set 它内部会去做一个转向的处理, 单机没有这个过程

1 )语法

  • $ redis-benchmark [option] [option value]

  • 参数

    选项 描述
    -h 指定服务器主机名
    -p 指定服务器端口
    -s 指定服务器 socket 方式连接
    -c 指定并发连接数
    -n 指定请求数
    -d 以字节的形式指定SET/GET值的数据大小
    -k 1=keep alive 0=reconnect
    -r SET/GET/INCR 使用随机 Key
    -P 通过管道传输请求
    -q 指定强制退出 Redis
    --csv 以CsV格式输出
    -l 生成循环,永久执行测试
    -t 仅运行以逗号分隔的测试命令列表

2 ) 单机测试

sh 复制代码
# 随机set/get1000000条命令1000个并发
bin/redis-benchmark -a 123456 -h 192.168.10.101 -p 6379 -t set,get -r 1000000 -n 1000000 -c 1000

3 ) 集群测试

sh 复制代码
# 随机set/get1000000条命令1000个并发
bin/redis-benchmark -a 123456 -h 192.168.10.101 -p 6371 -t set, get -r 1000000 -n 1000000 -c 1000

4 ) 对比结果

  • 综合上述单机和集群跑出来的数据结果,单机要更快!

集群原理

  • 我们之前用到的单机,主从,哨兵这几种模式数据都是存在单个节点上
    • 如果说是主从的话,会有从节点,从节点也只是对主节点的数据进行复制
    • 而我们单个节点它存储是有上限的,而且我们说它还有写压力等
  • 集群其实就是把请求包括数据的存储都分在了不同的节点上,就是把数据进行了分片存储
    • 当一个分片的数量达到上限的时候,还可以给它分成多个分片

1 ) 哈希槽

  • 集群的原理是什么? 它的本质是哈希槽
    • Redis 集群,它并没有选用一致性哈希,一致性哈希它是一个圆环,它的节点是分配在这个圆环上
    • 当我们插入和删除节点的时候,它是会影响响临近的节点,对其他的节点没有影响,这是它的优点
    • 但是缺点就是在节点比较少的情况下,当你插入一个新的节点的时候,它影响到数据会比较多
    • 因为我们要做数据迁移,除非你有上千个节点,这个时候添加一个节点影响的就微乎其微了
    • 所以说它不太适合那种节点比较少的分布式的缓存
    • 一般我们公司里的集群不可能达到上千个节点,因为它性能本身就很高
    • 所以说 Redis 的集群它并没有选择一致性哈希算法
    • 它采用的是哈希槽的这种概念,主要原因就是一致性哈希它对于数据的分布
    • 节点的位置的控制并不是很友好
  • 哈希槽其实是两个概念
    • 第一个概念就是哈希算法,Redis Cluster 的 hash算法,它不是简单的 hash()
      • 而是内部的一个crc16的算法, 是一种校验算法
    • 第二个就是槽位的一个概念,就是空间分配的规则
      • 其实哈希槽的本质和一致性哈希算法是非常相似的
      • 不同点就是对于哈希空间的定义
        • 一致性哈希的空间是一个圆环,节点分布是基于圆环的
          • 没有办法很好的就是控制数据的分布
          • 圆环节点分布在圆环上,你节点比较少的时候,插入一个节点
          • 对临近的节点有影响,数据迁移就会比较多
          • 除非现在这个环上有上千个节点,在添加一个节点的时候,它的影响就非常非常小了
          • 所以它不适合少量数据节点的分布式方案
        • 而 Redis Cluster 槽位空间,它是可以自定义分配的
          • 就类似于像windows 盘符分区, 这种分区可以自定义大小,自定义位置
          • 就很好的可以去方便的管理,比如说我现在在D盘上右键扩展卷
          • 我就把D盘的一部分分出去变成一个E盘,对E盘还可以合并其他盘或删除E盘
          • 这样来回操作都没有什么问题,非常方便管理
  • 注意,对于槽位的转移和分派,Redis集群是不会自动进行的,而是需要人工配置的
    • 所以,Redis集群的高可用是依赖于节点的主从复制和主从间的故障转移。
  • Redis Cluster 它内部的哈希槽是 16384 个,通过 之前 check 检查的命令可以看出
    • 对于主节点的槽位的分配还是非常平均的
    • 这默认是Redis Cluster 自己去做的,当然我们人为的也可以去做这样的分配
    • 每个key 通过计算都会落在一个具体的槽位上,这个槽位,比如说属于哪个节点的
    • 然后这个我们自己在添加槽的时候,就可以自己来定义了
    • 比如说你的这个机器硬盘比较小,我们给它分配少一点
  • 哈希槽的这种概念就很好的解决了一致性哈希的一个缺点,而且它在容错和扩展上也非常的方便
  • 虽然说它表象跟一致性哈希一样,都是对受影响的数据进行转移
  • 但哈希槽本质其实是对槽位的转移
    • 就是它会把故障的节点负责的这个槽位转到其他正常的节点上
    • 扩展节点也是一样的, 比如说我现在新加了一个节点
    • 我可以把其他节点上的槽再转移到这个新的节点上,就非常的方便,影响很低的
    • 因为它固定了聚集在这些槽的某一个节点

2 ) 16384 个 slots (槽位)

  • Redis Cluster 没有单机那种 16个数据库 (0 - 15) 数据库的概念了,就是我们已经看不到数据库了

  • 而是分成了 16384 个 slots (槽位) ,每个节点负责其中一部分槽位,槽位的信息存储于每个节点中

  • 那我们客户端这边是怎么来操作集群的呢?

    • 当客户端连接集群的时候,首先它会得到一份集群的槽位配置信息
    • 然后把它缓存到客户端本地,这样客户端要查找某个key的时候,就可以直接定位到目标节点
    • 同时因为槽位的信息可能会存在客户端服务器不一致的情况
    • 那这个里边还会有纠错机制来实现槽位信息的一个调整
    • 客户端,随便找一台都能连上,对吧?都能连上,然后连上之后看到的效果都是一样的

3 )槽位定位算法

  • Redis Cluster 默认会对key值使用CRC16算法进行hash得到一个整数值
  • 再把这个整数对 16384 取余,取完余以后会得到一个具体的槽位
  • 这个就是槽位的计算公式: HASH_SLOT = CRC16(key) mod 16384
  • 不管是 SET/GET 都是用这个方式
  • 基于此,Redis Cluster 它提供了灵活的节点的扩容和缩容的方案
    • 而且可以在不影响集群对外提供服务的情况下,为我们的集群添加节点进行扩容
    • 也可以下线部分节点进行缩容
  • 这里的槽其实就是 Redis Cluster 管理数据的基本单位
    • 集群的伸缩,其实就是咱们的槽和对应的数据在节点之间的移动
    • 对于这个槽位算法,简单的理解就扩容缩容之后槽需要重新分配,数据也需要重新迁移
    • 但是服务不需要下线,而且他对于数据和节点的影响非常的小
  • 为什么是 16834 个槽,而不是别的数字呢?
    • https://github.com/redis/redis/issues/2576
    • 这里考虑心跳消息头的一个大小, 会达到 8k,过于庞大,比较占带宽
    • 还有就是关于节点,数量不可能到达1000的,16834 足够
    • 第三个就是就是槽位越小节点少的情况下压缩率越高
      • 哈希槽的存储是通过 bitmap 形式来进行保存的
      • 传输的过程中会对 bitmap 进行压缩
      • 如果哈希槽越多,压缩率就会很低,而 16834 / 8 约等于 2kb 这个压缩率会很高
相关推荐
小陈工4 小时前
Python Web开发入门(十七):Vue.js与Python后端集成——让前后端真正“握手言和“
开发语言·前端·javascript·数据库·vue.js·人工智能·python
科技小花8 小时前
数据治理平台架构演进观察:AI原生设计如何重构企业数据管理范式
数据库·重构·架构·数据治理·ai-native·ai原生
一江寒逸8 小时前
零基础从入门到精通MySQL(中篇):进阶篇——吃透多表查询、事务核心与高级特性,搞定复杂业务SQL
数据库·sql·mysql
D4c-lovetrain8 小时前
linux个人心得22 (mysql)
数据库·mysql
阿里小阿希9 小时前
CentOS7 PostgreSQL 9.2 升级到 15 完整教程
数据库·postgresql
荒川之神9 小时前
Oracle 数据仓库雪花模型设计(完整实战方案)
数据库·数据仓库·oracle
做个文艺程序员9 小时前
MySQL安全加固十大硬核操作
数据库·mysql·安全
不吃香菜学java9 小时前
Redis简单应用
数据库·spring boot·tomcat·maven
一个天蝎座 白勺 程序猿9 小时前
Apache IoTDB(15):IoTDB查询写回(INTO子句)深度解析——从语法到实战的ETL全链路指南
数据库·apache·etl·iotdb
不知名的老吴9 小时前
Redis的延迟瓶颈:TCP栈开销无法避免
数据库·redis·缓存