大厂Redis 性能优化的 13 条军规!收好了

redis 是基于单线程模型实现的,也就是 Redis 是使用一个线程来处理所有的客户端请求的,尽管 Redis 使用了非阻塞式 IO,并且对各种命令都做了优化(大部分命令操作时间复杂度都是 O(1)),但由于 Redis 是单线程执行的特点,因此它对性能的要求更加苛刻,本文我们将通过一些优化手段,让 Redis 更加高效的运行 。
本文我们将使用以下手段,来提升 Redis 的运行速度:
  1. 缩短键值对的存储长度;
  2. 使用 lazy free(延迟删除)特性;
  3. 设置键值的过期时间;
  4. 禁用长耗时的查询命令;
  5. 使用 slowlog 优化耗时命令;
  6. 使用 Pipeline 批量操作数据;
  7. 避免大量数据同时失效;
  8. 客户端使用优化;
  9. 限制 Redis 内存大小;
  10. 使用物理机而非虚拟机安装 Redis 服务;
  11. 检查数据持久化策略;
  12. 禁用 THP 特性;
  13. 使用分布式架构来增加读写速度 。
1.缩短键值对的存储长度键值对的长度是和性能成反比的,比如我们来做一组写入数据的性能测试,执行结果如下:
大厂Redis 性能优化的 13 条军规!收好了

文章插图
 
从以上数据可以看出,在 key 不变的情况下,value 值越大操作效率越慢,因为 Redis 对于同一种数据类型会使用不同的内部编码进行存储,比如字符串的内部编码就有三种:int(整数编码)、raw(优化内存分配的字符串编码)、embstr(动态字符串编码),这是因为 Redis 的作者是想通过不同编码实现效率和空间的平衡,然而数据量越大使用的内部编码就越复杂,而越是复杂的内部编码存储的性能就越低 。
这还只是写入时的速度,当键值对内容较大时,还会带来另外几个问题:
  • 内容越大需要的持久化时间就越长,需要挂起的时间越长,Redis 的性能就会越低;
  • 内容越大在网络上传输的内容就越多,需要的时间就越长,整体的运行速度就越低;
  • 内容越大占用的内存就越多,就会更频繁的触发内存淘汰机制,从而给 Redis 带来了更多的运行负担 。
因此在保证完整语义的同时,我们要尽量的缩短键值对的存储长度,必要时要对数据进行序列化和压缩再存储,以 JAVA 为例,序列化我们可以使用 protostuff 或 kryo,压缩我们可以使用 snAppy 。
2.使用 lazy free 特性lazy free 特性是 Redis 4.0 新增的一个非常使用的功能,它可以理解为惰性删除或延迟删除 。意思是在删除的时候提供异步延时释放键值的功能,把键值释放操作放在 BIO(Background I/O) 单独的子线程处理中,以减少删除删除对 Redis 主线程的阻塞,可以有效地避免删除 big key 时带来的性能和可用性问题 。
lazy free 对应了 4 种场景,默认都是关闭的:
lazyfree-lazy-eviction nolazyfree-lazy-expire nolazyfree-lazy-server-del noslave-lazy-flush no它们代表的含义如下:
  • lazyfree-lazy-eviction:表示当 Redis 运行内存超过 maxmeory 时,是否开启 lazy free 机制删除;
  • lazyfree-lazy-expire:表示设置了过期时间的键值,当过期之后是否开启 lazy free 机制删除;
  • lazyfree-lazy-server-del:有些指令在处理已存在的键时,会带有一个隐式的 del 键的操作,比如 rename 命令,当目标键已存在,Redis 会先删除目标键,如果这些目标键是一个 big key,就会造成阻塞删除的问题,此配置表示在这种场景中是否开启 lazy free 机制删除;
  • slave-lazy-flush:针对 slave(从节点) 进行全量数据同步,slave 在加载 master 的 RDB 文件前,会运行 flushall 来清理自己的数据,它表示此时是否开启 lazy free 机制删除 。
建议开启其中的 lazyfree-lazy-eviction、lazyfree-lazy-expire、lazyfree-lazy-server-del 等配置,这样就可以有效的提高主线程的执行效率 。
3.设置键值的过期时间我们应该根据实际的业务情况,对键值设置合理的过期时间,这样 Redis 会帮你自动清除过期的键值对,以节约对内存的占用,以避免键值过多的堆积,频繁的触发内存淘汰策略 。
4.禁用长耗时的查询命令Redis 绝大多数读写命令的时间复杂度都在 O(1) 到 O(N) 之间,在官方文档对每命令都有时间复杂度说明,地址:https://redis.io/commands,如下图所示:
大厂Redis 性能优化的 13 条军规!收好了

文章插图
 
其中 O(1) 表示可以安全使用的,而 O(N) 就应该当心了,N 表示不确定,数据越大查询的速度可能会越慢 。因为 Redis 只用一个线程来做数据查询,如果这些指令耗时很长,就会阻塞 Redis,造成大量延时 。


推荐阅读