Redis命令性能优化及事务使用过程

2次阅读

共计 3512 个字符,预计需要花费 9 分钟才能阅读完成。

场景

` 假设有这样一个使用场景,依次执行下面的 5 条命令
命令 1:hset mall:sale:freq:ctrl:860000000000001 599055114591 1(hash 结构,field 表示购买的商品 ID,value 表示购买次数)
简单说明:mall:sale:freq:ctrl:860000000000001 是一个 hash 表;599055114591 表示 key;1 表示 key 对应的 value
命令 2:hset mall:sale:freq:ctrl:860000000000001 599055114592 2
命令 3:expire mall:sale:freq:ctrl:860000000000001 3127(设置过期时间)
简单说明:给 hash 表 mall:mall:sale:freq:ctrl:860000000000001 设置过期时间
命令 4:set mall:total:freq:ctrl:860000000000001 3
简单说明:set key vlaue
命令 5:expire mall:total:freq:ctrl:860000000000001 3127(设置过期时间)
简单说明: set key 过期时间 `

优化缘由

执行一条命令 经历的过程

  • 发送命令网络传输时间
  • 命令在 Redis 服务端队列中等待的时间
  • 命令执行的时间(Redis 中的 slowlog 只是检测这一步骤的时间)
  • 结果返回的 Redis 客户端的时间

` 执行一条命令 就需要经过上面的过程,发送命令-〉命令排队-〉命令执行-〉返回结果
那么执行 5 条命令,可想而知,性能优化的空间还是蛮大的,
下面咱们来进行优化一下吧 `

优化

第一次优化:利用 hmset 命令将两条 hmset 命令合二为一

` 命令 1 和命令 2 合二为一
hmset mall:sale:freq:ctrl:860000000000001 599055114591 1 599055114592 2
expire mall:sale:freq:ctrl:860000000000001 3127
set mall:total:freq:ctrl:860000000000001 3
expire mall:total:freq:ctrl:860000000000001 3127`

第二次优化:将 set 和 expire 命令合二为一

` 将命令 4 和命令 5 合二为一
命令 a:hmset mall:sale:freq:ctrl:860000000000001 599055114591 1 599055114592 2
命令 b: expire mall:sale:freq:ctrl:860000000000001 3127
命令 c: setex mall:total:freq:ctrl:860000000000001 3127 3`

第三次优化:使用 pipeline

需要注意:RedisCluster 中使用 pipeline 时必须满足 pipeline 打包的所有命令 key 在 RedisCluster 的同一个 slot 上

分析下是否在同一个 slot 上

slot 原理简介

`Redis 集群使用数据分片(sharding)而非一致性哈希(consistency hashing)来实现:一个 Redis 集群包含 16384 个哈希槽(hash slot),数据库中的每个键都属于这 16384 个哈希槽的其中一个,集群使用公式 CRC16(key) % 16384 来计算键 key 属于哪个槽,其中 CRC16(key) 语句用于计算键 key 的 CRC16 校验和。
集群中的每个节点负责处理一部分哈希槽。
举个例子,一个集群可以有三个哈希槽,其中:
节点 A 负责处理 0 号至 5500 号哈希槽。
节点 B 负责处理 5501 号至 11000 号哈希槽。
节点 C 负责处理 11001 号至 16384 号哈希槽。
这种将哈希槽分布到不同节点的做法使得用户可以很容易地向集群中添加或者删除节点。比如说:
如果用户将新节点 D 添加到集群中,那么集群只需要将节点 A、B、C 中的某些槽移动到节点 D 就可以了。
与此类似,如果用户要从集群中移除节点 A,那么集群只需要将节点 A 中的所有哈希槽移动到节点 B 和节点 C,然后再移除空白(不包含任何哈希槽)的节点 A 就可以了。
因为将一个哈希槽从一个节点移动到另一个节点不会造成节点阻塞,所以无论是添加新节点还是移除已存在节点,又或者改变某个节点包含的哈希槽数量,都不会造成集群下线。`

