背景介绍
当kamailio需要做集群或者主备时, 需要对集群节点做数据同步。
DMQ_USRLOC
用来对注册用户信息
做同步
DMQ
用来实现数据同步的方式
Dialog
会话信息
本次以常见的两个节点方式为例介绍,kamailio
的节点并没有主备
的概念,这点和opensips
有点不一样。
节点1 |
节点2 |
172.16.4.111 |
172.16.4.113 |
kamailo版本:
version: kamailio 5.8.5 (x86_64/linux)
DMQ 模块介绍
DMQ 用于节点之间使用SIP消息(KDMQ
)进行同步, 新节点可以通过发送可用的消息通知
来加入集群,
如果节点不响应其他活跃节点的消息,那么就会被踢出集群。 集群节点的kamailio
版本必须一致。
DMQ 参数解析
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
|
# 本地发送和接收DMQ 消息的地址
modparam("dmq", "server_address", "sip:172.16.4.111:5464")
# 本地监听DMQ消息的地址,默认 NULL
modparam("dmq", "server_socket", "udp:172.16.4.111:5464")
# 通知备节点地址,默认 NULL
modparam("dmq", "notification_address", "sip:172.16.4.113:5464")
# 通知消息通道,默认"notification_peer"
modparam("dmq", "notification_channel", "peers")
# 是否可以解析多个IPv4/IPv6地址,0,只解析第一个地址;非0,通过host解析所有的ip. 默认 0
modparam("dmq", "multi_notify", 1)
# DMQ工作线程数量,默认 2
modparam("dmq", "num_workers", 4)
# DMQ工作线程休眠时间,默认0
modparam("dmq", "worker_usleep", 0)
# DMQ心跳时间,默认 60 秒
modparam("dmq", "ping_interval", 90)
|
要提前监听listen=udp:172.16.4.111:5462
DMQ 重要函数
- dmq_handle_message()
处理DMQ 消息, 可以用在REQUEST_ROUTE
- dmq_process_message()
和dmq_handle_message()
类似,但是处理是立即的,不再是copy这个请求到共享内存中给DMQ
workers去处理。
- dmq_send_message(channel, node, body, content_type)
发送DMQ消息到单节点,示例:
dmq_send_message("channel1", "sip:10.0.0.21:5060", "Message body...", "text/plain");
- dmq_bcast_message(channel, body, content_type)
发送DMQ消息到所有节点,示例:
dmq_bcast_message("channel1", "Message body...", "text/plain");
- dmq_t_replicate()
复制当前的SIP消息到所有节点。只能用在REQUEST_ROUTE
- dmq_is_from_node()
判断当前请求是不是被其他的节点发送过。示例:
1
2
3
4
5
6
7
8
9
|
if(is_method("REGISTER")) {
if (dmq_is_from_node()) {
# coming from a DMQ node - already authenticated there
# now just save contact, etc...
} else {
# coming from end point - authenticate, save contact, etc...
dmq_t_replicate("1"); # source address checked, skip the loop test
}
}
|
DMQ 实战
为方便观察server_socket
和server_address
的区别,特意把这两个的端口设置不同,
以及两个节点的ping_interval
时间不一样。
- 1节点 172.16.4.111配置
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
|
listen=udp:172.16.4.111:5465
loadmodule "dmq.so"
modparam("dmq", "server_address", "sip:172.16.4.111:5464")
modparam("dmq", "server_socket", "udp:172.16.4.111:5465")
modparam("dmq", "notification_address", "sip:172.16.4.113:5464")
modparam("dmq", "notification_channel", "peers")
modparam("dmq", "num_workers", 4)
modparam("dmq", "ping_interval", 30)
...
request_route {
...
if(is_method("KDMQ")) {
dmq_process_message();
}
...
}
|
- 2节点 172.16.4.113配置
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
|
listen=udp:172.16.4.113:5464
loadmodule "dmq.so"
modparam("dmq", "server_address", "sip:172.16.4.113:5464")
modparam("dmq", "server_socket", "udp:172.16.4.113:5465")
modparam("dmq", "notification_address", "sip:172.16.4.111:5464")
modparam("dmq", "notification_channel", "peers")
modparam("dmq", "num_workers", 4)
modparam("dmq", "ping_interval", 40)
...
request_route {
...
if(is_method("KDMQ")) {
dmq_process_message();
}
...
}
|
172.16.4.111 发送请求的sip信令图如下:

可以看到KDMQ
消息发送是通过server_socket
发出的,其中的sip信令填充了server_address
。
172.16.4.113 发送请求的sip信令图如下:

同理,和111的情况一致。
所以为避免占用较多的端口, 可以把server_socket
和server_address
设置为同一个端口。
当节点2服务停掉之后,得到的信令图:

