如何优雅的使用 IPtables 在多租户环境中实现 TCP 限速

系统 Linux
由于 abuse 发生在连接建立阶段,还没有进入到业务代码,所以无法从应用的层面进行限速,解决发现就是通过 iptables 实现的。详细的实现方法可以参考这篇文章。

[[440071]]

我们有个服务以类似 SideCar 的方式和应用一起运行,SideCar 和应用通过 Unix Domain Socket 进行通讯。为了方便用户,在开发的时候不必在自己的开发环境中跑一个 SideCar,我用 socat 在一台开发环境的机器上 map UDS 到一个端口。这样用户在开发的时候就可以直接通过这个 TCP 端口测试服务,而不用自己开一个 SideCar 使用 UDS 了。

因为所有人都要用这一个地址做开发,所以就有互相影响的问题。虽然性能还可以,几十万 QPS 不成问题,但是总有憨憨拿来搞压测,把资源跑满,影响别人。我在使用说明文档里用红色大字写了这是开发测试用的,不能压测,还是有一些视力不好的同事会强行压测。隔三差五我就得去解释一番,礼貌地请同事不要再这样做了。

最近实在累了。研究了一下直接给这个端口加上 per IP 的 rate limit,效果还不错。方法是在 Per-IP rate limiting with iptables[1] 学习到的,这个公司是提供一个多租户的 SaaS 服务,也有类似的问题:有一些非正常用户 abuse 他们的服务,由于 abuse 发生在连接建立阶段,还没有进入到业务代码,所以无法从应用的层面进行限速,解决发现就是通过 iptables 实现的。详细的实现方法可以参考这篇文章。

iptables 本身是无状态的,每一个进入的 packet 都单独判断规则。rate limit 显然是一个有状态的规则,所以要用到 module: hashlimit。(原文中还用到了 conntrack,他是想只针对新建连接做限制,已经建立的连接不限制速度了。因为这个应用内部就可以控制了,但是我这里是想对所有的 packet 进行限速,所以就不需要用到这个 module)

完整的命令如下: 

  1. $ iptables --new-chain SOCAT-RATE-LIMIT  
  2. $ iptables --append SOCAT-RATE-LIMIT \  
  3.     --match hashlimit \  
  4.     --hashlimit-mode srcip \  
  5.     --hashlimit-upto 50/sec \  
  6.     --hashlimit-burst 100 \  
  7.     --hashlimit-name conn_rate_limit \  
  8.     --jump ACCEPT  
  9. $ iptables --append SOCAT-RATE-LIMIT --jump DROP  
  10. $ iptables -I INPUT -p tcp --dport 1234 --jump SOCAT-RATE-LIMIT 

第一行是新建一个 iptables Chain,做 rate limit;

第二行处理如果在 rate limit 限额内,就接受包;否则跳到第三行,直接将包 DROP;

最后将新的 Chain 加入到 INPUT 中,对此端口的流量进行限制。

有关 rate limit 的算法,主要是两个参数:

  1.   --hashlimit-upto 其实本质上是 1s 内可以进入多少 packet,50/sec 就是 20ms 一个 packet;
  2.   那如何在 10ms 发来 10 个 packet,后面一直没发送,怎么办?这个在测试情景下也比较常见,不能要求用户一直匀速地发送。所以就要用到 --hashlimit-burst。字面意思是瞬间可以发送多少 packet,但实际上,可以理解这个参数就是可用的 credit。

两个指标配合起来理解,就是每个 ip 刚开始都会有 burst 个 credit,每个 ip 发送来的 packet 都会占用 burst 里面的 credit,用完了之后再发来的包就会被直接 DROP。这个 credit 会以 upto 的速度一直增加,但是最多增加到 burst(初始值),之后就 use it or lost it.

举个例子,假如 --hashlimit-upto 50/sec --hashlimit-burst 20 的话,某个 IP 以匀速每 ms 一个 packet 的速度发送,最终会有多少 packets 被接受?答案是 70. 最初的 20ms,所有的 packet 都会被接受,因为 --hashlimit-burst 是 20,所以最初的 credit 是 20. 这个用完之后就要依赖 --hashlimit--upto 50/sec 来每 20ms 获得一个 packet credit 了。所以每 20ms 可以接受一个。

这是限速之后的效果,非常明显:

 

 

责任编辑:庞桂玉 来源: 奇妙的Linux世界
相关推荐

2023-09-18 08:00:00

Kubernetes容器集群

2022-09-13 07:14:29

云计算SaaS多租户

2015-10-10 10:21:26

OpenStackRegion多Region

2021-10-26 10:28:41

开发架构Kubernetes

2020-10-16 08:57:51

云平台之多租户的实践

2011-03-16 09:05:29

iptablesNAT

2022-04-30 11:10:40

Nacos集群环境企业

2021-12-01 09:00:00

公共云云计算服务器

2011-09-27 11:09:13

2011-03-16 11:15:12

2022-10-08 00:00:04

DataObjectFlowable流程

2011-03-15 14:50:03

使用IPTables

2022-11-01 11:55:27

ReactVue3

2022-11-11 07:48:56

ORM链式轮播图

2022-11-15 07:50:47

ORM链式操作删除

2021-12-21 15:17:53

Kubernetes缓存Linux

2015-11-26 10:53:45

LinuxWindowsMac OS

2017-07-26 11:32:50

NETRabbitMQ系统集成

2023-06-07 13:50:00

SaaS多租户系统

2020-09-15 07:00:00

SaaS架构架构
点赞
收藏

51CTO技术栈公众号