背景
-
测试环境并行测试:一个服务有多个需求同时进行测试,需要nginx根据特定信息将流量转发到指定测试机。
-
全链路压测:流量无区分,影响线上用户,只能在业务低峰进行压测,需要值守,成本较高,需要能够流量隔离,随时可以进行压测。
-
灰度发布:需要nginx根据指定信息将流量转发到指定的灰度机器上。
ngx_lua模块
ngx_lua是Nginx的一个模块,将Lua嵌入到Nginx中,从而可以使用Lua来编写脚本,这样就可以使用Lua编写应用脚本,部署到Nginx中运行,即Nginx变成了一个Web容器;这样开发人员就可以使用Lua语言开发高性能Web应用了。
ngx_lua提供了与Nginx交互的很多的API,对于开发人员来说只需要学习这些API就可以进行功能开发.
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),更多干货实践,欢迎交流分享~