惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

T
Troy Hunt's Blog
F
Fortinet All Blogs
D
DataBreaches.Net
Google DeepMind News
Google DeepMind News
Y
Y Combinator Blog
The Register - Security
The Register - Security
T
Tailwind CSS Blog
OSCHINA 社区最新新闻
OSCHINA 社区最新新闻
月光博客
月光博客
V
Vulnerabilities – Threatpost
S
Securelist
S
SegmentFault 最新的问题
T
Threat Research - Cisco Blogs
CTFtime.org: upcoming CTF events
CTFtime.org: upcoming CTF events
让小产品的独立变现更简单 - ezindie.com
让小产品的独立变现更简单 - ezindie.com
P
Privacy International News Feed
S
Schneier on Security
钛媒体:引领未来商业与生活新知
钛媒体:引领未来商业与生活新知
L
LangChain Blog
GbyAI
GbyAI
Apple Machine Learning Research
Apple Machine Learning Research
cs.CL updates on arXiv.org
cs.CL updates on arXiv.org
美团技术团队
Cyberwarzone
Cyberwarzone
C
Cisco Blogs
Application and Cybersecurity Blog
Application and Cybersecurity Blog
Google Online Security Blog
Google Online Security Blog
M
MIT News - Artificial intelligence
U
Unit 42
V
V2EX
C
CERT Recently Published Vulnerability Notes
云风的 BLOG
云风的 BLOG
B
Blog
博客园 - 叶小钗
Attack and Defense Labs
Attack and Defense Labs
Security Archives - TechRepublic
Security Archives - TechRepublic
aimingoo的专栏
aimingoo的专栏
Hacker News: Ask HN
Hacker News: Ask HN
博客园 - Franky
Engineering at Meta
Engineering at Meta
Schneier on Security
Schneier on Security
C
CXSECURITY Database RSS Feed - CXSecurity.com
酷 壳 – CoolShell
酷 壳 – CoolShell
T
The Blog of Author Tim Ferriss
IT之家
IT之家
W
WeLiveSecurity
Cisco Talos Blog
Cisco Talos Blog
K
Kaspersky official blog
Martin Fowler
Martin Fowler
SecWiki News
SecWiki News

陈少文的网站

