Hello,
I have Kamailio installed as SIP redirect for an SBC to make routing decisions.
I'm using SQLOps module with postgresql 11.5 where I have multiple tables containing each around 6M record of routing codes: Code options 392342 sup1|sup2|sup3 Where code field is of prefix_range data type and has a gist index.
I'm sending traffic of 300 CPS to SBC which is forwarding it to Kamailio, and Kamailio respond with 300 multiple choice with the routing decision.
In normal cases, everything is going smoothly where Kamailio repsonds up to 50 ms.
But during the process of loading data to the routing tables, Kamailio response to SBC is dramatically delayed , where for some calls it takes up to 7 seconds to respond.
Noting that during this process the data are loaded to staging tables and not to live tables used by Kamailio.
Kamailio is installed on a VM with 32GB RAM and 16 vcores.
Following configuration is used in Kamailio: fork=yes children=10
following are the customized parameters in postgresql.conf max_connections = 100 shared_buffers = 8GB effective_cache_size = 24GB maintenance_work_mem = 2GB checkpoint_completion_target = 0.7 wal_buffers = 16MB default_statistics_target = 100 random_page_cost = 1.1 effective_io_concurrency = 200 work_mem = 5242kB min_wal_size = 1GB max_wal_size = 2GB max_worker_processes = 16 max_parallel_workers_per_gather = 8 max_parallel_workers = 16
Following is the routing logic I'm using:
route{
if (is_method("INVITE")) { $var(inc) = $(ct{param.value,tgrp}); xlog("L_INFO","CONTACT : $var(inc)" ); xlog("L_INFO","from number : $rU" ); if($var(inc)!=0) route(customer); route(block);
} }
route[customer] { sql_query("cb", "select caid from customeridentification where trunk='$var(inc)'", "ra"); $var(cid)=$dbr(ra=>[0,0]); sql_result_free("ra"); xlog("L_INFO","cid: $var(cid) \n");
sql_query("cb", "select routetablename from carrieraccount where caid=$var(cid)", "ra"); $var(tid)=$dbr(ra=>[0,0]); sql_result_free("ra");
if($var(cid)!=0) route(query); else route(block);
}
route[query] {
#sql_query("cb", "select supplierid from route_$var(cid) where prefix @>'$rU' order by prefix limit 1", "ra"); sql_query("cb", "select get_routing('$var(tid)','$rU')", "ra"); $var(sup)=$dbr(ra=>[0,0]); sql_result_free("ra"); xlog("L_INFO","supplieris: $var(sup) \n"); #$var(x)=$(var(sup){s.replace,|,}{s.len})/4;
$var(a)=$(var(sup){s.len}); $var(z)=$(var(sup){s.replace,|,}); $var(b)=$(var(z){s.len}); $var(suplen)=$var(a) - $var(b);
if($var(sup)!=0) route(send); else route(block); } route[send] { xlog("L_INFO","Inside Send \n"); $var(i)=0; append_to_reply("Contact:"); while($var(i)<$var(suplen) + 1) { $var(s)=$(var(sup){s.select,$var(i),|}); $var(s)=$(var(s){s.select,0,;}); append_to_reply("<sip:$rU;tgrp=$(var(s){s.ltrim})@ xxx.xxx.xxx.xxx:5060;user=phone>"); if($var(i)<$var(suplen)) append_to_reply(","); $var(i)=$var(i)+1; } append_to_reply("\r\n"); sl_send_reply("300","Multiple Choices"); exit; }
route[block] { xlog("L_INFO","INSIDE BLOCK" ); append_to_reply("Contact:sip:$rU;tgrp=999999@xxx.xxx.xxx.xxx:5060;user=phone\r\n"); sl_send_reply("300","Multiple Choices"); exit; }
How can we enhance the Kamailio response in case of load on the postgresql server.
Regards, Ali Taher
Ali,
If Kamailio is performing a database-bound workload, there's no way to make it respond faster if the database is being slow. Excluding things like caching of route responses, how would that be logically possible? :-)
Since we use PostgreSQL (and prefix_range) very extensively, I can say that such extreme slow-downs when loading data are abnormal; relational databases in general, and Postgres's MVCC in particular, are specifically designed to deal with concurrently servicing intensive read operations amidst bulk writes. Speculating purely a priori, these delays are probably caused by very high I/O demand of a slow storage subsystem; you can attempt to ascertain that by running 'iostat -x 1' while loading the new data and looking at percentage utilisation on the relevant storage interface, or with 'iotop' or similar tools.
But if the database responds slowly due to high background I/O load, you can't make Kamailio render an answer any faster. About the only thing you can do is to try mitigate the negative effects of this on the SIP level:
(1) Send a '100 Trying' pre-emptively before initiating the query; this will dampen the retransmissions that otherwise occur, and whose proliferation could cause a positive feedback loop and deepen your problems in a database slow-down scenario;
(2) Do asynchronous processing of the SQL query with t_suspend() / t_continue() -- though, you should carefully weigh the downsides of this given the (small) additional overhead of suspending/resuming every transaction under normal operating conditions.
For more background on this topic, consider a look at my blog post on the subject from some years ago:
http://www.evaristesys.com/blog/tuning-kamailio-for-high-throughput-and-perf...
Hope that helps!
Cheers,
-- Alex
PS. You may wish to escape the value of '$rU' and not lift it directly into your SQL queries, e.g.
https://www.kamailio.org/wiki/cookbooks/5.3.x/transformations#sescapecommon
https://www.kamailio.org/wiki/cookbooks/5.3.x/transformations#sqlval
Otherwise, you may be exposing yourself to a possible SQL injection attack, i.e. if I get creative with what I put in the user part of the request URI in a way that doesn't jam Kamailio's SIP parser.
Thanks Alex for drawing my attention regarding escaping $rU before using it in sql queries. But I'm not sure where to use sql.val in this case ? Do you mean I can use either {s.escape.common} or {sql.val} ?
Regarding the 100 trying , should I put modparam("tm", "auto_inv_100_reason", "Trying") in the beginning of if (is_method("INVITE")) block ?
Regards, Ali Taher
-----Original Message----- From: sr-users sr-users-bounces@lists.kamailio.org On Behalf Of Alex Balashov Sent: Tuesday, December 10, 2019 11:21 AM To: Kamailio (SER) - Users Mailing List sr-users@lists.kamailio.org Subject: Re: [SR-Users] Kamailio delayed reponse in case of database load
Ali,
If Kamailio is performing a database-bound workload, there's no way to make it respond faster if the database is being slow. Excluding things like caching of route responses, how would that be logically possible? :-)
Since we use PostgreSQL (and prefix_range) very extensively, I can say that such extreme slow-downs when loading data are abnormal; relational databases in general, and Postgres's MVCC in particular, are specifically designed to deal with concurrently servicing intensive read operations amidst bulk writes. Speculating purely a priori, these delays are probably caused by very high I/O demand of a slow storage subsystem; you can attempt to ascertain that by running 'iostat -x 1' while loading the new data and looking at percentage utilisation on the relevant storage interface, or with 'iotop' or similar tools.
But if the database responds slowly due to high background I/O load, you can't make Kamailio render an answer any faster. About the only thing you can do is to try mitigate the negative effects of this on the SIP level:
(1) Send a '100 Trying' pre-emptively before initiating the query; this will dampen the retransmissions that otherwise occur, and whose proliferation could cause a positive feedback loop and deepen your problems in a database slow-down scenario;
(2) Do asynchronous processing of the SQL query with t_suspend() / t_continue() -- though, you should carefully weigh the downsides of this given the (small) additional overhead of suspending/resuming every transaction under normal operating conditions.
For more background on this topic, consider a look at my blog post on the subject from some years ago:
http://www.evaristesys.com/blog/tuning-kamailio-for-high-throughput-and-perf...
Hope that helps!
Cheers,
-- Alex
PS. You may wish to escape the value of '$rU' and not lift it directly into your SQL queries, e.g.
https://www.kamailio.org/wiki/cookbooks/5.3.x/transformations#sescapecommon
https://www.kamailio.org/wiki/cookbooks/5.3.x/transformations#sqlval
Otherwise, you may be exposing yourself to a possible SQL injection attack, i.e. if I get creative with what I put in the user part of the request URI in a way that doesn't jam Kamailio's SIP parser.
-- Alex Balashov | Principal | Evariste Systems LLC
Tel: +1-706-510-6800 / +1-800-250-5920 (toll-free) Web: http://www.evaristesys.com/, http://www.csrpswitch.com/
_______________________________________________ Kamailio (SER) - Users Mailing List sr-users@lists.kamailio.org https://lists.kamailio.org/cgi-bin/mailman/listinfo/sr-users
On Thu, Dec 12, 2019 at 02:39:03PM +0000, Ali Taher wrote:
Thanks Alex for drawing my attention regarding escaping $rU before using it in sql queries. But I'm not sure where to use sql.val in this case ? Do you mean I can use either {s.escape.common} or {sql.val} ?
I think either one works for this case, and I use {s.escape.common} myself and am comfortable with that, but {sql.val} is the one that is _specifically_ contemplated for SQL injection prevention.
Regarding the 100 trying , should I put modparam("tm", "auto_inv_100_reason", "Trying") in the beginning of if (is_method("INVITE")) block ?
Well, let's take a step back. Are you creating any transactions? If not, TM settings are irrelevant.
In more typical uses of Kamailio, a "100 Trying" is sent when a TM transaction is created, which is most typically upon t_relay().
However, with a redirect server, you're not doing any relaying, and most likely not creating any transactions anyway; simple data query replies via redirect are usually--and prudently--stateless.
So, a simple
sl_send_reply("100", "Trying");
will do.
-- Alex
Sorry I meant putting modparam("tm", "auto_inv_100_reason", "Trying") as parameter. As per tm module , auto_inv_100 parameter is by default set as 1 , but still Kamailio is not sending it, is there some function that trigger it ?
-----Original Message----- From: sr-users sr-users-bounces@lists.kamailio.org On Behalf Of Ali Taher Sent: Thursday, December 12, 2019 4:39 PM To: Kamailio (SER) - Users Mailing List sr-users@lists.kamailio.org Subject: Re: [SR-Users] Kamailio delayed reponse in case of database load
Thanks Alex for drawing my attention regarding escaping $rU before using it in sql queries. But I'm not sure where to use sql.val in this case ? Do you mean I can use either {s.escape.common} or {sql.val} ?
Regarding the 100 trying , should I put modparam("tm", "auto_inv_100_reason", "Trying") in the beginning of if (is_method("INVITE")) block ?
Regards, Ali Taher
-----Original Message----- From: sr-users sr-users-bounces@lists.kamailio.org On Behalf Of Alex Balashov Sent: Tuesday, December 10, 2019 11:21 AM To: Kamailio (SER) - Users Mailing List sr-users@lists.kamailio.org Subject: Re: [SR-Users] Kamailio delayed reponse in case of database load
Ali,
If Kamailio is performing a database-bound workload, there's no way to make it respond faster if the database is being slow. Excluding things like caching of route responses, how would that be logically possible? :-)
Since we use PostgreSQL (and prefix_range) very extensively, I can say that such extreme slow-downs when loading data are abnormal; relational databases in general, and Postgres's MVCC in particular, are specifically designed to deal with concurrently servicing intensive read operations amidst bulk writes. Speculating purely a priori, these delays are probably caused by very high I/O demand of a slow storage subsystem; you can attempt to ascertain that by running 'iostat -x 1' while loading the new data and looking at percentage utilisation on the relevant storage interface, or with 'iotop' or similar tools.
But if the database responds slowly due to high background I/O load, you can't make Kamailio render an answer any faster. About the only thing you can do is to try mitigate the negative effects of this on the SIP level:
(1) Send a '100 Trying' pre-emptively before initiating the query; this will dampen the retransmissions that otherwise occur, and whose proliferation could cause a positive feedback loop and deepen your problems in a database slow-down scenario;
(2) Do asynchronous processing of the SQL query with t_suspend() / t_continue() -- though, you should carefully weigh the downsides of this given the (small) additional overhead of suspending/resuming every transaction under normal operating conditions.
For more background on this topic, consider a look at my blog post on the subject from some years ago:
http://www.evaristesys.com/blog/tuning-kamailio-for-high-throughput-and-perf...
Hope that helps!
Cheers,
-- Alex
PS. You may wish to escape the value of '$rU' and not lift it directly into your SQL queries, e.g.
https://www.kamailio.org/wiki/cookbooks/5.3.x/transformations#sescapecommon
https://www.kamailio.org/wiki/cookbooks/5.3.x/transformations#sqlval
Otherwise, you may be exposing yourself to a possible SQL injection attack, i.e. if I get creative with what I put in the user part of the request URI in a way that doesn't jam Kamailio's SIP parser.
-- Alex Balashov | Principal | Evariste Systems LLC
Tel: +1-706-510-6800 / +1-800-250-5920 (toll-free) Web: http://www.evaristesys.com/, http://www.csrpswitch.com/
_______________________________________________ Kamailio (SER) - Users Mailing List sr-users@lists.kamailio.org https://lists.kamailio.org/cgi-bin/mailman/listinfo/sr-users _______________________________________________ Kamailio (SER) - Users Mailing List sr-users@lists.kamailio.org https://lists.kamailio.org/cgi-bin/mailman/listinfo/sr-users