TC限速实践

背景

近期项目的一个大屏项目经常出现一些问题,主要原因是上游数据开始变的不稳定,为了确保展示的稳定,自动容错等做了很多工作,一切准备就绪了,关键的问题来了,要如何测试一些极端场景?比如我想看看我依赖的数据A出现网络异常的情况,我的代码是报错,友好提示,还是展示兜底数据等。

最终在网上简单了解后找到了一个不错的工具,TC(traffic control),这是linux自带工具,感觉非常好用,这里整理记录一下基础知识以及一些小坑。

基础知识

报文分组从输入网卡(入口)接收进来,经过路由的查找,以确定是发给本机的,还是需要转发的。如果是发给本机的,就直接向上递交给上层的协议,比如TCP,如果是转发的,则会从输出网卡(出口)发出。网络流量的控制通常发生在输出网卡处,Linux内核中由TC(Traffic Control)实现。TC是利用队列规定建立处理数据包的队列,并定义队列中的数据包被发送的方式,从而实现流量控制。基本原理:

基本原理

这里我们还会用到一个工具netem ,它是 Linux 在2.6 及以上内核版本提供的一个网络模拟功能模块。该功能模块可以用来在性能良好的局域网中,模拟出复杂的互联网传输性能,如时延,丢包,抖动等场景。

TC框架的设计

TC是由“队列规程(Qdisc),类别(Class),过滤器(Filter)”三者组成的,具体描述可以直接参考官方描述,在命令行里输入

man tc

就可以直接看见官方的使用文档加描述,不喜欢看英文的小伙伴可以直接在网上搜索相关翻译,已经有人整理出来了。

NAME
       tc - show / manipulate traffic control settings

SYNOPSIS
       tc qdisc [ add | change | replace | link ] dev DEV [ parent qdisc-id | root ] [ handle qdisc-id ] qdisc [ qdisc specific parameters ]
      ......
DESCRIPTION
       Tc is used to configure Traffic Control in the Linux kernel. Traffic Control consists of the following:

       SHAPING
              When traffic is shaped, its rate of transmission is under control. Shaping may be more than lowering the available bandwidth - it is also used to smooth out bursts
              in traffic for better network behaviour. Shaping occurs on egress.
      ......

关于这三者的关系,找到一个描述直观的简图:


简图

在写命令行的时候,这张图一定要刻在脑子里。

关于这三者的深一步原理,网上发现一片写的很好的文章,这里借用一下图片:

原理图

更多详情就不复制粘贴了,大家可以自行去看原文。

使用命令

命令的实际执行是按照 创建根队列--》创建类别class--》为类别创建对应过滤器filter,对应网卡接收的数据包会一层一层下发到过滤器进行过滤或相关处理。
有关队列的操作如下:

 tc qdisc [add | change | replace | link] dev DEV [parent qdisk-id |root] [handle qdisc-id] qdisc [qdisc specific parameters]

tc的功能很强大,比如队列还可以分为CBQ、HTB等,但是我们又不想成为资深运维大佬,只是想使用一些简单的功能,那么我们就基于简单场景列几个命令。

  • 查看网卡
sar -n DEV 1 2 

首先查看我们的机器实际使用了哪个网卡,比如我的机器使用的是eth0

  • 查看已有配置
tc qdisc show dev eth0
  • 清空已有配置
tc qdisc del dev eth0 root
  • 新建一个全局延迟队列
tc qdisc add dev eth0 root netem delay 200ms

到这一步,已经可以针对整个机器设置出网延迟了。

再介绍后面的命令之前,这里要再稍微介绍一个重要的基础知识。在TC中,使用"major:minor"这样的句柄来标识队列和类别。其中major和minor都是数字。对于队列来说,minor总是为0,即"major:0"这样的形式,也可以简写为"major: "

  • 新建一个根队列,并设置三个分类
