简介
lua-resty-redis 是由著名OpenResty社区成员Agent Zhang(章亦春)创建的。这是一个与OpenResty集成的Lua模块,允许你在Nginx环境中直接进行Redis操作。利用OpenResty的强大功能,lua-resty-redis提供了异步非阻塞的Redis API,帮助开发者构建高性能、高并发的应用。
lua-resty-redis的核心在于其非阻塞I/O模型。它基于OpenResty的ngx.socket.tcp()接口实现,利用了LuaJIT的高效性能和Nginx事件循环机制。这意味着在处理大量并发请求时,即使Redis服务器繁忙,也不会导致Nginx的工作线程被阻塞,从而提高了整体系统的响应速度。
此外,该库提供了丰富的Redis命令支持,包括但不限于数据读写、哈希操作、集合操作、有序集合、发布订阅等。它的API清晰简洁,易于理解和使用,使得你可以快速地将Redis功能融入到你的OpenResty应用程序中。
应用场景
- 缓存管理:利用Redis的高速读写能力,可以作为动态内容的高速缓存层,降低对后端数据库的压力。
- 分布式会话:借助lua-resty-redis,可以在多台服务器之间共享用户的会话状态。
- 消息队列:通过其发布的订阅功能,可以构建简单的消息队列系统,实现任务的异步处理。
- 实时数据分析:利用Redis的数据结构,如计数器、集合等,进行实时统计和分析。
主要特点
- 非阻塞I/O - 基于OpenResty的异步TCP套接字接口,确保高并发场景下的效率。
- Redis命令支持 - 提供了Redis的所有主要命令,方便你执行各种操作。
- 错误处理 - 提供了良好的错误处理机制,便于定位和解决问题。
- 可扩展性 - 可以自定义连接池策略,适应不同规模和需求的系统。
- 简洁API - 易于理解和使用的API,加速开发过程。
安装
这里通过OPM工具包安装,更多请查看OpenResty实战系列 | 包管理工具OPM和LuaRocks
代码语言:javascript复制opm get openresty/lua-resty-redis
版本信息
代码语言:javascript复制# opm info openresty/lua-resty-redis
Name : lua-resty-redis
Version : 0.27
Abstract : Lua redis client driver for the ngx_lua based on the cosocket API
Author : Yichun "agentzh" Zhang (agentzh)
Account : openresty
Code Repo : https://github.com/openresty/lua-resty-redis
License : BSD 2-Clause "Simplified" or "FreeBSD" license
Original Work : yes
基础使用
使用 lua-resty-redis 设置和获取一个键值对基本示例redis_test_01.lua
文件
--[[-----------------------------------------------------------------------
* | Copyright (C) Shaobo Wan (Tinywan)
* |------------------------------------------------------------------------
--]]
-- redis config
local redis = require "resty.redis"
local red = redis:new()
red:set_timeouts(1000, 1000, 1000) -- 1 秒
-- 通过宿主机链接
local ok, err = red:connect("192.168.13.168", 6379)
if not ok then
ngx.say("[x] failed to connect: ", err)
return
end
-- 设置权限
local res, err = red:auth("123456")
if not res then
ngx.say("[x] failed to authenticate: ", err)
return
end
-- 设置权限
-- 请注意这里 auth 的调用过程
local count, err = red:get_reused_times()
ngx.say("[x] get_reused_times count: ", count)
if 0 == count then
res, err = red:auth("123456")
if not res then
ngx.say("[x]failed to authenticate: ", err)
return
end
elseif err then
ngx.say("[x]failed to get reused times: ", err)
return
end
ngx.say("[x] set result: ", ok)
local res, err = red:get("name")
if not res then
ngx.say("[x] failed to get name: ", err)
return
end
if res == ngx.null then
ngx.say("[x] name not found.")
return
end
ngx.say("[x] get name : ", res)
-- 连接池大小是100个,并且设置最大的空闲时间是 10 秒
local ok, err = red:set_keepalive(10000, 100)
if not ok then
ngx.say("[x] failed to set keepalive: ", err)
return
end
red:get_reused_times()
方法
- 如果当前连接不是从内建连接池中获取的,该方法总是返回
0
,也就是说,该连接还没有被使用过。 - 如果连接来自连接池,那么返回值永远都是非零。
这个方法可以用来确认当前连接是否来自池子。对于 Redis 授权,实际上只需要建立连接后,首次认证一下,后面只需直接使用即可。换句话说,从连接池中获取的连接都是经过授权认证的,只有新创建的连接才需要进行授权认证。所以大家就看到了 count, err = red:get_reused_times()
这段代码,并有了下面 if 0 == count then
的判断逻辑。
代码语言:javascript复制通过curl脚本测试请求打印结果
$ curl -i http://openresty.tinywan.com/lua_redis_test
HTTP/1.1 200 OK
Server: openresty/1.17.8.2
Date: Tue, 23 Jul 2024 07:16:23 GMT
Content-Type: text/html; charset=utf-8
Transfer-Encoding: chunked
Connection: keep-alive
Vary: Accept-Encoding
[x] set result: OK
[x] get name : Tinywan
如果指定的密码是错误的,那么上面的示例将向HTTP客户端输出以下内容:
代码语言:javascript复制failed to authenticate: ERR invalid password
事务支持
这个库支持Redis事务redis_transactions_test.lua
文件
--[[-----------------------------------------------------------------------
* | Copyright (C) Shaobo Wan (Tinywan)
* |------------------------------------------------------------------------
--]]
local cjson = require "cjson"
-- redis config
local redis = require "resty.redis"
local red = redis:new()
red:set_timeouts(1000, 1000, 1000) -- 1 秒
-- 通过宿主机链接
local ok, err = red:connect("192.168.13.168", 6379)
if not ok then
ngx.say("[x] failed to connect: ", err)
return
end
-- 设置权限
local res, err = red:auth("123456")
if not res then
ngx.say("[x] failed to authenticate: ", err)
return
end
-- 设置权限
local ok, err = red:multi()
if not ok then
ngx.say("failed to run multi: ", err)
return
end
ngx.say("[x] multi ans: ", cjson.encode(ok))
local ans, err = red:set("resty_name", "Tinywan")
if not ans then
ngx.say("[x] failed to run sort: ", err)
return
end
ngx.say("[x] set ans: ", cjson.encode(ans))
local ans, err = red:lpop("resty_name")
if not ans then
ngx.say("[x] failed to run sort: ", err)
return
end
ngx.say("[x] set ans: ", cjson.encode(ans))
ans, err = red:exec()
ngx.say("[x] exec ans: ", cjson.encode(ans))
red:close()
通过curl脚本测试请求打印结果
代码语言:javascript复制$ curl -i http://openresty.tinywan.com/lua_redis_transactions_test
HTTP/1.1 200 OK
Server: openresty/1.17.8.2
Date: Tue, 23 Jul 2024 07:29:53 GMT
Content-Type: text/html; charset=utf-8
Transfer-Encoding: chunked
Connection: keep-alive
Vary: Accept-Encoding
[x] multi ans: "OK"
[x] set ans: "QUEUED"
[x] set ans: "QUEUED"
[x] exec ans: ["OK",[false,"WRONGTYPE Operation against a key holding the wrong kind of value"]]
小结
lua-resty-redis是一个强大的工具,能够帮助开发者充分利用OpenResty和Redis的优势,构建高性能的Web服务。无论是简单的缓存解决方案还是复杂的分布式系统,它都能提供稳定且高效的支撑。