最近看了一些nginx 相关的文章,想着用Nginx 来写一些简单脚本,其实也可以满足很多需求。事实上也有很多这样的实现,用Nginx + lua 来开发高并发服务器。
lua
Lua(发音: /ˈluːə/)是一个简洁、轻量、可扩展的脚本语言。Lua在葡萄牙语中的意思是月亮。Lua是一种轻量语言,它的官方版本只包括一个精简的核心和最基本的库。这使得Lua体积小、启动速度快。它用ANSI C语言编写并以源代码形式开放,编译后仅仅一百余K,可以很方便的嵌入别的程序里。和许多“大而全”的语言不一样,网路通讯、图形界面等都没有默认提供。但是Lua可以很容易地被扩展:由宿主语言(通常是C或C++)提供这些功能,Lua可以使用它们,就像是本来就内置的功能一样。事实上,现在已经有很多成熟的扩展模块可供选用。
print("Hello, world!")
Nginx 的看家本领就是速度,Lua 的拿手好戏亦是速度,这两者的结合在速度上无疑有基因上的优势。最先将 Nginx,Lua 组合到一起的是 OpenResty。
OpenResty
OpenResty(也称为 ngx_openresty)是一个全功能的 Web 应用服务器。它打包了标准的 Nginx 核心,很多的常用的第三方模块,以及它们的大多数依赖项。通过揉和众多设计良好的 Nginx 模块,OpenResty 有效地把 Nginx 服务器转变为一个强大的 Web 应用服务器,基于它开发人员可以使用 Lua 编程语言对 Nginx 核心以及现有的各种 Nginx C 模块进行脚本编程,构建出可以处理一万以上并发请求的极端高性能的 Web 应用。
极速体验
了解了这些,我都迫不及待的要体验一下了。无奈网络上找到的教程都参差不齐,另外就是,对于新手,搭建环境就需要耗费很多时间。这个时候就显示出docker 的牛逼之处了,一键搭建环境。强烈建议任何一个程序员都掌握docker使用。
docker pull openresty/openresty:alpine-fat
- 首先,创建 conf 和 logs 两个文件夹
- 在conf中创建nginx.conf
worker_processes 1; error_log logs/error.log; events { worker_connections 1024; } http { server { listen 80; location / { default_type text/html; content_by_lua ' ngx.say("<p>hello, world</p>") '; } } }
也可以这样
location / { default_type text/html; content_by_lua_block { ngx.say("HelloWorld") } }
- 检查本地端口占用
netstat -tlunp | grep 80
- 启动Docker
docker run -d --name="pc-openresty" -p 80:80 -v $PWD/config/nginx.conf:/usr/local/openresty/nginx/conf/nginx.conf:ro -v $PWD/logs:/usr/local/openresty/nginx/logs openresty/openresty:alpine-fat
- 终止Docker
docker kill pc-openresty && docker rm pc-openresty
使用docker 带来的网络瓶颈
在学习的时候,看到了这个问题,在这里记录一下,以防万一遇到。
我们刚开始使用的时候,是这样启动的:
docker run -d -p 80:80 openresty
首次压测过程中发现 Docker 进程 CPU 占用率 100%,单机接口 4-5 万的 QPS 就上不去了。经过我们多方探讨交流,终于明白原来是网络瓶颈所致(OpenResty 太彪悍,Docker 默认的虚拟网卡受不了了 ^_^)。
最终我们绕过这个默认的桥接网卡,使用 --net
参数即可完成。
docker run -d --net=host openresty
使用lua 修改header
我们可以实现一个代理转发服务器,并且在转发的时候,根据参数去转发到特定的url,带上特定的参数和特定的header,这是一个十分有意思和有用的项目,主要用到了header_filter_by_lua,有空实现一下。
location /forward { internal; proxy_pass http://$my_upstream$my_uri; header_filter_by_lua ' local cjson = require "cjson" headers = cjson.decode(ngx.var.headers) for k, v in pairs(headers) do ngx.header[k] = v end ngx.header["hello"] = "word" '; }
location / { proxy_pass http://mybackend; header_filter_by_lua 'ngx.header.Foo = "blah"'; }
参考文档
* https://openresty.org/cn/
* https://moonbingbing.gitbooks.io/openresty-best-practices/content/base/intro.html
* https://www.zybuluo.com/zslzxc/note/1054750
* https://jinnianshilongnian.iteye.com/category/333854