kubernetes 版本更新记录(1.11-1.22)

可直接查看官方github: https://github.com/kubernetes/kubernetes/tree/master/CHANGELOG,包含1.2.md 至当前最新的 1.23.md,共22个版本。

这里简单记录 1.11至1.23的更新要点,方便查阅。更早的版本参考以前记录的这篇文章——《从 k8s changelog 了解 k8s》

发布通知可参考:https://groups.google.com/g/kubernetes-announce

周数 版本 时间 笔记
50 1.23 (12 月 7 日) KubeCon + CloudNativeCon NA
15 1.24 (4 月 12 日)  
    (4 月 26 日) KubeCon + CloudNativeCon EU
32 1.25 (8 月 9 日)  
    (8 月 22 日) KubeCon + CloudNativeCon NA
49 1.26 (12 月 6 日)  

1.23(未发布)

  • 使用 Golang 1.16.7 构建
  • Client-go 事件库允许自定义垃圾邮件过滤功能。
  • 允许节点扩展本地卷
  • 将 Cluster Autosaler 更新到 1.22.0 版
  • 更新基础镜像包
    • debian 到 v1.9.0
    • debian-iptables 到 v1.6.6
    • setcap 到 v2.0.4
  • apiserver 公开了 4 个 CIDR 分配状态的新指标
  • cri-tools 依赖更新到 v1.22.0

1.22 (2021-08-06)

53 项增强功能:13 项增强功能已升级到稳定版,24 项增强功能正在进入 beta 版,16 项增强功能正在进入 Alpha 版,还有 3 项功能已经被弃用。

  • 发布周期从每年 4 个版本更改为 3 个版本。
    • Kubernetes 发布周期的长度约为 15 周。
    • 第一个 Kubernetes 版本应该在 1 月的第二/三个星期开始。
    • 最后一个 Kubernetes 版本应该在 12 月中旬完成。
  • 使用 Golang 1.16.7 构建
  • 删除几个 beta Kubernetes API

  • 服务器端应用(Server-side Apply)GA。 Kubernetes API 服务器上运行的一个新的字段所有权和对象合并算法。
  • Kubernetes客户端凭证插件, Stable。1.11版本以来一直处于测试。
  • etcd 更新至3.5.0-beta.3。
  • cgroups v2 API 控制内存分配与隔离,内存QoS。alpha
  • node 节点支持 swap。
  • Windows 增强和功能。
  • kubelet seccomp 配置文件。 alpha
  • 非 root 用户的身份运行 kubeadm 控制平面组件,v1beta3 为首选api版本。alpha
  • client-go 凭证插件 GA

1.21 (2021-01-11~4-8)

51 项增强功能:13 项增强功能已进入稳定阶段,16 项增强功能已转为 beta 版,20 项增强功能已进入 alpha 版,弃用了 2 项功能。

  • CronJobs,GA
  • 不可变secret/configmap,stable
  • IPv4 / IPv6 双协议栈支持,beta。双栈支持可以将原生 IPv6 路由到 Pod 和 service,同时仍允许集群在需要的地方使用 IPv4。
  • kubelet 优雅节点关闭,alpha
  • pv 健康监控。 alpha
  • 简化构建kubernetes,标准化原生 Golang 构建工具
  • 弃用 PodSecurityPolicy,v1.25 中删除。
  • 弃用 topologyKeys,改由topology-aware hints(拓扑感知提示)替换,alpha。
  • EndpointSlice stable
  • sysctl 支持 stable

关于 ietf rfc 和 k8s kep

无论是 IETF RFCs, 还是 K8S KEPs,亦或是Pyton PEPs 、 Rust RFCs,都是为了解决一个问题:如何解决项目发展到很大规模时的功能协作问题。

名词释义:

  • IETF RFC - IETF Request For Comments: IETF 意见征集稿
  • K8S KEP - Kubernetes Enhancement Proposal: k8s增强特性提案
  • Pyton PEP - Python Enhancement Proposal:Python改进建议书
  • Rust RFC - Rust request for comments

