IVR系統(tǒng)與中間件
通過IVR實現(xiàn)的業(yè)務都是用戶實時參與的,具有一定的實時性,每筆事務的信息量較小,所以,都屬于典型的聯(lián)機事務處理(OLTP)業(yè)務。隨著IVR單臺集成度的不斷提高,使語音呼叫的密度大大增加,形成了對IVR后臺業(yè)務數(shù)據(jù)庫的大量并發(fā)訪問,對后臺數(shù)據(jù)庫壓力也大大增加。
現(xiàn)在處理大量并發(fā)OLTP訪問的通用方式是利用中間件技術,以減少后臺數(shù)據(jù)庫的負擔,降低頻繁的數(shù)據(jù)庫連接與斷開帶來的系統(tǒng)開銷,縮短事務處理的時間,提高數(shù)據(jù)訪問的效率,同時,利用交易中間件,還可以保證交易處理的完整性,避免可能引起的數(shù)據(jù)不一致。但在IVR系統(tǒng)中使用中間件和中間件的傳統(tǒng)使用方式有所不同。傳統(tǒng)上中間件的使用是單客戶端——單訪問,而在IVR中有可能是單客戶端——多并發(fā)訪問,這種不同給整個系統(tǒng)的實現(xiàn)帶來了挑戰(zhàn),只有采用特定的手段,才能使兩者緊密結合在一起,形成一個高性能的IVR系統(tǒng)。
當前流行的優(yōu)秀中間件有BEA TUXEDO,IBM TXSeries,TONG LINK/EASY等產(chǎn)品,本文僅對BEA TUXEDO在IVR中的使用進行闡述。
IVR系統(tǒng)的實現(xiàn)方式
下面是當前流行的IVR實現(xiàn)方式(以單機900線的IVR為例):
1. 單線程實現(xiàn)
此方式利用了有限狀態(tài)機的原理,利用一個線程不斷地依次監(jiān)控話路的狀態(tài),并執(zhí)行相應的操作,并完成其狀態(tài)的遷移。要使一次輪詢的時間足夠小,程序中執(zhí)行的單個操作以及狀態(tài)的遷移,都必須只占用極短的時間,也就是說,程序中只能使用非阻塞(異步)的操作方式。
2. N線程實現(xiàn)
該實現(xiàn)方式和單線程方式的原理是一樣的,只是基于系統(tǒng)穩(wěn)定和處理能力方面的考慮,利用三個(或N個)線程分擔處理呼叫,這樣每個線程分擔300(900/N)線語音呼叫。同樣,程序中只能使用非阻塞(異步)的操作方式。
3. 多線程實現(xiàn)
呼叫處理上的多線程方式和前面介紹的單/N線程方式的實現(xiàn)原理有著本質(zhì)的區(qū)別,每當有呼叫時,系統(tǒng)就產(chǎn)生一個線程,用來監(jiān)控、跟蹤用戶操作的全過程,當呼叫結束后,此線程也結束。由于線程間互不影響,線程內(nèi)部可以采用阻塞(同步)的方式進行數(shù)據(jù)操作。
TUXEDO編程接口
TUXEDO服務器端為了保證與多個客戶端的通信,為每個客戶端建立一塊獨立的連接資源,稱為上下文(Context);而客戶端本身也分配了專用的資源,用來存儲發(fā)送/接收的數(shù)據(jù)。在新版的TUXEDO中,每個Context分別對應一個User License。
需要特別注意的是,TUXEDO對每個應用連接的訪問請求進行了限制,具體來說,就是在一個Context上,未完成的訪問請求數(shù)目不能超過50個,如果到達了50個,后續(xù)的請求就會返回“Elimit”的錯誤,直到請求隊列長度小于50為止。
1.單線程與多線程模式
在TUXEDO中,涉及單線程還是多線程的關鍵API是tpinit,主要作用是使Server端分配相應的資源,并建立連接。涉及到的API定義如下:tpinit(),tpgetctxt(),tpsetctxt()。
(1)單線程/進程
在單線程/進程模式下,通過調(diào)用tpinit,使Server端為每個Client端建立一個獨立的Context。如圖1所示,每個客戶端都利用一個單獨的連接與服務器進行通信,獨享一個請求隊列。
在單線程/進程的模式下,TUXEDO API的使用不需要任何專門設置:
tpinit( (TPINIT *)NULL) //建立連接
(2)多線程
在多線程模式下,調(diào)用tpinit就Server端為每個線程建立一個獨立的Context。如圖2所示,每個線程利用一個單獨的連接與服務器進行通信,獨享一個請求隊列。
在多線程的模式下,TUXEDO API的使用按以下步驟進行:
Ⅰ.在父進程中分配tpinit參數(shù)空間:
tpinitbuf = tpalloc(TPINIT, NULL, TPINITNEED(0));
Ⅱ.在父進程中設置多線程(多上下文)標記:
tpinitbuf->flags = TPMULTICONTEXTS;
Ⅲ.在線程中建立與Server連接,分配獨立Context資源: tpinit(tpinitbuf);
Ⅳ.在線程中保存Context資源句柄:tpgetctxt(&ctxt, 0);
Ⅴ.在線程中設置此線程使用的Context資源:tpsetctxt(ctxt, 0);
Ⅵ.線程中繼續(xù)其他API使用,使用方式不受影響。
注:TUXEDO7.1(含)以后的版本,才支持此多線程模式。
(3)偽多線程
所謂偽多線程模式,是指整個應用利用了多線程機制,在每個線程中也調(diào)用tpinit建立了與TUXEDO Server端的應用連接,但是,實際上Server端并沒有為每個線程建立一個獨立的Context,而是所有線程共享一個Context資源。如圖3所示,所有線程都利用一個共享的連接與服務器進行通信,共享一個請求隊列。
2.同步/異步調(diào)用模式
TUXEDO的請求/響應方式有同步和異步兩種。同步方式中,請求方要一直等待到有響應后,再執(zhí)行其他操作,也稱為阻塞方式; 異步方式中,請求方發(fā)送出請求后,立即得到一個響應句柄,繼續(xù)執(zhí)行其他操作,在合適的時候,再利用響應句柄,得到此請求的響應結果,也稱為非阻塞方式。
涉及到API定義如下: tpcall(),tpacall(),tpgetreply()。其中,tpcall是同步調(diào)用方式,tpacall是發(fā)起異步請求,tpgetreply是得到異步請求的結果。
需要注意的是,只有將tpacall和tpgetreply的參數(shù)flags設置為TPNOBLOCK,才能實現(xiàn)真正的非阻塞方式,否則,僅僅能夠?qū)崿F(xiàn)發(fā)送請求和取結果的異步分離,不能保證請求和取結果兩個動作本身的非阻塞化。
前面我們提到,TUXEDO對每個Context上未完成的訪問請求數(shù)目進行了限制,不能超過50個,這個限制對于同步/異步方式同樣有效,即未完成的tpcall的數(shù)目,或者已經(jīng)tpacall成功,但是未用tpgetreply成功取回結果的數(shù)目,都不能超過50個。
IVR與TUXEDO的結合
1. IVR單線程實現(xiàn)
在單進程/線程IVR中,由于只有一個進程/線程,所以,利用TUXEDO的單線程/進程方式即可,考慮到數(shù)據(jù)訪問的速度不可能一直穩(wěn)定在毫秒級,所以,必須利用TUXEDO真正的異步調(diào)用模式,保證整個IVR系統(tǒng)輪詢和狀態(tài)遷移的時效性。
這里要注意900線的IVR存在一個Context只能對應50個未完請求的限制。但900線IVR中,超過50個并發(fā)TUXEDO請求的可能性是存在的,而且在系統(tǒng)繁忙階段,一旦系統(tǒng)性能稍有下降,后臺數(shù)據(jù)庫操作時間超過3~5秒,在這段時間內(nèi),累積的tpacall請求超過50個的可能性非常大。
因此,對應一個大規(guī)模的IVR系統(tǒng),如果利用單線程來實現(xiàn),在其中又結合了TUXEDO, 由于不能突破50個的限制,很難提供高效、穩(wěn)定的實現(xiàn)方案。
2. IVR N線程實現(xiàn)
在N線程 IVR中,可以利用TUXEDO的單線程和多線程方式,甚至可以利用偽多線程方式,同樣,必須利用TUXEDO真正的異步調(diào)用模式。
如果利用TUXEDO單線程或者偽多線程方式,數(shù)字對比仍然是“900∶50”,和單線程IVR一樣的問題還會出現(xiàn)。如果我們利用TUXEDO多線程方式,數(shù)字對比就是“900∶N*50”,這樣,就可以解決單線程IVR中遇到的不能突破50個請求的限制問題。因此,對應一個大規(guī)模的IVR系統(tǒng),如果利用N線程實現(xiàn),在其中結合使用TUXEDO多線程方式,由于將限制擴大到了N*50,所以,系統(tǒng)繁忙階段,也能夠保證提供出高效、穩(wěn)定的實現(xiàn)方案。
3. IVR多線程實現(xiàn)
在多線程IVR中,同樣可以利用TUXEDO的單線程、多線程、偽多線程方式,根據(jù)我們對多線程IVR的分析,各線程相對獨立,互不影響,利用TUXEDO的同步調(diào)用模式就可以了。
如果利用TUXEDO單線程或者偽多線程方式,我們?nèi)匀粫龅健罢埱蟆毕拗茊栴}。如果利用TUXEDO多線程方式,則可以解決“請求”限制問題,但是,各線程頻繁地TPINIT、TPTERM會占用系統(tǒng)資源,而且多線程生成的多Context,并發(fā)占用了大量的license,如果license數(shù)量是60,那么這時遇到的問題將是license限制,購買大量的license也就意味著投資的增加,否則,系統(tǒng)繁忙階段,就不能提供穩(wěn)定的服務。
通過分析,我們發(fā)現(xiàn),每線IVR對應一個線程,占用一個Context,獨享50個請求的限制,非常浪費,可以考慮多個線程共享一個Context。
我們可以這樣實現(xiàn): 在父進程中通過9次tpinit可得到9個Context訪問句柄,將900線IVR分成9組,每組100線,每100線共享一個Context,在這100線各自對應的線程中,先調(diào)用tpsetctxt,指定此線程利用的Context,這樣就形成“100∶50”的比例關系,完全可以保證系統(tǒng)在繁忙階段提供高效的服務。IVR多線程實現(xiàn)方式如下圖所示:
在多線程的模式下,TUXEDO API的使用需要專門步驟:
(1) 在父進程中分配tpinit參數(shù)空間:
tpinitbuf = tpalloc(TPINIT, NULL, TPINITNEED(0));
(2) 在父進程中設置多線程(多上下文)標記:
tpinitbuf->flags = TPMULTICONTEXTS;
(3) 在父進程中建立與Server連接,分配獨立Context資源:tpinit(tpinitbuf);
(4) 在父進程中保存Context資源句柄:
tpgetctxt(&ctxt1, 0);
(5) 重復N次步驟(3)和(4)。
(6) 在某組IVR線程中都設置線程使用的共享Context資源:tpsetctxt(ctxtN, 0);
(7) 線程中繼續(xù)其他API使用,使用方式不受影響。
結論
由于IVR系統(tǒng)實現(xiàn)方式的不同,TUXEDO中間件使用方式的不同,系統(tǒng)規(guī)模的不同,為我們的系統(tǒng)設計提供了眾多組合的可能,同時,也只有了解這些不同的實現(xiàn)方式,才能在眾多組合中選擇出有效方案。
通過以上介紹,我們知道,從功能上說,大容量IVR系統(tǒng)與TUXEDO等中間件進行結合是一種趨勢。從系統(tǒng)實現(xiàn)上,我們也可以相信,IVR與TUXEDO一定可以提供一種有效的實現(xiàn)方式組合,架構出高效、穩(wěn)定、投資節(jié)省的IVR系統(tǒng)。