把面试官当陪练,在找工作中才会越战越勇
大家好我是小义同学,这是大厂面试拆解——项目实战系列的第4篇文章。
大家都是知道Redis纯内存数据库,处理速度很快,CPU架构,也会影响到 Redis 的性能
本文主要解决的一个问题在 Redis 为什么变慢,如何解决的?
一句话描述:Multi-Core CPU Optimization
Redis线程类型 | 配置 | 功能描述 | CPU 绑定核心 |
---|---|---|---|
主线程 | server_cpulist 0-7:2 | 事件循环,处理客户端连接和命令调度 | 0, 2, 4, 6 |
I/O 线程 | server_cpulist 0-7:2 | 解析客户端的读写操作 | 0, 2, 4, 6 |
BIO 线程 | bio_cpulist 1,3 | 执行耗时的后台任务(关闭文件、AOF fsync) | 1, 3 |
AOF 重写子进程 | aof_rewrite_cpulist 8-11 | 重写 AOF 文件,优化日志 | 8, 9, 10, 11 |
BGSAVE 子进程 | bgsave_cpulist 1,10-11 | 保存内存快照到磁盘(RDB 文件) | 1, 10, 11 |
下面是分析过程
大纲如下
怎么会变慢呢?
redis-cli -h 127.0.0.1 -p 6379 --intrinsic-latency 120
Max latency so far: 110 microseconds.
Max latency so far: 119 microseconds.
redis-cli -h 127.0.0.1 -p 6379 --latency-history -i 1
min: 0, max: 1, avg: 0.13 (98 samples) -- 1.00 seconds range
min: 0, max: 1, avg: 0.08 (99 samples) -- 1.01 seconds range
观察到的 Redis 运行时延迟是其基线性能的 2 倍及以上,就可以认定 Redis 变慢了
- 一般要求:Redis 中,以 100000 q/s 的速率运行 4 KB 字符串的基准测试,实际将消耗 3.2 Gbit/s 的带宽,这很可能适合 10 Gbit/s 的链路。
工具提供了服务器和客户端模式,来在两个主机之间执行网络吞吐量测试。
在服务端运行iperf,以在本机端口8899上启用iperf
输入命令iperf –s –p 8899 –i 1 –M
iperf: option requires an argument -- M
iperf -c server IP -p 8899 -i 1 -t 10 -w 20K
------------------------------------------------------------
Client connecting to 172.20.0.113, TCP port 8899
TCP window size: 40.0 KByte (WARNING: requested 20.0 KByte)
------------------------------------------------------------
[ 3] local 172.20.0.114 port 56796 connected with 172.20.0.113 port 12345
[ ID] Interval Transfer Bandwidth
[ 3] 0.0- 1.0 sec 614 MBytes 5.15 Gbits/sec
[ 3] 1.0- 2.0 sec 622 MBytes 5.21 Gbits/sec
[ 3] 2.0- 3.0 sec 646 MBytes 5.42 Gbits/sec
[ 3] 3.0- 4.0 sec 644 MBytes 5.40 Gbits/sec
带宽满足
★查缺补漏1 : 事件驱动:C10M是如何实现的?
线程类型 | 配置 | 功能描述 | CPU 绑定核心 |
---|---|---|---|
主线程 | server_cpulist 0-7:2 | 事件循环,处理客户端连接和命令调度 | 0, 2, 4, 6 |
I/O 线程 | server_cpulist 0-7:2 | 解析客户端的读写操作 | 0, 2, 4, 6 |
BIO 线程 | bio_cpulist 1,3 | 执行耗时的后台任务(关闭文件、AOF fsync) | 1, 3 |
AOF 重写子进程 | aof_rewrite_cpulist 8-11 | 重写 AOF 文件,优化日志 | 8, 9, 10, 11 |
BGSAVE 子进程 | bgsave_cpulist 1,10-11 | 保存内存快照到磁盘(RDB 文件) | 1, 10, 11 |
配置文件
https://raw.githubusercontent.com/redis/redis/6.0/redis.conf
# Redis Server and I/O threads are bound to CPU cores 0,2,4,6.
# 主线程:轮训方式 分配客户端请求到不同IO线程
#1.如何把待读客户端分配给IO线程执行
#2.
# IO线程: 客户端读取数据/将数据写回客户端
# 功能:1. 解析客户端发起读请求 IO_THREADS_OP_READ-->readQueryFromClient
# 2 处理写数据到客户端 IO_THREADS_OP_WRITE-->writeToClient
# 数量:1-128个
# 命令:
#numactl --cpunodebind=0 --physcpubind=0,2,4,6 redis-server /path/to/redis.conf
# 思考一下:为什么不绑定固定的1个物理核上? 对cpu竞争严重
# numactl --hardware
#node 0 cpus: 0 1 2 3 4 5 6 7
server_cpulist 0-7:2
# Set bio threads to cpu affinity 1,3:
#Q1 bio_threads功能是? bioProcessBackgroundJobs
# 1. BIO_AOF_FSYNC--redis_fsync Aof持久化
# 2 BIO_CLOSE_FILE 关闭文件
#Q2 what is Aof 所有对数据库进行过写入的命令(及其参数)记录到 AOF file
bio_cpulist 1,3
# Set aof rewrite child process to cpu affinity 8,9,10,11:
# aof rewrite child
# number:1
# aof_rewrite_cpulist 8-11
#
# Set bgsave child process to cpu affinity 1,10,11
# bgsave child `fork` 之后的子进程能够获取父进程内存中的数据
# Redis 在执行 BGSAVE 操作时,将其子进程绑定到 CPU 核心 8 至 11 上运行
# bgsave_cpulist 1,10-11
https://github.com/redis/redis/blob/6.2.17/src/rdb.c#L1440C9-L1440C28
int rdbSaveBackground(char *filename, rdbSaveInfo *rsi)
/* Child */
redisSetProcTitle("redis-rdb-bgsave");
redisSetCpuAffinity(server.bgsave_cpulist);
retval = rdbSave(filename,rsi);
int redisSetCpuAffinity(const char *cpulist) {
cpu_set_t cpuset;
CPU_ZERO(&cpuset);
// 解析 cpulist,例如 "0-3,5"
// 将解析后的 CPU 核心添加到 cpuset 中
// 设置当前线程的 CPU 亲和性
if (sched_setaffinity(0, sizeof(cpu_set_t), &cpuset) != 0) {
// 错误处理
return-1;
}
return0;
}
查看 NUMA 与核心分布
lscpu | grep "^NUMA node"
NUMA node(s): 2
NUMA node0 CPU(s): 0-5
NUMA node1 CPU(s): 6-11
numactl --hardware
available: 2 nodes (0-1)
node 0 cpus: 0 1 2 3 4 5
node 1 cpus: 6 7 8 9 10 11
确认核心 8–11 属于同一 NUMA 节点,以保证内存本地性。
触发 AOF 重写redis 127.0.0.1:6379> BGREWRITEAOF Background append only file rewriting started
查找子进程 PID
$ ps -eLo pid,ppid,psr,comm | grep redis-server | grep BGREWRITEAOF
2134 2100 8 redis-server: BGREWRITEAOF
PSR processor that process is currently assigned to
直接看结果 来源 Redis核心技术与实战
假设你在点外卖,前 99 次下单都只用了 1 秒,但第 100 次突然用了 10 秒。虽然大多数时候都很快,但偶尔慢一下,这“偶尔的慢”就是所谓的尾延迟(Tail Latency)。
假如 Redis 一共处理了 10000 个请求:
那我们说:
Non-uniform memory access (NUMA) is a [computer memory] design used in [multiprocessing], where the memory access time depends on the memory location relative to the processor.
非均匀内存访问 ( NUMA ) 是一种用于多处理系统的计算机内存设计,其内存访问时间取决于内存相对于处理器的位置
从网卡读取请求,到处理请求举例,看数据的位置
Redis实例【我从这这读取】
|
|
操作系统内核 <---- 从内核缓冲区读取网络数据【我在这里】
| |
v v
网络数据 <---- 写入内核缓冲区 <---- 网络中断处理程序
| |
| |
| v
| 从网卡读取数据
| |
| v
| 网卡
网络中断处理程序 Redis 实例
│ │
+-----+------+ +--------+-----+
| CPU Socket1 |───跨CPU Socket访问───| CPU Socket2 |
+------------+ 【 总线 】 +------------+
│ │
↓ ↓
+----------------+ +----------------+ +----------------+
| 内存 | | 内存 | | 内存 |
| +----------+ | | | | |
| | 网络数据 | | | (空白) | | (空白) |
| +----------+ | | | | |
+----------------+ +----------------+ +----------------+
cpu 对Redis 性能有影响
感谢阅读,如果你觉得这节课对你有一些启发,也欢迎把它分享给你的朋友。
扫码关注腾讯云开发者
领取腾讯云代金券
Copyright © 2013 - 2025 Tencent Cloud. All Rights Reserved. 腾讯云 版权所有
深圳市腾讯计算机系统有限公司 ICP备案/许可证号:粤B2-20090059 深公网安备号 44030502008569
腾讯云计算(北京)有限责任公司 京ICP证150476号 | 京ICP备11018762号 | 京公网安备号11010802020287
Copyright © 2013 - 2025 Tencent Cloud.
All Rights Reserved. 腾讯云 版权所有