Kamailio-HTable 万年缓存技术

Kamailio HTable

Posted by Claire on October 17, 2024

在程序开发的时候我们都知道,缓存可以存放临时的数据、高性能需求的数据,典型的就是Redis,使用高效的Hash数据结构提供极致的性能需求,而不是依赖数据库。那么在Kamailio这边,也有一些这样的需求,比如黑白名单、访问频次、业务静态属性等,Htable出现了。

速览:

HTable

Htable 正如它的名字,它就是一个哈希表结构容器,在共享内存中保存,不同线程可以共同读取,可以支持多种类型的定义,可以支持从数据库载入缓存。在Sip服务器中一个典型的场景就是作为缓存系统,元素也支持过期。

什么是hash table ? http://en.wikipedia.org/wiki/Hash_table.

功能介绍

从数据库初始化

如果配置了DB url,就能够从数据库获取初始化数据,那么就是取决于四个字段key name、key type、value type、key value,当然这四个字段也支持自定义。你可以选择配置指定的字段,或者独立设置一个与之对应的只读视图来获取数据

  • key name: string类型,是key名
  • key type: key的类型
    • 0 代表 普通类型,key就是’key_name’
    • 1 代表 数组类型,key就是’key_name[n]’
  • value type:内容的类型
    • 0 - string类型
    • 1 - integer类型
  • key value:string类型 key的内容
modparam("htable", "key_name_column", "kname") #Default value is 'key_name'.
modparam("htable", "key_type_column", "ktype") #Default value is 'key_type'.
modparam("htable", "value_type_column", "vtype") #Default value is 'value_type'.
modparam("htable", "key_value_column", "kvalue") #Default value is 'key_value'.
modparam("htable", "expires_column", "expiry") #Default value is 'expires'.

使用如下配置数据库信息:

modparam("htable", "db_url", "mysql://kamailio:kamailiorw@localhost/kamailio")

如果你是pg,那么

modparam("htable", "db_url", "postgres://kamailio:kamailiorw@localhost/kamailio")

如何定义 htable 数据

"htname=>size=_number_;autoexpire=_number_;dbtable=_string_"

  • htname 是具体的哈希表名
  • size 来控制要为哈希表创建的槽 (存储桶) ,数越大,意味着插槽越多,冲突越少的可能性越高。为表创建的实际数字槽(或存储桶)为 2^size。此值的可能范围为 2 到 31,较小或较大的值将增加到 3(8 个槽)或减少到 14(16384 个槽)。请注意,当为键计算的哈希 ID 发生冲突时,每个槽可以存储多个项目。同一插槽中的项目存储在链表中。换句话说,大小并没有设置哈希表中可以存储的项目数量的限制,只要有足够的可用共享内存,就可以添加新项目
  • autoexpire 如果未对哈希表进行更新,则从哈希表中删除项目的时间(以秒为单位)。如果缺少或设置为 0,则项目不会过期
  • dbtable 启动时要加载的数据库名称,不写就不加载
  • cols 列名
  • dbmode 0 不回写入DB-默认,1 服务暂停时回写入DB
  • initval 返回为空时,会返回一个数字,而不是null
  • updateexpire 如果设置为1,则一个值的过期时间会被充值当值被更新
  • dmqreplicate 如果设置为1,就会通过DMQ模块,将数据同步到其他副本节点
  • coldelim 列分隔符
  • colnull 数据库里面Null值进入htable可转的值,一般使用就是null转空字符串

结合以上定义,来看看这些样例

modparam("htable", "htable", "a=>size=4;autoexpire=7200;dbtable=htable_a;") 缓存名叫a, 2小时自动过期,db里面加载过来的表名叫htable_a

modparam("htable", "htable", "b=>size=5;") 缓存名叫b, 为哈希表初始换2^5个卡槽

modparam("htable", "htable", "c=>size=4;autoexpire=7200;initval=1;dmqreplicate=1;") 缓存名叫c,为哈希表初始换2^4个卡槽,2小时自动过期,返回为空默认为1,使用DMQ进行副本数据同步

其他参数:

  • array_size_suffix (str) 要添加的后缀
  • fetch_rows (integer) 一次要从数据库中获取多少行
  • timer_interval (integer) 检查过期 htable 值的间隔(s)
  • db_expires (integer) 如果设置为 1,则模块从/到数据库加载/保存哈希表中项目的过期值。这个值的刷新最终还是需要依赖RPC指令,不是服务自行完成
  • enable_dmq (integer) 如果设置为 1,则开启DMQ复制
  • dmq_init_sync (integer) 如果设置为 1,将在启动时请求其他节点同步
  • timer_procs (integer) 如果设置为 1 或更大,则模块将创建自己的计时器进程来扫描哈希表中的过期数据
  • event_callback (str) 事件回调定义
  • event_callback_mode (int) 控制何时执行 event_route[htable:init]: 0 - 所有模块初始化后;1 - 在第一个工作进程中