tc qdisc add dev eth0 root handle 1:  prio
# 这里的handle 1: 就是指定新生成的队列句柄id是1。
# 这三个命令为根队列1创建三个类别,分别是1:11、1:12和1:13,它们分别占用40、40和20mbit的带宽。
tc class add dev eth0 parent 1: classid 1:11 htb rate 40mbit ceil 40mbit

tc class add dev eth0 parent 1: classid 1:12 htb rate 40mbit ceil 40mbit

tc class add dev eth0 parent 1: cllassid 1:13 htb rate 20mbit ceil 20mbit

  • 为队列设置过滤器
tc filter add dev eth0  parent 1:0 protocol ip prio 1 u32 match ip dport 80 0xffff flowid 1:11 
# "protocol ip"表示该过滤器应该检查报文分组的协议字段。"prio 1"表示它们对报文处理的优先级是相同的。
# u32选择器(命令中u32后面的部分)来匹配不同的数据流
# flowid 1:11"表示将把该数据流分配给类别1:11

tc filter add dev eth0 parent 1:0 protocol ip prio 1 u32 match ip  dst 10.96.123.33 flowid 1:12 

#这个是指定ip的过滤
  • 查看当前分类与过滤器的配置信息
tc class show dev eth0
tc filter show dev eth0
  • 查看当前流量实际分发情况
tc -s qdisc ls dev eth0     

相关单位

tc命令所有的参数都可以使用浮点数,可能会涉及到以下计数单位。

带宽或流速单位:

kbps 千字节/s mbps 兆字节/s (bps或者一个无单位数字,表示字节数/s)

kbit KBits/s mbit MBits/s

数据的数量单位

kb或k 千字节 mb或m 兆字节 (b或者一个无单位数字,字节)

kbit 千bit mbit 兆bit

时间的计量单位

s, sec或secs 秒 ms, msec或mescs 毫秒

us, use, usecs或一个无单位数字 微s

踩坑实战

看完了这些,起初我只是想针对某个ip进行一下限速,这个过程中有几个小坑。

  1. tc暂时只能在实体机上执行
  2. tc命令需要root来执行
  3. 确认好默认队列,因为一旦限速规则和默认队列重复,现在的机器都是远程登录的,如果限速过大,将直接导致你无法再进行远程操作,只能重启机器了……

那么我要针对一个ip限速,可以执行下面这个脚本

#!/bin/bash
interface=eth0
ip=100.88.128.149
delay=300ms
loss=5%

tc qdisc add dev $interface root handle 1: prio
# 这个命令会创建3个默认的class  1:1 1:2 1:3 PRIO 另一种意义的pfifo_fast 基于优先级的有类队列规则
tc filter add dev $interface protocol ip  parent 1: prio 1 u32 match ip dst $ip match ip dport $port 0xffff flowid 1:1 
tc filter add dev $interface protocol all parent 1: prio 2 u32 match ip dst 0.0.0.0/0 flowid 1:2
tc filter add dev $interface protocol all parent 1: prio 2 u32 match ip protocol 1 0xff flowid 1:2
# 将指定的ip和端口数据发送给 1:1 , 将其他流量指向1:2
tc qdisc add dev $interface parent 1:2 handle 20: sfq
tc qdisc add dev $interface parent 1:1 handle 10: netem delay $delay loss $loss
# 创建1:1队列,同时设置延迟和丢包率,创建1:2队列接受默认流量

还有一些其他常用的命令

netem  corrupt  0.2%   # 模拟包损坏
netem  delay  10ms   reorder  25%  50%  # 模拟包乱序,有25%的数据包(50%相关)会被立即发送,其他的延迟10ms。
netem  duplicate 1%  # 随机产生1%的重复数据包 。

其他更复杂的操作,可以参考一下下面的文章

参考:
https://www.jianshu.com/p/4b5cc3845f2c
https://blog.csdn.net/dog250/article/details/40483627
https://www.ibm.com/developerworks/cn/linux/1412_xiehy_tc/index.html
https://blog.csdn.net/zhaobryant/article/details/38797739
https://qastack.cn/server/389290/using-tc-to-delay-packets-to-only-a-single-ip-address

推荐阅读更多精彩内容