2026-01-18 04:34:31
Redis 是一个使用 C 语言编写的开源 Key-Value 数据库,也是可支持网络、基于内存的持久化 NoSQL 数据库,提供多种语言(如 Java、C/C++、C#、PHP 等)的 API 驱动。在传统单机模型中,应用通过 DAO 访问数据库获取数据,随着互联网普及,应用访问量上升,直接访问数据库压力大。将 Redis 作为缓存中间件,应用可将数据存储在内存中直接读取,提高获取数据速度,降低服务器压力。不过,Redis 采用单线程模型,命令由一个线程串行执行,执行耗时长的命令会拖慢后续命令,可能产生性能问题。以下将介绍 Redis 的配置、参数,以及性能分析与优化技巧。
Redis 运行依赖配置,不同配置影响其性能,常用配置如下:
可通过“./redis-cli -p 6379 info”命令查看 Redis 参数,重要参数及相关描述如下:
connected_clients:已连接客户端的数量。
client_longest_output_list:当前连接的客户端当中,最长的输出列表。
client_longest_input_buf:当前连接的客户端当中,最大输入缓存。
blocked_clients:正在等待阻塞命令。
used_memory:由 Redis 分配器分配的内存总量,以字节(byte)为单位。
used_memory_human:以可读格式返回 Redis 分配的内存总量。
used_memory_rss:从操作系统的角度,返回 Redis 分配的内存总量。
used_memory_peak:Redis 的内存消耗峰值,以字节为单位。
used_memory_peak_human:以可读格式返回 Redis 的内存消耗峰值。
used_memory_lua:Lua 引擎所使用的内存大小,以字节为单位。
mem_fragmentation_ratio:“used_memory_rss”和“used_memory”之间的比率。
mem_allocator:编译时指定的 Redis 使用的内存分配器。
跟踪内存使用率:当 Redis 内存使用率超过可用内存的 95%时,部分数据开始在内存与 Swap 空间来回交换,若未开启 RDB 快照或 AOF 持久化策略,缓存数据在 Redis 崩溃时有丢失风险。开启并触发快照功能时,Redis 会 fork 子进程复制当前内存数据到硬盘,若当前使用内存超过可用内存的 45%时触发快照功能,此时内存交换可能丢失数据,若 Redis 实例上有大量频繁更新操作,问题更严重。可减少 Redis 内存占用率或使用以下技巧避免内存交换:
尽可能使用 Hash 数据结构:Redis 储存小于 100 个字段的 Hash 结构时存储效率高,在不需要集合“set”操作或“list”的“push/pop”操作时,应尽可能使用 Hash 结构。
设置“key”的过期时间:存储对象时设置“key”的过期时间可减少内存使用率,若“key”在明确时间周期内使用或旧“key”不大可能被使用,可用 Redis 过期时间命令(expire、expireat、pexpire、pexpireat)设置过期时间,Redis 会在“key”过期时自动删除。
回收“key”:在 Redis 配置文件中设置“maxmemory”的值可限制 Redis 最大使用内存,修改后重启实例生效。当内存使用达到设置的最大阀值时,需选择一种“key”的回收策略,可在“redis.conf”配置文件中修改“maxmemory-policy”属性。若 Redis 数据集中的“key”都设置了过期时间,“volatile-ttl”策略较好;若“key”在达到最大内存限制时没能迅速过期或根本未设置过期时间,设置为“allkeys-lru”更合适,它允许 Redis 从整个数据集中挑选近期最少使用的“key”进行删除(LRU 淘汰算法)。Redis 还提供其他淘汰策略,如“volatile-lru”(使用 LRU 算法从已设置过期时间的数据集合中淘汰数据)、“volatile-ttl”(从已设置过期时间的数据集合中淘汰即将过期的数据)、“volatile-random”(从已设置过期时间的数据集合中随机淘汰数据)、“allkeys-random”(从数据集合中任意淘汰数据)、“no-enviction”(禁止淘汰数据)。设置“maxmemory”的值为系统可用内存的 45%或 95%(取决于持久化策略),设置“maxmemory-policy”为“volatile-ttl”或“allkeys-lru”(取决于过期设置),可比较准确限制 Redis 最大内存使用率,在绝大多数场景下可确保 Redis 不会进行内存交换。
通过 slowlog 查出引发延迟的慢命令:Redis 中的“slowlog”命令可快速定位超出指定执行时间的慢命令,默认情况下命令执行时间超过 10ms 就会被记录到日志。“slowlog”只记录命令执行时间,不包含 IO 往返操作及由网络延迟引起的慢响应。通常 1GB 带宽的网络延迟预期在 200μs 左右,若一个命令仅执行时间就超过 10ms(近网络延迟的 50 倍),可使用“redis-cli”工具,输入“slowlog get”命令查看,返回结果的第三个字段将以微秒为单位显示命令的执行时间,若只需查看最后 10 个慢命令,输入“slowlog get 10”即可。
客户端连接监控:Redis 是单线程模型,只能单核处理客户端请求。客户端连接数增长会使处理请求的线程资源降低分配给单个客户端连接的处理时间,每个客户端等待 Redis 共享服务的响应时间延长。因此,监控客户端连接数很有必要,通过监控可确定客户端创建连接数的数量是否超出预期,以及客户端是否没有有效释放连接。查看命令为“./redis-cli -p 6379 info |grep connected_clients”。Redis 默认允许客户端连接的最大数量是 10000,连接数超过 5000 以上可能影响 Redis 性能。可尝试通过以下办法降低客户端连接数:
服务器内存足够时,可增加 Redis 的实例个数,均摊客户端连接。
服务器内存足够时,可增加 maxmemory 配置,提高处理速度。
应用通过连接池调用 Redis,可适当降低 Redis 连接的空闲数量。
若以上方法未能降低 Redis 的连接数,可限制客户端连接数来提高性能。
限制客户端连接数:设置最大连接数可限制非预期的连接数增长,保持 Redis 性能最优。Redis2.6 版本及以上允许使用者通过配置文件(redis.conf)配置“maxclients”属性,来修改客户端连接的最大值。根据连接数负载情况,这个数字应设置为预期连接数峰值的 110 到 150 之间,若连接数超出这个数值,Redis 会拒绝并立刻关闭新来的连接。如新连接尝试失败,将返回一个错误消息,客户端可执行对应的处理措施。
重启 Redis 服务器:若内存碎片率超过 1.5,重启 Redis 服务器可让额外产生的内存碎片失效并作为新内存使用,使操作系统恢复高效的内存管理。额外碎片的产生是由于 Redis 释放了内存块,但编译时制定的内存分配器(“libc”、“jemalloc”或“tcmalloc”)并没有返回内存给操作系统。通过比较“used_memory_peak”、“used_memory_rss”和“used_memory_metrics”的数据指标可检查额外内存碎片的占用。如果过去 Redis 内存使用的峰值“used_memory_peak”和“used_memory_rss”的值大致相等,且二者明显超过“used_memory”的值,则额外的内存碎片正在产生。在“redis-cli”工具上输入“info memory”可以查看上面三个指标的信息。重启服务器前,需在“redis-cli”工具上输入“shutdown save”命令,强制让 Redis 数据库执行保存操作并关闭 Redis 服务,这样能保证关闭 Redis 时不丢失任何数据。在重启后,Redis 会从硬盘上加载持久化的文件,确保数据集持续可用。
限制内存交换:如果内存碎片率低于 1,Redis 实例可能会把部分数据交换到硬盘上,将严重影响 Redis 的性能。可以增加可用物理内存或减少 Redis 实例内存占用,具体可查看“used_memory”章节的优化建议。
修改内存分配器:Redis 支持“glibc’s malloc”、“jemalloc11”和“tcmalloc”等几种不同的内存分配器,每个分配器在内存分配和碎片上都有不同的实现。修改 Redis 默认内存分配器,需要完全理解这几种内存分配器的差异,也需重新编译 Redis,因此,不建议普通管理员修改。通过这个方法可了解 Redis 内存分配器所做的工作,改善内存碎片问题。