巨变与机遇的未来十年 Kubernetes 平台管理软件压力测试方案 使用镜像部署 Hexo 静态页面 终于等到你 - GitHub 镜像仓库服务(ghcr.io) 一起来学 Go --(6)Interface 一起来学 Go --(5)Goroutine 和 Channel 什么是函数式编程 如何在 Kubernetes 集群集成 Kata 柯里化与偏函数 使用 PyGithub 自动创建 Label 软件产品是团队能力的输出 Helm 2 、Helm 3 比较 IoT 变现 Kubernetes 中的 DNS 服务 国内的 Helm 镜像源 Harbor 使用自签证书支持 Https 访问 DevOps 工具链之 Prow 如何使用 kfctl 安装 Kubeflow VS Code 无法下载 Go 插件的工具包 工程师更应具有服务精神 你不知道的 Docker 使用技巧 使用 Docker 运行 Tensorflow 论中国 什么是左移 如何清空 Git 仓库全部历史记录 一禅小和尚 有风吹过厨房 时间的玫瑰 如何在 CentOS 安装 GPU 驱动 开发 Tips(19) 使用 Velero 备份 Kubernetes 集群 Kubernetes Cheat Sheet 开发 Tips(18) 如何构建一个 Java 工程 开发 Tips(17) KubeSpray 安装 Kubernetes 报错 ip in ansible_all_ipv4_addresses 基于 Kubernetes 和 Jenkins 搭建自动化测试系统 在 Kubernetes 上动态创建 Jenkins Slave 使用 Jenkins 进行服务拨测 开发 Tips(16) Kubernetes 签发 Ingress 证书及日常故障运维 Kubernetes 中 Deployment 的基本操作 Kubernetes 中的证书 如何使用 KubeBuilder 开发一个 Operator Kubernetes 1.6.0 安装问题汇总 镜像管理工具 -- Harbor 开发 Tips(15) Docker 如何拉取镜像 开发 Tips(14) 使用 Helm 安装 harbor 开发 Tips(13) 使用 S2I 构建云原生应用 在 Kubernetes 中使用 emptyDir、hostPath、localVolume 开发 Tips(12) 开发 Tips(11) 代码质量分析工具 SonarQube 使用 Kubeadm 安装 Kubernetes 集群 一起来学 Go --(4)常用函数 Kubernetes 中的 Ceph Kubernetes 之 Volumes Kubernetes 之 Labels、Selectors 开发 Tips(10) 开源正在重构商业模式 Kubernetes 之网络 Kubernetes 之 API 使用 Helm 和 Operator 快速部署 Prometheus Kubernetes 复杂有状态应用管理框架 -- Operator Kubernetes 的包管理器 -- Helm 一起来学 Go --(3)Go Modules 如何一步一步地优化博客方案 kubectl 实用指南 Kubernetes 中的基本概念 搭建远程 Kubernetes 开发环境 大公司和小公司的 ToB 思路 开发 Tips(9) Go 入门指南 一起来学 Go --(2)数据与逻辑结构 如何预防 Web 富文本中的 XSS 攻击 django-xss-cleaner 云工作时代 一起来学 Go --(1)背景与特点 SaaS 开发团队的不同阶段 你不知道的 Git 使用技巧 输出既服务 微服务设计 继续奔跑 开发 Tips(8) 从账户安全到二次验证 Django 性能之数据库查询优化 Django 性能之分库分表 敏捷开发之研发流程 打造一致性的团队 开发 Tips(7) Pytest 进阶学习之 Mock PaaS 部署之 buildpack Go 开发配置 领域输出才是 PaaS 的核心竞争力 Pytest 入门学习 开发 Tips(6) 如何使用 Jenkins、Docker、GitLab 搭建 Django 自动化部署流程
后端服务之接口流量控制
微信公众号 · 2018-01-11 · via 陈少文的网站

1. 流控

缓存、降级和限流是保护高并发系统的常用方法。缓存以空间换时间、减少了 CPU 和网络调用的耗时;降级保护了核心服务的高可用,高峰时段延时或拒绝处理非核心请求;限流是通过限制并发请求来保护系统。

限流就是,在有限资源的情况下,每个 API 接口单位时间内的服务能力有限,如果,对 API 接口的访问次数不加控制,会造成 API 接口的滥用,甚至招致 DDos 攻击。同时,如下图,API 接口的延迟,也会随着请求量的提升而迅速提升。因此,需要控制单位时间内, API 接口的请求量。

2. 什么是时间窗口

时间窗口,指的是一个统计周期的时间段。有两种时间窗口,一种是自然时间窗口,一种是滑动时间窗口。

上图,就是一个自然时间窗口,每分钟一个窗口。例如,15:01~15:02 统计一次。这种方式的问题是,如果每分钟限流为 N ,那么图中红色时间窗口的最大值是 2N。此时,限流失去了效果。因此,便有了滑动窗口。

滑动窗口的核心,就是将时间划分为更细的粒度。例如,现在是 15:02:20 ,那么统计的滑动窗口就是 15:01:20 ~ 15:02:20,不同于上面以分钟作为最小粒度,这里的滑动窗口以秒作为最小粒度,从而获得更加精准的流量控制。

3. 流量控制算法

  • 计数器算法
    计数器算法的思路是限制一个接口在某个维度(IP、用户、某种资源)上的响应次数。通过设置一个计数器,每响应一次,计数器加一,当计数器超过阈值时,拒绝服务。这种算法对总数量进行了简单的限制,而不是平均速率限流。
  • 漏桶算法
    请求以一定速率进入到漏桶中,漏桶以一定速率响应请求,当水流入速度过大时,拒绝服务。

  • 令牌桶算法
    按照固定速率往桶里添加令牌。随着时间流逝,系统会按恒定时间间隔往桶里加入Token,如果桶已经满了,就不再添加。新请求来临时,会各自拿走一个 Token,如果没有 Token 可拿了就阻塞或者拒绝服务

