nginx+lua在我司的实践
导读:nginx是一个高性能的反向代理服务器,lua是一个小巧的脚本语言,这两个的巧妙结合会擦出怎样的火花呢。
关键词:nginx,lua,nginx+lua
前言
nginx,lua,nginx+lua,这三个名词不知道大家熟悉多少。为了后面内容的展示,我简单的介绍一下它们,想深入了解的网上资料很多,在这就不啰嗦了。nginx是一个高性能的反向代理服务器,一般会处在网站的最前端(有可能前面还会加一层slb,在这暂时忽略),用来做后端web服务的代理;lua是一个小巧的脚本语言,其设计的目的就是嵌入应用程序中,为其提供一些扩展和增强,比如redis,nginx等等;nginx+lua顾名思义就是nginx和lua的结合体,这两者之间沟通的桥梁是nginx_lua_module,它是nginx的一个模块,有了它nginx和lua才能互通,笔者在最近几年的工作中恰好有这方面的开发经验,所以想把这些真实的使用场景分享出来供大家做参考,具体的api doc还请大家参考官方资料。
案例1-入口层流量的灰度识别
何谓入口层流量的灰度识别呢,简单来说就是A用户的请求打到线上环境,B用户的请求打到灰度环境,目的就是做新功能的验证,实现逻辑很简单,大体流程如下:
1.测试同学在灰度控制台配置灰度规则,规则里会约束哪些url下哪些商户的请求进入灰度环境;
2.灰度控制台推送规则给入口层nginx,nginx会将规则存储到本地内存中,借助ngx.shared.DICT;
3.请求进入的时候(通过rewrite_by_lua_file触发)获取本地内存中的规则进行比对,如何命中规则就将请求转发到灰度环境,对nginx来说就是切换不同的upstream,比如线上是prod_serverA,灰度是gray_serverA;
代码片段如下:
upstream gray_serverA {
server 192.68.1.1:8080;
}
upstream prod_serverA {
server 192.68.1.2:8080;
}
server {
listen 80;
server_name graytest.demo.com;
charset utf-8;
location ~ \.do$ {
set $backend 'prod_serverA'; #默认的upstream为线上服务
rewrite_by_lua_file "conf/lua-gray/rewriter.lua"; # rewrite_by_lua_file 可以简单的理解为一个过滤器,nginx在rewrite阶段会执行你指定的脚本文件,
#在这个文件中我们会判断请求是否为灰度请求如果是灰度请求就将backend改为gray_serverA
proxy_pass http://$backend;
}
}
案例2-入口层记录错误日志
之前有同学反馈说springmvc偶尔会报415错误,这个错误的一个常见原因是传递的Content-Type头不对,比如后端需要application/json,但是前端传递了application/x-www-form-urlencoded,那就会报这个错。但是跟前端确认了传递的头是没有问题的,有人猜测可能是头信息有特殊字符,导致后端web 容器(tomcat、resin)解析头出现了问题,既然这样把所有请求头打出来一看究竟,于是lua再一次出场,这次主要用来输出请求头到日志文件中,主要用到了log_by_lua_block这个指令,代码片段如下:
location ~ \.do$ {
proxy_pass http://$backend;
log_by_lua_block {
//判断下如果http 响应状态码为415就输出请求头到文件中
if tonumber(ngx.var.status) == 415 then
ngx.log(ngx.ERR,"upstream reponse status is 415,please notice it,here are request headers:")
local h, err = ngx.req.get_headers(100,true)
if err == "truncated" then
ngx.log(ngx.ERR,"request headers beyond 100,will not return")
else
local cjson = require("cjson")
ngx.log(ngx.ERR,cjson.encode(h))
end
end
}
}
想详细了解这个案例的,请移步到我的另一篇博客(https://www.cnblogs.com/chopper-poet/p/11625144.html)。
案例3-将nginx信息注册到监控平台
需求很简单,当nginx启动的时候将自身信息上报到redis中,上报内容包扣自身的ip,代理的域名信息等,有个监控平台会定期从redis读取这些信息做展示,方便运维干活,流程很简单就是定时读取自身ip和代理的域名信息写到redis中,为什么要定时呢,这里还起到一种心跳的效果,当长时间没有上报时可能是nginx出问题了,主要用到的指令如下:
1.init_worker_by_lua_file "conf/ua-grayngxReloadListener.lua",当nginx启动或者reload的时候会执行指定的文件;
2.ngx.worker.id() 这个方法会返回nginx worker进程的编号,从0开始,如果nginx有4个worker,那取值范围为0-3,这个主要是为了防止并发上报,因为第一步里面提到的init_worker_by_lua_file,如果有几个worker就会触发几次,所以为了只上报一次,会判断下返回值是否为0,也就是只让第一个worker执行;
3.ngx.timer.every 用来执行定时任务;
代码片段如下:
local workerId = ngx.worker.id() if(workerId == 0) then
ngx.log(ngx.INFO,'workerId is 0 will startup task') local ok, err = ngx.timer.every(4,function()
#1. get local ip and domins
#2. write to redis
end) else
ngx.log(ngx.INFO,'workerId is not 0 ,just ignore it')
end
案例4-将入口层流量同时转发到多个后端服务
类似于消息队列的发布订阅一样,在nginx这一层可以将一个请求同时发到多个地址,代码片段如下:
location ~ /capture_test$ {
content_by_lua_block {
ngx.req.read_body()
res1, res3 = ngx.location.capture_multi{
{ "/capture_test1",{ method = ngx.HTTP_POST, always_forward_body=true}},
{ "/capture_test2",{ method = ngx.HTTP_POST, always_forward_body=true}},
}
ngx.say(res3.body)
ngx.exit(res3.status)
}
总结
上面列举了nginx+lua在我司使用的四个案例,真实场景要复杂很多,为了方便大家理解,特意将案例做了简化。如果觉得有用,请点个推荐。
参考资料
https://github.com/openresty/lua-nginx-module
nginx+lua在我司的实践的更多相关文章
- 基于nginx+lua+redis高性能api应用实践
基于nginx+lua+redis高性能api应用实践 前言 比较传统的服务端程序(PHP.FAST CGI等),大多都是通过每产生一个请求,都会有一个进程与之相对应,请求处理完毕后相关进程自动释放. ...
- 用Nginx+Lua(OpenResty)开发高性能Web应用
在互联网公司,Nginx可以说是标配组件,但是主要场景还是负载均衡.反向代理.代理缓存.限流等场景:而把Nginx作为一个Web容器使用的还不是那么广泛.Nginx的高性能是大家公认的,而Nginx开 ...
- Nginx+Lua(OpenResty)开发高性能Web应用
使用Nginx+Lua(OpenResty)开发高性能Web应用 博客分类: 跟我学Nginx+Lua开发 架构 ngx_luaopenresty 在互联网公司,Nginx可以说是标配组件,但是主要场 ...
- 使用Nginx+Lua(OpenResty)开发高性能Web应用
摘自(http://jinnianshilongnian.iteye.com/blog/2280928) 在互联网公司,Nginx可以说是标配组件,但是主要场景还是负载均衡.反向代理.代理缓存.限流等 ...
- 搭建OpenResty(Nginx+Lua)
这篇文章是一个多月前写的,当时之所以搭建这个是为了最大程度上发挥Nginx的高并发效率(主要是结合lua脚本),参考的话,主要参考张开涛先生写的跟开涛学Nginx+lua系列文章,地址为:https: ...
- 单机闭环 使用Nginx+Lua开发高性能Web应用
[西域骆驼D1532101213]西域骆驼(VANCAMEL)D1532101213 休闲套脚鞋 卡其43[行情 报价 价格 评测]-京东 http://item.jd.com/1856564.htm ...
- 跟我学OpenResty(Nginx+Lua)开发目录贴 (转)
使用Nginx+Lua开发近一年的时间,学习和实践了一些Nginx+Lua开发的架构,为了让更多人使用Nginx+Lua架构开发,利用春节期间总结了一份基本的学习教程,希望对大家有用.也欢迎谈探讨学习 ...
- Nginx基础 - Nginx+Lua实现灰度发布与WAF
1.Nginx加载Lua环境默认情况下Nginx不支持Lua模块, 需要安装LuaJIT解释器, 并且需要重新编译Nginx, 建议使用openrestry 1)环境准备 [root@localhos ...
- 使用Nginx+Lua代理Hadoop HA
一.Hadoop HA的Web页面访问 Hadoop开启HA后,会同时存在两个Master组件提供服务,其中正在使用的组件称为Active,另一个作为备份称为Standby,例如HDFS的NameNo ...
随机推荐
- npm install 不更改 package-lock.json 文件的解决方法
package-lock.json 文件是版本锁定文件 package-lock.json 是在 `npm install` 时候生成的一份文件,用以记录当前状态下实际安装的各个 npm packag ...
- Java散点
1.在Java中,所有需要保存在常量池中的数据,长度最大不能超过65535,这当然也包括字符串的定义
- JVM系列六(自定义插入式注解器).
一.概述 从前面 文章 中我们可以了解到,javac 的三个步骤中,程序员唯一能干预的就是注解处理器部分,注解处理器类似于编译器的插件,在这些插件里面,可以读取.修改.添加抽象语法树中的任意元素.因此 ...
- spring boot集成spring-boot-starter-mail邮件功能
前情提要 以目前IT系统功能来看,邮件功能是非常重要的一个功能.例如:找回密码.邮箱验证,邮件动态码.忘记密码,邮件营销等,都需要用到邮件功能.结合当下最流行的spring boot微服务,推出了sp ...
- AcWing 206. 石头游戏 矩阵乘法|矩阵快速幂
AcWing 206. 石头游戏 石头游戏在一个 n 行 m 列 (1≤n,m≤8) 的网格上进行,每个格子对应一种操作序列,操作序列至多有10种,分别用0~9这10个数字指明. 操作序列是一个长度不 ...
- webpack实践——DLLPlugin 和 DLLReferencePlugin的使用
DLLPlugin 和 DLLReferencePlugin的使用 DLLPlugin 和 DLLReferencePlugin 用某种方法实现了拆分 bundles,同时还大大提升了构建的速度. 1 ...
- const和volitale
1. const只读变量 const修饰的变量是只读的,本质还是变量 const修饰的局部变量在栈上分配空间(可以通过指针修改) const修饰的全局变量在全局数据区分配空间(指针也修改不了) con ...
- 字符串转hash
#include<bits/stdc++.h> using namespace std; unsigned hash[]; ; int ans; int main() { ;k<=; ...
- 【LC_Lesson7】---将两个有序链表合成新的一个有序链表
将两个有序链表合并为一个新的有序链表并返回.新链表是通过拼接给定的两个链表的所有节点组成的. 示例: 输入:1->2->4, 1->3->4 输出:1->1->2- ...
- linux入门系列8--shell编程
本文将结合前面介绍的Linux命令.管道符等知识,通过VI编辑器编写Shell脚本,实现能自动化工作的脚本文件. 在讲解Linux常用命令"linux入门系列5--新手必会的linux命令& ...