这些形形色色的 RFC/Xep 在不同语境下意思也不完全一致,具体看社区达成的共识。无论是什么场景,初心都是有利于不同角色间的协作。以下是我整理的一些好处:

  • 对于项目管理人,能够跟踪重大功能从概念到实施整个路径。
  • 对于PM(项目经理、产品经理),以一个连贯的叙述,向外界阐述为什么这个特定的版本很重要。
  • 对于项目核心开发人员,需要一个前瞻性的路线图(roadmap)来规划什么时候落地那些特性。
  • 对于开发经理等,通过 rfc 快速掌握全局,安排开发工作。
  • 对于开发者,通过编写 rfc 理清自己的思路,避免过早的陷入实现细节。
  • 对于社区,可以加强沟通,扩大知识的范围,避免知识掌握在少数人手中。
  • 对于新人,通过 rfc 了解项目发展历程,更好融入社区
  • 对于一定经验的从业人员,通过 rfc 跟进社区动态,获知业内的最佳实践方案,调整学习方向,改进工作业务的内容
  • 对于资深的黑客,通过 rfc 了解本技术的特性,与其它同类社区的差异,为什么要设计这些特性,是怎么设计的,怎样更好地运用(攻破)它们

当然,一个东西当然不可能仅带来优点而没有缺点:

  • 写文档,不是所有人都愿意去做。
  • 额外的流程,会降低我们的开发速度。
  • 项目管理人员也需要花费额外的心思维护和处理rfc相关的工作。

至于有的人说什么开发圣经之类的,个人觉得也大可不必,rfc 就是一个记录设计思路的文档,掌握思路和背后的思考,才是我们开发者应该关注的。

rfc 经过长年累月会累积产生特别多的内容,我们并不需要对每个rfc都熟知,也没有必要,一般快速了解全貌,再针对性看个人感兴趣的。

ps: 写文档和写单元测试一样,虽然开发者可能不太喜欢,但还是要坚持才行啊。

参考资料


kubernetes cpu绑核配置

经过压测,我们发现绑核功能导致cpu不能充分利用,只能利用到 65%-70%,因而最后并没有启用该功能。同行有位大佬给出的结论是,docker绑核是软实现的,不能被系统灵活调度,qps下降是正常现象。

这篇文章仅做记录。

一、CPU 管理策略

CPU 管理策略通过 kubelet 参数 --cpu-manager-policy 来指定。支持两种策略:

  • none: 默认策略,表示现有的调度行为。
  • static: 允许为节点上具有某些资源特征的 pod 赋予增强的 CPU 亲和性和独占性。

同时,要求使用 --kube-reserved 和/或 --system-reserved--reserved-cpus 来保证预留的 CPU 值大于零,可以不是整数,最终计算reserved cpu时会向上取整。

要使得绑核生效,pod 的配置需要 request 和 limit 的值相等。

二、设置步骤

1. 确认非绑核

随便找一个可用的pod,确认目前非绑核状态:

  • docker ps 确认docker id
  • docker inspect查找 pid
  • taskset 查看cpu绑定情况
# docker ps|grep demo
# docker inspect xxx|grep Pid
            "Pid": 123203,
            "PidMode": "",
            "PidsLimit": 0,
# taskset -c -p 123203
pid 123203's current affinity list: 0-71

当前机器的核数时72核,可以看到容器没有绑核。

2. 修改kubelet配置

cd /var/lib/kubelet
mv cpu_manager_state bak_cpu_manager_state

修改 kubelet 的启动参数,添加: –cpu-manager-policy=static 和 –kube-reserved=cpu=1(给cpu池子留点资源)。各人的kubelet启动配置不完全一致,以下仅供参考。

# vi /etc/systemd/system/kubelet.service.d/10-kubeadm.conf

# 在 Environment= 列添加/修改下面两行
Environment="... ...
--cpu-manager-policy=static \
--kube-reserved=cpu=1,memory=1000Mi"

重启kubelet

systemctl daemon-reload
systemctl start kubelet
systemctl status kubelet

3. 修改pod的yaml配置

仅供参考:

          resources:
            limits:
              cpu: '4'
              ephemeral-storage: 40Gi
              memory: 8G
            requests:
              cpu: '4'
              ephemeral-storage: 40Gi
              memory: 8G
 

4. 确认已绑核

pod 不需要重启,也会自动绑核

