Openresty+Lua Redis连接池实现

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Openresty+Lua Redis连接池实现相关的知识,希望对你有一定的参考价值。

参考技术A 使用方法:

输出:

Lua+Redis+OpenResty实现电商详情页

电商详情页案例介绍

电商的详情页是并发量很高的服务,开发者通常采用静态化或缓存的方式减少后台服务器的压力

案例的技术点:

  1. OpenResty服务器,

    介绍和安装可以参考 https://blog.csdn.net/u013343114/article/details/123991729

  2. Lua调用Redis

  3. Lua的http模块

  4. Lua页面模板

下面先使用几个案例,介绍这些技术点

使用Lua连接Redis

OpenResty的库中自带的resty.redis可以用于连接Redis

在openresty/nginx/conf新建lua目录,新建redis_test.lua文件

-- 导入resty.redis
local redis = require "resty.redis"
-- 创建redis对象
local red = redis:new()
-- 连接redis ok返回成功信息,erro是错误信息
local ok,err = red:connect("127.0.0.1",6379)
if not ok then
        ngx.say("connect failed",err)
        return
end
-- 调用set命令
ok,err = red:set("city","wuhan")
if not ok then
        ngx.say("redis set failed",err)
        return
end
ngx.say("set city ok<br>")
-- 调用get命令
local val,err = red:get("city")
if not val then
        ngx.say("redis get failed",err)
        return
end
if val == ngx.null then
        ngx.say("city is null")
        return
end
-- 输出结果
ngx.say("city==>",val)

修改nginx.conf

server 
        listen 8080;
        location /redis_test 
           default_type text/html;
           content_by_lua_file conf/lua/redis_test.lua;
        

重启nginx,访问

使用Lua发送HTTP请求

使用Lua发送http请求可以借助开源框架 lua-resty-http

https://github.com/ledgetech/lua-resty-http

下载文件:http_headers.lua、http.lua、http_connect.lua

保存到openresty/lualib/resty目录下

基本的http请求

创建http_test.lua

-- 创建连接对象
local httpc = require("resty.http").new()
-- 发送GET请求
local res, err = httpc:request_uri("http://192.168.101.11:8001/item?id=99", 
    method = "GET",
    headers = 
        ["Content-Type"] = "application/x-www-form-urlencoded"
    
)
if not res then
    ngx.log(ngx.ERR, "request failed: ", err)
    return
end
-- 返回请求内容
local status = res.status
local length = res.headers["Content-Length"]
local body   = res.body
ngx.say("body:",body)

使用SpringBoot开发接口

@RestController
public class HelloController 

    @Value("$server.port")
    private Long port;

    @RequestMapping("item")
    public String item(Long id)
        return "From: "+ port +",Get Item " + id;
    

修改nginx.conf

 location /http_test3 
 	default_type text/html;
	content_by_lua_file conf/lua/http_test.lua;
 

重启nginx,访问

URL哈希实现负载均衡

下面案例通过对id参数进行哈希运算,对服务器列表实现负载均衡

local http = require("resty.http").new()  
-- 服务器列表
local hosts = "192.168.101.11:8001","192.168.101:11:8002"
-- 获得id参数
local item_id= ngx.var.arg_id
if not item_id then
	ngx.say("id is null")
	return
end
-- 获得哈希值
local id_hash = ngx.crc32_long(item_id)
-- 计算下标 lua从1开始
local index = (id_hash % 2) +1
-- 通过下标获得主机名,执行GET请求
local resp, err = http:request_uri("http://"..hosts[index],   
    method = "GET",  
    path = "/item?id="..item_id,  
    headers =   
        ["Content-Type"] = "application/x-www-form-urlencoded"  
      
)
if not resp then  
    ngx.say("request error :", err)  
    return  
end  
ngx.say(resp.body)  
http:close()

让后台接口在8001和8002两个端口启动,不同的id会访问不同的服务器

使用Lua创建页面模板

