AskOverflow.Dev

AskOverflow.Dev Logo AskOverflow.Dev Logo

AskOverflow.Dev Navigation

  • 主页
  • 系统&网络
  • Ubuntu
  • Unix
  • DBA
  • Computer
  • Coding
  • LangChain

Mobile menu

Close
  • 主页
  • 系统&网络
    • 最新
    • 热门
    • 标签
  • Ubuntu
    • 最新
    • 热门
    • 标签
  • Unix
    • 最新
    • 标签
  • DBA
    • 最新
    • 标签
  • Computer
    • 最新
    • 标签
  • Coding
    • 最新
    • 标签
主页 / unix / 问题 / 545033
Accepted
cyqsimon
cyqsimon
Asked: 2019-10-04 20:50:22 +0800 CST2019-10-04 20:50:22 +0800 CST 2019-10-04 20:50:22 +0800 CST

在 CentOS 7 中限制特定端口的带宽?

  • 772

我在我的 VPS 上运行 CentOS 7,我想限制特定端口的带宽。我环顾四周,在我能找到的解决方案中,要么是对界面的限制,要么是模糊描述的 iptable 设置,似乎只在 CentOS 6 上尝试过。

就我而言,我的 Shadowsocks(代理应用程序)服务器端正在侦听 port 1080、1081和1082on eth0。我想允许1080无限带宽,但同时限制1081在10821MBps 左右。由于它是代理应用程序,因此入站和出站流量大致相等。请注意,它是一个监听 3 个端口的 Shadowsocks 实例,而不是每个监听 1 个端口的 3 个实例,因此按进程限制带宽不适用。

但除此之外,任何解决方案对我来说都是可行的,无论是 CentOS 开箱即用的支持,还是某种中间监控层。只要它完成工作,我就愿意接受。

提前致谢。

centos
  • 1 1 个回答
  • 6413 Views

