Redis凭借内存存储和单线程事件模型换来了极高的性能表现,但这份性能是有前提的——参数配置得当。不少人把Redis装好就直接丢到线上跑,默认配置在低并发测试环境里一切正常,等流量一上来,各种问题就冒头了:内存被打满导致写入被拒、RDB持久化时主线程卡顿、连接数飙升触发拒绝服务、主从复制延迟越拉越大。这些问题几乎都能追溯到参数层面。这篇文章按照内存管理、持久化、网络连接、复制四个板块,把生产环境必须检查和调整的参数逐个讲透。

内存管理参数:先想清楚内存满了怎么办
生产环境第一个要动的参数就是maxmemory。默认配置下Redis不限制内存使用,一旦数据持续增长把机器内存吃光,操作系统会触发OOM Killer直接杀掉Redis进程,造成的后果比任何业务异常都严重。建议根据机器物理内存来设置,一般预留出操作系统和其他进程的开销,单机只跑Redis的情况下,maxmemory设置为物理内存的50%到70%比较稳妥。
设置了内存上限还不够,还得告诉Redis内存满了之后的处理策略,也就是maxmemory-policy。默认值是noeviction,内存写满后所有写请求都会报OOM错误,如果你的业务写多读少,分分钟就会出现大面积报错。常见的可选策略有几类:allkeys-lru会对所有键按LRU算法淘汰最久没使用的;volatile-lru只淘汰设置了过期时间的键;allkeys-lfu按访问频率淘汰,适合有明显热点数据的场景;volatile-ttl优先淘汰快要过期的键。
选策略的关键在于数据特征。如果全部数据都可以缓存化、丢了能从数据库回源,allkeys-lru或allkeys-lfu是首选,简单粗暴且不会报错。如果Redis里同时存了缓存数据和不能丢的持久数据,那不能丢的键不要设置过期时间,然后用volatile-lru,把淘汰范围限制在缓存部分。另外提醒一点,volatile系列策略在没有任何键设置过期时间时,效果等同于noeviction,这是很多人踩过的坑。
# redis.conf 内存相关配置 maxmemory 8gb maxmemory-policy allkeys-lru # 建议同时关注碎片率,生产上 mem_fragmentation_ratio 大于 1.5 就需要警惕 INFO memory
还有一个容易被忽视的细节是lazyfree-lazy-eviction。默认情况下删除大键是在主线程同步执行的,如果业务里有大集合类型的键被淘汰,可能造成毫秒级的阻塞。把lazyfree相关选项打开,可以让删除操作放到后台线程异步执行,用少量的CPU换更平滑的延迟表现。
持久化参数:RDB和AOF的取舍与配置
Redis的持久化有RDB快照和AOF日志两种方式,生产上通常二选一或者混合使用。RDB默认的save条件是save 3600 1 300 100 60 10000,意思是3600秒内至少1次修改、300秒内至少100次修改、60秒内至少10000次修改就触发bgsave。写量大的业务经常撞上这个触发条件,而fork子进程做快照虽然不阻塞主线程,但fork本身在内存占用高的时候可能造成几百毫秒的停顿,特别是开启了内存大页的情况下更明显。
AOF的核心参数是appendfsync,它决定了刷盘频率。always表示每条命令都fsync,数据最安全但性能损耗大;everysec是折中方案,每秒刷一次盘,最多丢一秒数据,这也是生产环境的推荐值;no则完全交给操作系统,性能最好但宕机时丢失的数据量不可控。另外auto-aof-rewrite-percentage和auto-aof-rewrite-min-size控制AOF重写触发条件,默认100和64mb,意思是AOF文件比上次重写后大一倍且超过64mb就触发重写。写流量大的场景建议把min-size调大一些,比如1gb以上,避免频繁重写。
# 持久化推荐配置 appendonly yes appendfsync everysec auto-aof-rewrite-percentage 100 auto-aof-rewrite-min-size 1gb no-appendfsync-on-rewrite yes # Redis 4.0+ 可开启混合持久化,RDB做全量 + AOF做增量 aof-use-rdb-preamble yes
这里要重点讲一下no-appendfsync-on-rewrite。AOF重写期间,主进程还在持续接收写命令,这些命令需要fsync到旧的AOF文件,而重写子进程同时在做大量磁盘IO,两者抢磁盘会导致fsync变慢,进而阻塞主线程。这个参数设为yes后,重写期间不再对旧AOF做fsync,最多丢掉重写期间的数据(新AOF里都有),换来的延迟收益非常可观。另外,如果机器内存超过10gb,建议关闭透明大页,否则fork的停顿时间会明显变长,这个是系统层面的配置但影响极大。
网络与连接参数:别让连接层成为瓶颈
先看tcp-backlog,默认值511,这个参数控制TCP三次握手完成但还没被Redis处理的连接队列长度。Redis是单线程处理命令的,如果瞬间有大量新连接涌入,队列满了之后新的握手会被直接丢弃,客户端表现为连接超时。高并发场景建议调整到2048以上,同时记得检查系统的somaxconn参数,Linux默认可能是128,系统层面不调大的话Redis这边设了也白设。
超时相关有三个参数要配套看。timeout指客户端空闲多久后被服务端主动断开,默认0表示永不超时,生产上建议设置成300左右,及时清理僵尸连接。tcp-keepalive默认300秒,用于探测死连接,配合timeout可以避免连接数只增不减。maxclients默认10000,限制同时连接的客户端数量,达到上限后新连接会被拒绝。设置时要预留足够余量,还要注意每个连接大约消耗几KB内存,别只顾着调大。
# 网络与连接配置 tcp-backlog 2048 timeout 300 tcp-keepalive 300 maxclients 20000 # 对应的系统参数调整 # sysctl -w net.core.somaxconn=2048 # sysctl -w net.ipv4.tcp_max_syn_backlog=2048
慢查询定位方面,slowlog-log-slower-than默认10毫秒,建议改成1000微秒(即1毫秒)甚至更低,配合slowlog-max-len设置为128以上,这样线上出现慢命令能第一时间发现。很多所谓Redis卡顿,事后查慢日志发现全是keys、smembers大集合这类命令,提前把监控做好比事后救火重要得多。
主从复制参数:保证数据同步的稳定性
主从架构下,repl-backlog-size是个关键参数,默认1mb实在太小。复制积压缓冲区的作用是:从库断线重连后,如果断线期间的写命令还留在缓冲区里,就可以做增量同步,不用全量重传。缓冲区太小,从库稍微网络抖动一下就得触发全量同步,主库fork出RDB全量传给从库,期间网络和磁盘压力剧增,还可能引起主库阻塞。写流量大的业务建议设置为64mb甚至更大,可以用写命令速率乘以预计最长断线时间来估算。
repl-timeout默认60秒,控制复制连接的超时判定,跨机房复制或者网络环境一般的情况下,可以适当调大到120秒,避免误判导致不必要的重连。min-replicas-to-write和min-replicas-max-lag是两个配合使用的参数,比如设置成1和10,表示至少有1个从库延迟在10秒以内主库才接受写入,这在一定程度上防止主库宕机时丢失过多数据,但要权衡可用性,从库全挂时主库会拒绝写入,需根据业务容忍度决定是否开启。
# 复制相关配置(主库侧) repl-backlog-size 128mb repl-timeout 120 repl-disable-tcp-nodelay no # 半一致性写入保障,按需开启 min-replicas-to-write 1 min-replicas-max-lag 10
repl-disable-tcp-nodelay保持默认的no即可,这样主库会合并小的TCP包发送,从库延迟更低。如果追求网络带宽效率可以设为yes,但从库看到的延迟会明显增大,绝大多数场景不划算。
调优落地建议与常见误区
参数调优不是抄一份配置就完事,核心思路是:先用INFO命令摸清当前实例的运行状况,观察used_memory和mem_fragmentation_ratio判断内存健康度,看instantaneous_ops_per_sec和connected_clients了解负载水平,再针对性地调整。改参数时优先用CONFIG SET在线生效,观察一段时间没有问题再写回配置文件,避免重启后配置丢失。
几个常见误区值得提醒。一是盲目照搬大厂的配置模板,别人的参数是建立在别人的数据规模和硬件条件上的,直接复制可能适得其反。二是只调Redis不看系统,文件描述符限制、somaxconn、透明大页这些系统参数对Redis影响不亚于自身配置。三是把所有压力都压到一个实例上,当单实例内存超过10gb或者QPS逼近10万时,应该考虑拆分实例或者引入集群模式,而不是继续在参数上抠性能。参数调优能榨出的是细节收益,架构上的合理规划才是根本。