# docker ps|grep demo
# docker inspect xxx|grep Pid
            "Pid": 123203,
            "PidMode": "",
            "PidsLimit": 0,
# taskset -c -p 123203
pid 123203's current affinity list: 2,4,38,39

三、参考资料


graph-easy 绘制流程图

前几天安装了 slides 这个工具,它有个挺有趣的功能,可以展示简单的流程图,便进一步学习了下 graph-easy 这个工具的使用。

一些简易流程图,如果用visio等工具来作图比较麻烦。使用 graph-easy 会简单的多,例如:

image-20210713142245900

image-20210713142255964

一、背景

Graph::Easy 是一个处理图形DSL的Perl模块,它有如下功能:

  • 提供了一种易懂,可读性很强的图形描述语言
  • 一种支持 ASCII Art 的基于网格的布局器
  • 可以导出为 Graphviz, VCG (Visualizing Compiler Graphs), GDL (Graph Description LAnguages) 和 GraphML 格式。
  • 可以从 Graphviz, VCG 和 GDL 导入图像。

二、安装

2.1 源码安装

这里以centos 7为例进行安装。可以从graph-easy 官网 进行下载包。

//下载安装包
wget https://cpan.metacpan.org/authors/id/S/SH/SHLOMIF/Graph-Easy-0.76.tar.gz

//解决依赖与编译安装
yum install perl perl-ExtUtils-MakeMaker graphviz
Makefile.PL
make test
make install

2.2 软件包安装

# centos
yum install perl 
yum install graphviz

# debian
apt-get install perl 
apt-get install graphviz

# 安装上述软件后安装 Graph::Easy
perl -MCPAN -e shell
cpan[1]> install Graph::Easy
graph-easy -version

Graph::Easy v0.76  (c) by Tels 2004-2008.  Released under the GPL 2.0 or later.

三、使用

第三章内容转载原文:graph easy绘制ascii简易流程图 - Xinkun Blog, 有修改。

3.1 hello world

先来一个入门的hello world。

[root@host /]# echo '[hello]->[world]' | graph-easy
+-------+     +-------+
| hello | --> | world |
+-------+     +-------+

graph-easy 的语法相对来说比较宽松,[hello]->[world][hello]-->[world],[ hello ]-->[ world ]都是可以的。这里可以根据个人的风格。我比较喜欢紧凑的风格。所以后面都是使用紧凑的方式来做。

3.2 线上加个上标

有时候要在连接线上加一个标志说明,比如我想要表明从上海坐车到北京,则可以使用下面的方式:

[root@host /]# echo "[shanghai]-- car -->[beijing]" | graph-easy
+----------+  car   +---------+
| shanghai | -----> | beijing |
+----------+        +---------+

3.3 画一个环

[root@host /]# echo "[a]->[b]->[a]" | graph-easy

  +---------+
  v         |
+---+     +---+
| a | --> | b |
+---+     +---+
[root@host /]# echo "[a]->[a]" | graph-easy

  +--+
  v  |
+------+
|  a   |
+------+

3.4 多个目标或者多个源

[root@host /]# echo "[a],[b]->[c]" | graph-easy
+---+     +---+     +---+
| a | --> | c | <-- | b |
+---+     +---+     +---+

[root@host /]# echo "[a]->[b],[c]" | graph-easy
+---+     +---+
| a | --> | b |
+---+     +---+
  |
  |
  v
+---+
| c |
+---+

3.5 多个流程在一个图内

[root@host /]# echo "[a]->[b]  [c]->[d]" | graph-easy
+---+     +---+
| a | --> | b |
+---+     +---+
+---+     +---+
| c | --> | d |
+---+     +---+

3.6 改变图方向

默认图方向是从左到右的。有时候想要从上向下的流程图。可以用标签来调整

[root@host /]# echo "graph{flow:south} [a]->[b]" | graph-easy
+---+
| a |
+---+
  |
  |
  v
+---+
| b |
+---+

更多示例:https://github.com/ironcamel/Graph-Easy/tree/master/t/txt

四、语法

graph-easy 语法都是基于 Graph::Easy::Parser

4.1 节点

  • 单节点:即单个节点,用[xx]表示,比如[a]那出来的就一个节点

  • 复合节点:由多个节点组成的一个复合节点。

    用[xx | xx | xx]表示,节点之间使用|分隔,比如[a | b | c | d]
    