lua-resty-template可以使用Lua创建类似JSP的模板

https://github.com/bungle/lua-resty-template

下载template和template.lua,保存到resty中

基本使用

view_template.lua

local template = require "resty.template"
-- 方法1 使用new方法进行页面渲染,message是自定义数据
local view = template.new "view.html"
view.message = "Hello, World!"
view:render()
-- 方法2 使用render实现页面渲染
template.render("view.html",  message = "Hello, World!" )

nginx/html/view.html

<!DOCTYPE html>
<html>
<body>
  <h1>message</h1>
</body>
</html>

nginx.conf

location /view_template 
     default_type text/html;
     content_by_lua_file conf/lua/view_template.lua;
     root html;
     index view.html;

访问效果

Lua+Redis+OpenResty实现电商详情页

实现思路

course.lua

-- 获得路径参数id
local id = ngx.var.id
-- 连接redis
local redis = require "resty.redis"
local red = redis:new()
local ok,err = red:connect("127.0.0.1",6379)
if not ok then
        ngx.say("connect failed",err)
        return
end
-- 查询该id的课程
local val,err = red:get("course"..id)
if not val then
        ngx.say("redis get failed",err)
        return
end
if val == ngx.null then
		-- 缓存为空,查询后台接口
		local httpc = require("resty.http").new()
		local res, err = httpc:request_uri("http://192.168.101.18:8002/course/"..id, 
			method = "GET",
			headers = 
				["Content-Type"] = "application/x-www-form-urlencoded"
			
		)
		if not res then
			ngx.log(ngx.ERR, "request failed: ", err)
			return
		end
		val = res.body
		if val == ngx.null then
			ngx.say("course not found ",id)
			return
		end
		-- 保存到redis
		red:set("course"..id,val)
end
-- 实现页面渲染
local template = require "resty.template"
template.caching(false)
local context = 
	course = val

template.render("course.html", context)

nginx.conf

location ~*/course/([0-9]+)$ 
    default_type text/html;
    root html;
    set $id $1;  #获得uri最后的数字保存到id变量中,lua中通过ngx.var.id获得
    index course.html;
    content_by_lua_file conf/lua/course.lua;

course.html\\css\\js 保存到nginx/html目录中

页面使用了Vue.js,其中Vue的 符号和Lua模板冲突,所以需要使用-raw-括起来,Lua不进行处理

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>课程页面</title>
    <link rel="stylesheet" type="text/css" href="/css/course.css">
</head>
<body>
<div id="course">
    <div style="background: #eee;">
        <div class="nav-wrap">
            <p class="nav-p-pc" style="margin-top:-25px;text-align:left;">
                <a href="/">课程列表</a>
                <span class="sharp-content">&gt;</span>
                <span class="nav-sec">-raw-course.courseName-raw-</span>
            </p>
        </div>
        <!-- 课程详情 -->
        ...
        -raw-course.price-raw-
        ...
    </div>
</div>
</body>
<script src="/js/vue.js"></script>
<script>
    var vue = new Vue(
        el: "#course",
        data: 
            course:*course* //以非转义方式绑定lua模板中的course对象
        ,
        created() 
            console.log(this.course);
        
    );
</script>
</html>

后台查询接口

@RestController
public class CourseController 

    @Autowired
    private CourseService courseService;

    @GetMapping("course/courseid")
    public Course getCourseById(@PathVariable("courseid")Integer courseid) 
        Course course = courseService.getCourseById(courseid);
        return course;
    

访问效果

以上是关于Openresty+Lua Redis连接池实现的主要内容,如果未能解决你的问题,请参考以下文章

Lua+Redis+OpenResty实现电商详情页

Lua+Redis+OpenResty实现电商详情页

Lua+Redis+OpenResty实现电商详情页

使用Lua+Redis+OpenResty实现电商首页并发优化

openresty通过 Lua + Redis 实现动态封禁 IP

非openresty方式安装Nginx + Lua + Redis 环境