巧用ngx_lua做流量分组

背景

  • 测试环境并行测试:一个服务有多个需求同时进行测试,需要nginx根据特定信息将流量转发到指定测试机。

  • 全链路压测:流量无区分,影响线上用户,只能在业务低峰进行压测,需要值守,成本较高,需要能够流量隔离,随时可以进行压测。

  • 灰度发布:需要nginx根据指定信息将流量转发到指定的灰度机器上。

ngx_lua模块

ngx_lua是Nginx的一个模块,将Lua嵌入到Nginx中,从而可以使用Lua来编写脚本,这样就可以使用Lua编写应用脚本,部署到Nginx中运行,即Nginx变成了一个Web容器;这样开发人员就可以使用Lua语言开发高性能Web应用了。

ngx_lua提供了与Nginx交互的很多的API,对于开发人员来说只需要学习这些API就可以进行功能开发.

Nginx 模块执行顺序与阶段

ngx_lua 运行指令

ngx_lua属于nginx的一部分,它的执行指令都包含在nginx的11个步骤之中了,相应的处理阶段可以做插入式处理,即可插拔式架构,不过ngx_lua并不是所有阶段都会运行的;另外指令可以在http、server、server if、location、location if几个范围进行配置:

指令 所处处理阶段 使用范围 解释
init_by_lua
init_by_lua_file
loading-config http nginx Master进程加载配置时执行;
通常用于初始化全局配置/预加载Lua模块
init_worker_by_lua
init_worker_by_lua_file
starting-worker http 每个Nginx Worker进程启动时调用的计时器,如果Master进程不允许则只会在init_by_lua之后调用;
通常用于定时拉取配置/数据,或者后端服务的健康检查
set_by_lua
set_by_lua_file
rewrite server,server if,
location,location if
设置nginx变量,可以实现复杂的赋值逻辑;
此处是阻塞的,Lua代码要做到非常快;
rewrite_by_lua
rewrite_by_lua_file
rewrite tail http,server,
location,location if
rewrite阶段处理,可以实现复杂的转发/重定向逻辑;
access_by_lua
access_by_lua_file
access tail http,server,
location,location if
请求访问阶段处理,用于访问控制
content_by_lua
content_by_lua_file
content location,location if 内容处理器,接收请求处理并输出响应
header_filter_by_lua
header_filter_by_lua_file
output-header-filter http,server,
location,location if
设置header和cookie
body_filter_by_lua
body_filter_by_lua_file
output-body-filter http,server,
location,location if
对响应数据进行过滤,比如截断、替换。
log_by_lua
log_by_lua_file
log http,server,
location,location if
log阶段处理,比如记录访问量/统计平均响应时间

设置流量标签

方式一:

请求方将tag添加到header中,直接请求原域名

标签分组

...
if (tag == "" or checkTag(host_pass, tag) == false)
    then
    return host_pass;
end
...

return host_pass.."_"..tag;
set_by_lua_file $host_pass set_tag.lua;

方式二:

请求方将tag拼接到域名中,nginx收到请求后,拆分request host,然后将tag添加到header中再转发给业务nginx。

域名转换

...
local host = ngx.var.host
local hostList = split(host, ".")
local subDomain = split(hostList[1], "-")
...
ngx.req.set_header("global-route-tag", subDomain[2])
ngx.header["global-route-tag"] = subDomain[2]
...
local test_host = ipList[1].."."..hostList[2].."."..hostList[3]
return test_host

set_by_lua_file $test_host  set_test_servers.lua ;

location / {
    ...
    proxy_pass http://$host_pass;
    proxy_set_header Host $test_host;
    proxy_set_header X-Forwarded-For $remote_addr;
    proxy_set_header X-Real-IP $remote_addr; 
    proxy_set_header X-Forwarded-Proto $scheme;
}

采用方式一在做测试时添加tag到header不直观,接口测试时需要借助其他工具添加tag,使用方式二可以降低操作复杂度,还可以避免办公网访问测试环境绑定host未生效的情况。因此我们在内部测试时更推荐方式二的配置方法。

结合dyups上下线带标签服务

在上期分享中,我们分享了nginx平滑上下线服务的过程,有同学已经注意到我们在落地实践的增量更新队列中已经支持了带tag的服务更新,当有tag的时候我们将tag按照一定规则拼接到upstream中,就可以继续平滑上下线服务了。

同学们可以复习下《转转WEB服务如何实现更平滑的变更》

实现效果

发布加标签分组,对同一个服务进行分组,发布平台在部署不同分组的时候,带上不同的标签。增加线上流量分组的功能,解决压测、灰度发布等需要流量分组的问题。 全链路压测泳道

总结

对于Nginx粘合Lua来开发应用可以说是一把锋利的瑞士军刀,可以帮我们很容易的解决很多问题,最后我们总结下基于Nginx+Lua的常用架构模式中一些常见实践和场景:

  • WEB应用防火墙(waf);
  • 限流;
  • 降级;
  • 服务质量监控。

关于作者

赵运周,转转运维开发,负责运维自动化工具、平台支撑。热爱思考,热爱运维。

转转研发中心及业界小伙伴们的技术学习交流平台,定期分享一线的实战经验及业界前沿的技术话题。

关注公众号「转转技术」(综合性)、「大转转FE」(专注于FE)、「转转QA」(专注于QA),更多干货实践,欢迎交流分享~

猜你喜欢

转载自juejin.im/post/7125232630416703518
今日推荐