4.2 连接线

  • 单向箭头:使用->表示,比如[a] -> [b]
  • 无方向连接线:使用–表示,比如[a] – [b]
  • 双横线单向箭头:使用==>表示,比如[a] ==> [b]
  • 点横线单向箭头:使用…>表示,比如[a] …> [b]
  • 波浪线单向箭头:使用~~>表示,比如[a] ~~> [b]
  • 横线、点单向箭头:使用.->表示,比如[a] .-> [b]
  • 双向箭头:使用<->表示,比如[a] <-> [b]
  • 双横线双向箭头:使用<=>表示,比如[a] <=> [b]

参考资料


linux tc 流量控制备忘

最近接触了linux tc,做一些记录。参考资料中有两篇文章值得看:

第一篇是携程大佬翻译的经典文章,第二篇是字节大佬顺带提了一些 tc 历史的文章。

一、背景

TC 在 Linux Kernel 2.2版本开始提出,并在2.4版本(2001年)完成。

Linux TC的诞生是为了实现QoS,它在netdev设备的入方向和出方向增加了挂载点,进而控制网络流量的速度,延时,优先级等。

Linux TC在整个Linux Kernel Datapath中的位置如下图所示:

image-20210712121802848

https://people.netfilter.org/pablo/netdev0.1/papers/Linux-Traffic-Control-Classifier-Action-Subsystem-Architecture.pdf

二、linux收发包整体框架

从客户端和服务端整体框架层面来看数据收发流程:

img

  1. 用户态(User Space)程序 Client 向另一台主机上的 Server 发送数据,需要通过调用内核态(Kernel Space)提供给用户态的 Socket 抽象层接口发送数据;
  2. Socket 抽象层接口收到用户态数据后,向下交给传输层接口(TCP 或 UDP);
  3. 传输层负责创建 sk_buff,并将用户数据(应用层数据)填充到缓冲区,做合法性检查后,添加传输层头部,并通过网络层注册的接口将数据包交给网络层处理;
  4. 网络层收到传输层数据包后,会查询路由表,决定数据包去向,如果是需要发出的数据包,会填充网络层头部,并交到内核虚拟网络接口设备的发送队列中;
  5. 虚拟网络接口从发送队列获取数据,调用对应网卡驱动发送数据;

Server 端接收数据时,按照相反的过程从网卡驱动中将数据包一层层上交,直到通过 Socket 抽象层接口将用户数据上交到用户态 Server 进程处理。

三、概念

报文分组从输入网卡接收进来,经过路由的查找, 以确定是发给本机的,还是需要转发的。如果是发给本机的,就直接向上递交给上层的协议,比如TCP,如果是转发的, 则会从输出网卡发出。

网络流量的控制通常发生在输出网卡处,我们可以通过改变发送次序来控制传输速率。一般说来, 由于我们无法控制自己网络之外的设备, 入口处的流量控制相对较难。

流量控制的一个基本概念是队列,每个网卡都与一个队列相联系,每个队列对应一个QDisc(排队规则), 每当内核需要将报文分组从网卡发送出去, 都会首先将该报文分组添加到该网卡所配置的QDisc中, 由该QDisc决定报文分组的发送顺序,可以说,所有的流量控制都发生在队列中。

