nginx 微服务 nginx做微服务网关
nginxapi网关进行限流的核心目的是作为保护监听服务,防止突发流量导致崩溃。1. 使用ngx_http_limit_req_module实现请求速率限制流,在http块定义共享内存区域并设置请求速率限制,在location中使用limit_req指令,并通过burst和nodelay控制突发流量处理方式;2. 使用ngx_http_limit_conn_module限制并发连接数,在http块定义共享内存区域并在位置中应用limit_conn指令;3. 可自定义限制流错误页面并返回指定状态码;4. 令牌桶允许突发流量,适合提高吞吐量,漏桶平滑流量输出,适合严格控制速率;5. 动态调整可通过nginx plus api、openresty redis或consul/etcd结合热加载实现;6. 监控可通过prometheus grafana等工具统计被限流请求数、响应时间及nginx资源使用情况;7. 场景如基于用户id或api key限流可使用nginx plus、openresty redis或自定义模块实现,具体选择需求依赖和技术栈。
微服务架构下,Nginx作为API网关进行限流,主要是为了保护远程服务,防止流量突发导致服务崩溃。核心解决控制请求带宽,短路避免。复杂方案
Nginx可以通过ngx_http_limit_req_module和 ngx_http_limit_conn_module 模块实现限流。之前用于限制请求速率(例如,每秒请求数),中部用于限制并发连接数。
1. 基于请求速率的限流(Rate Limiting):ngx_http_limit_req_module
首先,需要在http块中定义一个共享内存区域,存储用于请求状态:http { limit_req_zone $binary_remote_addr zone=mylimit:10mrate=10r/s; # ...其他配置}登录后复制
这里,$binary_remote_addr 是客户端IP地址的二进制表示,zone=mylimit:10m 定义了一个名为 mylimit 的共享内存区域,大小为 10MB。rate=10r/s 表示允许每秒 10 个请求。
然后,在需要限制流的服务器或 location 块中使用 limit_req 指令:server { location /api/ { limit_req zone=mylimitburst=20 nodelay; # ...其他配置}}登录后复制
burst=20 允许短时间内突发20个请求,超过这个数量的请求将被延迟处理或拒绝。 nodelay表示立即处理突发请求,而不是队列等待。如果不加nodelay,突发请求会队列等待,直到满足速率限制。
2. 基于并发连接数的限流(连接限制): ngx_http_limit_conn_module
类似地,首先在 http 块中定义一个共享内存区域:http { limit_conn_zone $binary_remote_addr zone=myconnlimit:10m; # ... 其他配置}登录后复制
然后,在 server 或 location 块中使用 limit_conn 指令:server { location /api/ { limit_conn myconnlimit 10; # ... 其他配置 }}登录后复制
这里,limit_conn myconnlimit 10 表示允许每个IP地址最多10个并发连接。
3. 错误处理
可以自定义错误页面,当请求被限流时返回:http { # ... limit_req_status 503; # 返回 503 状态码 error_page 503 /503.html; server { location = /503.html { return 503 quot;服务不可用quot;; # 可以指向一个自定义的 HTML 页面 } }}登录后如何选择合适的限流策略? vs. 漏桶
令牌桶和漏桶是两种常见的限流算法。Nginx 的 ngx_http_limit_req_module 实际上是基于漏桶算法的变体实现的。令牌桶(Token Bucket):以恒定速率生成令牌,需要请求获取令牌才能通过。如果桶中没有令牌,请求将被拒绝或延迟。优点一定是允许流量的突发程度。漏桶(Leaky Bucket):请求进入桶中,以恒定的速率跳跃。如果桶满了,请求将被拒绝。 优点是平滑流量,防止吞吐量服务被突发流量冲击。
选择哪种算法取决于你的具体需求。如果你的服务可以忍受一定程度的突发流量,并且希望吞吐量,那么令牌桶可能更适合。如果你的服务对延迟敏感,并且需要严格控制流量速率,那么漏桶可能更适合。 Nginx 的 ngx_http_limit_req_module 通过突发参数允许一定程度的突发,因此实际上是一个混合的策略。微服务架构下,如何动态调整 Nginx 限流配置?
在解决微服务架构下的静态配置通常是不够的,因为流量模式可能会随着时间变化。动态调整限流配置可以通过以下几种方式实现:
Nginx Plus API:Nginx Plus 提供了 API,可以动态修改配置、限流参数。这是一个商业包含方案。
OpenResty Redis:使用OpenResty(基于Nginx的Lua平台)和Redis。Lua脚本可以从Redis中读取限制流配置,并动态应用到Nginx。 这种方案更加灵活,但需要一定的开发工作。
例如,可以编写一个 Lua 脚本,定期从 Redis 中获取限流规则,并使用 ngx.shared.DICT 在 Nginx 工作进程之间共享这些规则。-- 从 Redis 获取限流配置local redis = require quot;resty.redisquot;local red = redis:new()red:set_timeout(1000) -- 1 secondarylocal ok, err =红色:连接(quot;127.0.0.1quot;, 6379)如果不行则ngx.log(ngx.ERR,quot;连接redis失败:quot;,err)返回本地rate_limit_config,err = 红色:get(quot;rate_limit_configquot;)如果不是rate_limit_config则ngx.log(ngx.ERR,quot;获取失败来自redis的rate_limit_config: quot;, err) returnend--解析JSON配置local cjson = require quot;cjsonquot;local config = cjson.decode(rate_limit_config)-- 应用限流规则 (假设使用了 ngx.shared.DICT)local shared_data = ngx.shared.my_rate_limit_datashared_data:set(quot;ratequot;, config.rate)shared_data:set(quot;burstquot;, config.burst)-- ... 在 Nginx 配置中使用 Lua 脚本读取shared_data中的值登录后复制
Consul/Etcd Nginx配置热加载:将限流配置存储在Consul或Etcd等配置中心,然后使用工具(如Consul Template或confd)监听配置变化,并自动更新Nginx配置文件,然后触发Nginx的热加载。如何监控Nginx
监控是限流策略的重要组成部分。需要监控以下指标:被限流的请求数量:通过 Nginx 的访问日志分析,或者使用 Nginx加的监控功能,可以统计被限流的请求数量。固定服务的响应:监控监听服务的响应时间,可以判断限流是否有效完成了服务的压力。Nginx的CPU和内存使用率:监控Nginx的CPU和内存使用率,可以判断Nginx本身是否成为瓶颈。
时间可以使用Prometheus Grafana等工具来收集展示和这些指标。例如,可以使用nginx-exporter来收集Nginx 的指标,然后使用 Prometheus 存储这些指标,最后使用 Grafana 创建仪表盘。
如何处理复杂的限流场景,例如基于用户 ID 或 API Key 的限流?
对于更复杂的限流场景,例如基于用户 ID 或 API Key 的限流,可以使用以下方法:
Nginx Plus API:Nginx Plus 提供了更高级的限流功能,可以基于请求的 Header 或 Cookie 等信息进行限流。
OpenResty Redis:使用 OpenResty 可以编写Lua 脚本,从请求中提取用户 ID 或 API Key,然后使用 Redis 存储每个用户或 API Key 的请求成分。例如,可以编写一个 Lua 脚本,从请求头中获取 API Key,使用 Redis 的 INCR 然后命令原子地增加该 API Key 的请求成分。--从请求头中获取 API Keylocal api_key = ngx.req.get_headers()[quot;X-API-Keyquot;]if not api_key then ngx.log(ngx.ERR, quot;请求头中未找到 API Key;) ngx.exit(ngx.HTTP_UNAUTHORIZED)end--连接 Redislocal redis = require quot;resty.redisquot;local red = redis:new()red:set_timeout(1000) -- 1 秒本地 ok, err = red:connect(quot;127.0.0.1quot;,, 6379)if not ok then ngx.log(ngx.ERR, quot;连接 redis 失败: quot;, err) returnend-- 构建 Redis Keylocal key = quot;api_key_limit:quot; .. api_key--增加请求增加本地 count, err = red:incr(key)if not count then ngx.log(ngx.ERR, quot;增加失败api key limit: quot;, err) returnend--设置过渡(例如,1 分钟)if count == 1 then red:expire(key, 60)end--获取限流配置(例如,每分钟 100 个请求)localrate_limit = 100--检查是否超过限制 if count gt;rate_limit then ngx.log(ngx.WARN, quot;API Key quot;, api_key, quot;超过rate limitquot;) ngx.exit(ngx.HTTP_TOO_MANY_REQUESTS)end-- ... 其他处理登录后复制
自定义 Nginx 模块:如果需要非常复杂的限流逻辑,可以考虑编写自定义的 Nginx 模块。这需要 C 语言编程技能。
根据你的具体需求和技术栈选择哪种方法。
Nginx Plus API 最简单,但需要付费。OpenResty Redis 更灵活,但需要一定的开发工作。自定义 Nginx 模块最强大,但也最复杂。
以上就是微服务架构下 Nginx 作为 API 网关的限流设计的内容详细,更多请关注乐哥常识网其他相关文章!