【网关开发】3.Openresty lua使用lmdb数据库
背景
网关的高可用是比较重要的内容,即使etcd数据库挂掉,也可以根据现有的数据提供负载均衡应用
所以采用几级缓存的形式 cache-->lmdb-->etcd
cache属于进程级别,每一个进程都有一个cache,lmdb相当于多个进程的共享内存,只有一个进程master进行同步更新etcd的数据,然后通过event来通知cache的更新
在进程内部,使用cache进行快速的读取。
这里使用的是kong提供的插件使用lmdb功能
源码准备
你可以直接用git将源码下载
git clone git@github.com:Kong/lua-resty-lmdb.git --recursive
会默认将子模块代码 (lmdb) 也一起下载
或者
你可以去网站下载源码
https://github.com/Kong/lua-resty-lmdb
https://github.com/LMDB/lmdb/tree/e2b82098fa592b20cb3ba79ddbf28f2b2a692e39
然后将lmdb 的代码放在lua-resty-lmdb lmdb目录中。这里需要注意的是lmdb分支,不是master,不然在编译阶段会出现找不到变量的情况
编译
./configure ... --add-module=$lua_clibs_src/lua-resty-lmdb
在一些以前的使用方式中,需要在lmdb中进行make,得到liblmdb.so 文件,并将这个文件放在lua代码的文件夹中
这个插件应该是不需要的,直接./configure 就可以
API 使用
API 的源码在 ./lib/resty 中,你可以把他移动到你的个人工程目录下
其实就是两个文件lmdb.lua 和transaction.lua,lmdb.lua 是对transaction.lua的封装,具体的实现可以用transaction.lua 进行的实现,所以最简单的方式就是只用 lmdb.lua 中的get和set
lmdb 可以指定db,如果不指定也会调用_default数据库
那怎么设置_default的lmdb的路径呢? 答案是使用nginx的指令lmdb_environment_path 和 lmdb_map_size
如果不指定着两个指令会报错
lmdb err err: unable to open DB for access: no LMDB environment defined
nginx.conf 配置文件
lmdb_environment_path ./dblmdb.lmdb;
lmdb_map_size 128m;
使用
local lmdb = require "resty.lmdb"
local ok, err = lmdb.set('__etcd_revision__', _new_revision)
if not ok then
ngx.log(ngx.ERR,'lmdb.set __etcd_revision__ err'..err)
end
local v = lmdb.get('__etcd_revision__')
if v then
ngx.log(ngx.INFO,'__etcd_revision__ err'..v)
end
--如果初始化可以清空数据可以使用
lmdb.db_drop(true)
相关链接
插件源码 https://github.com/Kong/lua-resty-lmdb
本文的工程代码:https://github.com/zhaoshoucheng/openresty
由于使用文档不全,在使用过程还是遇到了许多的问题的。
相关issues讨论:https://github.com/Kong/lua-resty-lmdb/issues/21
其实如何使用也完全可以参考kong的源码。毕竟这个项目是kong的一部分,全局搜索lmdb,就可以一目了然。
kong : https://github.com/Kong/kong
插件原理
扩展地址:https://konghq.com/blog/new-storage-engine-for-kong-hybrid-and-db-less-deployments
lua_resty_lmdb有两个部分。一个是Nginx C模块,它管理LMDB资源,并充当访问存储在LMDB数据库中的数据的抽象层。该模块还公开了Lua库通过LuaJIT的FFI设施调用的安全C API。
另一部分是一个lua库,它为lua代码提供了实际的API接口。它使用lua_resty_lmdb C模块提供的C API安全地与lmdb库交互。
总结思考
- 准备源码时,注意依赖的版本或者分支,可以--recursive下载子模块的最好,不然也要注意版本的对应关系。不然会存在莫名其妙的错误,而且很难查找。
- 在插件使用时, 多想想--add-module 或者 --with 等使用方式。
- 多想想插件是否使用了一些nginx的变量、配置的设定。
- 实在找不到问题时可以多提提issues,有时候确实是文档不够充分。