漏桶算法能够限制数据的传输速率,请求超过处理速率时,会被直接丢弃;而令牌桶算法能够在限制数据的平均传输速率的同时,还可以通过加快添加令牌的速率来处理突发请求。

4. 不同类型的限流器

  • 请求限流器
    限制每个用户每秒可发送 N 个请求
  • 并发请求限流器
    限制每秒最高请求数。请求限流器限制的是累积量,而并发限制的是峰值。
  • 基于使用量的负载降级
    将请求分为关键 API 请求和非关键 API 请求。设计系统时,为关键 API 请求预留一定资源,当非关键 API 请求需要占用预留资源时,不预分配,直接拒绝服务。
  • 基于 Worker 利用率的负载降级
    如果某个 worker 太忙,无法处理分配给它的请求,它会缓慢降级非关键请求,当然是先从测试请求开始。如果降低测试请求的过程中,worker 的处理能力恢复到好的状态,那我们就可以开始缓慢地恢复流量。

5. 实现

对于 Nginx 接入层限流可以使用 Nginx 自带了两个模块:连接数限流模块 ngx_http_limit_conn_module 和漏桶算法实现的请求限流模块 ngx_http_limit_req_module。

  • ngx_http_limit_conn_module

limit_conn 是对某个 KEY 对应的总的网络连接数进行限流。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
http {
    # 配置限流 Key 和存放 Key 对应信息的共享内存区域大小
    limit_conn_zone $binary_remote_addr zone=addr:10m;
    # 被限流后,默认日志级别
    limit_conn_log_level error;
    # 被限流后,返回的状态码
    limit_conn_status 503;
    ...
    server {
    ...
    location /limit {
        # 配置存放 Key 和计数器的共享内存区域,指定 Key 的最大连接数
        limit_conn addr 1;
    }

此处使用 Key 为 $binary_remote_addr 表示 IP 地址,还可以使用 $server_name 表示域名,不同的 Key 值从不同维度限制流量。

测试

1
ab -n 5 -c 5 http://127.0.0.1/limit/
  • ngx_http_limit_req_module
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
http {
	## 对每一个IP的请求限制为1次每秒
	limit_req_zone $binary_remote_addr zone=perip:10m rate=1r/s;
	# 被限流后,默认日志级别
    limit_conn_log_level error;
    # 被限流后,返回的状态码
    limit_conn_status 503;
    ...
    server {
    ...

	location /limit {
	    # burst 配置桶的大小,nodelay 表示非延迟模式,允许突发处理请求。
		limit_req zone=perip burst=3 nodelay;
	}
}

测试

1
ab -n 5 -c 5 http://127.0.0.1/limit/
  • 设置 IP 黑白名单
1
2
3
4
5
6
location / {
    allow 192.168.1.1/24;
    allow 127.0.0.1;
    deny 1.2.3.4;
    # deny  all;
}
  • django-ratelimit

django-ratelimit 是一个基于缓存的接口限速包,使用装饰器对 API 接口进行流量控制。。

安装

1
pip install django-ratelimit

使用

1
2
3
4
5
6
7
8
9
from ratelimit.decorators import ratelimit

@ratelimit(key='ip')
def myview(request):
    # ...

@ratelimit(key='ip', rate='100/h')
def secondview(request):
    # ...

这里的 Key 表示的是统计的维度,可以是 ip、get 中获取的某个参数、post 中获取的某个参数、header 中获取的某个参数、user、user_or_ip。rate 表示的是限速 X/u,X 表示数字,u 表示时间单位,可以是,s、m、h、d。

rate 还可以是一个函数,只需要返回指定的格式即可。通过这种方式,可以实现一些特殊的限制功能。比如,匿名用户和登录用户可以采用不同的限制值。

6. 分布式流控

分布式限流最关键的是要将限流服务做成原子化。

解决方案是,通过 Redis + Lua 或者 Nginx + Lua 的技术,实现对请求并发数和总数在时间窗口下的控制。使用 Lua 实现令牌通或漏桶算法。

7. 参考