服务器不丢包背后的兵法:Redis在万亿级日访问量下的中断优化
作者:CQITer小编 时间:2018-05-29 16:15
2017 年年初以来,随着 Redis 产品的用户量越来越大、接入服务越来越多,再加上美团点评 Memcache 和 Redis 两套缓存融合......

这导致 Redis 服务端的总体请求量从年初最开始日访问量百亿次级别上涨到高峰时段的万亿次级别,因此给运维和架构团队都带来了极大的挑战。
原本稳定的环境也因为请求量的上涨带来了很多不稳定的因素,其中一直困扰我们的就是网卡丢包问题。
起初线上存在部分 Redis 节点还在使用千兆网卡的老旧服务器,而缓存服务往往需要承载极高的查询量,并要求毫秒级的响应速度,如此一来千兆网卡很快就出现了瓶颈。
经过整治,我们将千兆网卡服务器替换为了万兆网卡服务器。本以为可以高枕无忧,但是没想到,在业务高峰时段,机器竟然也出现了丢包问题,而此时网卡带宽使用还远远没有达到瓶颈。
定位网络丢包的原因
从异常指标入手
首先,我们在系统监控的 net.if.in.dropped 指标中,看到有大量数据丢包异常,那么第一步就是要了解这个指标代表什么。

这个指标的数据源,是读取 /proc/net/dev 中的数据,监控 Agent 做简单的处理之后上报。
以下为 /proc/net/dev 的一个示例,可以看到第一行 Receive 代表 in,Transmit 代表 out,第二行即各个表头字段,再往后每一行代表一个网卡设备具体的值。
其中各个字段意义如下:

/proc/net/dev 的数据来源,根据源码文件 net/core/net-procfs.c,可以知道上述指标是通过其中的 dev_seq_show() 函数和 dev_seq_printf_stats() 函数输出的。
通过上述字段解释,我们可以了解丢包发生在网卡设备驱动层面,但是想要了解真正的原因,需要继续深入源码。
static int dev_seq_show(struct seq_file *seq, void *v)
{
if (v == SEQ_START_TOKEN)
/* 输出/proc/net/dev表头部分 */
seq_puts(seq, "Inter-| Receive "
" | Transmit\n"
" face |bytes packets errs drop fifo frame "
"compressed multicast|bytes packets errs "
"drop fifo colls carrier compressed\n");
else
/* 输出/proc/net/dev数据部分 */
dev_seq_printf_stats(seq, v);
return 0;
}
static void dev_seq_printf_stats(struct seq_file *seq, struct net_device *dev)
{
struct rtnl_link_stats64 temp;
/* 数据源从下面的函数中取得 */
const struct rtnl_link_stats64 *stats = dev_get_stats(dev, &temp);
/* /proc/net/dev 各个字段的数据算法 */




