也许有人对于OpenResty不太熟悉,但是一说到Nginx,可能都有所了解。作为控制速率和并发量控制的Nginx被很多公司所采用,而OpenResty就是在Nginx的基础上升级的,提供了Lua扩展,大大提升了Nignx对并发的处理能力,可以达到10K~1000K。OpenResty其实和Tengine一样,都是基于Nginx的衍生版本,融入了各自一些业务的新特性。
这里用一个例子来说明使用Lua脚本,通过OpenResty和Redis实现业务数据的缓存。一般商城系统都会包括各种各样的广告,对于首页的广告访问量一般来说都是比较频繁的。如果每访问一次就去请求Mysql或者Oracle数据库,势必会给数据库带来一定的压力。所以经常的做法就是这部分不易经常变化的数据缓存下来。浏览器访问时直接访问缓存获取数据,如果没有再来请求数据库。
如上图所示,首页广告访问的思路分为以上几个步骤:
1)用户请求地址,访问OpenResty,从Nginx的本地缓存(Nginx-Cache)中获取,如果获取到直接返回,获取不到则进行下一步。
2)通过Lua脚本访问Redis中的数据,如果有则直接返回【且会先把数据放到Nginx的本地缓存中】,没有则直接进行下一步。
3)通过Lua脚本访问Mysql,从Mysql中获取数据,再将数据存到Redis中,并返回结果。
OpenResty的安装
这里只介绍一下Linux环境下OpenResty的安装。
① 分别执行以下命令进行安装
# 添加仓库执行命令
yum install yum-utils
yum-config-manager --add-repo https://openresty.org/package/centos/openresty.repo
# 执行安装
yum install openresty
② 安装成功后,会在默认目录【/usr/local/openresty】有对应的内容。由于OpenResty是基于Nginx的衍生的,因此,在OpenResty下其实就已经安装好了Nginx【/usr/local/openresty/nginx目录】。我们还需要去修改nginx.conf将配置文件使用的根设置为root,这里设置的目的就是将来使用Lua脚本的时候,可以直接加在Root下的Lua脚本【这里根据自己的需要设置用户以及目录】。
另外由于会使用Nginx的缓存模块,所以在conf中也需要事先配置好Nginx缓存模块。
脚本编写
按照上述步骤,整个访问分为三个环节。具体代码以及详细解释如下:
ngx.header.content_type="application/json;charset=utf8"
-- 获取请求参数
local uri_args = ngx.req.get_uri_args();
-- 获取请求的ID
local id = uri_args["id"];
-- 获取本地缓存
local cache_ngx = ngx.shared.dis_cache;
-- 根据ID 获取本地缓存数据
local contentCache = cache_ngx:get('content_cache_'..id);
-- 判断从本地是否获取的有数据
if contentCache == "" or contentCache == nil then
-- 本地没有,则去读取Redis
-- 加在redis模块
local redis = require("resty.redis");
local red = redis:new()
red:set_timeout(2000)
-- 连接redis
red:connect("192.168.132.132", 6379)
-- 查询数据
local rescontent=red:get("content_"..id);
-- 判断从redis是否获取的有数据
if ngx.null == rescontent then
-- 没有,则直接从Mysql中获取数据
local cjson = require("cjson");
local mysql = require("resty.mysql");
local db = mysql:new();
db:set_timeout(2000)
local props = {
host = "192.168.132.132",
port = 3306,
database = "changgou_content",
user = "root",
password = "123456"
}
local res = db:connect(props);
-- 执行SQL并将结果转换成json数据格式
local select_sql = "select url,pic from tb_content where status ='1' and category_id="..id.." order by sort_order";
res = db:query(select_sql);
local responsejson = cjson.encode(res);
-- 设置到Redis中
red:set("content_"..id,responsejson);
-- 返回结果
ngx.say(responsejson);
-- 关闭数据库
db:close()
else
-- 设置到Nginx Cache中
cache_ngx:set('content_cache_'..id, rescontent, 2*60);
-- 返回结果
ngx.say(rescontent)
end
-- 关闭Redis的连接
red:close()
else
-- 返回结果
ngx.say(contentCache)
end
配置拦截路由
脚本写好之后,需要去配置相应的Server拦截对应的路径,拦截后,交给对应的Lua脚本进行处理。
server{
listen 80;
# 监听域名
server_name localhost;
# 表示所有以localhost/read_content的请求都由该配置处理
localtion /read_content {
# 都交给/usr/local/server/lua/read_content.lua脚本进行处理
content_by_lua_file /usr/local/server/lua/read_content.lua;
}
}
每次修改了Nginx.conf文件都需要去重新启动Nginx【/usr/local/openresty/nginx】。以上使用Lua脚本以及OpenResty、Redis的缓存就简单实现了。