最近在用opensips(3.3.10)版本支持信创和国产数据库,因为是使用源码编译构建,所以arm版本编译很顺利,在支持国产数据库的过程中遇到一些问题,现对这些问题做个总结。

1. 尽量少用数据库
2. 在无法避免使用数据库时,使用轻量模块(数据读)
3. 使用odbc模块(数据读写)

1. 尽量少用数据库

opensips的大部分模块比如usrloc, dialog, cluster, rtpengine等这些是支持nodb模式的,所以我们是构建项目尽量少用组件,服务越简单,越可靠。opensips当然还有些模块比如dispatcher必须要用db模式,此时就必须要考虑以下两种方式了。

2. 使用轻量模块

2.1 db_text

db_text是opensips提供的轻量级文件处理模块,此模块需要注意三点:
1. 无法像mysql一样生成自增id,所以对于这样的字段可以去掉。
2. 它把数据存在内存中,只有在服务死掉时才同步到文件,所以如果想用db_text
   存储acc,那么内存会有写爆的风险。
3. db_text的表数据类型可能会和mysql中的表类型不一致。我指的是mysql的int到db_text有可能是str,所以实际可根据错误来修改(这应该是db_text的bug)。

opensips认为db_text也是一种数据库,所以需要version表,以dispatcher为例,那么就需要两个表:version和dispatcher

  1. version:

    table_name(str) table_version(int)
    acc:7
    active_watchers:12
    address:5
    b2b_entities:2
    b2b_logic:4
    b2b_sca:1
    cachedb:2
    carrierfailureroute:2
    carrierroute:3
    cc_agents:3
    cc_calls:3
    cc_cdrs:2
    cc_flows:2
    closeddial:1
    clusterer:4
    cpl:2
    dbaliases:2
    dialog:11
    dialplan:5
    dispatcher:8
    domain:3
    domainpolicy:3
    dr_carriers:3
    dr_gateways:6
    dr_groups:2
    dr_partitions:1
    dr_rules:4
    emergency_report:1
    emergency_routing:1
    emergency_service_provider:1
    fraud_detection:1
    freeswitch:1
    globalblacklist:2
    grp:3
    imc_members:2
    imc_rooms:2
    jwt_profiles:1
    jwt_secrets:1
    load_balancer:3
    location:1013
    missed_calls:5
    presentity:5
    pua:9
    qr_profiles:1
    rc_clients:1
    rc_demo_ratesheet:1
    rc_ratesheets:1
    rc_vendors:1
    registrant:3
    re_grp:2
    rls_presentity:1
    rls_watchers:2
    route_tree:2
    rtpengine:1
    rtpproxy_sockets:0
    silo:6
    sip_trace:5
    smpp:1
    speed_dial:3
    subscriber:8
    tcp_mgm:1
    tls_mgm:3
    uri:2
    userblacklist:2
    usr_preferences:3
    watchers:4
    xcap:4
  2. dispatcher
id(int,auto) setid(int) destination(str) socket(str,null) state(int) weight(str) priority(int) attrs(str) description(str)
1:1:sip\:192.168.9.124\:5261::0:1:0:pstn=100:test

opensips.cfg中的配置方式:

loadmodule "db_text.so"
modparam("dispatcher", "db_url", "text:///data/sbc/text")

/data/sbc/text目录下:

/data/sbc/text
[root@sbc-lb text]# ll
total 8
-rw-r--r-- 1 root root 207 Dec  6 17:44 dispatcher
-rw-r--r-- 1 root root 911 Dec  6 16:25 version

2.2 db_http

opensips提供了一种http的方式,可以把数据通过http的方式发送给server。
http Server可以接收数据写数据库。这个我没有实际实践过,看了官方文档,应该是可行的。

2.3 db_sqlite

sqlite是大部分服务不能对接国产数据库,但必须使用数据库的唯一方式。
但是由于sqlite在高并发下,性能不强。
而且它存储数据在本地文件夹下,opensips在做主备方案时,主备只能各存各的,数据不一致。

3. 使用odbc模块

