OpenResty与Lua实现高并发请求处理
前言
介绍
OpenResty 是一个基于 Nginx 与 Lua 的高性能 Web 平台,其内部集成了大量精良的 Lua 库、第三方模块以及大多数的依赖项。用于方便地搭建能够处理超高并发、扩展性极高的动态 Web 应用、Web 服务和动态网关。由中国人张亦春发起,提供了很多高质量的第三方模块。
OpenResty 通过汇聚各种设计精良的 Nginx 模块(主要由 OpenResty 团队自主开发),从而将 Nginx 有效地变成一个强大的通用 Web 应用平台。这样,Web 开发人员和系统工程师可以使用 Lua 脚本语言调动 Nginx 支持的各种 C 以及 Lua 模块,快速构造出足以胜任 10K 乃至 1000K 以上单机并发连接的高性能 Web 应用系统。
OpenResty 的目标是让你的Web服务直接跑在 Nginx 服务内部,充分利用 Nginx 的非阻塞 I/O 模型,不仅仅对 HTTP 客户端请求,甚至于对远程后端诸如 MySQL、PostgreSQL、Memcached 以及 Redis 等都进行一致的高性能响应。
配置
安装 OpenResty 软件后,因为 OpenResty 基于 Nginx 开发,所以配置 OpenResty 只需要配置 Nginx 即可。
在 OpenResty 安装目录下配置 nginx
# nginx 拦截 /update_context 请求,交给 lua 脚本处理 location /update_context { content_by_lua_file /root/lua/update_content.lua } location /get_context { content_by_lua_file /root/lua/get_content.lua }
Lua 脚本
lua redis 脚本参考:https://github.com/openresty/lua-resty-redis
lua mysql 脚本参考:https://github.com/openresty/lua-resty-mysql
update_content.lua 脚本
ngx.header.content_type="application/json;charset=utf8" local cjson = require("cjson") local mysql = require("resty.mysql") -- 获取用户的请求参数 local uri_args = ngx.req.get_uri_args() -- 获取请求参数中的 id local id = uri_args["id"] -- 连接 mysql local db = mysql:new() db:set_timeout(1000) local props = { host = "192.168.8.4", port = 3306, database = "changgou_content", user = "root", password = "123456" } -- 查询mysql local res = db:connect(props) 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) db:close() -- 连接redis local redis = require "resty.redis" local red = redis:new() red:set_timeouts(1000, 1000, 1000) local ok, err = red:connect("192.168.8.4", 6379) if not ok then ngx.say("failed to connect: ", err) return end red:set("content_"..id, cjson.encode(res)) red:close() ngx.say("{flag:true}")
get_content.lua 脚本
ngx.header.content_type="application/json;charset=utf8" local cjson = require("cjson") local mysql = require("resty.mysql") local uri_args = ngx.req.get_uri_args() local id = uri_args["id"] -- 获取nginx缓存数据,如果没有从redis中获取 -- 需要定义 ngx.shared.dis_cache 模块,lua 缓存命名空间(dis_cache) local cache_ngx = ngx.shared.dis_cache; local contentCache = cache_ngx:get("content_"..id) if contentCache == "" or contentCache == nil then ngx.say("contentCache not found ") else ngx.say(contentCache) return end -- 连接redis local redis = require "resty.redis" local red = redis:new() red:set_timeouts(1000, 1000, 1000) local ok, err = red:connect("192.168.8.4", 6379) if not ok then ngx.say("failed to connect: ", err) return end -- 从 redis 中获取数据 local res, err = red:get("content_"..id) if not res then ngx.say("failed to get content_"..id, err) return end if res == ngx.null then ngx.say("content_"..id.." not found.") -- redis缓存中没有连接数据库查询,并放入redis缓存中 local db = mysql:new() local props = { host = "192.168.8.4", port = 3306, database = "changgou_content", user = "root", password = "123456" } local ok, err, errcode, sqlstate = db:connect(props) if not ok then ngx.say("failed to connect: ", err, ": ", errcode, " ", sqlstate) return end ngx.say("connected to mysql.") local select_sql = "select url,pic from tb_content where status = '1' and category_id =" ..id.." order by sort_order" local res, err, errcode, sqlstate = db:query(select_sql) if not res then ngx.say("bad result: ", err, ": ", errcode, ": ", sqlstate, ".") return end -- 设置缓存到 nginx 中, 10*60: 10分钟 cache_ngx:set("content_"..id, res, 10*60) -- 存入缓存到 redis 中 red:set("content_"..id, cjson.encode(res)) -- 输出 ngx.say("content_"..id, cjson.encode(res)) db:close() return end -- 设置缓存到 nginx 中 cache_ngx:set("content_"..id, res, 10*60) ngx.say("content_"..id, res) red:close()
定义 ngx.shared.dis_cache 模块 ,需要在 nginx 配置文件中的 http 模块下添加
# 定义 lua 缓存命名空间(dis_cache)及其大小(128m) lua_shared_dict dis_cache 128m;
如图