为实现复杂QoS,队列需要使用不同的过滤器(Filter)来把报文分组分成不同的类别(Class),因此类别(class)和过滤器(Filter)也是流量控制的另外两个重要的基本概念。

  1. qdisc(排队规则)

    QDisc(排队规则)是queueing discipline的简写,它是理解流量控制(traffic control)的基础。无论何时,内核如果需要通过某个网络接口发送数据包,它都需要按照为这个接口配置的qdisc(排队规则)把数据包加入队列。然后,内核会尽可能多地从qdisc里面取出数据包,把它们交给网络适配器驱动模块。最简单的QDisc是pfifo它不对进入的数据包做任何的处理,数据包采用先入先出的方式通过队列。不过,它会保存网络接口一时无法处理的数据包。
    

    其中qdisc又分为 不分类qdisc 和可分类qdisc:

    • CLASSLESS QDisc

      不可分类 QDisc 只能附属于设备的根。用法如下:
           
      tc qdisc add dev DEV root QDISC QDISC-PARAMETERS
      tc qdisc del dev DEV root
           
      一个网络接口上如果没有设置QDisc,pfifo_fast就作为缺省的QDisc。
           
      - pfifo_fast就是系统的标准QDISC。它的队列包括三个波段(band)。在每个波段里面,使用先进先出规则。而三个波段(band)的优先级也不相同,band 0的优先级最高,band 2的最低。如果band0里面有数据包,系统就不会处理band 1里面的数据包,band 1和band 2之间也是一样。数据包是按照服务类型(Type of Service,TOS)被分配多三个波段(band)里面的。
      - red是Random Early Detection(随机早期探测)的简写。如果使用这种QDISC,当带宽的占用接近于规定的带宽时,系统会随机地丢弃一些数据包。它非常适合高带宽应用。
      - sfq是Stochastic Fairness Queueing的简写。它按照会话(session--对应于每个TCP连接或者UDP流)为流量进行排序,然后循环发送每个会话的数据包。
      - tbf是Token Bucket Filter的简写,适合于把流速降低到某个值。
      
    • CLASSFUL QDISC

      可分类的qdisc包括: 
      - CBQ是Class Based Queueing(基于类别排队)的缩写。它实现了一个丰富的连接共享类别结构,既有限制(shaping)带宽的能力,也具有带宽优先级管理的能力。带宽限制是通过计算连接的空闲时间完成的。空闲时间的计算标准是数据包离队事件的频率和下层连接(数据链路层)的带宽。
      - HTB是Hierarchy Token Bucket的缩写。通过在实践基础上的改进,它实现了一个丰富的连接共享类别体系。使用HTB可以很容易地保证每个类别的带宽,它也允许特定的类可以突破带宽上限,占用别的类的带宽。HTB可以通过TBF(Token Bucket Filter)实现带宽限制,也能够划分类别的优先级。
      - PRIO QDisc不能限制带宽,因为属于不同类别的数据包是顺序离队的。使用PRIO QDisc可以很容易对流量进行优先级管理,只有属于高优先级类别的数据包全部发送完毕,才会发送属于低优先级类别的数据包。为了方便管理,需要使用iptables或者ipchains处理数据包的服务类型(Type Of Service,ToS)。
      
  2. class(类别)

    某些QDisc(排队规则)可以包含一些类别,不同的类别中可以包含更深入的QDisc(排队规则),通过这些细分的QDisc还可以为进入的队列的数据包排队。通过设置各种类别数据包的离队次序,QDisc可以为设置网络数据流量的优先级。

  3. filter(过滤器)

    Filter(过滤器)用于为数据包分类,决定它们按照何种QDisc进入队列。无论何时数据包进入一个划分子类的类别中,都需要进行分类。分类的方法可以有多种,使用fileter(过滤器)就是其中之一。使用filter(过滤器)分类时,内核会调用附属于这个类(class)的所有过滤器,直到返回一个判决。如果没有判决返回,就作进一步的处理,而处理方式和QDISC有关。需要注意的是,filter(过滤器)是在QDisc内部,它们不能作为主体。

四、SFQ

tc有很多内容,如果未来有场景需要深入学习,再开新文章记录下。这里只转载了sfq的用法。再次推荐文初列的两篇文章。

4.1 SFQ(Stochastic Fairness Queueing,随机公平排队)

日常使用中,如果只想尽可能公平地响应每个请求,sfq 可解愁。本小节转自文初的文章一。

随机公平排队(SFQ)是公平排队算法族的一个简单实现。相比其他算法,SFQ 精准性要差一些,但它所需的计算量也更少,而结果几乎是完全公平的(almost perfectly fair)。

img

SFQ 中的核心是 conversion(会话)或 flow(流),大部分情况下都对应一个 TCP session 或 UDP stream。每个 conversion 对应一个 FIFO queue,然后将流量分到不 同 queue。发送数据时,按照 round robin 方式,每个 session 轮流发送。