在以上的方式都不能满足的条件下,必须要使用数据库,比如acc。
当然acc也有db_flatstore模块支持快速写,但是这个也是和写文件一样,存储在本地,opensips主备模式,不太适用。
此时只能用odbc来对接国产数据库了,进入今天的主题。    
参考文章:https://www.cnblogs.com/itschen/p/14831048.html

3.1 准备知识

达梦,高斯,OceanBase这些数据库都是有"模式"的概念,这个模式对应的是schema。
但是此参数在odbc配置数据库信息时,所有的数据库都是不提供的,另外达梦的schema要带引号。
这个"模式"其实和mysql的数据库名是差不多一个概念。
opensips的sql语句都是未带库名,只有表名。

3.2 odbc对接

3.2.1 达梦
  1. 使用参照文章 https://www.cnblogs.com/itschen/p/14831048.html 安装unixodbc
  2. 把达梦的libdodbc.so相关的so库(这个库需要注册达梦官方网站,找他们的客服要),放到/usr/local/odbc/lib/下(自己定义,直接放到/usr/local/lib下也行)。
  3. export LD_LIBRARY_PATH=/usr/local/odbc/lib:/usr/local/lib:$LD_LIBRARY_PATH,
  4. ldd libdodbc.so,看看是否缺库,缺啥安装啥。
  1. odbcinst.ini

    [DM8 ODBC DRIVER]
    Description = ODBC DRIVER FOR DM8
    DRIVER = /usr/local/odbc/lib/libdodbc.so
  2. odbc.ini

    [DM8]
    Description = ODBC DRIVER FOR DM8
    Driver = DM8 ODBC DRIVER
    SERVER = 172.16.6.224 
    DATABASE = sbc
    UID = test
    PWD = test123
    TCP_PORT = 5238

    然后isql -v dm8 正常就连上了dm数据库了。

opensips如何配置呢:

  1. opensips的Makefile.conf.templete里的exclude_modules去掉db_unixodbc。
  2. db_url: unixodbc://test:test123@172.16.6.224:5238/dm8

    小技巧:docker-compose.yaml里如果密码带有$符号,那么怎么才能使用此$,不被转义呢?
    答案是再加个$,比如密码是test12#$, 那么docker-compose.yaml配置时为:test12#$$ 

这些只能是连上了数据库,但是在执行sql出错,还是schema的问题。

3.2.2 高斯

高斯和达梦的对接方式差不多,区别

  1. odbc.init的配置
  2. 高斯的schema不用加引号
  3. gsqlowdbcw.so库需要glibc2.28的版本,所以要提前安装好

gsqlowdbcw.so 要去华为的官网上找。

  1. odbcinst.ini

    [GaussMPP]
    Description = ODBC DRIVER FOR GaussDB 
    Driver64    = /usr/local/odbc/lib/gsqlodbcw.so
    setup       = /usr/local/odbc/lib/gsqlodbcw.so
  2. odbc.ini

    [gb]
    Driver     = GaussMPP
    Servername = 172.16.6.223 
    Database   = sbc
    Username   = huaweibase
    Password   = Huaweibase123
    Port       = 26000 
    Sslmode    = allow

    只是能连接上,如要正确使用sql要改源码。

    3.2.3 OceanBase

    由于oceanBase兼容mysql比较好,所以直接使用mysql驱动就行,不用使用odbc方式,当然使用odbc也行。
    另外由于oceanBase的mysql在配置的时候,用户名会带有'@'字符,opensips会报错,要改源码。

    opensips需要改的源码位置为:db/db_id.c,具体可参考kamailio的来。

4 如何处理schema?

由于此模式也就相当于opensips在执行sql时,前面指定schema,又或者这样

select table_version from xing_sbc.version where table_name = 'dialog';

所以为避免改动过多,我采用的策略是在表名前加schema前缀,需要改动db/db.c里的代码。

小技巧: 在docker-compose.yaml里,对接达梦时,要传双引号,可采用如下配置:
unixodbc://dmtest:kdbase#@172.16.4.112:5236/dm8?Schema=\\"opensips\\"

白沙云影
1 声望3 粉丝

一个专注于voip的频道