OpenResty 简介

OpenResty 是一种基于 Nginx 并且使用 C 语言开发的、同时使用 Lua 作为用户语言的 Web 平台。如果把 Nginx 比作 Linux 内核,那么 OpenResty 则可以看做是一种 Liunx 的发行版,其对原有的 Nginx 做了很大的补充与扩展,使得我们可以在 Nginx 中编写并执行 Lua 脚本。Open 表示开源的,而 Resty 则代表了 restful 的接口风格。

OpenResty 环境搭建

创建 openresty 用户

useradd openresty

安装 openresty (其它环境的安装方法)

sudo yum-config-manager --add-repo https://openresty.org/yum/cn/centos/OpenResty.repo
sudo yum install openresty

创建文件夹 openresty-test,并根据以下的目录结构创建文件夹以及相应的文件

$ tree openresty-test/
openresty-test/
├── conf
│   └── nginx.conf
├── logs
│   ├── access.log
│   └── error.log
└── lua
    └── nginx.lua

openresty-test 文件夹应属于 openresty 用户,如果不是使用如下命令进行修改

chown -R openresty:openresty openresty-test

修改 nginx.conf 如下

worker_processes 1;
error_log logs/error.log;
events {
    worker_connections 1024;
}

http {
    server {
        listen 6699;
        location / {
            default_type text/html;
            # 关闭lua缓存,只能用于方便调试,修改lua文件后nginx不需要重新reload
            lua_code_cache off;
            # 引入Lua脚本文件
            content_by_lua_file lua/nginx.lua;
        }
    }
}

以上内容设置完毕之后,启动 openresty

openresty -p openresty-test

如果需要重新加载配置文件

openresty -p openresty-test -s reload

编写限流脚本

在 nginx.conf 中我们把 lua/nginx.lua 引入到了配置中,接下来我们开始书写 Lua 代码。

我们的限流使用了 Redis 来帮助实现,具体代码如下

查看 lua 代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
-- 修改content-type
ngx.header.content_type = "text/plain"

local ip = ngx.req.get_headers()["X-Real-IP"]
if ip == nil then
ip = ngx.req.get_headers()["x_forwarded_for"]
end
if ip == nil then
ip = ngx.var.remote_addr
end

local redis = require "resty.redis"
local red = redis:new()
red:set_timeout(1000) -- 一秒

local ok, err = red:connect("172.19.3.27", 6379)
if not ok then
ngx.say("failed to connect: ", err)
return
end

local freq = "freq." .. ip -- 出现频率
local bucket = "bucket." .. ip

local res, err = red:get(bucket)
if res == ngx.null then
red:set(freq, 0) -- 重置频率
red:set(bucket, 0)
red:expire(bucket, 10)
end

local num = tonumber(red:get(freq))
if num ~= nil and num > 5 then
ngx.say("访问频率受限")
return
end

ngx.say(num)
red:incr(freq)

限流的原理非常简单,客户端每请求一次就会给计数器加 1,如果计数器达到 5 那么服务端就会告知访问频率到达限制。计数器每 10 秒钟重置一次,这意味着每个 IP 在 10 秒钟内最多请求 5 次。

总结

其实 Nginx 的限流是可以通过配置直接实现的,不需要这么复杂,我举这么个例子就是想描述一下 OpenResty 的工作方式。在 Lua 中我们除了可以访问 Nginx 和 Redis 的模块,还有很多其它的模块 OpenResty 也已经为我们提供好了,下面就是这样的一个列表,更详细的信息可以在 OpenResty 的官网中查到

参考

OpenResty 最佳实践
https://github.com/openresty/lua-nginx-module
OpenResty + Lua + Redis 实现 IP 限流
在 Nginx 使用 Lua 扩展功能