这种机制会产生非常公平的结果,不会因为单个 conversion 太大而把其他 conversion 的带宽都 挤占掉。SFQ 被称为“随机的”(stochastic)是因为它其实并没有为每个 session 分配一个 queue,而是用算法将流量哈希到了一组有限的 queue

但这里会出现另一个问题:多个 session 会可能会哈希到同一个 bucket(哈希槽), 进而导致每个 session 的 quota 变小,达不到预期的整流带宽(或速度)。为避免这个 问题过于明显,SFQ 会不断变换它使用的哈希算法,最终任何两个会话冲突的持续时间 都不会很长,只会有几秒钟。

SFQ 只有在实际出向带宽已经非常饱和的情况下才有效,这一点非常重要!否则, Linux 机器上就不存在 queue,因此也就没用效果。稍后会看到如何将 SFQ 与其他 qdisc 相结合来实现一般情况下的公平排队

说的更明确一点:没用配套的整流配置的话,单纯在(连接 modem 的)以太网接口上配 置SFQ 是毫无意义的

SFQ 大部分情况下默认参数就够了:

  • perturb

    每隔多少就重新配置哈希算法。如果这个参数没设,哈希算法就永远不会重新配置。 建议显式设置这个参数,不要为空。10s 可能是个不错的选择。

  • quantum

    在轮到下一个 queue 发送之前,当前 queue 允许出队(dequeue)的最大字节数。默认是 一个 MTU。不建议设置为小于 MTU 的值。

  • limit

    SFQ 能缓存的最大包数(超过这个阈值将导致丢包)。

如果你有一个带宽已经饱和的网络设备,那下面的配置有助于提高公平性:

$ tc qdisc add dev ppp0 root sfq perturb 10

$ tc -s -d qdisc ls
qdisc sfq 800c: dev ppp0 quantum 1514b limit 128p flows 128/1024 perturb 10sec
 Sent 4812 bytes 62 pkts (dropped 0, overlimits 0)

解释:

  • 800c::自动分配的 handle number(句柄编号)
  • limit 128p:最大缓存 128 个包
  • flows 128/1024:这个 sfq 有 1024 个哈希槽(hash buckets),其中 128 个当前有 数据待发送。
  • perturb 10sec:每隔 10s 换一次哈希算法。

五、常用命令

#查看现有的队列
tc -s qdisc ls dev eth0

#查看现有的分类
tc -s class ls dev eth0

# 清理原有的队列类型
tc qdisc del dev eth0 root

5.1 针对端口进行限速

#查看现有的队列
tc -s qdisc ls dev eth0

#查看现有的分类
tc -s class ls dev eth0

#创建队列
tc qdisc add dev eth0 root handle 1:0 htb default 1 
#添加一个tbf队列,绑定到eth0上,命名为1:0 ,默认归类为1
#handle:为队列命名或指定某队列

#创建分类
tc class add dev eth0 parent 1:0 classid 1:1 htb rate 10Mbit burst 15k
#为eth0下的root队列1:0添加一个分类并命名为1:1,类型为htb,带宽为10M
#rate: 是一个类保证得到的带宽值.如果有不只一个类,请保证所有子类总和是小于或等于父类.
#ceil: ceil是一个类最大能得到的带宽值.

#创建一个子分类
tc class add dev eth0 parent 1:1 classid 1:10 htb rate 10Mbit ceil 10Mbit burst 15k
#为1:1类规则添加一个名为1:10的类,类型为htb,带宽为10M

#为了避免一个会话永占带宽,添加随即公平队列sfq.
tc qdisc add dev eth0 parent 1:10 handle 10: sfq perturb 10
#perturb:是多少秒后重新配置一次散列算法,默认为10秒
#sfq,他可以防止一个段内的一个ip占用整个带宽

#使用u32创建过滤器
tc filter add dev eth0 protocol ip parent 1:0 prio 1 u32 match ip sport 22 flowid 1:10

#删除队列
tc qdisc del dev eth0 root

配置完成后加入本地启动文件:  
/etc/rc.local

5.2 针对不同的ip进行限速

#!/bin/bash

#清空原有规则
tc qdisc del dev eth0 root

#创建根序列
tc qdisc add dev eth0 root handle 1: htb default 1

#创建一个主分类绑定所有带宽资源(20M)
tc class add dev eth0 parent 1:0 classid 1:1 htb rate 20Mbit burst 15k