1 个回答

  • Voted
  1. Best Answer
    A.B
    2019-10-09T05:49:00+08:002019-10-09T05:49:00+08:00

    只能使用Linux 的 Traffic Control来限制流量。

    只是为了澄清一下,shadowsocks创建一个隧道,一侧作为 SOCKS5 代理(sslocal考虑到给定端口,我假设这是在 OP 服务器上运行的),与远程端点(ssserver)通信,该端点本身将与实际目标通信服务器。shadowsocks 处理 SOCKS5 UDP ASSOCIATE,然后在与 (SOCKS5) TCP 端口相同的端口上使用 (SOCKS5) UDP。

    此解决方案对 TCP 和 UDP 均按原样(见注 1)工作,但 UDP 可能会带来额外的挑战:如果源正在创建“大于 MTU”大小的 UDP 数据包(这可能不应该由行为良好的客户端或服务器),它们会变得支离破碎。tc,它在ingress中比netfilter更早工作,在egress中比netfilter晚,将看到这些片段。UDP 端口在片段中不可用,因此没有过滤器能够捕获它们,并且几乎不会发生限制。TCP 自然地使用 MTU 来限制数据包大小(并且无论如何都要进行路径 MTU 发现)在大多数设置中不会遇到这个问题。

    这是一个数据包流 ascii 图片(整个图片通常表示一个客户端活动导致两个流,一个在代理的左侧,一个在代理的右侧):

                  traffic controlled      TCP self-adjusting / no UDP control
                 ------------->               <-------------
               /                \           /                \
      clients |                  |  proxy  |                  |  remote  ====== real servers
               \                / (sslocal) \                / (ssserver)
                 <-------------               ------------->
                  traffic controlled       already rate limited
    

    无需担心与远程服务器的流量:

    • 从代理到远程服务器的传出当然会受到客户端传入的限制,
    • 从远程/服务器传入代理
      • TCP 通常会调整并表现得像客户端的流量。
      • UDP不会有这种可能性,除非应用协议可以做到。例如:如果通过简单 UDP 的两个视频源从服务器端到达并超过客户端的限制,则两个客户端流都可能被破坏。应该有一个应用程序反馈来减少带宽,这超出了这个范围。

    无论如何,将远程/服务器端流量链接到客户端以供tc使用会变得更加复杂,可能涉及 shadowsocks 内部的更改。

    对于只发送数据的 SOCKS5 客户端,需要限制来自它们的入口以限制带宽,对于只接收数据的 SOCKS5 客户端,需要限制它们的出口以限制带宽:除非正在使用的应用程序是众所周知的,否则两种方式都应该是流量控制的.

    交通控制是一个复杂的话题,我几乎无法触及。我将给出两种答案:一种简单粗暴的只做监管(丢弃过量),一种更复杂的,做整形(包括在不得不丢弃之前延迟),使用 IFB 接口来解决入口限制.

    应阅读以下文档以了解概念和 Linux 实现:

    http://www.tldp.org/HOWTO/Traffic-Control-HOWTO/

    此外,在 shell 脚本中实现的这个命令(并使用与此答案中类似的机制)也确实可以创造奇迹:

    https://github.com/magnific0/wondershaper

    简陋

    策略操作用于丢弃任何多余的数据包匹配端口(这是一种粗略的方法)。它通常用于入口,但也适用于出口。流量是速率受限的,但在各种速率受限的客户端之间可能存在波动和不公平的共享(尤其是在涉及 UDP 与 TCP 的情况下)。

    • 出口(传出数据包)

      允许附加过滤器的最简单的qdisc是prio qdisc ,它的特定功能不会真正被使用。

      tc qdisc add dev eth0 root handle 1: prio
      

      只需为每个端口添加一个以下过滤器(8mbits/s <=> 1MBytes/s)(u16 at 0 layer transport表示“源端口”),即可完成 TCP 和 UDP (另请参见注释 2):

      tc filter add dev eth0 parent 1: protocol ip basic match 'cmp(u16 at 0 layer transport eq 1081)' action police rate 8mibit burst 256k
      tc filter add dev eth0 parent 1: protocol ip basic match 'cmp(u16 at 0 layer transport eq 1082)' action police rate 8mibit burst 256k
      

      如果我误解了 1081 和 1082 应该只有一个共同的限制,请使用它而不是上面的两个,将它们分组在同一个操作中(使用basic / ematch过滤器很容易),然后将处理它们单个令牌桶:

      tc filter add dev eth0 parent 1: protocol ip basic match 'cmp(u16 at 0 layer transport eq 1081) or cmp(u16 at 0 layer transport eq 1082)' action police rate 8mibit burst 256k
      
    • 入口(传入数据包)

      Ingress比egress更受限制(不能进行整形),但无论如何都没有在简单的情况下完成。使用它只需要添加一个ingressqdisc (见注 3):

      tc qdisc add dev eth0 ingress
      

      等效过滤器(u16 at 2 layer transport表示“目标端口”):

      tc filter add dev eth0 ingress protocol ip basic match 'cmp(u16 at 2 layer transport eq 1081)' action police rate 8mibit burst 256k
      tc filter add dev eth0 ingress protocol ip basic match 'cmp(u16 at 2 layer transport eq 1082)' action police rate 8mibit burst 256k
      

      或单个限制,而不是上述两个:

      tc filter add dev eth0 ingress protocol ip basic match 'cmp(u16 at 2 layer transport eq 1081) or cmp(u16 at 2 layer transport eq 1082)' action police rate 8mibit burst 256k
      

    清洁 tc

    egress,ingress或这两种设置都可以替换为下面的改进版本。应先清理以前的设置。

    要删除以前应用的 tc 设置,只需删除root和ingress qdiscs。它们下方的所有内容,包括过滤器,也将被删除。具有保留句柄 0:的默认接口根qdisc将被放回。

    tc qdisc del dev eth0 root
    tc qdisc del dev eth0 ingress
    

    使用类 qdiscs 和 IFB 接口进行更复杂的设置

    使用shape可以在必须丢弃数据包之前延迟数据包,应该会改善整体结果。Hierarchy Token Bucket ( HTB ),一个有类的 qdisc 将处理带宽,而在它之下,随机公平队列 ( SFQ ) 将提高客户端之间在受限带宽内竞争时的公平性。

    • 出口

      这是描述下一个设置的 ascii 图片:

                          root 1:   HTB classful qdisc
                            |
                          / | \
                         /  |  \
                        /   |   \
                       /    |    \
                      /    1:20  1:30  HTB classes
                     /    8mibit  8mibit
                    /       |       \
                   /        |        \
                  /        20:       30:
                 /         SFQ       SFQ
           still 1:
           default         port         port
      incl. port 1080      1081         1082
      

      有限的带宽不会借用额外的可用流量(OP 没有要求):这就是为什么它们不是“整个可用带宽”默认类的子类。剩下的默认流量,包括 1080 端口,只是停留在 1:,不做特殊处理。在允许类借用可用带宽的不同设置中,应将这些类放在其速率设置为最大可用带宽的准确值的父类之下,以了解借用什么。因此,配置需要针对每种情况进行微调。我保持简单。

      htb 有类 qdisc:

      tc qdisc add dev eth0 root handle 1: htb
      

      htb 类、附加的 sfq 和指向它们的过滤器:

      tc class add dev eth0 parent 1: classid 1:20 htb rate 8mibit
      tc class add dev eth0 parent 1: classid 1:30 htb rate 8mibit
      
      tc qdisc add dev eth0 parent 1:20 handle 20: sfq perturb 10
      tc qdisc add dev eth0 parent 1:30 handle 30: sfq perturb 10
      
      tc filter add dev eth0 parent 1: protocol ip prio 1 basic match 'cmp(u16 at 0 layer transport eq 1081)' flowid 1:20
      tc filter add dev eth0 parent 1: protocol ip prio 1 basic match 'cmp(u16 at 0 layer transport eq 1082)' flowid 1:30
      

      或单个限制,而不是上面的 6 个命令:

      tc class add dev eth0 parent 1: classid 1:20 htb rate 8mibit
      tc qdisc add dev eth0 parent 1:20 handle 20: sfq perturb 10
      tc filter add dev eth0 parent 1: protocol ip prio 1 basic match 'cmp(u16 at 0 layer transport eq 1081)' flowid 1:20
      tc filter add dev eth0 parent 1: protocol ip prio 1 basic match 'cmp(u16 at 0 layer transport eq 1082)' flowid 1:20
      
    • 入口

      入口qdisc 不能用于整形(例如延迟数据包),而只能使用过滤器将它们丢弃,就像在简单情况下一样。为了获得更好的控制,可以使用一个技巧:中间功能块,它显示为人工出口接口,入口流量可以通过过滤器重定向,但与网络堆栈的其余部分几乎没有交互。一旦到位,就可以在其上应用出口功能,即使其中一些可能并不总是有帮助,考虑到传入流量的真正控制权不在接收系统手中。所以在这里我设置ifb0界面然后在上面复制(出口) 设置,以使某种入口整形表现得比监管更好。

      创建ifb0 (参见注释 4)并应用与之前的egress相同的设置:

      ip link add name ifb0 type ifb 2>/dev/null || :
      ip link set dev ifb0 up
      
      tc qdisc add dev ifb0 root handle 1: htb
      

      指向它们的类和过滤器:

      tc class add dev ifb0 parent 1: classid 1:20 htb rate 8mibit
      tc class add dev ifb0 parent 1: classid 1:30 htb rate 8mibit
      
      tc qdisc add dev ifb0 parent 1:20 handle 20: sfq perturb 10
      tc qdisc add dev ifb0 parent 1:30 handle 30: sfq perturb 10
      
      tc filter add dev ifb0 parent 1: protocol ip prio 1 basic match 'cmp(u16 at 2 layer transport eq 1081)' flowid 1:20
      tc filter add dev ifb0 parent 1: protocol ip prio 1 basic match 'cmp(u16 at 2 layer transport eq 1082)' flowid 1:30
      

      或单个限制,而不是上面的 6 个命令:

      tc class add dev ifb0 parent 1: classid 1:20 htb rate 8mibit     
      tc qdisc add dev ifb0 parent 1:20 handle 20: sfq perturb 10
      tc filter add dev ifb0 parent 1: protocol ip prio 1 basic match 'cmp(u16 at 2 layer transport eq 1081)' flowid 1:20
      tc filter add dev ifb0 parent 1: protocol ip prio 1 basic match 'cmp(u16 at 2 layer transport eq 1082)' flowid 1:20
      

      从eth0的入口到ifb0 出口的重定向在下面完成。为了优化,只重定向目标端口而不是所有流量。无论如何,实际的过滤和整形都是在ifb0中完成的。

      tc qdisc add dev eth0 ingress
      tc filter add dev eth0 ingress protocol ip basic match 'cmp(u16 at 2 layer transport eq 1081)' action mirred egress redirect dev ifb0
      tc filter add dev eth0 ingress protocol ip basic match 'cmp(u16 at 2 layer transport eq 1081)' action mirred egress redirect dev ifb0
      

    笔记:

    1. 在 Debian 10 / 内核 5.3 上使用一些网络命名空间进行了测试。命令语法也在 CentOS 7.6 容器/内核 5.3(而不是 3.10)上进行了测试。

    2.u32 match ip sport 1081 0xffff本来可以用来匹配源端口 1081。但它不能处理 IP 选项的存在。可以处理它,但它实际上需要三个u32过滤器u32 match tcp src 1081 0xffff的复杂使用,如手册页中所述。所以我最终选择了。 basic match

    3.是否指定ingress了保留句柄ffff:(指定的句柄值被忽略),所以我宁愿不指定它。引用 ingress byparent ffff:可以替换为 just ingressso 这就是我选择的。

    4、第一次创建IFB接口时,会加载ifb模块,默认会在初始命名空间中自动创建ifb0和ifb1接口,如果询问接口名称ifb0会报错,而实际创建为命令的结果。同时,如果只是加载模块,这个接口不会出现在网络命名空间(例如:容器)中,所以仍然需要在那里。因此,添加2>/dev/null || :解决了这两种情况。当然,我假设 IFB 支持确实可用。

    • 8

