最近被分配了一个任务,任务描述很简单,就一句话:如何基于 packetbeat
分析 redis 的网路通信情况,而不对 redis 本身(CPU/Memory/Network)产生影响;
首先,需要回答一个问题:会产生什么影响?
通常来讲,运行抓包系统会占用 CPU 和 Memory 等资源,而 redis 本身对 CPU 和 Memory 使用也有较高要求,即希望资源都是自己的才好;
那也问题就变成了:redis 是怎么部署在服务器上运行的?对于 24 核或 32 核服务器,redis 是怎么使用的?
经过确认,我们会在一台 24 核的物理机上跑 8~10 个 redis 实例(分属不同 cluster),但没有对 cpu 和内存使用进行任何限制;换句话说,24 个 CPU 核心和 Memory 都处于“任君多采撷”状态;
由于 packetbeat 的内存占用相对 redis 来说基本可以忽略,因为后文只讨论 CPU ;
因此,我们可以得到的结论是:无论将 packetbeat
跑在哪个核心上,都会“占用一定的 redis 的资源”;
那么问题就变成了:允许百分之多少的 CPU 被 packetbeat 占用?
粗略估算结果如下:
- 24 核心 CPU ,单核跑满相当于占用了 4.17% 的 CPU 资源;若占用两个 CPU 核心,则对应 8.34% ;
- 我们的报警系统对 redis 的 CPU 报警设置为:单核占用达到 90% ,总体占用达到 40% ;
- 对于业务比较繁忙的 redis 来说,CPU 占用能够达到整体 30% 左右;
- 由此看来,即使跑满 2 个 CPU 核心也没什么大问题;
另外还有一个疑问:从 redis 的视角来看 24 个核心真的是完全等同的么?是否存在某种优先选择策略?
似乎这个问题又和 CPU 的硬件架构扯上了关系,即 SMP
和 NUMA
都是怎么玩的;
经确认:我们线上机器的 CPU 架构都是 NUMA(由两个 node 构成),并且 redis 会倾向于使用 NUMA node1 中的 cpusets ,那么将 packetbeat
绑定到 NUMA node2 上运行应该是相对更合理的方式;
谈及绑定问题,原则上讲会涉及 CPU 绑定,Memroy 绑定,IRQ 绑定等等;因此,它们之前的关系及影响,以及部署考量都需要研究确认;
针对 CPU 绑定,即 CPU 亲缘性问题,存在多种处理方式:
- taskset
- numactl
- isolcpus
- cgroups
需要确认这些方式有何不同,应该使用哪种,为什么?
选定 CPU 绑定方式后,Memory 和 IRQ 绑定如何处理?IRQ 处理是否应该绑定到 CPU 亲缘性选择的相同 CPU 上么?
上述情况还只是一般性的讨论,对于基于 go 语言实现的 packetbeat
来说,由于 OS thread 的创建数量是由 runtime 自行决定的,而 goroutine 跑在哪个 OS thread 上则是由 go 运行时调度器决定的;packetbeat
的功能至少可以拆分为网络抓包功能和抓包分析功能,而这两者基于多少 goroutine 实现,以及两者之间的相互影响(例如 CPU 跑高导致抓包时的丢包行为)都是应该考虑考虑的;总之,一般情况下,我们认为将 packetbeat
绑定到一组 cpu 上运行似乎是更好的选择;
现状如下:
- redis 实例的运行尚未考虑 CPU 亲缘性问题;
- 基于
taskset
控制packetbeat
的 CPU 绑定,但理论上讲,无论如何绑定,总归会对 redis 产生一定影响; - 由于 redis 的网络流量非常大,万兆网卡跑满状态下,每秒大概要保存 1.2GB 数据,通常我们会抓取 10s 数据包,因为 12GB 的数据对于硬盘和带宽的影响都需要考虑;