结论

` 由此可知 命令 a 和命令 b 在同一个 slot 上,命令 c 在另外一个 slot 上
所以命令 a 和命令 b 用 pipline 来处理 `

如何使用 pipline

  • 先创建一个 txt 文件

`vim pipeline.txt
hmset mall:sale:freq:ctrl:860000000000001 599055114591 1 599055114592 2
expire mall:sale:freq:ctrl:860000000000001 3127`

  • 格式化 使得 这个文本文件中每一行都必须以 \r\n 而不是 \n 结束

需要安装下 dos2unix

a、brew install dos2unix

b、unix2dos pipeline.txt

  • 命令执行

cat pipeline.txt | redis-cli --pipe

第四次优化 使用 高级特性:hashtag

CRC16(key) % 16384 来计算键 key 属于哪个槽 可知,key 决定了存储在哪个 slot 上,那么使用 hashtag 可以使得 满足部分 key 一致的所有 key 都存储在同一个 slot 上

比如

mall:sale:freq:ctrl:{860000000000001} 只要 key 中有 {860000000000001} 这一部分,就一定落在同一个 slot 上

** 注意:使用 hashtag 特性 不能把 key 的离散性变得非常差 **

  • 离散性好

mall:sale:freq:ctrl:{860000000000001} 这种 key 还是与用户相关

  • 离散性差

`mall:{sale:freq:ctrl}:860000000000001
所有的 key 都会落在同一个 slot 上,导致整个 Redis 集群出现严重的倾斜问题 `

经过这 4 次优化 perfect ==> 5 条 Redis 命令压缩到 3 条 Redis 命令,并且 3 条 Redis 命令只需要发送一次,并且结果也一次就能全部返回

pipline

  • 未使用 pipline

  • 使用了 pipline

  • 性能对比

这是一组统计数据出来的数据,使用 Pipeline 执行速度比逐条执行要快,特别是客户端与服务端的网络延迟越大,性能体能越明显

性能测试代码

pipeline 实现 mdel

redis 提供了 mset、mget 方法 但没有提供 mdel 方法 可以借助 pipeline 实现

将不同类型的操作命令合并提交

原生批命令 (mset, mget) 与 Pipeline 对比

  • 原生批命令是原子性,pipeline 是非原子性

    (原子性概念: 一个事务是一个不可分割的最小工作单位, 要么都成功要么都失败。原子操作是指你的一个业务逻辑必须是不可拆分的. 处理一件事情要么都成功,要么都失败,原子不可拆分)

  • 原生批命令一命令多个 key, 但 pipeline 支持多命令(存在事务),非原子性
  • 原生批命令是服务端实现,而 pipeline 需要服务端与客户端共同完成

使用 pipeline 组装的命令个数不能太多,不然数据量过大,增加客户端的等待时间,还可能造成网络阻塞,可以将大量命令的拆分多个小的 pipeline 命令完成

事务

  • redsi 事务

  • discard 事务

  • 命令错误,语法不正确,导致事务不能正常结束

  • 运行错误,语法正确,但类型错误,事务可以正常结束

  • watch 命令

` 使用 watch 后,multi 失效,事务失效
WATCH 的机制是:
在事务 EXEC 命令执行时,Redis 会检查被 WATCH 的 key,
只有被 WATCH 的 key 从 WATCH 起始时至今没有发生过变更,EXEC 才会被执行。
如果 WATCH 的 key 在 WATCH 命令到 EXEC 命令之间发生过变化,则 EXEC 命令会返回失败。`

源码地址

https://gitee.com/pingfanrenbiji/springboot-jedisCluster/blob/master/demo/src/main/java/com/example/pipline/PipelineTest.java

参考文档

`https://www.jianshu.com/p/884…
http://www.gxlcms.com/redis-3…
https://blog.csdn.net/huangba…
https://blog.csdn.net/w1lgy/a…
官方文档:
http://redisdoc.com/topic/clu…`

本文使用 mdnice 排版

正文完
 0