#创建子分类
tc class add dev eth0 parent 1:1 classid 1:10 htb rate 20Mbit ceil 10Mbit burst 15k
tc class add dev eth0 parent 1:1 classid 1:20 htb rate 20Mbit ceil 20Mbit burst 15k

#避免一个ip霸占带宽资源(git1有讲到)
tc qdisc add dev eth0 parent 1:10 handle 10: sfq perturb 10
tc qdisc add dev eth0 parent 1:20 handle 20: sfq perturb 10

#创建过滤器
#对所有ip限速
tc filter add dev eth0 protocol ip parent 1:0 prio 2 u32 match ip dst 0.0.0.0/0 flowid 1:10
#对内网ip放行
tc filter add dev eth0 protocol ip parent 1:0 prio 1 u32 match ip dst 12.0.0.0/8 flowid 1:20

六、术语

  • Queueing Discipline (qdisc,排队规则)

    管理设备队列(queues of devices)的算法,可以是管理入向(incoing/ingress )队列,也可以是管理出向队列(outgoing/egress)。

  • root qdisc(根排队规则)

    attach 到网络设备的那个 qdisc。

  • Classless qdisc(无类别排队规则)

    对所有包一视同仁,同等对待。

  • Classful qdisc(有类别排队规则)

    一个 classful qdisc 会包含多个类别(classes)。每个类别(class)可以进一步包 含其他 qdisc,可以是 classful qdisc,也可以是 classless qdisc。

    严格按定义来说,pfifo_fast 属于有类别排队规则(classful),因为它内部包 含了三个 band,而这些 band 实际上是 class。但从用户配置的视角来说,它是 classless 的,因为这三个内部 class 用户是无法通过 tc 命令配置的。

  • Classes(类别)

    每个 classful qdisc 可能会包含几个 class,这些都是 qdisc 内部可见的。对于每 个 class,也是可以再向其添加其他 class 的。因此,一个 class 的 parent 可以 是一个 qdisc,也可以是另一个 class

    Leaf class 是没有 child class 的 class。这种 class 中 attach 了一个 qdisc ,负责该 class 的数据发送

    创建一个 class 时会自动 attach 一个 fifo qdisc。而当向这个 class 添加 child class 时,这个 fifo qdisc 会被自动删除。对于 leaf class,可以用一个更合适的 qdisc 来替换掉这个fifo qdisc。你甚至能用一个 classful qdisc 来替换这个 fifo qdisc,这样就可以添加其他 class了。

  • Classifier(分类器)

    每个 classful qdisc 需要判断每个包应该放到哪个 class。这是通过分类器完成的。

  • Filter(过滤器)

    分类过程(Classification)可以通过过滤器(filters)完成。过滤器包含许多的判 断条件,匹配到条件之后就算 filter 匹配成功了。

  • Scheduling(调度)

    在分类器的协助下,一个 qdisc 可以判断某些包是不是要先于其他包发送出去,这 个过程称为调度,可以通过例如前面提到的 pfifo_fast qdisc 完成。调度也被 称为重排序(reordering),但后者容易引起混淆。

  • Shaping(整形)

    在包发送出去之前进行延迟处理,以达到预设的最大发送速率的过程。整形是在 egress 做的(前面提到了,ingress 方向的不叫 shaping,叫 policing,译者注)。 不严格地说,丢弃包来降低流量的过程有时也称为整形。

  • Policing(执行策略,决定是否丢弃包)

    延迟或丢弃(delaying or dropping)包来达到预设带宽的过程。 在 Linux 上, policing 只能对包进行丢弃,不能延迟 —— 没有“入向队列”(”ingress queue”)

  • Work-Conserving qdisc(随到随发 qdisc)

    work-conserving qdisc 只要有包可发送就立即发送。换句话说,只要网卡处于可 发送状态(对于 egress qdisc 来说),它永远不会延迟包的发送

  • non-Work-Conserving qdisc(非随到随发 qdisc)

    某些 qdisc,例如 TBF,可能会延迟一段时间再将一个包发送出去,以达到期望的带宽 。这意味着它们有时即使有能力发送,也不会发送。

七、参考资料