相关问题

  • smartmontools - 自动测试是否与运行简短测试相同?

  • systemctl 命令在 RHEL 6 中不起作用

  • 为什么我的交换机没有从指定的池中获取地址

  • 在 CentOS7 GNOME 的 Applications-menu 选项卡中创建自定义菜单

  • 奇怪的路由器与centos 6一起工作[关闭]

Sidebar

Stats

  • 问题 205573
  • 回答 270741
  • 最佳答案 135370
  • 用户 68524
  • 热门
  • 回答
  • Marko Smith

    模块 i915 可能缺少固件 /lib/firmware/i915/*

    • 3 个回答
  • Marko Smith

    无法获取 jessie backports 存储库

    • 4 个回答
  • Marko Smith

    如何将 GPG 私钥和公钥导出到文件

    • 4 个回答
  • Marko Smith

    我们如何运行存储在变量中的命令?

    • 5 个回答
  • Marko Smith

    如何配置 systemd-resolved 和 systemd-networkd 以使用本地 DNS 服务器来解析本地域和远程 DNS 服务器来解析远程域?

    • 3 个回答
  • Marko Smith

    dist-upgrade 后 Kali Linux 中的 apt-get update 错误 [重复]

    • 2 个回答
  • Marko Smith

    如何从 systemctl 服务日志中查看最新的 x 行

    • 5 个回答
  • Marko Smith

    Nano - 跳转到文件末尾

    • 8 个回答
  • Marko Smith

    grub 错误:你需要先加载内核

    • 4 个回答
  • Marko Smith

    如何下载软件包而不是使用 apt-get 命令安装它?

    • 7 个回答
  • Martin Hope
    user12345 无法获取 jessie backports 存储库 2019-03-27 04:39:28 +0800 CST
  • Martin Hope
    Carl 为什么大多数 systemd 示例都包含 WantedBy=multi-user.target? 2019-03-15 11:49:25 +0800 CST
  • Martin Hope
    rocky 如何将 GPG 私钥和公钥导出到文件 2018-11-16 05:36:15 +0800 CST
  • Martin Hope
    Evan Carroll systemctl 状态显示:“状态:降级” 2018-06-03 18:48:17 +0800 CST
  • Martin Hope
    Tim 我们如何运行存储在变量中的命令? 2018-05-21 04:46:29 +0800 CST
  • Martin Hope
    Ankur S 为什么 /dev/null 是一个文件?为什么它的功能不作为一个简单的程序来实现? 2018-04-17 07:28:04 +0800 CST
  • Martin Hope
    user3191334 如何从 systemctl 服务日志中查看最新的 x 行 2018-02-07 00:14:16 +0800 CST
  • Martin Hope
    Marko Pacak Nano - 跳转到文件末尾 2018-02-01 01:53:03 +0800 CST
  • Martin Hope
    Kidburla 为什么真假这么大? 2018-01-26 12:14:47 +0800 CST
  • Martin Hope
    Christos Baziotis 在一个巨大的(70GB)、一行、文本文件中替换字符串 2017-12-30 06:58:33 +0800 CST

热门标签

linux bash debian shell-script text-processing ubuntu centos shell awk ssh

Explore

  • 主页
  • 问题
    • 最新
    • 热门
  • 标签
  • 帮助

Footer

AskOverflow.Dev

关于我们

  • 关于我们
  • 联系我们

Legal Stuff

  • Privacy Policy

Language

  • Pt
  • Server
  • Unix

© 2023 AskOverflow.DEV All Rights Reserve