常用的 Redis 优化手段有哪些?
每个软件的常规操作有两种,一种是使用,另一种就是调优,对于 Redis 来说也是一样。关于 Redis 调优的问题一般会出现在 Redis 面试的后期,以此来考察面试者对于 Redis 的实际应用掌握,以及对于 Redis 高性能的追求与理解,因此本文就来重点的聊一聊关于 Redis 调优的相关问题。
我们本文的面试题是,Redis 常见的优化手段有哪些?
典型回答
最有效的提高 Redis 性能的方案就是在没有必要开启持久化的情况下,关闭 Redis 的持久化功能,这样每次对 Redis 的操作就无需进行 IO 磁盘写入了,因此性能会提升很多。
其他优化 Redis 的常见手段有,缩短键值对的存储长度和不使用耗时长的 Redis 命令。
缩短键值对的存储长度
键值对的长度是和性能成反比的,比如我们来做一组写入数据的性能测试,执行结果如下:
| 数据量 | key 大小 | value 大小 | string:set 平均耗时 | hash:hset 平均耗时 | | :--- | :--- | :--- | :--- | :--- | | 100w | 20byte | 512byte | 1.13 微秒 | 10.28 微秒 | | 100w | 20byte | 200byte | 0.74 微秒 | 8.08 微秒 | | 100w | 20byte | 100byte | 0.65 微秒 | 7.92 微秒 | | 100w | 20byte | 50byte | 0.59 微秒 | 6.74 微秒 | | 100w | 20byte | 20byte | 0.55 微秒 | 6.60 微秒 | | 100w | 20byte | 5byte | 0.53 微秒 | 6.53 微秒 |
从以上数据可以看出,在 key 不变的情况下,value 值越大操作效率越慢,因为 Redis 对于同一种数据类型会使用不同的内部编码进行存储,比如字符串的内部编码就有三种:int(整数编码)、raw(优化内存分配的字符串编码)、embstr(动态字符串编码),这是因为 Redis 的作者是想通过不同编码实现效率和空间的平衡,然而数据量越大使用的内部编码就越复杂,而越是复杂的内部编码存储的性能就越低。
这还只是写入时的速度,当键值对内容较大时,还会带来另外几个问题:
- 内容越大需要的持久化时间就越长,需要挂起的时间越长,Redis 的性能就会越低;
- 内容越大在网络上传输的内容就越多,需要的时间就越长,整体的运行速度就越低;
- 内容越大占用的内存就越多,就会更频繁的触发内存淘汰机制,从而给 Redis 带来了更多的运行负担。
因此在保证完整语义的同时,我们要尽量的缩短键值对的存储长度,必要时要对数据进行序列化和压缩再存储,以 Java 为例,序列化我们可以使用 protostuff 或 kryo,压缩我们可以使用 snappy。
禁止使用耗时长的 Redis 命令
Redis 绝大多数读写命令的时间复杂度都在 O(1) 到 O(N) 之间,在官方文档对每个命令都有时间复杂度说明,地址:https://redis.io/commands,如下图所示:
image.png其中 O(1) 表示可以安全使用的,而 O(N) 就应该当心了,N 表示不确定,数据越大查询的速度可能会越慢。因为 Redis 只用一个线程来做数据查询,如果这些指令耗时很长,就会阻塞 Redis,造成大量延时。
要避免 O(N) 命令对 Redis 造成的影响,可以从以下几个方面入手改造:
- 决定禁止使用 keys 命令;
- 避免一次查询所有的成员,要使用 scan 命令进行分批的,游标式的遍历;
- 通过机制严格控制 Hash、Set、Sorted Set 等结构的数据大小;
- 将排序、并集、交集等操作放在客户端执行,以减少 Redis 服务器运行压力;
- 删除 (del) 一个大数据的时候,可能会需要很长时间,所以建议用异步删除的方式 unlink,它会启动一个新的线程来删除目标数据,而不阻塞 Redis 的主线程。
考点分析
Redis 优化的手段有很多,老子教育我们“天下难事必作于易,天下大事必作于细”,我们只有将每个 Redis 优化的细节都做到位,才能打造一个性能优秀的 Redis 服务,才能在茫茫面试的人群中脱颖而出,高手过招通常看得都是细节,上面大概回答了本文的面试题,也属于卓有成效的几种方法,但如果能回答出更多优化的技巧的话,相信一定能让面试官惊喜万分,给他眼前一亮的感觉。
和此知识点相关的面试题还有以下这些:
- Redis 的管道机制 Pipeline 知道吗?
- 你还知道其他的优化手段吗?
- 说一下 Redis 的慢查询?
知识扩展
1.Redis 管道技术——Pipeline
管道技术 (Pipeline) 是客户端提供的一种批处理技术,用于一次处理多个 Redis 命令,从而提高整个交互的性能。也就是说 Pipeline 并不是 Redis 服务器的功能,而是客户端提供的批量处理 Redis 命令的功能。
通常情况下 Redis 是单行执行的,客户端先向服务器发送请求,服务端接收并处理请求后再把结果返回给客户端,这种处理模式在非频繁请求时不会有任何问题,但如果出现集中大批量的请求时,因为每个请求都要经历先请求再响应的过程,这就会造成网络资源浪费,此时就需要管道技术来把所有的命令整合一次发给服务端,再一次响应给客户端,这样就能大大的提升了 Redis 的响应速度。
普通命令模式,如下图所示: 普通模式.png