一文带你了解 OpenNJet KV Store及实现

原创
2023/11/09 11:00
阅读数 49

NGINX 向云原生演进,All inOpenNJet


1. 特性介绍

OpenNJet 实现了可持久化的键值存储(key-value store)功能,并提供了相应的API对键值进行操作。基于KV Store提供的能力,可以用于如下场景:

  • 模块动态配置信息的持久化
  • OpenNJet不同模块间运行状态信息的共享
  • 外部系统对NJet运行模块的动态参数调整

例如OpenNJet 目前提供的动态Worker数目调整功能,就是通过设置特定的KEY值,以此来触发Master 进程对运行Worker进程的管理。

2. 实现方案

开源社区已经有大量的中间件,如Redis, Etcd,这些中间件都可以用来做键值存储的数据库, 但这样不仅需要OpenNJet中有相应模块与其进行交互,并且部署时增加了外部组件的依赖。

OpenNJet KV Store 的实现上,使用了轻量级的内存数据库 LMDB。LMDB是基于内存映射的,效率高,并且访问简单,不需要单独的数据管理进程,只要在访问代码里引用LMDB库。LMDB的文件结构简单,包含一个数据文件和一个锁文件,通过锁控制来实现事务隔离,LMDB文件可以同时由多个进程打开。使用该方案,整体架构简单清晰。

OpenNJet 与其它负载均衡产品KV Store 功能的比较:

  OpenNJet nginx OSS nginx Plus APISIX
是否支持 支持 无内置KV Store 支持 支持
实现方式 LMDB / 共享内存 Etcd
使用方式 Restful, Lua, C API / Restful, Njs Restful, Lua
是否收费 开源免费 / 付费使用 开源免费

3. 使用说明

3.1 C API

使用C开发OpenNJet的扩展模块时,可以使用OpenNJet提供的kv 能力,对kvstore进行操作。

以数据面的模块为例,模块中需要包含OpenNJet源码中的头文件:

#include <njt_http_kv_module.h>
该头文件中kvstore相关的函数原型声明如下:
int njt_db_kv_get(njt_str_t *key, njt_str_t *value);
int njt_db_kv_set(njt_str_t *key, njt_str_t *value);
int njt_db_kv_del(njt_str_t *key);

调用样例代码如下:

static int kv_get_example()
{
    njt_str_t lmdb_key = njt_string("test_key");
    njt_str_t lmdb_value;
    njt_int_t ok;
    lmdb_value.len=0;
    lmdb_value.data=NULL;
    ok = njt_db_kv_get(&lmdb_key, &lmdb_value);
    if (ok == NJT_OK)
    {
       ...
    }

    return NJT_OK;
}

3.2 Lua 方式

OpenNJet 提供了封装后的Lua kv store API,在Lua 中引用"njt.kv" Lua 库, 之后使用Lua 函数对kv store 进行操作,函数包括:db_kv_get, db_kv_set, db_kv_del。

测试代码如下:

location /lua_kv_test {
           content_by_lua_block {
              local kv = require("njt.kv")
              local args, err = njt.req.get_uri_args()
              local key = args["key"]
              local rc,msg = kv.db_kv_get(key)
              if rc == 0 then
                 njt.say("old value is: "..msg)
              else
                 njt.say("there is no such key in kv")
              end

              local newValue = key .."_"..tostring(os.time())
              rc = kv.db_kv_set(key, newValue)
              if rc == 0 then
                 njt.say("set to new value: "..newValue)
              else
               njt.say("error occuried")
              end
           }
         }

        location /lua_kv_del {
          content_by_lua_block {
             local kv=require("njt.kv")
             local args, err= njt.req.get_uri_args()
             local key=args["key"]     
             local _, msg= kv.db_kv_del(key)
             njt.say(msg)
          }
     } 

3.3 Restful 方式

使用官网提供的RPM 包安装后,生成的控制面njet_ctrl配置中,已包含一个可以用来设置kv值的location

    location /kv {
            dyn_sendmsg_kv;
        }

可以使用Restful 的方式,GET,POST, DELETE 来对键值进行操作。

使用控制面提供的Restful 接口在设置键值时,将在key前添加 "kv_http_" 的前缀。如果使用C或Lua API,与Restful 接口设置的键值需要互操作的场景下, 在C或Lua API调用对应函数时,需要自行添加"kv_http_" 的前缀。


OpenNJet 最早是基于 NGINX1.19 基础 fork 并独立演进,具有高性能、稳定、易扩展的特点,同时也解决了 NGINX 长期存在的难于动态配置、管理功能影响业务等问题。

邮件组 官网

展开阅读全文
加载中
点击引领话题📣 发布并加入讨论🔥
打赏
0 评论
0 收藏
0
分享
返回顶部
顶部