可以看到sip消息少了节点2的活跃信息
DMQ_USRLOC 模块介绍
DMQ_USRLOC 参数解析
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
|
# 是否开启DMQ_USRLOC模块,默认 0,不开启
modparam("dmq_usrloc", "enable", 1)
# 是否在服务一启动时就同步数据,默认 0,不启动同步
modparam("dmq_usrloc", "sync", 0)
# 批量同步数据条数,同步之后进入batch_usleep时间, 默认0,不开启批量同步
modparam("dmq_usrloc", "batch_size", 4000)
# 批量同步休眠时间,默认 0,不开启批量同步
modparam("dmq_usrloc", "batch_usleep", 1000)
# 设置同步消息的大小,最大65536,默认60000
modparam("dmq_usrloc", "batch_msg_size", 500000)
# 批量同步联系人条数,默认1,最大150
modparam("dmq_usrloc", "batch_msg_contacts", 50)
# usrloc domain同步参数
modparam("dmq_usrloc", "usrloc_domain", "location")
# 是否同步socker信息,默认 0,不同步;1,同步proto:host:port;2,同步socket name;
modparam("dmq_usrloc", "replicate_socket_info", 1)
# 是否同步删除信息,默认 1,同步;0,不同步删除动作,当usrloc的过期时间很短时,此时设置为0,让其自己删除更高效。
modparam("dmq_usrloc", "usrloc_delete", 0)
|
DMQ_USRLOC 实战
- 1节点72.16.4.111配置:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
|
listen=udp:172.16.4.111:5460
listen=udp:172.16.4.111:5464
loadmodule "dmq.so"
modparam("dmq", "server_address", "sip:172.16.4.111:5464")
modparam("dmq", "server_socket", "udp:172.16.4.111:5464")
modparam("dmq", "notification_address", "sip:172.16.4.113:5464")
modparam("dmq", "notification_channel", "peers")
modparam("dmq", "num_workers", 4)
modparam("dmq", "ping_interval", 30)
loadmodule "dmq_usrloc.so"
modparam("dmq_usrloc", "enable", 1)
modparam("dmq_usrloc", "sync", 1)
modparam("dmq_usrloc", "batch_msg_contacts", 50) # 50 contacts / message
modparam("dmq_usrloc", "batch_size", 10000) # 10000 contacts / batch
modparam("dmq_usrloc", "batch_usleep", 500000)
...
request_route {
...
if(is_method("KDMQ")) {
dmq_handle_message();
}
...
}
|
- 2节点 172.16.4.113配置:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
|
listen=udp:172.16.4.113:5460
listen=udp:172.16.4.113:5464
loadmodule "dmq.so"
loadmodule "dmq_usrloc.so"
modparam("dmq", "server_address", "sip:172.16.4.113:5464")
modparam("dmq", "server_socket", "udp:172.16.4.113:5464")
modparam("dmq", "notification_address", "sip:172.16.4.111:5464")
modparam("dmq", "notification_channel", "peers")
modparam("dmq", "num_workers", 4)
modparam("dmq", "ping_interval", 30)
modparam("dmq_usrloc", "enable", 1)
modparam("dmq_usrloc", "sync", 1)
modparam("dmq_usrloc", "batch_msg_contacts", 50) # 50 contacts / message
modparam("dmq_usrloc", "batch_size", 10000) # 10000 contacts / batch
modparam("dmq_usrloc", "batch_usleep", 500000)
...
request_route {
...
if(is_method("KDMQ")) {
dmq_handle_message();
}
...
}
|
使用软电话注册到172.16.4.111:5460
,sip信令图如下:

172.16.4.111同步注册数据到172.16.4.113的信令图如下:

通过kamctl ul show
分别查看111和113机器上存储的usrloc数据:
- 172.16.4.111机器:

- 172.16.4.113机器:

可以知道同步到113机器上的过期时间和111机器上的过期时间不一致。
Dialog 模块介绍
dialog的其他参数暂时不介绍,新增以下配置:
1
2
3
4
5
|
modparam("dialog", "enable_dmq", 1)
...
if (is_method("INVITE")) {
dlg_manage();
}
|
dialog 集群效果
使用两个软电话1003,1008注册到172.16.4.111:5460
机器上,1003拨打1008,
然后使用kamctl dialog show
分别查看两台机器上的dialog信息。
DMQ发送的sip同步信令:

查看两台机器上的dialog信息:
- 172.16.4.111机器:

- 172.16.4.113机器:

存在的问题
目前当113这个机器上使用 如下的配置:
1
2
3
|
if(is_method("KDMQ")) {
dmq_handle_message();
}
|
DMQ在发送dialog消息时可以返回200Ok
。
但是如果用的是dmq_process_message()
,此时会报错 400 Bad Request
.
113机器上提示没有解析到content length
,目前在github上已提bug了.