如何写入和读取?

$sht(test=>x)='aaa';
$sht(test=>5)=0;
$sht(test=>x[0])='abc';

#在ha中删除key为test的数据
sht_rm("ha", "test"); 

#按照key正则表达去删除
sht_rm_name_re("ha=>.*");

#按照value正则表达去删除
sht_rm_value_re("ha=>.*");

sht_rm_name("ha", "re", ".*"),sht_rm_name(htable, op, val) 更多灵活的批量根据keyname的情况去删除方式 The op parameter:

  • re - match the val parameter as regular expression.
  • sw - match the val parameter as ‘starts with’.
  • ew - match the val parameter as ‘ends with’.
  • in - match the val parameter as ‘includes’.

value也是同样的:sht_rm_value("ha", "re", ".*");, sht_rm_value(htable, op, val)

  • re - match the val parameter as regular expression.
  • sw - match the val parameter as ‘starts with’.
  • ew - match the val parameter as ‘ends with’.
  • in - match the val parameter as ‘includes’.

sht_reset("ha$var(x)"); 删除哈希表中所有内容

修改string类型:

sht_setxs("ha", "test", "abc", "10"); 将test=10 改为 test=abc,过期test=10 并将 test设置为abc

修改integer类型:

sht_setxs("ha", "test", "100", "10");

sht_match_name(htable, op, mval) 对于key查询,支持四种匹配方式

  • eq - match the val parameter as string equal expression.
  • ne - match the val parameter as string not-equal expression.
  • re - match the val parameter as regular expression.
  • sw - match the val parameter as ‘starts with’ expression.

以下都是类似的:

sht_has_name(htable, op, mval) sht_match_str_value(htable, op, mval) sht_has_str_value(htable, op, mval)

其他

sht_lock(htable=>key) 锁定key sht_unlock(htable=>key) 解锁key

sht_iterator_start("i1", "h1"); sht_iterator_end("i1"); sht_iterator_next(iname) sht_iterator_rm(iname) sht_iterator_sets(iname, sval) sht_iterator_seti(iname, ival) sht_iterator_setex(iname, exval)

伪变量

  • $sht(htable=>key)

  • $shtex(htable=>key)

  • $shtcn(htable=>key)

  • $shtcv(htable=>key)

  • $shtinc(htable=>key)

  • $shtitkey(iname)

  • $shtitval(iname)

  • $shtrecord(attribute)

RPC指令

  • htable.get htable key 获取一个值
...
# Dump $sht(students=>alice)
kamcmd htable.get students alice

# Dump $sht(students=>15)
kamcmd htable.get students s:15

# Dump first entry in array key course $sht(students=>course[0])
kamcmd htable.get students course[0]
  • htable.delete htable key 删除一个值
# Delete $sht(students=>alice)
kamcmd htable.delete students alice

# Delete $sht(students=>15)
kamcmd htable.delete students s:15

# Delete first entry in array key course $sht(students=>course[0])
kamcmd htable.delete students course[0]
  • htable.sets htable key value 设置一个字符串的值
# Set $sht(test=>x) as string
kamcmd htable.sets test x abc

# Set $sht(test=>5) as string
kamcmd htable.sets test s:5 abc

# Set firsti entry in array key x $sht(test=>x[0]) as string
kamcmd htable.sets test x[0] abc
  • htable.seti htable key value 设置一个数字的值
# Set $sht(test=>x) as integer
kamcmd htable.seti test x 123

# Set $sht(test=>5) as integer
kamcmd htable.seti test s:5 123

# Set first entry in array key x $sht(test=>x[0]) as integer
kamcmd htable.seti test x[0] 123
  • htable.setex htable key expire、htable.setxs htable key value expire、 htable.setxi htable key value expire 过期一个key,顺便是否需要设置一个新的值(字符串或数字)
  • htable.dump htable 导出哈希表所有数据
  • htable.reload htable 重新加载刷新哈希表
  • htable.store htable 将哈希表保存到数据库
  • htable.flush htable 清空哈希表
  • htable.listTables 列出所有表格
  • htable.stats 统计
  • htable.dmqsync [htable] dmq同步