1.2 安装配置与单线程模型 本节摘要:编译安装 Redis、改对生产必改的几个参数,并看清"单线程"的真实边界——命令执行单线程,IO 与落盘早已多线程化。这个边界直接决定后面所有性能话题的推理方式。 动手装一个 生产环境建议源码编译,版本选偶数稳定版(如 7.2、7.4): 返回 PONG 就说明服务活了。改配置建议单独拷一份再改,别直接改默认文件。 装完先跑一轮冒烟测试,把"装好了"变成"验证过": 本机压测十万级每秒是正常水位,低一个数量级先查是不是编译时缺优化参数、跑在了虚拟机的共享核上。CONFIG GET 的输出确认配置文件真的被读进去了——改了文件却忘了重启或忘了指定配置路径,是新手部署翻车的头两名。
本节摘要:编译安装 Redis、改对生产必改的几个参数,并看清"单线程"的真实边界——命令执行单线程,IO 与落盘早已多线程化。这个边界直接决定后面所有性能话题的推理方式。
生产环境建议源码编译,版本选偶数稳定版(如 7.2、7.4):
wget https://download.redis.io/releases/redis-7.4.tar.gz tar xzf redis-7.4.tar.gz && cd redis-7.4 make -j4 && make install PREFIX=/usr/local/redis /usr/local/redis/bin/redis-server --port 6390 & /usr/local/redis/bin/redis-cli -p 6390 ping
返回 PONG 就说明服务活了。改配置建议单独拷一份再改,别直接改默认文件。
装完先跑一轮冒烟测试,把"装好了"变成"验证过":
redis-benchmark -p 6390 -t set,get -n 100000 -q # 十万次读写压测 SET: 112359.55 requests per second GET: 118483.44 requests per second redis-cli -p 6390 CONFIG GET maxmemory maxmemory-policy # 确认关键项生效 1) "maxmemory" 2) "4294967296" 3) "maxmemory-policy" 4) "allkeys-lru"
本机压测十万级每秒是正常水位,低一个数量级先查是不是编译时缺优化参数、跑在了虚拟机的共享核上。CONFIG GET 的输出确认配置文件真的被读进去了——改了文件却忘了重启或忘了指定配置路径,是新手部署翻车的头两名。
bind 0.0.0.0 # 按网卡收敛,别真写 0.0.0.0 上公网 port 6390 # 换掉默认端口,减少扫描噪音 requirepass 你的强密码 # 无密码等于裸奔,公网每小时都有扫描器 maxmemory 4gb # 必须设,否则内存吃到触发系统淘汰进程 maxmemory-policy allkeys-lru # 缓存场景常用,见第 5 章 appendonly yes # 开 AOF,重启不丢数据
前三个管安全,后三个管"内存在内存里怎么活、怎么不丢"。把默认值和修改理由并排放一起,更能看出风险在哪:
| 参数 | 出厂默认 | 建议值 | 不改的后果 |
|---|---|---|---|
| bind | 全网卡 | 内网地址 | 公网暴露,扫描器分钟级光顾 |
| requirepass | 空 | 强随机串 | 任何人可读写删 |
| port | 6379 | 自选 | 默认端口受定向扫描最多 |
| maxmemory | 0 不限 | 物理内存六到七成 | 吃光内存被系统杀进程 |
| appendonly | no | yes | 重启数据清零 |
装完的操作系统层还有两件事常被漏掉:文件句柄数要够(连接数加持久化文件,万级起步),透明大页要关——它会让 fork 后的写时复制以两兆为单位复制内存,第 6 章的快照内存峰值会被它成倍放大。前者在系统限制里调,后者在开机参数里关,都是一次配置长期受益的动作。
"Redis 是单线程"这句话在 6.0 之后已经不准确。准确的版本是:命令执行器是单线程,其余环节各有多线程。

为什么敢单线程还快?三个条件凑齐:内存操作本身纳秒到微秒级;单线程免去了锁与上下文切换;基于 epoll 的事件循环让一万条空闲连接也不占 CPU。瓶颈通常在内存容量和网络带宽,不在 CPU——所以多线程执行命令收益有限,反而破坏无锁这个大前提。
6.0 引入的 IO 线程容易和"多线程执行"混淆,值得单独说清:读请求、解析协议、写回响应这三步可以分给 IO 线程并行做,但命令的执行仍然汇聚回主线程排队。也就是说并行的是"搬运",串行的是"计算"——数据结构仍然只被一个线程碰,无锁前提完好无损。默认配置下 IO 线程是关着的,十万级每秒以下的中等负载开了收益也不明显;网卡的吞吐先到顶时再考虑开。
⚠️ 常见坑:单线程的反面是"一条慢命令阻塞所有客户端"。KEYS 在百万键的库里要跑数百毫秒,期间所有请求排队。生产环境用 SCAN 增量遍历,删除大集合用 UNLINK 异步删。
# 服务端 redis-cli -p 6390 info threads # 模拟慢命令(仅测试环境!) redis-cli -p 6390 debug sleep 2 # 另一个终端在 sleep 期间发请求,会观察到请求被阻塞约 2 秒
这个实验比任何文档都直观:主线程睡了两秒,整个世界就停了两秒。
线程分工不靠背,用操作系统直接验证:
# 看服务进程一共开了几个线程 ps -T -p $(pidof redis-server) | wc -l 14 # 主线程之外:IO 线程若干、bio 后台线程若干,各司其职 ps -T -p $(pidof redis-server) | awk 'NR>1 {print $NF}' | sort | uniq -c
十几个线程跑在一个"单线程"服务里并不矛盾:bio 线程族负责慢速收尾——关闭文件描述符、异步刷 AOF、释放大对象的内存,它们处理的全是"不碰数据结构"的杂活。判断某个动作会不会阻塞主线程,标准就一条:这个动作要不要读写数据结构本身。要,就在主线程排队;不要,多半已被挪去后台。
顺带纠正一个反向误解:既然瓶颈不在 CPU,那监控里 CPU 单核打满要不要管?要。单核满通常意味着某条命令在空转、或包太大解析太慢,top 里看哪个核满,SLOWLOG 里看同期记录,两相对照基本能锁定元凶。这类停顿在第 8 章有专门工具接棒:LATENCY 框架把 command 事件的尖刺记下来,配合慢日志把"卡了多少、卡在哪条命令"一次查清。