Kong 插件开发 - 缓存自定义实体

缓存自定义实体

如果有自定义的实体,可以通过 database_cache这个依赖把实体缓存到内存中。

local cache = require "kong.tools.database_cache"

这个模块暴露出来的方法如下:

  • ok, err = cache.set(key, value)

    根据指定的key把一个lua对象缓存到内存中。这个value可以是任何lua的数据类型,包括table。返回true或者 false和操作错误引起的 err。

  • value = cache.get(key)

    根据制定的 key 从被存储的 Lua 对象中检索

  • cache.delete(key)

    根据指定的 key 删除缓存的对象

  • newvalue, err = cache.incr(key, amount)

    将指定键中存储的数字增加指定的单位数量。该数字需要已经存在于缓存中,否则将返回错误。如果成功,则返回新的递增值,否则返回错误

  • value = cache.get_or_set(key, function)

    这是一个实用方法,它使用指定的键检索对象,但是如果对象是nil,那么将执行传递的函数,它的返回值将用于存储指定键的对象。这有效地确保对象仅从数据存储加载一次,因为每个其他调用将从内存中高速缓存加载对象

回过头来看我们authentication插件这个例子,用一个指定的api-key 来检索证书,写的代码如下:

-- access.lua

local credential

-- Retrieve the apikey from the request querystring
local apikey = request.get_uri_args().apikey
if apikey then -- If the apikey has been passed, we can check if it exists

  -- We are using cache.get_or_set to first check if the apikey has been already stored
  -- into the in-memory cache at the key: "apikeys."..apikey
  -- If it's not, then we lookup the datastore and return the credential object. Internally
  -- cache.get_or_set will save the value in-memory, and then return the credential.
  credential = cache.get_or_set("apikeys."..apikey, function()
    local apikeys, err = dao.apikeys:find_by_keys({key = apikey}) -- Lookup in the datastore
    if err then
      return responses.send_HTTP_INTERNAL_SERVER_ERROR(err)
    elseif #apikeys == 1 then
      return apikeys[1] -- Return the credential (this will be also stored in-memory)
    end
  end)
end

if not credential then -- If the credential couldn't be found, show an error message
  return responses.send_HTTP_FORBIDDEN("Invalid authentication credentials")
end

这样做之后,不管客户端用特定的 api-key 进行多少次请求,从第一次请求之后的每次搜索都会在内存中进行,不需要再查询数据库。

更新或者删除一个自定义的实体

每当在数据存储上更新或删除缓存自定义实体时,例如使用Admin API,它都会在数据存储区中的数据与在Kong节点内存中缓存的数据之间产生不一致。为了避免这种不一致,我们需要从内存存储中删除缓存的实体,并强制Kong从数据存储中再次请求它。为了这样做,我们必须实现一个处理无效钩子

无效的自定义实体

当一个实体被创建、更新或者删除的时候,Kong 会把这些操作通知到所有的nodes,并告知执行了哪些命令或者哪些实体会受到影响。这些不仅针对 APIs\Plugins\Consumers,而且也对自定义的实体有效。

感谢这一特性,我们可以监听这些事件和根据一些适当的动作做出响应,当被缓存的实体在数据库中改动之后,我们可以明确的从缓存中移除它,避免数据库与缓存中数据不一直的问题。从内存中移除缓存之后,会触发再次请求数据库,重新缓存实体。

Kong 传播的事件如下:

event name description
ENTITY_CREATED When any entity is being created.
ENTITY_UPDATED When any entity is being updated.
ENTITY_DELETED When any entity is being deleted.

为了监听这些事件,我们需要实现 hooks.lua 文件,并且在我们的插件中发布它,例如:

-- hooks.lua

local events = require "kong.core.events"
local cache = require "kong.tools.database_cache"

local function invalidate_on_update(message_t)
  if message_t.collection == "apikeys" then
    cache.delete("apikeys."..message_t.old_entity.apikey)
  end
end

local function invalidate_on_create(message_t)
  if message_t.collection == "apikeys" then
    cache.delete("apikeys."..message_t.entity.apikey)
  end
end

return {
  [events.TYPES.ENTITY_UPDATED] = function(message_t)
    invalidate_on_update(message_t)
  end,
  [events.TYPES.ENTITY_DELETED] = function(message_t)
    invalidate_on_create(message_t)
  end
}

在上边这个例子中,我们监听了 ENTITY_UPDATED 和 ENTITY_DELETED 两个事件,并且调用了适当的方法来相应。其中,message_t table 包含的事件属性如下:

property name type description
collection String 受操作影响的数据存储的集合
entity Table 最近更新、删除或者创建的实体
old_entity Table 只对更新事件有效,更新之前的实体

这里 entity 和 old_entity的属性,并不是 schema 中定义的所有属性,而是一个子集。这个情况是因为每个事件是通过 UDP 包发送的,受到 512 bytes的大小限制。这个子集是通过 schema 中的 marshall_event 函数来返回的。

marshall_event

这个函数序列化了在hooks.lua中用到的最小版本需要的字段的实体。如果这个函数没有被实现,默认 Kong 不会发送任何实体的字段。

例如:

-- daos.lua

local SCHEMA = {
  primary_key = {"id"},
  -- clustering_key = {}, -- none for this entity
  fields = {
    id = {type = "id", dao_insert_value = true},
    created_at = {type = "timestamp", dao_insert_value = true},
    consumer_id = {type = "id", required = true, queryable = true, foreign = "consumers:id"},
    apikey = {type = "string", required = false, unique = true, queryable = true}
  },
  marshall_event = function(self, t) -- This is related to the invalidation hook
    return { id = t.id, consumer_id = t.consumer_id, apikey = t.apikey }
  end
}

上边这个例子在自定义的实体中提供了 marshall_event,返回一个包含 id, consumer_id和 apikey的对象。在我们的hooks中不需要 creation_date来无效这个实体,所以我们不关心在事件中传播它。参数 t table是一个包含全部字段的原对象。

注意:这个lua table的 json 序列化串被返回的时候不能大于512 bytes, 以保证整个时间在一个 UDP 包中。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 156,423评论 4 359
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 66,339评论 1 289
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 106,241评论 0 237
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 43,503评论 0 203
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 51,824评论 3 285
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,262评论 1 207
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,615评论 2 309
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,337评论 0 194
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 33,989评论 1 238
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,300评论 2 240
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 31,829评论 1 256
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,193评论 2 250
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 32,753评论 3 230
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 25,970评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,708评论 0 192
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 35,295评论 2 267
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,207评论 2 258

推荐阅读更多精彩内容

  • Spring Cloud为开发人员提供了快速构建分布式系统中一些常见模式的工具(例如配置管理,服务发现,断路器,智...
    卡卡罗2017阅读 134,083评论 18 139
  • 1. Java基础部分 基础部分的顺序:基本语法,类相关的语法,内部类的语法,继承相关的语法,异常的语法,线程的语...
    子非鱼_t_阅读 31,292评论 18 399
  • 指令集 lua_capture_error_log lua_use_default_type lua_malloc...
    吃瓜的东阅读 11,853评论 0 2
  • 发现 关注 消息 iOS 第三方库、插件、知名博客总结 作者大灰狼的小绵羊哥哥关注 2017.06.26 09:4...
    肇东周阅读 11,592评论 4 59
  • pod react到项目时会出现如下错误 完整的Podfile如下 注意: Podfile目录和 .xcodepr...
    大虾咪阅读 406评论 0 0