大家好,我本次分享的主題是FreeSWITCH高可用部署與云原生集群部署,主要是談一談從高可用到彈性伸縮的一些技術(shù)應(yīng)用。
具體包含以下相關(guān)內(nèi)容:雙機(jī)、三機(jī),到可彈性伸縮的通信集群建設(shè)經(jīng)驗(yàn),包含?對?通話、呼叫中?及?視頻會議、?志監(jiān)控等場景,涉及FreeSWITCH、Kamailio、WebRTC、MCU、SFU、Docker、K8S、ETCD、NATS、Loki等相關(guān)技術(shù)。
主要會介紹我們用到的一些技術(shù),希望能對大家有所幫助。上面提到的一些技術(shù)其實(shí)也不算是新技術(shù),通信技術(shù)已經(jīng)歷幾十年發(fā)展,早在二三十年前大家就已經(jīng)在研究高可用相關(guān)技術(shù)。不過因?yàn)樾聲r(shí)代的發(fā)展,最近大家開始關(guān)注云原生等相關(guān)技術(shù),相應(yīng)基礎(chǔ)設(shè)施產(chǎn)生一些變化,通信與互聯(lián)網(wǎng)的聯(lián)系也越來越緊密,由此產(chǎn)生了更多新的玩法。
01 單點(diǎn)故障
其實(shí),一切的起源都是來自“單點(diǎn)故障”這個(gè)問題,我們就由此展開來進(jìn)行介紹。
A和B兩個(gè)通信的實(shí)體,兩個(gè)電話(人)通過一臺服務(wù)器進(jìn)行通信,當(dāng)然這個(gè)服務(wù)器可以是FreeSWITCH,也可以是任何其它服務(wù)器。假設(shè)這臺服務(wù)器由于通信鏈路中斷或者是網(wǎng)絡(luò)連接中斷,A和B則無法完成通信,這就是單點(diǎn)故障的起源。
那要想解決這個(gè)單點(diǎn)故障,就需要另外的服務(wù)器通過迂回路由或是其它辦法來克服單點(diǎn)故障的問題。
02雙機(jī)HA
一般來說,克服這個(gè)單點(diǎn)故障的方法就是雙機(jī)HA(High Availability),即主備高可用。
雙機(jī)HA的主要原理是:有一臺主機(jī)和一臺備機(jī),假如主機(jī)出現(xiàn)問題斷連,備機(jī)可以接替成為主機(jī)繼續(xù)進(jìn)行工作,如此不斷進(jìn)行主備交換。主機(jī)與備機(jī)為同一IP地址,對于A和B來說可能感知的到或者根本感知不到主備機(jī)所進(jìn)行的切換,因?yàn)橥ㄓ崟r(shí)A和B看到的僅僅只是IP地址,當(dāng)任何一臺服務(wù)器切換到主機(jī)時(shí),它就占有了對外服務(wù)的IP地址,這個(gè)IP地址我們就叫做虛擬的IP,也叫業(yè)務(wù)IP或浮動IP。本身每臺服務(wù)器底層還有一個(gè)IP,但對外提供服務(wù)的IP(即A和B看到的IP)其實(shí)是虛擬IP。
這樣當(dāng)服務(wù)器發(fā)生切換的時(shí)候,A和B仍然是和原來的IP進(jìn)行通話,他們可能會感覺到網(wǎng)絡(luò)的短暫卡頓,然后恢復(fù)正常,而感知不到服務(wù)器是否有進(jìn)行切換,這就是主備高可用的原理。
為了實(shí)現(xiàn)主備高可用,由于主服務(wù)器和備服務(wù)器之間有一些數(shù)據(jù)需要同步,所以就需要一種數(shù)據(jù)同步機(jī)制。
當(dāng)然這個(gè)數(shù)據(jù)同步的機(jī)制有很多種,例如通過日志、消息隊(duì)列等等,在FreeSWITCH中主要是通過數(shù)據(jù)庫來同步這些數(shù)據(jù)。主服務(wù)器會實(shí)時(shí)將A和B(A和B可能有成千上萬個(gè))通話的數(shù)據(jù)寫入到數(shù)據(jù)庫當(dāng)中,備機(jī)可以在數(shù)據(jù)庫當(dāng)中查詢數(shù)據(jù),一旦發(fā)生主備切換,備機(jī)從數(shù)據(jù)庫當(dāng)中取得數(shù)據(jù),重新建立通話場景,A和B就可以繼續(xù)進(jìn)行通話。
在這種情況下,數(shù)據(jù)庫也就成為了一個(gè)單點(diǎn),為了解決這個(gè)問題,數(shù)據(jù)庫同樣需要主備高可用。
FreeSWITCH的主備切換原理:首先主機(jī)包含一個(gè)Param,參數(shù)為:
當(dāng)備機(jī)發(fā)生切換的時(shí)候,備機(jī)會執(zhí)行一個(gè) sofia recover 命令,從數(shù)據(jù)庫中取得數(shù)據(jù)重建通話的場景,向A和B發(fā)送 reINVITE。前面我們說A和B感知不到,其實(shí)也能感知到,因?yàn)锳和B收到了重新建連的邀請,繼續(xù)進(jìn)行通話。一般這個(gè)通話過程大概在1-3秒內(nèi)解決,A和B只是覺得會短暫的卡頓,不用掛斷重新呼叫。
我們先排除數(shù)據(jù)庫的影響(默認(rèn)數(shù)據(jù)庫是主備高可用的),來看FreeSWITCH的主備高可用。
為了能準(zhǔn)確感知進(jìn)行主服務(wù)器和備服務(wù)器之間的切換,需要有一個(gè)東西叫心跳(心跳線),一般心跳線在之前都是用串口線,因?yàn)樾奶皇呛唵蔚膫鲙讉€(gè)字節(jié)的信息,對帶寬的要求不大。但現(xiàn)在在一些虛擬機(jī)中,不包含物理的串口,就只能用網(wǎng)線來實(shí)現(xiàn)。通過一個(gè)網(wǎng)線,不停的有心跳,備機(jī)可以借此感知主機(jī)的狀態(tài),一旦產(chǎn)生主機(jī)崩潰、斷連,備機(jī)會接管IP。
當(dāng)然這個(gè)情況下也可能會產(chǎn)生誤判,考慮到心跳線本身的斷開影響,我們可以通過兩根心跳線或雙網(wǎng)卡的方法避免出現(xiàn)這種誤判的情況??傊?,我們需要更多的機(jī)制來保護(hù)系統(tǒng),避免出現(xiàn)兩個(gè)服務(wù)器同時(shí)綁定同一個(gè)IP,同時(shí)寫入服務(wù)器導(dǎo)致服務(wù)器錯(cuò)亂的情況產(chǎn)生。
當(dāng)然,這種情況下會有一些問題,兩臺機(jī)器作為一臺機(jī)器使用,可能會造成資源的浪費(fèi)。還有一套方式是負(fù)載分擔(dān)(Load Balance),A和B之間有50%的話務(wù)分別放置于兩臺主機(jī),兩臺主機(jī)可以同時(shí)達(dá)到滿負(fù)荷承載。但這種情況同樣存在一定問題,假設(shè)原本每臺可以承受一千路通話,兩臺配合總共可以承受兩千路通話,當(dāng)其中一臺主機(jī)出現(xiàn)問題,另一臺在滿負(fù)載的情況下,實(shí)際上系統(tǒng)的吞吐量只能達(dá)到一千,就會發(fā)生擁塞發(fā)生問題。
所以說一般主備負(fù)載分擔(dān)的情況下,我們會保證兩臺FreeSWITCH主機(jī)每臺的話務(wù)量不要超過其設(shè)計(jì)容量的50%,這樣是比較安全的。當(dāng)然,這樣算起來我們實(shí)際上還是有50%的浪費(fèi),我們也可以采取通信降級的策略,當(dāng)一臺主機(jī)出現(xiàn)故障時(shí),僅使用另外一臺主機(jī),根據(jù)實(shí)際業(yè)務(wù)需求,保證部分通話連接的正常使用。
不過負(fù)載分擔(dān)對于A和B會有一定的要求,前面我們說到主備的方式,A和B都只能看到一臺服務(wù)器(實(shí)際上是兩臺服務(wù)器),是一個(gè)IP地址。但是在負(fù)載分擔(dān)的情況下,A和B都能看到兩臺機(jī)器,這就需要一定的邏輯(在A和B上做),需要能夠分發(fā)比如將50%的話務(wù)量分到一臺主機(jī),剩余50%分到另外一臺主機(jī)。而且有時(shí)候兩臺主機(jī)的性能不一樣,可能一個(gè)是64核,另一個(gè)是32核,需要根據(jù)主機(jī)性能對話務(wù)量進(jìn)行分配,比如一個(gè)60%,一個(gè)40%。這樣就會對A的要求比較高,需要能夠感知主機(jī)來進(jìn)行負(fù)載的分發(fā)。
在實(shí)際的部署當(dāng)中,我們一般都是采用這樣的結(jié)構(gòu)(如圖所示)。FreeSWITCH作為媒體服務(wù)器,前面再放上代理服務(wù)器,一般是用Kamailio或者openSIPS做代理。Kamailio只代理SIP就是指處理通信的建立和分發(fā),一臺Kamailio后端可以放很多的FreeSWITCH。因?yàn)镕reeSWITCH要過媒體,要進(jìn)行錄音、質(zhì)檢、分析等等媒體的處理,所以FreeSWITCH的處理能力就不如Kamailio強(qiáng)。這樣前面放一個(gè)Kamailio,后端可以放很多FreeSWITCH進(jìn)行通信。
當(dāng)然Kamailio需要主備高可用,而Kamailio和FreeSWITCH之間是用Load Balance,這樣用HA+負(fù)載分擔(dān)的方式就完成了一種比較大的通信集群。而且由于A和B兩側(cè)的業(yè)務(wù)邏輯有可能會不一樣,比如說一側(cè)是中繼,一側(cè)是話務(wù)員是本次的系統(tǒng)電話,這時(shí)我們可以放兩個(gè)不同的Kamailio,管理起來會更方便一些。
當(dāng)然我們也可以使用一個(gè)Kamailio,將A和B放在一側(cè),但這樣的話腳本和邏輯的判斷上就會比較復(fù)雜。因?yàn)楸仨氁袛嗤ㄔ捠怯葾還是B過來的,還是從FreeSWITCH過來的,需要判斷呼叫的方向,邏輯會相對比較復(fù)雜。
還有一種情況就是異地災(zāi)備,什么是異地災(zāi)備?舉個(gè)例子,我們可能有兩個(gè)機(jī)房分別在北京和上海,都用FreeSWITCH和主備高可用,這樣平常主要通過北京的機(jī)房,一旦出現(xiàn)問題可以通過迂回路由經(jīng)由上海的機(jī)房進(jìn)行通信。
但是異地災(zāi)備同樣需要一些數(shù)據(jù)的同步,這就又對A提出了一定要求,因?yàn)锳面對的是北京和上海兩個(gè)機(jī)房。所以說高可用是無窮無盡的,只要有需求只要改架構(gòu)就需要相應(yīng)的考慮,但萬變不離其宗,其實(shí)就是HA和負(fù)載均衡這兩種邏輯。當(dāng)然具體地來說,A上可能靠DNS輪詢,也可以將北京或上海的地址直接寫進(jìn)設(shè)備當(dāng)中,自己執(zhí)行策略根據(jù)情況來進(jìn)行切換等等。
那么,我們來看B這一側(cè)。A和B進(jìn)行通話,有可能會呼叫進(jìn)來之后執(zhí)行IVR有些應(yīng)用,這些應(yīng)用同樣需要主備高可用。比如有人打電話進(jìn)來,Kamailio是負(fù)責(zé)信令的,F(xiàn)reeSWITCH負(fù)責(zé)媒體,但是具體的邏輯是由應(yīng)用來負(fù)責(zé)的,需要由它來告訴FreeSWITCH應(yīng)該什么時(shí)候處理媒體、什么時(shí)候錄音、放音等等,所以應(yīng)用側(cè)同樣需要主備高可用。
當(dāng)然,一般的這種IVR我們認(rèn)為它大體都是無狀態(tài)的,接入通話掛斷之后再接入一個(gè)新的通話同樣還是這個(gè)IVR,所以一般都會用負(fù)載分擔(dān)的方式,可以承擔(dān)多個(gè)IVR的業(yè)務(wù)。
但是有一些服務(wù)它是有狀態(tài)的,比如說呼叫中心當(dāng)中常用的ACD。ACD需要check坐席的狀態(tài),以及隊(duì)列的狀態(tài),有多少客戶在等待、有多少坐席在服務(wù)、哪個(gè)坐席正在跟客戶溝通、哪個(gè)坐席正處于空閑,它需要跟蹤這些狀態(tài)。一般來說對于這種有狀態(tài)的服務(wù),還是要采用主備高可用的方式。當(dāng)然,雙機(jī)HA同樣可能會出現(xiàn)兩臺機(jī)器同時(shí)發(fā)生問題的情況,這時(shí)候我們就擴(kuò)展到 —— 三機(jī)。
03Raft
三臺機(jī)器的場景更為麻煩,由此我們引入了一個(gè)協(xié)議叫做Raft,還有一個(gè)叫做PaxOS,不過現(xiàn)在比較常用的還是Raft協(xié)議。
Raft其實(shí)是一個(gè)共識協(xié)議,它的主要作用是做Log。首先它是用一個(gè)分布式的系統(tǒng),分布式系統(tǒng)主要是解決容錯(cuò)的問題。那么怎么解決呢?就是同步日志。比如一臺機(jī)器上的日志,我要將這些日志副本同步到其它的服務(wù)器上去,當(dāng)然我們說到的日志可能也是數(shù)據(jù),數(shù)據(jù)庫數(shù)據(jù)或者通話的數(shù)據(jù)或者是狀態(tài)的數(shù)據(jù)等等。一般來說Raft都是奇數(shù)的,因?yàn)槠渥裱贁?shù)服從多數(shù)的原則,通過投票來進(jìn)行選舉。
Raft中包含三個(gè)節(jié)點(diǎn),Leader(領(lǐng)導(dǎo))是一個(gè)主服務(wù)器,所有人會選舉選出一個(gè)Leader來,由Leader來決定什么時(shí)候修改數(shù)據(jù)。然后它會把這些數(shù)據(jù)同步給Follower(追隨者),所有的數(shù)據(jù)會從Leader上進(jìn)行修改,之后會同步到Follower上。正常的情況下,集群內(nèi)有Leader和Follower,數(shù)據(jù)就可以在服務(wù)器間進(jìn)行同步。但又一種情況是作為Leader的主服務(wù)器掛掉了,其它所有的服務(wù)器就會變?yōu)?a target="_blank">Candidate(候選者),有機(jī)會被選舉成為新的Leader,通過這個(gè)機(jī)制可以保證有一臺服務(wù)器是可以保存這些數(shù)據(jù)的。
但是它雖然能保存數(shù)據(jù)卻不能對外提供服務(wù),Raft集群規(guī)定其中有一臺主機(jī)負(fù)責(zé)寫數(shù)據(jù),另外兩臺負(fù)責(zé)備份,只有集群當(dāng)中有多數(shù)的主節(jié)點(diǎn)和備節(jié)點(diǎn)活著的時(shí)候,比如說3個(gè)死了1個(gè),則還可以繼續(xù)對外提供服務(wù)。但是如果是死了兩個(gè),就不能繼續(xù)對外提供服務(wù)了。
那么,這是為什么?如圖最右側(cè)我們來看,假設(shè)原來的主服務(wù)器與其它服務(wù)器斷開鏈接,此時(shí)它還是能正常進(jìn)行服務(wù)。而另外的兩臺服務(wù)器會根據(jù)當(dāng)前情況判斷,重新選舉出一臺作為主服務(wù)器。此時(shí),整個(gè)集群當(dāng)中就會同時(shí)出現(xiàn)兩臺主服務(wù)器產(chǎn)生沖突。所以一定要遵循少數(shù)服從多數(shù)的原則,只有當(dāng)整個(gè)集群中有多數(shù)的節(jié)點(diǎn)活著的時(shí)候才能對外提供服務(wù)。
當(dāng)然,如果我們說要把所有的ACD里面都要實(shí)現(xiàn)一個(gè)Raft是很難的。目前有一個(gè)應(yīng)用叫做ETCD,我們可以直接將服務(wù)連接到ETCD上,它會告訴我們誰是主誰是備。但是這樣又帶來了一個(gè)問題,本來三臺機(jī)器就可以,我們還需要另外再裝三臺ETCD,這樣會帶來更大的開銷和浪費(fèi),多用了一倍的資源。
但是當(dāng)我們的集群比較大的時(shí)候,比如除了ACD外我們還有其它服務(wù)如BCD、CDE等等。如果各種微服務(wù)的數(shù)量比較多,可以公用一個(gè)ETCD的話,相比較而言開銷也就沒那么大了。
簡單的總結(jié)一下:
雙機(jī)可以提?可靠性,但投?資源和獲得回報(bào)不成正?;
為了節(jié)省服務(wù)器,把不同的服務(wù)放到相同的物理服務(wù)器或虛擬機(jī)上,可能適得其反;
集群可以提?可靠性,但只有集群?夠?,資源才能有效利?;
雙機(jī)需要的服務(wù)器數(shù)量是偶數(shù)的,?少2臺;
分布式系統(tǒng)(集群)需要的服務(wù)器數(shù)量是奇數(shù)的,?少3臺。
一般的來說,有一臺FreeSWITCH服務(wù)器就夠了,如果想雙機(jī)設(shè)備的話就需要兩臺服務(wù)器,如果需要數(shù)據(jù)庫的話就是四臺。有可能還會放Nginx代理HTTP,還有可能會放Kamailio來代理SIP。當(dāng)然我們主要使用NATS,這是一個(gè)消息隊(duì)列。然后使用Etcd來做選主,有可能使用Redis來做緩存,還有可能做日志、監(jiān)控等各種服務(wù)器。還有可能rtpengine、存儲、業(yè)務(wù)系統(tǒng)......
總之,要是想建立一個(gè)可靠的系統(tǒng)至少需要十幾臺服務(wù)器,它對外所能提供的服務(wù)能力也超不過一臺服務(wù)器的服務(wù)。所以如果集群規(guī)模比較小,那就沒有什么意義,投入天文數(shù)字但實(shí)際上整體的收益很小。如果想要集群規(guī)模做的足夠大,類似云服務(wù),那么投入多少臺服務(wù)器其實(shí)都無所謂了,因?yàn)殚_銷是相對比較小了。當(dāng)然,這些最終還是需要根據(jù)業(yè)務(wù)本身來做權(quán)衡。
04XSwitch實(shí)踐
接下來介紹一些XSwitch的具體實(shí)踐。
XSwitch即XSwitch集群,一般來說最小的配置就是雙機(jī),主備高可用,F(xiàn)reeSWITCH和PostgreSQL放在一塊。
對于有一定預(yù)算的客戶,我們就建議他們將數(shù)據(jù)庫獨(dú)立出來,放在獨(dú)立的服務(wù)器上,總共4臺服務(wù)器。Nginx一般我們可以跟FreeSWITCH放在一起,然后有可能我們會放Kamailio。
如果預(yù)算充足也可以將它們都獨(dú)立出來,這樣后面就可以放更多的FreeSWITCH。
再就是異地的,負(fù)載分擔(dān)。
因?yàn)閃ebRTC只有媒體, 所以就是直接到FreeSWITCH,信令可以通過Nginx或者Kamailio實(shí)現(xiàn),因?yàn)樾帕疃际腔赪ebSocket來做的,這是WebRTC的高可用。當(dāng)然,媒體前面我們提到有個(gè)rtpengine也可以做代理,可以把后臺的FreeSWITCH隱藏起來,這就是更復(fù)雜的一些應(yīng)用了。
XSwitch如何實(shí)現(xiàn)多租戶呢?其實(shí)我們有好多種方式,一種就是Per tenant per FreeSWITCH,每個(gè)租戶給它一臺FreeSWITCH,每個(gè)FreeSWITCH一個(gè)Docker,使用同一個(gè)數(shù)據(jù)庫,我們用的是PostgreSQL,里面可以天然的分Schema,每個(gè)Schema都是彼此隔離的,這樣的話可以給每個(gè)租戶分一個(gè)Schema。
也就是每個(gè)租戶一個(gè)域名,每個(gè)租戶一個(gè)Docker,每個(gè)租戶一個(gè)Schema,數(shù)據(jù)庫是同一個(gè)。前面放一個(gè)sbc,用Kamailio來做信令的代理,當(dāng)然sbc現(xiàn)在我們是單機(jī)部署的,以后也可以做HA。
具體的代碼其實(shí)我們就寫了一個(gè)映射表,因?yàn)槲覀儸F(xiàn)在集群規(guī)模比較小,還沒有放數(shù)據(jù)庫,通過域名就可以直接查到對應(yīng)的IP地址,來進(jìn)行分發(fā)。我們使用的是Kamailio+Lua。
在應(yīng)用側(cè)我們就使用了NATS。NATS是一個(gè)消息隊(duì)列,所以它具有消息隊(duì)列的一些基本特性,比如說Pub/Sub來進(jìn)行推送,還有一個(gè)就是Queue Groups,可以通過一個(gè)隊(duì)列進(jìn)行訂閱,這種情況下就可以做負(fù)載分擔(dān)。生產(chǎn)者生成了一條消息,消費(fèi)者可以負(fù)載分擔(dān)的消費(fèi)這些消息。
那么我們就用它來做集群的應(yīng)用:來了一個(gè)電話到Kamailio進(jìn)行分發(fā),分發(fā)到不同的FreeSWITCH,通過NATS分配給不同的Controller,這個(gè)Controller就是應(yīng)用側(cè),應(yīng)用側(cè)會控制通話的邏輯。
當(dāng)來了一個(gè)電話到了FreeSWITCH以后,NATS會分給某一個(gè)Controller,這個(gè)時(shí)候Controller就跟某一臺FreeSWITCH建立了一個(gè)虛擬的對應(yīng)關(guān)系,在這個(gè)電話的生存期間它就可以控制這路電話的通話行為和呼叫流程。
當(dāng)然,這個(gè)Controller也可以額外增加,F(xiàn)reeSWITCH也可以。NATS也連接到了Kamailio,Kamailio也可以感知到NATS,這時(shí)候如果我們擴(kuò)展、彈性伸縮,F(xiàn)reeSWITCH不夠用我們又加了幾臺,這個(gè)時(shí)候FreeSWITCH就會給NATS發(fā)一個(gè)消息,NATS會把這個(gè)消息發(fā)給Kamailio,Kamailio就感知到我現(xiàn)在有了6臺FreeSWITCH,它就會重新計(jì)算它的路由表,我們用的是dispatcher模塊,重載dispatcher模塊的數(shù)據(jù),然后它就會把新的通話分發(fā)給新的FreeSWITCH,這樣就完成了一個(gè)擴(kuò)容,這也就是彈性伸縮。
彈性伸縮的“伸”還是比較容易的,只需要往上加機(jī)器就行?!翱s”才是比較困難的,有時(shí)候需要等所有的話務(wù)量都去掉之后才能進(jìn)行。
當(dāng)然,“縮”還有一個(gè)就是可能大家都認(rèn)為的,比如其中一臺機(jī)器掛掉了,我重啟一下。其實(shí)重啟之后它就不是原來那臺機(jī)器了,我們這邊用的都是FreeSWITCH的UUID,重啟之后UUID會發(fā)生改變。雖然IP地址有可能變有可能不變,但我們認(rèn)為它是變了,因?yàn)槭且慌_新的機(jī)器了。
所以說在這個(gè)集群里面,即使是重啟了以后,它也不是原來那臺機(jī)器了。我們在哲學(xué)里曾學(xué)過:“?不能兩次踏?同?條河流”就是這個(gè)意思。如果想要做集群,那就要把它做成是無狀態(tài)的最好,這樣才能大規(guī)模的分發(fā)和復(fù)用。
所以說使用的機(jī)制主要是Docker和K8S。當(dāng)然,將FreeSWITCH放在K8S里面并不容易,首先我們先放到Docker里面,先完成容器化,然后再放到K8S里面。因?yàn)镵8S它是一個(gè)網(wǎng)絡(luò),優(yōu)點(diǎn)就是不知道它在哪臺物理機(jī)上運(yùn)行,想啟動就啟動,想關(guān)閉就關(guān)閉。但是FreeSWITCH、SIP,尤其是RTP,它們有一大堆的端口,就會比較麻煩。
那么,我們是怎么做的呢?我們使?Kamailio做Ingress,負(fù)責(zé)信令進(jìn)來。Kamailio還是雙機(jī),然后它分發(fā)給后端的FreeSWITCH,F(xiàn)reeSWITCH不夠用了就執(zhí)行Scale Up,相反就Scale Down。
但是具體的我們使用了一個(gè)東西叫做VIP,這個(gè)VIP是我們自己寫的一個(gè)協(xié)議,因?yàn)楝F(xiàn)在的K8S主要是針對HTTP來優(yōu)化的,對SIP類的應(yīng)用就會比較麻煩。所以我們就自己寫了一個(gè)應(yīng)用,在每臺物理機(jī)或者虛擬機(jī)上,都有一個(gè)VIP的服務(wù)。當(dāng)FreeSWITCH啟動的時(shí)候,同樣每臺機(jī)器上也只啟動一個(gè)FreeSWITCH,它告訴VIP打開一對端口,然后VIP就把這些端口通過iptables打開,就可以正常分發(fā)了。萬一這臺機(jī)器死了之后,端口就是空著不用也無所謂,因?yàn)镕reeSWITCH也死了,不會有服務(wù)往這上面發(fā)了。當(dāng)機(jī)器重啟之后,端口仍舊還是使用這幾個(gè)端口段,所以也沒有問題。這種情況下RTP就是直接到FreeSWITCH,前端還是通過Kamailio進(jìn)行分發(fā)SIP。
這種應(yīng)用就是每個(gè)Node上只運(yùn)??個(gè)FreeSWITCH,每個(gè)Node上運(yùn)??個(gè)vip。當(dāng)然,VIP這個(gè)東西叫做DaemonSet,每臺機(jī)器上只起一個(gè)VIP服務(wù),這個(gè)服務(wù)也在集群當(dāng)中。通過這種方式我們就可以動態(tài)的打開SIP和RTP的端口,這樣可以做彈性的伸縮。這是我們做的一些應(yīng)用。
當(dāng)然,如果一個(gè)Node 64核、128核,能不能運(yùn)行多個(gè)FreeSWITCH?可以的,其實(shí)這樣就需要按端口段來分開,可以做成兩個(gè)Pod,一個(gè)占10000-20000,另一個(gè)占30000-50000。這樣的話通過這種方式,保證兩個(gè)FreeSWITCH同時(shí)啟動的時(shí)候互不影響,同樣管理也會更加復(fù)雜。
下面是在Kamailio中使用NATS的一些基本代碼:
05會議
下面還有一種就是會議。
我們平常的負(fù)載分擔(dān)分發(fā)是盡量平均的分發(fā)到不同的FreeSWITCH,這是最好的分發(fā)策略。但是會議不能,會議需要把呼入同一個(gè)會議號的,都分發(fā)到同一臺FreeSWITCH上。這里我們用了Kamailio中一個(gè)“2”的策略,“hash over to URI”。
當(dāng)然,實(shí)際使用的時(shí)候會議規(guī)模比較大,一臺FreeSWITCH不能滿足,我們需要放到多臺FreeSWITCH上,這個(gè)時(shí)候我們就用了“7”這個(gè)策略,“hash over the content of PVs string”。我們可以自己創(chuàng)建一個(gè)字符串,只要是計(jì)算出來不同的終端,它在一個(gè)組內(nèi),通過分組,只要計(jì)算出來字符串是相同的,就會分配到同一臺FreeSWITCH。
視頻會議有這么幾種方式:Mesh是無狀態(tài)的,MCU就是所有的東西都通過中間融屏,SFU是通過它進(jìn)行分發(fā),不融屏。
我們也會做會議的級聯(lián),通過多個(gè)FreeSWITCH級聯(lián)來實(shí)現(xiàn)較大規(guī)模的會議。
級聯(lián)也會出現(xiàn)一個(gè)問題,叫做“看對眼”,就是出限類似無限循環(huán)的效果,如上圖中的樣子。
那么,我們是怎么做的?我們在會議當(dāng)中,首先我們說怎么將兩個(gè)FreeSWITCH的會議串起來。
很簡單,就是在第一臺FreeSWITCH里面 conference 3000(會議號),然后呼叫另外一臺FreeSWITCH也呼3000,另外一臺FreeSWITCH收到呼叫以后,直接conference 3000 加入會議,這個(gè)時(shí)候就是把兩個(gè)會議進(jìn)行串起來。
串起來之后,我們就可以設(shè)置兩個(gè)畫布,第一個(gè)是“video_initial_canvas”,表示我把我的圖像放在哪個(gè)canvas上;第二個(gè)是“video_initial_watching_canvas”,表示我看哪個(gè)canvas。
通過這種方式,我們也完成了MCU和SFU的互通。我們現(xiàn)在打通了Agora、TRTC以及MediaSoup之類的應(yīng)用。
06日志
最后一個(gè)我想說的就是日志。
日志很簡單,都有一些現(xiàn)成的服務(wù):
Homer是做SIP的日志的,它的實(shí)現(xiàn)原理就是FreeSWITCH或Kamailio插入一個(gè)Agent,會將收到的消息轉(zhuǎn)發(fā)給它,將SIP的圖畫出來;Loki就是存放日志的,我們會把所有的日志都發(fā)給它;另外還有Zabix、Grafana、Promuthus。
這里面關(guān)鍵的一點(diǎn)是,每天成千上萬路的通話并發(fā),我們需要知道哪一路通話跟哪一路是相關(guān)的。所以說要有一個(gè)uuid,F(xiàn)reeSWITCH里面每一路通話都有一個(gè)uuid,這個(gè)UUID要跟call-id關(guān)聯(lián)起來。通過call-id就可以找到對應(yīng)的uuid,通過uuid就可以找到另外一條腿的uuid。
上面是呼入,呼出的時(shí)候使用的是這個(gè)參數(shù):outbound-use-uuid-as-callid。
如果FreeSWITCH對外發(fā)出一路呼叫,在SIP當(dāng)中的Call-ID和內(nèi)部的uuid是一致的,這樣就可以找到它們的對應(yīng)關(guān)系,日志和SIP的對應(yīng)關(guān)系。
這樣的話,A進(jìn)來,通過A的Call-ID就可以找到uuid,通過B的uuid就可以找到對應(yīng)的Call-ID。通過Other-Leg-Unique-ID,這個(gè)在事件里面會有,或者Channel-Call-UUID,都能找到到對方,找到A和B。
07總結(jié)
最后,簡單的總結(jié)一下。通信的集群我們要用到各種各樣的開源軟件,要有雙機(jī)、三機(jī),彈性伸縮,包括?對?通話、呼叫中?及?視頻會議、?志監(jiān)控等場景。最終還是萬變不離其宗,不管使用的是任何軟件,它們的基本原理是不變的。
審核編輯:劉清
-
RTC
+關(guān)注
關(guān)注
2文章
542瀏覽量
66777 -
MCU技術(shù)
+關(guān)注
關(guān)注
0文章
19瀏覽量
5817 -
SFUD
+關(guān)注
關(guān)注
0文章
5瀏覽量
1073
原文標(biāo)題:FreeSWITCH高可用部署與云原生集群部署
文章出處:【微信號:livevideostack,微信公眾號:LiveVideoStack】歡迎添加關(guān)注!文章轉(zhuǎn)載請注明出處。
發(fā)布評論請先 登錄
相關(guān)推薦
評論