import bea.jolt.JoltRemoteService;
import bea.jolt.JoltSession;
import bea.jolt.JoltSessionAttributes;
public class SimpleApp {
public static void main(String[] args) {
JoltSession session;
JoltSessionAttributes sattr;
JoltRemoteService joltService;
String userName = "";
String userPassword = "";
String appPassword = "";
String userRole = "";
sattr = new JoltSessionAttributes();
sattr.setString(JoltSessionAttributes.APPADDRESS,
"http://XX.XX.X:8307");
sattr.setInt(JoltSessionAttributes.IDLETIMEOUT, 300);
session = new JoltSession(sattr, userName, userRole, userPassword,
appPassword);
joltService = new JoltRemoteService("testServiceName", session);
joltService.setString("sw01_1", "<Hello>");
joltService.setString("sw01_2", "<Hello>");
joltService.setString("sw01_3", "<Hello>");
joltService.setString("sw01_4", "<Hello>");
joltService.setString("sw01_5", "<Hello>");
joltService.setString("sw01_6", "<Hello>");
joltService.setString("sw01_7", "<Hello>");
joltService.setString("sw01_8", "<Hello>");
joltService.call(null);
}
}
摘要:
本《功略》集中了TUXEDO應用中,可能涉及到的所有時間參數,并分別對其進行詳細描述,不但對其出處、取值等基本屬性進行查證,而且,通過分析其內在的控制機制,給出設置建議,以期能夠達到透徹理解、方便查閱、準確使用的目的。
1 前言
金融、電信等眾多行業的綜合營業系統中,廣泛使用了TUXEDO交易中間件,用來處理大量并發的聯機事務處理(OLTP)業務。典型的OLTP業務,每筆業務的信息量較小,而且,具有一定的實時性,對時間的要求非常嚴格。
TUXEDO,聯系著DATABASE和客戶端軟件,憑借其多層次的超時控制機制,達到客戶端快速響應,服務器端穩定可靠的效果。
TUXEDO的多層次的超時控制機制中,涉及到的時間參數不少于10個,再加上與之緊密聯系的DATABASE中的幾個超時參數,確實比較復雜。遺憾的是,目前還沒有的專門的文檔對它們進行詳細說明,而是分散在不同的專題中分別說明,而且,不同的專題中,解釋的詳細程度也不一樣,在查閱過程中,多有不便。
本文試圖將這些參數集中起來,對每一個都加以詳細說明,并試圖解釋每個參數存在的原因。大部分參數時間長短的設置,除個別外,基本沒有固定的模式,只要了解它們的具體含義,并結合具體應用系統的實際要求,相信大家都能夠作出合理的配置。
2 全功略解讀
2.1 SCANUNIT
2.1.1 參數出處
UBBCONFIG配置文件 -> RESOURCES -> SCANUNIT 。
2.1.2 時間單位
秒,且必須為5的倍數。
2.1.3 取值范圍
大于0小于等于60中5的倍數,即{5,10,15,20,25,30,35,40,45,50,55,60}。
2.1.4 默認取值
10 。
2.1.5 用途解釋 ⑴
這個參數大家都會用,比較好理解,TUXEDO中,BBL是用來對Bulletin Board進行管理和監控的系統進程,它基于時間片的輪詢方式,時間片的大小就是SCANUNIT的值,SCANUNIT是Tuxedo對系統進行管理的最基本時間單位。每隔SCANUNIT,BBL對Bulletin Board進行一次檢查,看看有沒有超時的事務或阻塞的服務請求。后面講到的很多時間參數都是以SCANUNIT為單位。
2.1.6 超時后果
僅僅是個輪詢時間單位而已,到時間就輪詢,如此而已。
2.1.7 設置考慮
作為一個涉及到整個TUXDO系統的基本單位時間,如果業務需要,對時間參數控制比較嚴格,設置為5也不算小。如果系統業務對時間要求不嚴格,那就大點兒,60也沒什么不可以;畢竟頻繁輪詢是要耗費更多系統資源的,而任何對資源的不必要的消耗都是浪費。
2.2 SANITYSCAN
2.2.1 參數出處
UBBCONFIG配置文件 -> RESOURCES -> SANITYSCAN 。
2.2.2 時間單位
SCANUNIT 。
2.2.3 取值范圍
1 ~32767 。
2.2.4 默認取值
大約120/SCANUNIT。
2.2.5 用途解釋 ⑵
進行系統健全性檢查,主要包括Server進程狀態和Bulletin Board數據結構,檢查Server進程是否存活,如果已經不存在,會清理Bulletin Board中相應的數據項及IPC資源,并根據參數配置決定是否重新啟動,如果設了RESTART=Y,所占的Message Queue不會被清除,Queue中的Request得到保留,仍會被處理。如果是MP模式,BBL還會給DBBL發狀態消息。
2.2.6 超時后果
僅僅是個系統健康檢查的間隔時間而已,到時間就檢查,如此而已。
2.2.7 設置考慮
作為一個涉及到整個TUXDO系統健康檢查的間隔時間,如果系統處在一個穩定的運行環境中,網絡、數據庫、應用都很穩定,那這個參數可以大一些;如果運行環境不穩定,系統繁忙,而且Server進程經常因異常(如超時)而死掉,那就設置小一些。設置的原則和SCANUNIT一樣:不要隨意浪費系統資源。
2.3 BBLQUERY
2.3.1 參數出處
UBBCONFIG配置文件 -> RESOURCES -> BBLQUERY。
2.3.2 時間單位
SCANUNIT
2.3.3 取值范圍 ⑶
BBLQUERY必須大于等于SANITYSCAN,tmloadcf 時會強制檢查,如果設的值小于SANITYSCAN,tmloadcf會自動調整為SANITYSCAN。
2.3.4 默認取值
大約300/SCANUNIT。
2.3.5 用途解釋 ⑷
BBL檢查,在MP模式下,BBL會每隔一段時間都發送了" I am ok "心跳信息給DBBL,這個間隔就是BBLQUERY。
2.3.6 超時后果 ⑸
如果DBBL在規定時間間隔內沒有收到某個BBL的信息,DBBL它會主動發送Request給那個BBL,判斷其是否正常。(如果等了DBBLWAIT后仍然沒有回復,DBBL會認為那臺機器有問題,然后,將其隔離。)
2.3.7 設置考慮
此設置僅僅在MP模式下才起作用。
在MP模式下,如果TUXEDO系統需要對不穩定的運行環境可能發生的故障作出快速的反應,那么BBLQUERY要設置小一些,讓系統快速的自我檢查。考慮網絡傳輸時間、系統反應速度等因素,網絡速度越慢,系統負載越重,取值越大;反之亦然。
如果系統運行環境很穩定,利用其默認值即可,甚至可以更大數值。
2.4 DBBLWAIT
2.4.1 參數出處
UBBCONFIG配置文件 -> RESOURCES -> DBBLWAIT。
2.4.2 時間單位
SCANUNIT。
2.4.3 取值范圍
大于0。
2.4.4 默認取值
1和20/SCANUNIT中的較大者 。
2.4.5 用途解釋 ⑹
如果DBBL在規定時間間隔BBLQUERY內沒有收到某個BBL的"I AM OK"信息,它會發Request給那個BBL,其等待回復的時間就是DBBLWAIT。
2.4.6 超時后果 ⑺
DBBL等了DBBLWAIT后仍然沒有回復,DBBL會認為相關BBL的機器有問題,然后,將其隔離(partation)。
2.4.7 設置考慮
此設置僅僅在MP模式下才起作用。
在MP模式下,考慮網絡傳輸時間、系統反應速度等因素,網絡速率越大,系統負載越輕,此數值越小;反之亦然。
2.5 BLOCKTIME
2.5.1 參數出處
UBBCONFIG配置文件 -> RESOURCES -> BLOCKTIME。
2.5.2 時間單位
SCANUNIT。
2.5.3 取值范圍
大于0。
2.5.4 默認取值
大約60/SCANUNIT。
2.5.5 用途解釋
Client端阻塞請求(Blocking call)服務的超時值,BBL發現有超時的Request時,會給相應的Client端發超時信息。
此參數僅僅在"阻塞請求"的情況下起作用,因此,理解它,關鍵要理解什么是阻塞請求(Blocking call)?習慣上,我們將"阻塞請求"理解為"同步請求",將"異步請求"理解為"非阻塞請求",是源于將"<發送請求-得到結果>"這一過程看成為一個整體。如果是整體的同步操作,就認為是"阻塞請求";如果是分開異步的操作,就認為是"非阻塞請求"。
其實,異步操作中,同樣存在"阻塞請求",tuxedo中,tpacall和tpgetrply這兩個異步操作各自本身就是"阻塞請求",tpacall是將請求發送到請求隊列,tpgetrply是將從結果隊列中取出結果,如果沒有特殊的設置,這兩個操作本身都是阻塞的,BLOCKTIME將起作用。
以Request/Reply方式為例,將成功發送請求的時長設置為T1,將請求處理的時長(含排隊等待)設置為T2,將成功取得結果的時長設置為T3,那么在下面不同的情況下,將觸發BLOCKTIME,引起超時:
(1) tpcall()不在transaction中,flag為0,當T1+T2+T3 > BLOCKTIME時,發生超時 ;
(2) tpcall()不在transaction中,flag為TPNOBLOCK,只有當一次調用即成功完成T1階段發送請求的任務后,T2+T3 > BLOCKTIME時,發生超時 ;
(3) tpacall()不在transaction中,flag為0,當T1 > BLOCKTIME時,發生超時 ;
(4) tpgetrply()不在transaction中,flag為0,當T2+T3 > BLOCKTIME時,發生超時 ;
(5) tpcall,tpacall,tpgetrply,在其他任何情況,BLOCKTIME都將不起作用。
(6) 如果請求處于事務交易(transaction)中,此參數不起作用,取代它的是 TransactionTimeOut。
2.5.6 超時后果
在上面描述的四種情況下,Server端 BBL返回Client端超時錯誤:tperrno = 13 (TPETIME)。同時,client端和Server端已經建立的聯接不受任何影響,繼續保持聯接。
2.5.7 設置考慮
此參數涉及整個TUXEDO系統,不能夠直接適應業務系統中不同場合的不同時間等待要求,而且在應用過程中,存在誤差,不適合進行精確到秒的時間控制。
準確有效的使用這個參數,需要考慮好以下幾個問題:
(1) 應用中是否完全依賴這個參數進行時間控制?
(2) 有哪些業務依賴這個參數進行時間控制?
(3) 平衡各種業務,此參數設置為多少?
(4) 除此參數外,是否需要利用其他的超時控制機制?
2.6 WSL CLOPT [-T Client_timeout]
2.6.1 參數出處
UBBCONFIG配置文件 -> SERVERS -> WSL -> CLOPT "-T"。
2.*** 默認取值
0 ,意味著無限等待時間。
2.6.5 用途解釋 ⑻
系統允許的Client靜默時長,即Client和WSH建立聯接后,如果在此指定的時間內客戶端沒有發送任何請求,WSH會自動回收與此Client端相關的資源。
2.6.6 超時后果 ⑼
WSH會自動釋放和這個Client端的聯接,并將此Client在Bulletin Board中的數據項清空,RollBack它未完成的事務 。
2.6.7 設置考慮
此參數的設置目的,主要是從Server的角度進行考慮,防止在Client端意外失效的情況下仍然耗費Server端的資源。
如果設置太小,那么頻繁的檢測同樣要消耗Server端一定的資源,而且,在使用長聯接的系統中,系統空閑時,容易造成已經建立的長聯接頻繁的釋放,影響正常業務的提供。
如果設置為0,不管發生什么狀況,哪怕是Client端系統真的崩潰了,也不會觸發此超時,這將造成Server端資源的無謂浪費。
建議:在業務負載不均衡的長聯接業務系統中,根據業務實際空閑時間,適當加大此數值。
2.7 WSL CLOPT [-t timeout]
2.7.1 參數出處
UBBCONFIG配置文件 -> SERVERS -> WSL -> CLOPT "-t"。
2.7.2 時間單位
SCANUNIT。
2.7.3 取值范圍
大于0。
2.7.4 默認取值
非安全應用為3,安全應用為6 。
2.7.5 用途解釋
建立聯接時長,指workstation Client建立與server端WSH建立聯接允許的最長時間,因為非安全應用建立聯接時不需要進行用戶校驗等步驟,因此,建立聯接需要的時間較短。同理,安全應用需要的時間較長。
2.7.6 超時后果
建立聯接失敗。
2.7.7 設置考慮
設置此參數,要分析業務系統中,網絡帶寬因素、用戶驗證的復雜程度等。
2.8 WSL CLOPT [-I init_timeout]
2.8.1 參數出處
UBBCONFIG配置文件 -> SERVERS -> WSL -> CLOPT "-I"。
2.8.2 時間單位
秒。
2.8.3 取值范圍
大于0。
2.8.4 默認取值
60 。
2.8.5 用途解釋 ⑽
WorkStation Client端和后臺建立聯接的超時參數值。
(注:感覺上此參數和 WSL CLOPT [-t timeout]功能類似)
2.8.6 超時后果
不確定,現有的文檔沒有一點兒解釋。按照字面解釋,應該是tpinit的超時時間,但是,在tpinit所有的錯誤中,只有TPESYSTEM可能承擔這個超時后果,而且僅僅是可能。
2.8.7 設置考慮
在使用過程中,沒有感覺到這個參數的存在,也從來沒有專門設置過。
2.9 WSL CLOPT [-N network_timeout]
2.9.1 參數出處
UBBCONFIG配置文件 -> SERVERS -> WSL -> CLOPT "-N"。
2.9.2 時間單位
秒。
2.9.3 取值范圍
大于等于0。
2.9.4 默認取值
0 。
2.9.5 用途解釋
網絡超時,指Workstation client利用網絡接收數據(receive data)的等待時間。
我們同樣需要分析觸發Network Timeout的不同條件。
以Request/Reply方式中的tpcall為例,將成功發送請求的時長設置為T1,將請求處理的時長(含排隊等待)設置為T2,將成功取得結果的時長設置為T3,那么在如下情況下,將觸發Network Timeout,引起超時:
(1) tpcall()不在transaction中,flag為0,當 BLOCKTIME> T1+T2+T3 > NetworkTimeout時,觸發此超時 ;
(2) tpcall() 在transaction中,flag為0,當TranactionTimeout> TI+T2+T3 > NetworkTimeout時,觸發此超時 ;
(3) tpcall()不在transaction中,flag為TPNOBLOCK,只有當一次調用即成功完成T1階段發送請求的任務后,當 BLOCKTIME> T2+T3 > NetworkTimeout時,觸發此超時 ;
(4) tpcall()在transaction中,flag為TPNOBLOCK,只有當一次調用即成功完成T1階段發送請求的任務后,當 TranactionTimeout> T2+T3 > NetworkTimeout時,觸發此超時 ;
(5) tpcall()不在transaction中,flag為TPNOTIME,當 T1+T2+T3 > NetworkTimeout時,觸發此超時 ;
(6) tpcall()在transaction中,flag為TPNOTIME,當 TranactionTimeout> TI+T2+T3 > NetworkTimeout時,觸發此超時 ;
(7) tpcall在其他任何情況,NetworkTimeout都將不起作用。
(8) 同理,可以確定NetworkTimeout在tpacall和tpgetrply中起的作用。
2.9.6 超時后果
在上面描述的六種情況下, Client端操作失敗,同時,client端斷開與Server端已經建立的聯接。Server端已經為此Client完成的操作和分配的資源不能立刻回滾和釋放,Server端需要等待前面介紹過的Client_timeout時間后,再釋放相關的資源。
2.9.7 設置考慮
此參數的設置目的,主要是從Client的角度進行考慮,防止在Server端意外失效的情況下,仍然消耗Client端的資源。
設置參數,必須避免小于BLOCKTIME或TransactionTimeout的情況,因為在這種情況下,會出現業務正常等待中,聯接卻中斷的現象,這是一定要避免的。
同時,由于此超時觸發的聯接中斷,并不能立刻釋放Server端的資源,帶來業務執行過程中的不確定性,因此,此參數要謹慎使用。
2.10 SVCTIMOUT
2.10.1 參數出處
UBBCONFIG配置文件 -> SERVICES -> SVCTIMEOUT 。
2.10.2 時間單位
秒
2.10.3 取值范圍
大于等于0。
2.10.4 默認取值
0,表示無限時長 。
2.10.5 用途解釋
服務處理時長(Service Processing Time),表示系統允許服務處理請求的時間長度。
此參數主要是維護Server端系統安全的角度,防止由于系統異常引起的失控服務占據系統資源,阻礙正常的后續業務請求。它起到了一個清道夫的作用,將不能有效提供服務的Services清除出系統,并依靠系統的其他機制,重新產生具有活力的Services。
2.10.6 超時后果
超時后,此Service所屬的Server將被系統的SIGKILL信號清除;此操作不會影響與此Server相關的其他正在運行的副本Servers。
如果系統設置SERVERS->RESTART=Y,那么,被清除的Server將立刻自動重新啟動。重新啟動的次數受隨后介紹的MAXGEN和GRACE兩個參數聯合限制。
如果系統設置SERVERS->RCMD為有效命令文件,那么,在重啟此Server時,將同時執行此命令,如向管理員發送通知郵件等。
如果SERVER沒有RESTART=Y設置,那么Server將不會自動重新啟動。
2.10.7 設置考慮
此參數不是系統全局參數,而是涉及到單個Service,可以根據不同的Service的處理時間進行設置。由于其主要起到系統清道夫的角色,因此,建議設置為正常Service處理時長的3倍較合適,以避免清除正常運行的Service,使正常運行的業務受到影響。
如果系統運行環境基本穩定,一旦出現底層網絡或數據庫系統故障,不是在短時間內能夠恢復,建議將此參數增大,至少為平均恢復時間,甚至可以利用默認值0,無限等待,避免此自動機制,而用人工介入的方法進行服務恢復。因為系統自動的、頻繁的SIGKILL將影響到整個TUXEDO系統的穩定。
2.11 GRACE
2.11.1 參數出處
UBBCONFIG配置文件 -> SERVERS -> GRACE 。
2.11.2 時間單位
秒。
2.11.3 取值范圍
0-2147,483,647。
2.11.4 默認取值
86400(24小時)。
2.11.5 用途解釋
此時間參數與其他兩個參數緊密相關RESTART, MAXGEN。
關聯起來解釋就是,當Server異常終止時,如果RESTART=Y,那么此SERVER可立即自動重新啟動,這個重新啟動的次數被限制為在GRACE指定的時間間隔內,重啟不超過MAXGEN-1 次。
如果RESTART這個參數為N,其他的相關參數將都無效。
2.11.6 超時后果
此參數不僅僅是時間的限制,如果在GRACE時間段內,此SERVER重啟次數已經達到MAXGEN-1,后續重啟將不能執行。
2.11.7 設置考慮
此組參數設置的綜合目的是避免運行Server無限的重啟,重啟次數說明了系統目前異常狀況的嚴重程度,如果在一定時間內,Server重啟次數達到了一定的數量,說明這個Server相關的資源已經出現較嚴重的故障,需要人工進行干預了。
另外,經過調優的生產系統是不需要自動重啟的,因此,RESTART這個參數更多是應用在系統測試版本中,在正常運行的生產系統中,應該有不同參數設置,謹慎使用,因為過多的重啟將有可能嚴重影響Server端的整體穩定性。
2.12 Transaction TimeOut
2.12.1 參數出處
tpbegin(timeout,0)。
2.12.2 時間單位
秒,且必須為SCANUINT的倍數。
2.12.3 取值范圍
大于等于0。
2.12.4 默認取值
無,使用時必須明確指定。
2.12.5 用途解釋
交易時長,確定交易(transaction)的持續時間,如果超過此時間,系統將返回超時錯誤。
分析其觸發條件,分兩種情況:
(1) Server端發起交易,
對Client而言,因為Client不在交易范圍內,即使BLOCKTIME設置小于此參數,起有效作用的仍然將是BLOCKTIME,而不是此參數。
(2) Client端發起交易。
對Client而言,因為Client在交易范圍內,此時,BLOCKTIME將失效,此參數取而代之。只要處理時間超過此參數,將觸發此超時,交易處理將隨時中斷。
2.12.6 超時后果
相關交易將被標識為abort only。注意,僅僅是標識為abort only,而不是系統自動執行tpabort進行交易恢復。隨后必須主動執行tpabort,恢復交易,保障交易完整性。如果沒有執行tpabort,系統將通過其他機制,恢復交易,保障交易完整性。
2.12.7 設置考慮
此參數的主要目的是將交易處理過程限制在合理的時間范圍內,如果確實是完成交易的條件不具備,系統也能夠作出反應,避免系統資源的長時間占用。因此,不管交易由Client還是由Server發起,此參數都要按照業務的實際狀況進行設置。如果設置為0,就基本相當于無限時長。(系統unsigned long數據類型的最大值)
2.13 TRANTIME
2.13.1 參數出處
UBBCONFIG配置文件 -> SERVICES -> TRANTIME/AUTOTRAN。
2.13.2 時間單位
秒,且必須為SCANUNIT的倍數。
2.13.3 取值范圍
0-2147,483,647。
2.13.4 默認取值
30 。
2.13.5 用途解釋
此參數必須與AUTOTRAN配合使用,表示不需要調用tpbegin,就可自動發起的隱含交易(AUTOTRAN implicitly transactions)處理持續時長。其實,起到與tpbegin(timeout,0)中的timeout相同的作用。
其實,AUTOTRAN這個參數更為重要,其默認值為N, 其作用描述如下:
(1) 請求發起方不在交易模式,AUTOTRAN=Y,Service將自動發起一個交易,TRANTIME將起作用;
(2) 請求發起方在交易模式,而且,其中的標記參數(flags)不是TPNOTRAN,那么,無論AUTOTRAN如何,Service將自動加入請求方交易中,TRANTIME將不起作用;
(3) 請求發起方在交易模式,而且,其中的標記參數(flags)是TPNOTRAN,如果AUTOTRAN=N,Service將自動加入請求方交易中,TRANTIME將不起作用;
(4) 請求發起方在交易模式,而且,其中的標記參數(flags)是TPNOTRAN,如果AUTOTRAN=Y,Service將不加入請求方交易中,而是產生一個新的交易,TRANTIME將在新交易中起作用;
2.13.6 超時后果
與tpbegin(timeout,0)中的timeout相同。
2.13.7 設置考慮
與tpbegin(timeout,0)中的timeout相同。
2.14 ORACLE XA OPENINFO參數:SESTM
2.14.1 參數出處
UBBCONFIG配置文件 -> GROUPS -> OPENINFO ->SESTM 。
2.14.2 時間單位
秒。
2.14.3 取值范圍
大于等于0,0表示無限時長。
2.14.4 默認取值
無,使用時必須明確設置 。
2.14.5 用途解釋
會話靜默等待時長,即全局交易中,作為資源管理器(resource manager)已經參與交易并完成相應的數據操作的數據庫,等待全局交易中的其他參與方操作完成的時間長度。
舉例說明:
假設一個全局交易由以下幾個部分組成:
(1)tpbegin(T,0) ->
(2)tpcall(S1) -> DB1 完成耗時 T1;
(3)tpcall(S2) -> DB2 完成耗時 T2;
(4)其他操作 耗時 T3
(5)tpcommit()
其中,tpcall(S1)訪問數據庫DB1, tpcall(S2)訪問數據庫DB2。
對DB1而言,如果T-T1> T2+T3 > SESTM1,則觸發超時;
對DB2而言,如果T-T1-T2 > T3 > SESTM2,則觸發超時;
由此可以看出,此參數的主要目的是對數據庫進行資源保護,避免在全局交易中,已經完成任務的數據庫,為等待其他參與方耗費過多的資源,畢竟ORACLE中并發全局交易的數量是很有限的。
2.14.6 超時后果
觸發此超時后,數據庫將自己主動回滾已經完成的任務,釋放全局交易資源。TUXEDO控制的全局交易進行TPCOMMIT時,如果總時間仍沒有超過Transaction TimeOut,那么TPCOMMIT將失敗,XALOG會記錄下ORACLE錯誤:"ORA-24756: Transaction does not exist"。確實如此,拿上面的例子來說,等到最后TPCOMMIT的時候,DB1已經主動回滾了所有的數據,不難理解,對DB1而言,它好像根本沒有參加過這個全局交易,自然就會有這樣的錯誤提示。
2.14.7 設置考慮
這個參數是從數據庫自我保護的角度設計的,對數據庫而言,是不得已的辦法。最好的措施還是TUXEDO能夠控制時間,趕在SESTM之前,進行TPABORT,主動通知數據庫進行數據回滾。
用一個簡單的比方:冬天,客人出門時沒有關門,SESTM時間后,客人還沒有回來,主人感覺到冷了,只好自己去關門,不管什么理由,這樣總是不太好。如果在SESTM時間內,客人能及時回來關門,主人就不會感覺那么差。
從前面的超時觸發分析,我們也能發現,只要設置SESTM 能夠大于 TransactionTimeOut的話,就能夠盡量的不觸發此超時機制,達到較好的效果。
2.15 ORACLE XA OPENINFO參數:SESWT
2.15.1 參數出處
UBBCONFIG配置文件 -> GROUPS -> OPENINFO -> SESWT。
2.15.2 時間單位
秒。
2.15.3 取值范圍
大于0。
2.15.4 默認取值
60 。
2.15.5 用途解釋
會話繁忙等待時長,指全局交易中的一個交易分支(transaction branch)正在一個會話(session)中處理數據過程中,如果第二個會話也要對此交易分支進行操作,那么第二個會話必須等待第一個會話完成,如果在等待SESWT后,第一個會話仍然沒有完成,那么第二個分支將觸發此超時。
舉例說明:
假設一個全局交易由以下幾個部分組成:
(1)tpbegin(T,0) ->
(2)tpcall(S1) -> DB1 完成數據操作耗時 T1;
(3)tpcall(S2) -> DB2 完成數據操作耗時 T2;
(4)其他操作 耗時 T3
(5)tpcommit()
其中,tpcall(S1)訪問數據庫DB1, tpcall(S2)訪問數據庫DB2,任何操作失敗后,將調用tpabort。
假設 T1+T2 > T > T1,也就是說,在成功執行第二步tpcall(S1)后,應用執行到第三步tpcall(S2),在執行過程中,將觸發TransactionTimeout,tpcall(S2)將返回錯誤,應用將立即調用tpabort進行交易回滾,DB1的數據將立刻回滾;而DB2并不能中斷tpcall(S2)引起的數據操作,對于ORACLE DB2而言,tpcall(S2)引起的數據操作屬于第一個會話,而tpabort引起的數據庫回滾操作是通過XA接口,屬于第二個會話,所以,tpabort作用到DB2上,只有等待第一個會話完成,如果等待SESWT后,第一個會話仍然沒有完成,即SESTM
2.15.6 超時后果
系統將返回XA_RETRY錯誤,提示TMS此操作不能完成,需再試一次。如果應用程序對此沒有再次嘗試的話,仍以上例說明,DB2只能利用SESTM2,觸發超時,自動回滾。
2.15.7 設置考慮
查閱ORACLE相關資源,發現oracal9.2與以前版本效果不同,以前的版本都是第二個會話在等待SESWT后,如果第一個會話操作仍然沒有結束,第二個會話能夠使第一個會話操作立即進行有效的回滾,使第一個會話返回錯誤:ORA-24761。
不難理解,兩者的區別是,打個簡單比方說,A正在用杯子喝水時,B要A放下杯子,B等待SESWT后:
oracle9.2的做法很民主,A還沒有用完,通知B,A還在用杯子,不能放下,還想讓A放下杯子,可以,再來一次;也就是說,只要A在用,B就不能讓人家放下杯子,某種程度上,A代表了強權。
Oracle9.2之前版本的做法很粗暴,通知A不能使用這個杯子了,必須放下,因為B讓你放下,而且已經等很久了,某種程度上,B代表了強權。
因此,如果是ORACLE9.2后的版本,SESWT適當放長一些,畢竟還是希望能夠等到能做事的時候,把想做的事情做了。如果是以前的版本,SESWT適當放短一些,反正一定能等到,為什么不少等一會兒呢?
2.16 ORACLE sqlnet.expire_time
2.16.1 參數出處
$ORACLE_HOME/network/admin/sqlnet.ora -> expire_time 。
2.16.2 時間單位
分鐘。
2.16.3 取值范圍
大于0。
2.1*** 默認取值
無 。
2.16.5 用途解釋 ⑾
死聯接檢測DCD(Dead Connection Detection)是 SQL*NetV2.1 和此版本以后的一個新特性, 當它檢測到對方 c/s 或者s/s 聯接意外終止時, 釋放相關占用的資源。
DCD 起初是專為客戶機沒有從會話中斷開聯接的情況下斷電的環境設計的。
DCD由服務端開始建立聯接。 這時候SQL*Net 從參數文件中讀取變量, 設置一個定時器定時產生信號。 這個時間間隔是sqlnet.ora文件中的SQLNET.EXPIRE_TIME提供的。
當定時器設定的時間到了之后, 服務器上的SQL*Net 發送一個探測包到客戶端。(如果是數據庫聯接, 目的端的服務器發送探測包到另一端)。 探測包是由空的SQL*Net包組成, 不體現SQL*Net層任何數據, 但會在下一層的網絡協議中產生數據流量。
如果客戶端的聯接仍然是活動的, 探測包被丟棄,計時裝置復位。 如果客戶端異常斷掉,服務器將收到由發送探測包的調用發出的錯誤。
2.16.6 超時后果
服務器將收到由發送探測包的調用發出的錯誤,SQL*Net 將會通知操作系統釋放聯接占用的資源。
需要說明的是, SQL*Net 2.1.x中 一個活動的孤兒進程(active orphan process) ,如單獨的查詢進程,在查詢完成之前不會被殺掉。 在SQL*Net 2.2中,孤兒進程占用的資源將會被無條件釋放,不管查詢是否結束。
2.16.7 設置考慮
ORACLE 在NT操作系統上,此功能表現很差,檢測出的無效聯接(dead connection)不能被盡快釋放,而必須等到數據庫重新啟動時才釋放。SQL*Net v2.3以后版本改善了以上問題。
此功能只是服務器的特性,如果不設置此參數,此功能將不啟動。按照ORACLE的建議,對大多數應用來說,設置10分鐘較合適,其實關鍵還是分析應用系統的實際情況。
同時,不難理解,作為一個數據庫自我管理的機制,也是要占用數據庫資源和網絡資源的,太頻繁的探測同樣會降低系統和網絡的性能。在低速網絡上,設置此參數,就需更為慎重。
客戶端不需要設置此參數。
2.17 ORACLE distributed_lock_timeout
2.17.1 參數出處
ORACLE初始參數文件:init.ora -> distributed_lock_timeout。
2.17.2 時間單位
秒。
2.17.3 取值范圍
大于0。
2.17.4 默認取值
60 。
2.17.5 用途解釋
分布式事務鎖等待超時(distributed transaction waiting for lock),指第二個事務處理需要的數據庫資源,正被第一個分布式事務占用而鎖定,那么,第二個事務將等待第一個分布式事務釋放此資源,等待distributed_lock_timeout時間后,如果第一分布式事務仍然沒有釋放此資源,第二個事務觸發此超時。
2.17.6 超時后果
如果資源被第一個事務正常使用鎖定,ORACLE回滾第二個事務,并返回錯誤:"ORA-02049: time-out: distributed transaction waiting for lock "。
如果第一個事務處理完成,資源釋放后,再嘗試第二個事務,就會成功。如果第二個事務不能等待資源自動釋放,那么可以采用處理數據庫死鎖(deadlock)的措施,人工介入,清除第一個事務,但一般不建議采用這種方式,因為第一個事務一般會正常結束的。
如果資源被第一個事務因為處于不確定分布事務狀態(in-doubt distributed transaction)而鎖定,ORACLE回滾第二個事務,并返回錯誤:"ORA-01591: lock held by in-doubt distributed transaction identifier "。
這種錯誤遇到的可能性較小,一般只有在分布事務的關鍵提交階段出現網絡、系統故障,才可能出現此故障,而且,當網絡、系統故障恢復后,ORACLE一般可以自己解決此問題,不需要人工介入。如果一定要人工介入,可以查閱ORACLE專門的手冊。
2.17.7 設置考慮
出現這樣的超時,是因為特定數據庫資源的使用碰撞,要分析應用系統的業務特點,確定碰撞可能發生的條件,在此條件下,資源可能被先來者鎖定多長時間(T1),后來者又能夠等多長時間(T2),再來設置此參數(T)的大小。如果在大多數情況下,T1 < T2, 那么就設置T1 < T < T2;反之,大多數情況下,T1 > T2,那么,就設置T < T2。
因此,不分析業務特點,一味的增大和減小是不恰當的。
2.18 ORACLE Max_commit_propagation_delay
2.18.1 參數出處
ORACLE初始文件:init.ora -> Max_commit_propagation_delay。
2.18.2 時間單位
0.01秒。
2.18.3 取值范圍
0 ~ 90000。
2.18.4 默認取值
700 。
2.18.5 用途解釋
最大提交傳播時延(MAX_COMMIT_PROPAGATION_DELAY,簡稱MCPD),在ORACLE RAC(或OPS)環境中才使用,表示在RAC系統中,一個instance系統提交產生的最新系統改變碼(SCN),能夠以多快的速度反應到另一個instance中。
舉例說明,RAC系統,有A,B兩個實例(instance),A、B本地系統改變碼為SCN1,A更新數據DATA1提交, LGWR操作完成后,A本地系統改變碼為SCN2,經過不大于MAX_COMMIT_PROPAGATION_DELAY時間后,B系統本地改變碼才變為SCN2。
2.18.6 超時后果
Global Cache Services 將刷新RAC中的SCN。不管SCN是否及時刷新,后續的數據查詢都不會因此產生數據庫錯誤。但,在此時間內,有可能查詢結果不是最新數據,產生讀一致性(read consistency)問題。
2.18.7 設置考慮
RAC環境中的所有實例,此參數值必須相同。
ORACLE8i后,建議常用的兩個值是0和700(默認),其他數值皆不建議。其實,這兩個數值就代表了RAC環境中,兩種SCN 產生機制:
Lamport Scheme和 Broadcast on Commit scheme。
設置為默認值700,表示采用Lamport Scheme,SCN改變不會完全同步,同步將在 7秒鐘內完成,而不是總等待7秒鐘后才完成。如果系統比較空閑,同步可能在0.5秒(甚至更短時間)內完成;不管系統多繁忙,同步時間也不可能超過7秒。不難理解,采用此模式,整個RAC系統的運行效率較高。
設置為0,表示采用Broadcast on Commit scheme,SCN改變完全同步。每當commit時(即LGWR 寫redo log時):
- LGWR發送消息更新全局SCN(global SCN),
- LGWR 發送消息給每個活動的實例更新其本地SCN(local SCN)。
有資料說,只要MCPD < 700,系統將采用Broadcast on Commit scheme。
Lamport Scheme能夠適應絕大部分應用的要求,只有個別實時性特別高的業務,才需要Broadcast on Commit scheme。通過分析,不難理解,Broadcast on Commit scheme將需要更多的系統資源。
3 總結
以上所有時間參數,都是tuxedo系統或ORACLE數據庫系統提供的時間控制機制,更多的是從維護本系統自身安全的角度,建立起相互之間溝通的規則。在Client 端,中間件服務器,數據服務器這相互聯系的三者之間,用一個簡單的比方,就是先保證自己盡量不給相關人帶來麻煩;一旦相關人出了麻煩,自己能夠自我保障,不受別人干擾。
這些時間參數還有的一個共性的特點就是"不精確",如果業務需要要精確到1秒,則必須依靠業務程序中更精確的時間編程。
總之,要保障整個業務系統的有效性和健壯性,必須了解都有哪些時間參數?都表示什么意思?都起哪些作用?自己的業務應用對時間要求是怎樣的?這些參數該如何配置才能滿足應用的要求?希望本文能夠在以上方面給大家帶來一點方便。
4 后記
自2002年真正在項目中利用TUXEDO起,就發現已有資料在時間參數解釋方面的缺憾,那時,就有寫這樣一個專題的打算,開始收集這方面的資料。由于后來工作內容的變化,也就沒有精力再作整理,但心里一直惦記著這件事情。直到前些天知道了BEA的這個活動,再到網絡上搜集資料,發現已經有了一些類似的資料,但感覺仍然不夠完整,不夠透徹,因此,我認為整理這樣一個專題資料,還是有必要的,便下決心借此機會做完這件事情。經過近十天的查閱、整理,終于完成,算是了我多年夙愿。
文中的參數,我僅僅使用過其中的12個,其他未用參數,主要是靠查閱資料和邏輯分析,根據我自己的理解進行解釋,再加上時間倉促,或遺漏、不妥之處,敬請指正,讓我們一起來使此《功略》更準確、更全面,讓更多的人從中受益。
5 參考文獻
http://e-docs.bea.com BEA TUXEDO RELEASE 7.1 。
http://dev2dev.bea.com.cn/techdoc/tuxedo/20030230.html 《Tuxedo 中關于時間的參數的說明》作者:不詳 。
《ORACLE8i Reference》。
《ORACLE9i Reference》。
《ORACLE8i Parallel Server Concepts and Administration》。
《ORACLE8i Application Developers Guide - Fundamentals》。
http://metalink.oracle.com 相關問題解決資料。
http://www.chinaunix.net 《DCD死聯接檢測》作者:yukaikai
注:文章中標注⑴~⑽涉及的內容,引自參考文獻-2 ,標注⑾涉及的內容,引自參考文獻-8 。
在沒有負載均衡的情況下,是由一個server(可能包含一個或多個service)來處理客戶端對其中service的請求,所有的請求首先放入這個server的隊列里面,然后server逐個取出處理。在UNIX系統上,TUXEDO較多的使用了隊列,并且也用到了共享內存和信號量,相關的UNIX系統參數會影響到系統的性能,但這個不在本文討論范圍之內,這里假設已經調到了合適的范圍,具體請查閱TUXEDO關于IPC的文檔。
現以一個帳單處理的server為例,負載均衡前server的ubb配置為:
billpay SRVGRP=GROUP1 SRVID=1
在單個server不能滿足性能要求的情況下,就考慮采用TUXEDO的負載均衡方法。
方法一是直接將相關server啟多份,將上面的配置改為:
billpay SRVGRP=GROUP1 SRVID=1 MIN = 5 MAX = 10
這樣tmboot的時候,就會有MIN = 5個billpay啟動,類似下面的情況:
billpay 00001.00001 GROUP1 1 0 0 ( IDLE )
billpay 00001.00002 GROUP1 2 0 0 ( IDLE )
(依此類推,共5個)
其中第二列是該server的隊列名,"."前面是GRPNO,后面是SRVID,每個server有自己的隊列。相關的另一個參數就是在ubb的*RESOURCES段的LDBAL,表示是否啟動Load Balancing,默認是"N"(不啟動),你可以通過設置成"Y"來啟動。這里需要注意的是,為"N"的時候并不表示多個server不能分擔負載。主要的差別是為"Y"時,TUXEDO在接收到請求時會按照它的負載均衡的算法來找到合適的server來處理,而設置成"N"時,總是由第一個可用的server來處理。通過這種方法可以讓多個server來處理大量并發的請求,就達到了改善性能的目的。
方法二是采用MSSQ(Multi Server, Single Queue),顧名思義,就是有多份server,但是只有一個隊列(請求隊列)。具體的配置是:
billpay SRVGRP=GROUP1 SRVID=1 MIN = 5 MAX = 10
RQADDR=" billpay" REPLYQ=Y
啟動后的情況如下:
billpay billpay GROUP1 1 0 0 ( IDLE )
billpay billpay GROUP1 2 0 0 ( IDLE )
(依此類推,共5個)
我們發現幾個billpay server都關聯相同的名為billpay的隊列,這就是所謂的Single Queue。
與直接多server相比,多了兩個參數,RQADDR是這多個server共用的隊列名,是一種邏輯名,可以自己命名,不和別的沖突就可以,REPLYQ是標示是否設置返回隊列,在使用MSSQ的時候是強烈建議設置,因為這樣可以將請求和返回分開,避免多個server共用隊列時造成混亂。相關的其它參數這里沒有詳細列出。
到底兩種方式和沒有負載均衡時有什么不同,后面將提供相關的測試結果。先分析一下兩種方法。方法一有多個隊列可以容納請求,但是這些大量的請求怎樣放入這些隊列必定有一定的策略,而且根據LDBAL的設置會不同,但是這個策略本身的運算也是一種消耗,因為每個請求都面臨著這個選擇。因為這種情況下每個隊列是和server對應的,所以隊列的選擇就意味著選擇了相應的那個server,這樣大量的請求就被分流。雖然有選擇的消耗,但是額外的好處也是顯而易見的,那就是有多個queue可用,有效避免了請求并發量很大時隊列的溢出,這種情況在實際的壓力測試中發生過。使用方法二時,放入隊列時不用做選擇,然后每個server的任務就是從隊列取出請求去處理,考慮到多個server并發取隊列,所以用MSSQ時其server的數目不宜太多,官方文檔建議2-12。而且在這種情況下,建議不要設置LDBAL=Y,因為MSSQ本身就是一種基于single queue的負載均衡的方法,這時再使用系統的策略已經沒有意義。這種方法也有一個問題,如果相對于請求數來說,處理得不夠快,就比第一種方法更容易造成隊列溢出。
因為我們無法知道TUXEDO一些具體的算法和策略,那就用一些具體的測試來比較吧。筆者在一個和實際生產系統配置相同的UNIX+ORACLE+TUXEDO8.0系統上做了一下試驗,被測服務是一個帳單查詢服務,每次根據一批ID從數據庫查詢出具體的帳單,由于都是實際數據和實際使用的服務,有一定的說明力,但是也不排除一些情況造成的誤差。以下是測試的一些結果,每個server的實際運行份數都是10。
一:客戶端數目為1,循環調用100次。
1. 方法一,LDBAL = Y or N。結果發現所有的請求都由其中的一個server處理,其它全部空閑。在此基礎上再進行兩次循環調用,結果還是一樣。
2. 用方法二,LDBAL = Y or N。其中兩次測試的情況是:
<1>19,19,2,2,1,18,18,1,1,19
<2>23,8,23,23,23,(其它空閑)
以上數據說明了兩種方式的調度策略是不一樣的,在單客戶端循環的情況下方法二更合適。
二:客戶端數目50,每個循環80次,統計總的執行時間。
1. 用single server。兩次測試的處理時間分別是219s和196s。
2. LDBAL = Y 方法一:三次測試時間為:63s,79s,69s
3. LDBAL = N 方法一:三次測試時間為:74s,79s,85s
4. LDBAL = Y 方法二:三次測試時間為:74s,73s,77s
5. LDBAL = N 方法二:三次測試時間為:78s,76s,75s
通過以上數據可以看出不管用那種方法,使用負載均衡相比單個server都可以在大量請求并發時得到更好的性能。但是同時也發現后四種情況的總時間差別不大,考慮一些實際的誤差,很難斷定哪種更好。
通過前面的分析,并查閱相關的文檔,建議采用的是兩種方式:多個server,不用MSSQ,設置LDBAL = Y;用MSSQ,設置LDBAL = N。當然,在使用TUXEDO的應用系統中,不能絕對的說哪一種方式更好,只能是根據具體的情況來分析,并通過實際的壓力測試來進行選擇,而且這個和具體server的特點也是有關的。
以上是一些個人分析和測試的結果,算是寫出來和大家探討,也希望大家提出自己的看法并討論。
一、中間件技術在系統設計規劃方面的經驗總結
1.1、中間件應用架構的選擇
這種架構選擇的焦點就是業務邏輯到底是放在前臺應用中還是放在后臺中間件應用中。其實,引入中間件平臺的原因之一就是業務邏輯的集中管理,出現這種爭論的原因主要是開發商對這種業務邏輯集中的理解不深,在應用設計的過程中仍然沒有擺脫以前兩層結構的影響,再加上因為業務邏輯集中會增加程序開發量,才出現了這種情況。我們認為,把業務邏輯集中在中間件服務器上不僅對于業務邏輯的集中管理有好處,而且對于系統的后期運行維護、軟件的升級管理都有著明顯的優勢。當然,在開發的工作量方面,業務邏輯集中時工作量大很多。
1.2、中間件服務分布的設計和優化原則
在Tuxedo中,Server可以理解成為Unix的一個進程,Service可以理解成為應用進程Server中的一個函數。用戶可以任意劃分Server和Service:既可以把所有的Service放在一個單一的Server中,也可以采用“一個Service一個Server”的方式。Tuxedo對此沒有任何限制。
中間件應用的性能直接影響到營業前臺服務的穩定性和連續性,而影響中間件應用性能的因素除了硬件資源的保證、數據庫響應時間、中間件應用軟件本身的質量之外,中間件應用服務的分布也起著至關重要的作用。我們有著這樣的一個例子,在前臺進入收費界面的時候,應用程序需要調用一個SERVICE名字叫A,A分布在一個叫SA的server中,而SA中又包含著很多其他的在線統計的SERVICE B,結果造成了SA響應B調用的時候執行時間比較長,所有的SA都在執行SERVICE B ,前臺請求SERVICE A得不到響應,收費的界面怎么都進不去,從而導致前臺收費業務中斷。這就是個典型的因為服務分布不當造成的系統故障。
我們在系統規劃設計過程中遵循的一個最基本原則就是盡量將“類似的Service”捆綁在一個Server之內。所謂“類似的Service”是指這些函數有相似的大小、執行時間、復雜度或者功能。我們來考慮一個極端的例子:假設一個Service A是完成非常簡單工作的,它的平均執行時間是100毫秒。另一個Service B進行數據庫的查詢,它的執行時間可能長達20秒。如果將這兩個Service捆綁在一起使用,就會出現非常嚴重的后果。大家知道,操作系統的基本調度單位是進程。在一個進程中的Service執行是串行的。Tuxedo把發往同一個Server的請求交易包放在同一個消息隊列中。當Service B在執行的時候,Service A的請求包必須在隊列里面等待20秒以上才可能被執行,雖然它的執行時間僅僅100毫秒。這顯然是不能容忍和應該避免的。
實際上,用戶在設計和開發應用程序的時候,并不能完全估計出每個Service的執行時間和頻度。所以對Server和Service的劃分優化是在應用程序開發完畢后進行調整的。調整的依據就是在系統運行的時候記錄每個Service的執行時間和頻度,然后根據這些數據來進行優化調整。下面就是我們在實際當中獲得經驗的一些系統總結。
1、 區分Service的不同類型:是業務操作還是簡單的數據訪問
在中間件應用中的Service可以進一步細分成負責完成業務操作和負責數據訪問的兩種類型。在設計的時候,最好把這兩種不同類型的Service區別出來。所謂完成業務操作的類型其實就是進行數據修改的操作,負責數據訪問的類型其實就是進行數據查詢的操作。但是在實際的系統運行過程中,凡是涉及到數據修改的操作過程中必然會有數據查詢的操作,這種類型的操作也應該規整到第1種類型中去。
2、 請求/響應類型的Service要和會話Service分開在不同的Server中
在Tuxedo中,一個Server要么支持請求/響應類型類型的Service,要么支持會話方式的Service。會話方式和請求/響應方式是兩種互斥的通訊方式。請求/響應方式效率比較高,是使用最頻繁的通訊類型。Tpcall/tpacall/tpforward都是這種類型的函數。會話方式適合大量的數據傳輸,但是它的代價是效率的下降。所以這兩種類型的Service要分開放在不同的Server里面。
3、 執行時間相似的Service放在同一個Server里面
在Tuxedo應用環境中,可能有成百上千的Service,這些Service的執行時間顯然是不同的。對于單線程的Server來說,雖然它可能有多個Service,但是這些Service的執行是串行的。如果某個Server擁有兩個Service,A和B。A的執行時間是100ms,B的執行時間是1000ms,也就是說執行一次B的時間可以執行十次A。那么當B在執行的時候,可能會有十個A在隊列里面等待。這種情況會急劇降低該Server處理Service的吞吐率。因此很自然的一個原則是把執行時間相似的Service放在同一個Server里面。
4、 具有相同執行頻度的Service放在同一個Server里面
在一個典型的Tuxedo應用系統中,并不是所有的Service的執行頻率都是相同的。可能一些Service被頻繁的執行,而另外一些Service只是偶爾才被執行幾次。把這些SERVICE分開可以避免偶爾調用的SERVICE堵塞頻繁調用的SERVICE。
5、 避免死鎖的情況發生
在Tuxedo中的死鎖情況有兩種,第一種是一個Server中的Service A去調用同在一個Server中的Service B。這種死鎖發生的原因是,對于單線程的Server來說,它其中的Service是串行執行的。Service A去調用Service B的時候,Service A還沒有執行完,它等待Service B的返回結果。 但是Service B不能執行,因為該Server還處于執行Service A的狀態。最終導致Service A超時而出錯。
第二種情況是兩個Server中的Service互相調用。例如Server1和Server2,Server1中的Service A去調用Server2中的Service X。同時Server2中的Service Y去調用Server1中的Service B。這種情況發生的死鎖和第一種情況非常類似,都是因為進程只能串行實行Service導致的。
這兩種死鎖情況在應用設計時特別要注意避免。第一種情況是比較容易察覺的,但是第二種情況就不大容易察覺。
1.3、中間件系統應用平臺FAILOVER方式的選擇在真實的生產運行環境中,運行平臺的failover是一個必須考慮的問題。Tuxedo平臺上的實現failover機制基本上有兩種,一種是利用tuxedo自己的failover機制配合前臺配兩個WSNADDR地址來實現failover。一種是利用雙機軟件來實現。
第一種方式是指使兩臺的中間件服務器處于MP工作模式下,在每一臺都啟動WSL進程,然后在中間件前臺配置兩個ip地址。通過自己實驗發現利用tuxedo自己的failover機制只有如下好處即不需要額外的操作系統和軟件的支持,但是其缺點確很多,主要缺點如下:
1、兩臺中間件平臺的MASTER切換必須要手工完成,無法自動完成。
2、前臺配置的兩個WSNADDR地址,如果第一個地址失敗,要重新連接到第二個地址需要很長的時間,并且在每次服務調用時都要等待同樣的時間。
通過雙機軟件來實現FAILOVER是指兩臺中間件服務器都配置在SHP模式下,然后利用雙機軟件的ip切換功能來實現failover。這種方法需要在各自的配置文件中加入另外一臺主機的WSL的信息,在另外一臺主機故障時,通過雙機軟件進行IP切換,再通過雙機切換腳本將這臺主機的備用WSL啟動即可。采用這種方式有以下優點
1、機器切換自動完成,不需要人工干預。
2、前臺業務不受影響,能保證業務開展的連續性。
缺點主要有
1、在正常情況下,每一臺主機的啟動中間件時,備用的WSL服務會啟動失敗,不過這不影響正常使用,備用的WSL只在另外一臺主機故障后才起作用。
2、需要額外的雙機配置和腳本配置工作。
經過這些比較,我們選定了采用雙機軟件的方案實現了中間件的failover機制。在以后的運行維護過程中起到了好的效果。
1.4、中間件與數據庫的連接方式的選擇在TUXEDO中間件應用中連接數據庫的方式有兩種,一種為通過XA方式連接數據庫,另外一種是在應用程序中自己連接數據庫。
通過XA方式連接數據庫是指利用關系型數據庫的XA接口,在tuxedo的配置文件中的OPENINFO段中加入連接信息,然后在server程序的初始化代碼的中調用中tp_open(或xa_open),當SERVER啟動時進行數據庫連接。
通過應用程序直接連接數據庫,數據庫的連接操作不一定是在SERVER啟動時進行的。
這兩種方式的連接在BOSS系統中都會用到,其中的區別主要就在于如果業務操作的事務為分布式事務時,則必須要用XA方式。詳細比較如下:
1、通過XA連接的方式可以實現分布式事務,即能夠保證事務在不同數據庫中的一致性。但是正是因為如此,它對中間件系統和數據庫系統都有額外的開銷,有時候這種開銷甚至會影響系統的性能。
2、通過應用程序直連數據庫的方法不能夠實現分布式事務,但是同時也因此減少了對系統的壓力。
綜上,選擇數據庫的連接方式對整個系統的性能影響也是至關重要的,我們有個原則,凡是在不涉及到分布式事務的地方就不用XA連接。過多的依賴了XA接口,會給系統帶來了許多額外的負擔和壓力,也會造成許多額外的故障。
二、中間件技術在系統維護方面的經驗總結在中間件的日常維護中,我們了解了一些TUXEDO的基本知識,摸索了一套行之有效的故障排除方法,積累了一些常見故障的排除經驗,現在與大家介紹如下:
2.1、LICENSE數的問題tuxedo的license由文本文件lic.txt來控制,位于udataobj目錄下,分為SDK/RTK兩種,兩種LICENSE不能合并使用。它控制的是并發用戶數并且有10%的冗余,這里的并發用戶數是指在某一時刻前臺程序已經發起tpinit還沒有作tpterm的連接數,所以在tuxedo中間件的使用中存在著長連接和短連接的問題。長連接是指tpinit后就開始一系列的服務調用,只在系統重啟或系統非常空閑的時候才做tpterm,而短連接是指每次服務調用前作tpinit,調用結束后立即作tpterm調用。因為短連接下的服務調用需要額外的連接時間消耗,這對系統響應時間會有影響,而長連接又會占用系統的并發用戶數。所以在系統設計時需要針對不同的應用情況做出不同的設計,比如針對接口類型的應用因為服務調用比較頻繁,進行連接的時間就會占比較大的比重,這時就需要使用長連接,而對于前臺應用類型的應用,連接過程的時間對于業務操作的時間來說是可以忽略的,這時就要用短連接來節約license資源。
2.2、客戶端連接的問題當客戶端無法連接中間件時,我們需要確認的是
1、 客戶端的WSNADDR是否設置或是否設置正確。
2、 系統配置文件中的MAXWSCLIENTS和MAXACCESS是否正確設置。
3、 WSL是否啟動,WSH的個數是否足夠。
4、 是否有防火墻,如果有防火墻存在,則需要在WSL的配置中作相應的地址映射和端口指定。
5、 操作系統是否有足夠的SCOKET資源使用。
解決了這些問題后,一般就可以解決客戶端連接不上的問題了。
在TUXEDO中,參數TMTRACE對故障的定位和排除很有作用,它是一個環境境變量。我們一般在系統監控的工作終端上將此參數設置為on,在前臺報系統故障的時候,我們直接進入故障模塊將故障重現,然后在終端機器的c:\或者tuxedo的安裝目錄下打開一個ULOG文件,在此文件中會發現tpcall服務的失敗信息,根據這個信息查找對應的SERVER和SERVICE的對應表,很快就可以找到問題服務。采用這種方式,維護人員不需要了解程序的具體流程就可以定位錯誤解決故障。
在TUXEDO的服務端,有幾類文件需要關注,這些文件包括ULOG文件、XA接口的trc文件、數據庫連接故障的sqlnet.log、標準輸出文件stdout(也可以被應用程序自己定義)。在這些文件中包含著豐富的系統運行錯誤告警信息。ULOG記載關于中間件的啟停記錄和系統本身的一些配置運行告警信息。XA的trc文件記錄的是XA接口方面的一些的錯誤信息,關于分布式事務的一些錯誤在這個文件中都有記錄。sqlnet.log記錄了應用程序和數據庫連接故障的信息,只要有當前日期時間的這個文件存在,應用和數據庫的連接就會存在問題。標準輸出文件stdout記錄了應用程序本身的運行信息。這些文件的跟蹤檢查對于及時主動的發現故障有著重要的意義。
2.3、事務控制的問題1、事務邊界的問題:在這里我們要遵循誰發起發起事務,誰就結束的原則,這里的誰主要是指中間件的前臺和后臺。我們知道在TUXEDO中事務的發起既可以在前臺程序中發起,也可以在后臺程序中發起。無論放在前臺還是放在后臺都有其優缺點。事務放在前臺增加了網絡傳輸的流量,當時可以保證異常情況下前后臺操作的一致性,事務放在后臺可以減少網絡流量,但是對于異常情況下前后臺操作的一致性很難保證。我們采用的是事務放在前臺程序中。但是無論放在前臺還是后臺,都要遵循誰發起,誰結束的原則。
2、XA接口使用的注意事項:首先是XA資源文件的配置,在oracle數據庫中一般用到的是libclntsh.a,我們可以先Make sample,提取其中用到的連接庫加入到RM文件中即可。其次在oracle8i之前要對XA進行授權,要在oracle的DBA用戶下執行grant select on dba_pending_transactions to public。
3、事務掛起的問題:在使用XA的情況下,我們經常會遇到這種情況,SERVER進程還在,可就是不做事。在相關的日志文件中總是報“當前的進程已經在一個本地事務中了”的錯誤,這時只有重啟該SERVER,才能排除故障。其實這是一個事務控制的問題,它產生的根本原因是在開啟全局事務前,該SERVER執行了一個本地的事務并且沒有提交或回滾。在程序代碼上表現為如下三種原因:
(1)、在調用該SERVER的某個帶DML語句的service前沒有加tpbegin。
(2)、在調用tpbegin后沒有判斷返回值。
(3)、tpbegin后的tpcall服務調用沒有判斷返回值,在全局事務超時后沒有能夠及時的退出后續的調用,導致下一個tpcall產生了一個本地事務。
此外,還會有一類比較特殊的問題,那就是TMS服務掛起的問題,利用tmadmin中的pq命令發現TMS的隊列中有很多請求存在,在這種情況下,一般只能等待其執行完成,情況嚴重時,則需要調整相應的數據庫參數,在ORACLE中該參數應該設為max_commit_propagation_delay>=90000。
在實際的運行維護中,我們發現即使把數據庫參數調整了,有時還會有TMS掛起的故障發生。針對這件事情我們專門作了研究,TMS之所以掛起是因為TMS在等待數據庫中DX獨占鎖的釋放,這種獨占鎖加鎖的對象一般都是ORACLE的系統對象,而這種獨占鎖的產生一般是在全局事務中執行著DML語句,當這種DML語句執行比較慢時,就會引起TMS的鎖等待現象。此外,我們還發現,一般的查詢語句是不會產生鎖的(OPS的lm_lock鎖除外),但是如果將查詢放入一個全局事務中時,它就會產生一個共享的DX鎖,如果這個在全局事務中的查詢的調用是通過ORACLE的工具包DBMS_SQL來進行的話,那就會產生一個DX的排他鎖。基于這些結果,我們建議在程序的開發過程中要遵循能不用XA全局事務的情況下就不用,能將查詢放到事務之外的就不要放到事務之內,能不用ORACLE工具包進行開發的就不要用。我們也按照這個原則要求我們的開發商,取得了比較好的效果。
4、事務超時設置的問題
中間件應用系統的事務超時控制很重要,不設置超時時間對系統來說簡直就是一種災難。我們曾經就有過因為超時時間的設置沒設和設置不當造成了嚴重的系統故障,最直接的故障就是系統報全局事務數不夠的錯誤,無法開啟新的事務,從而導致前臺業務的終止。TUXEDO的超時主要有三種,一個是在代碼中的tpbegin超時(值為其參數)T1,他控制整個事務的完成時間,第二個為XA連接的超時(配置文件中的open_info中的SesTm )T2,他控制同一連接中對于分布式事務鎖的等待超時時間,還有一個為數據庫中等待數據庫對象非分布式事務鎖釋放的超時時間(_dirstributed_lock_timeout)T3。這三個超時共同作用并且有如下的關系 T1
2.4、服務不能正常啟動的問題在實際的維護工作中,經常會出現服務不能正常啟動的現象。明明所有的服務都已經關閉了,tmboot就是起不來。這種原因一般是因為系統的IPC資源沒有釋放。IPC資源是操作系統用來進行進程間通訊的系統資源,主要包括信號燈、共享內存、消息隊列。在UNIX操作系統下通過IPCS命令可以清楚的看到IPC資源的使用情況。當服務無法啟動的時觀察IPCS就會發現tuxedo運行環境的用戶下的ipc資源沒有被釋放,這時使用ipcrm命令清除相應的IPC資源,再啟動服務就可以了。
草木瓜 2006-6-1
------------------------
一、簡介
------------------------
外部應用訪問Tuxedo服務是很經常的事,一般有兩種方法WTC和Jolt,網上很多關于Jolt調用Tuxedo服務
文章,描述的太多籠統,其實通過Jolt并不是很復雜的事情,這里使用Eclipse3.1+Jolt+WebLogic8.1
+Tuxedo9.0環境描述調用服務的全過程。
Jolt是Bea Tuxedo自帶的jar組件,在Tuxedo9.0的安裝過程中可以看到安裝的Jolt組件。
調用服務理論步驟是這樣的:
1.先準備Tuxedo服務端代碼
2.在Tuxedo中配置Jolt相關文件
3.啟動Tuxedo服務
4.配置WebLogic服務與Tuxedo Jolt相關的參數
5.配置Eclipse3.1啟動WebLogic服務
6.編寫Eclipse Servlet代碼,運行調用服務。
本例使用了《Windows Tuxedo的安裝配置-數據庫補充》一文中的Tuxedo數據服務文件,所以在啟動
Tuxedo服務前,必須先啟動數據庫實例,因為在tpsvinit()里面就配置了數據連接。關于Tuxedo配置
要點需參閱《Tuxedo的安裝配置-...》的四篇文章。
------------------------
二、Tuxedo服務文件全代碼
------------------------
這里把server.pc服務文件代碼再次列出。其中包括三個服務DBREAD(讀數據庫)和TOUPPER(轉換大寫)。
本例不使用TOUPPER,所以不用理會那段代碼。
其中liwei/liwei@windb連接的表tuxedo_test,結構如下:
CREATE TABLE TUXEDO_TEST(
ID NUMBER(2),
NAME VARCHAR2(10)
)
ID NAME
------------------------
1 aaaaaaa
2 bbbbbbb
#include <stdio.h>
#include <ctype.h>
#include <atmi.h> /* TUXEDO Header File */
#include <userlog.h> /* TUXEDO Header File */
EXEC SQL BEGIN DECLARE SECTION;
VARCHAR ora_no[2];
int ora_id;
VARCHAR ora_value[10];
VARCHAR ora_cn[30];
EXEC SQL END DECLARE SECTION;
EXEC SQL INCLUDE sqlca;
tpsvrinit()
{
strcpy(ora_cn.arr,"liwei/liwei@windb");
ora_cn.len = strlen(ora_cn.arr);
ora_cn.arr[ora_cn.len]='\0';
//EXEC SQL WHENEVER SQLERROR GOTO cnError;
EXEC SQL CONNECT :ora_cn;
return(0);
}
tpsrvdone()
{
EXEC SQL COMMIT WORK RELEASE;
}
DBREAD(TPSVCINFO *rqst)
{
strcpy(ora_no.arr,(char *)rqst->data);
ora_no.len=strlen(ora_no.arr);
ora_no.arr[ora_no.len]='\0';
userlog("ERRSRV: %s",ora_no.arr);
EXEC SQL select name into :ora_value from tuxedo_test where id=:ora_no;
if(sqlca.sqlcode!=0)
{
userlog("ERRSRV: select name from tuxedo_test where id=, sqlcode=%ld , sqlerr=\n",sqlca.sqlcode);
strcpy(rqst->data,sqlca.sqlerrm.sqlerrmc);
tpreturn(TPFAIL, 0, rqst->data, 0L, 0);
}
/* Return the transformed buffer to the requestor. */
strset(rqst->data,"");
strcpy(rqst->data,ora_value.arr);
tpreturn(TPSUCCESS, 0, rqst->data, 0L, 0);
}
TOUPPER(TPSVCINFO *rqst)
{
int i;
for(i = 0; i < rqst->len-1; i++)
rqst->data[i] = toupper(rqst->data[i]);
/* Return the transformed buffer to the requestor. */
tpreturn(TPSUCCESS, 0, rqst->data, 0L, 0);
}
------------------------
三、編譯服務
------------------------
編譯命令的注意事項,以前Tuxedo系列文章都提過。
proc server.pc include=%TUXDIR%\include
buildserver -o server -f server.c -s DBREAD -s TOUPPER -v -l orasql9.lib
------------------------
四、配置Tuxedo服務的config文件
------------------------
完全文件如下:
#Liwei
*RESOURCES
IPCKEY 123456
DOMAINID liweiapp
MASTER lw
MAXACCESSERS 150
MAXSERVERS 100
MAXSERVICES 100
MODEL SHM
LDBAL N
*MACHINES
LWYM
LMID = lw
TUXDIR = "E:\bea\tuxedo9.0"
TUXCONFIG = "G:\Liwei\Tuxedo\dbread\tuxconfig"
APPDIR = "G:\Liwei\Tuxedo\dbread"
MAXWSCLIENTS=1
TLOGDEVICE = "G:\Liwei\Tuxedo\dbread\TLOG"
TLOGNAME=TLOG
TLOGSIZE = 100
*GROUPS
APPGRP LMID=lw GRPNO = 1
#OPENINFO="Oracle_XA:Oracle_XA+Acc=P/liwei/liwei+SqlNet=linux+SesTm=600+MaxCur=5+LogDir=."
#TMSNAME="TMS_ORA9i" TMSCOUNT=2
JSLGRP LMID=lw GRPNO = 2
JREPGRP LMID=lw GRPNO = 3
*SERVERS
server SRVGRP=APPGRP SRVID=1
#WSL SRVGRP=APPGRP SRVID =300
#CLOPT="-A -- -n //192.168.0.166:8888 -d/dev/tcp -m1 -M5 -x 10"
JSL SRVGRP=JSLGRP SRVID=301
CLOPT="-A -- -n //192.168.0.166:9878 -M 10 -x 10 -m 2"
JREPSVR SRVGRP=JREPGRP SRVID=302
CLOPT="-A -- -W -P E:\bea\tuxedo9.0\udataobj\jolt\repository\jrepository"
*SERVICES
DBREAD
TOUPPER
細心一看,這個config文件比在*GROUPS和*SERVERS各加了兩項對應內容:
JSLGRP LMID=lw GRPNO = 2
JREPGRP LMID=lw GRPNO = 3
和
JSL SRVGRP=JSLGRP SRVID=301
CLOPT="-A -- -n //192.168.0.166:9878 -M 10 -x 10 -m 2"
JREPSVR SRVGRP=JREPGRP SRVID=302
CLOPT="-A -- -W -P E:\bea\tuxedo9.0\udataobj\jolt\repository\jrepository"
這兩項是用于jolt的訪問接口。JSL和JREPSVR必須是獨自的GROUP,由于外部調用通過JSL和JREPSVR直接于
Tuxedo服務通信,WSL就沒用了。JSL的主機地址是Tuxedo服務器地址,端口是隨意指定的,不要與其他重復
即可,一般設置的大一點。在config里面加入這此內容后,config文件就Ok了。
------------------------
五、配置jrepository文件
------------------------
直接打開E:\bea\tuxedo9.0\udataobj\jolt\repository\jrepository文件添加以下內容:
add SVC/DBREAD:vs=1:ex=1:bt=STRING:\
bp:pn=STRING:pt=string:pf=167772161:pa=rw:ep:
add PKG/SIMPSERV:DBREAD:
這個文件如果沒有DBREAD配置,調用會提示DBREAD not avaliable,DBREAD配置錯誤,會提示DBREAD has
been modifed ...
對這個文件操作還有以下兩種方式:
方式一:在IE打開E:\bea\tuxedo9.0\udataobj\jolt\RE.html,是個java applet,里面是圖形界面,添加
完服務,設置好參數即可。具體方法可以查閱網上資料,有圖文解說的。
方式二:在命令行鍵入Java bea.jolt.admin.jbld //192.168.0.166:9878 services.rep,其中//192..要與
JSL的設置一致。services.rep是隨意的一個文件,不過文件內容絕對不隨意,如下:
service=DBREAD
inbuf=STRING
outbuf=STRING
export=true
param=STRING
type=string
access=inout
要執行這個命令設置jdk環境變量是必不可少的,PATH,CLASSPATH。我的CLASSPATH加入了以下內容,
E:\bea\tuxedo9.0\udataobj\jolt\joltwls.jar;
E:\bea\tuxedo9.0\udataobj\jolt\joltjse.jar;
E:\bea\tuxedo9.0\udataobj\jolt\jolt.jar;
E:\bea\tuxedo9.0\udataobj\jolt\joltadmin.jar
個人認為對于這個java命令joltadmin是必須的,其他三個沒用,不過沒有親自嘗試。
方式一,二修改后,jrepository文件會顯得比較亂,所以我不喜歡!最好是自已手工修改。
------------------------
六、編譯啟動服務
------------------------
當然,數據庫必須要有了,編譯config后,啟動tuxedo服務。
tmloadcf -y config
tmboot -y
提示如下:
exec BBL -A :
process id=3520 ... Started.
Booting server processes ...
exec server -A :
process id=3812 ... Started.
exec JSL -A -- -n //192.168.0.166:9878 -M 10 -x 10 -m 2 :
process id=252 ... Started.
exec JREPSVR -A -- -W -P E:\bea\tuxedo9.0\udataobj\jolt\repository\jrepository :
process id=2920 ... Started.
4 processes started.
------------------------
七、配置Eclipse3.1
------------------------
我們要在Eclipse里面啟動WebLogic服務,《Eclipse3.1 Web開發配置》一文中已經說明了,如何配置
WebLogic8.1的服務器,這里對WebLogic的服務本身也要做此必要的配置。
打開選用的WebLogic8.1服務路徑,編輯config.xml文件,本機位置G:\Liwei\WebLogic\WebServer\config.xml。
加入如下內容:
<JoltConnectionPool FailoverAddresses="http://192.168.0.166:9878"
MaximumPoolSize="2" MinimumPoolSize="1" Name="JoltPool"
PrimaryAddresses="http://192.168.0.166:9878"
SecurityContextEnabled="false" Targets="webServer"/>
<StartupClass
ClassName="bea.jolt.pool.servlet.weblogic.PoolManagerStartUp"
LoadBeforeAppActivation="true" Name="MyStartup" Targets="webServer"/>
<ShutdownClass
ClassName="bea.jolt.pool.servlet.weblogic.PoolManagerShutDown"
Name="MyShutdown" Targets="webServer"/>
這里要說明一下:PrimaryAddresses,FailoverAddresses地址是前面Tuxedo配置文件指定的JSL地址和端口
SecurityContextEnabled一定要是false!所有name是隨意的,StartupClass和ShutdownClass的ClassName
絕對不能錯!
除此方法,還可以通過Weblogic服務的控制臺進行管理。啟動服務后,在http://localhost:7001/console/
登陸后的主頁面上選擇 連接性->通過 JOLT 的 Tuxedo ->配置新的Jolt 連接緩沖池...輸入參數內容就是
上面config.xml的參數。另外首頁中 已部署的資源 ->啟動和關閉 需要設置兩個Class,參數也同上。
連接性->通過 JOLT 的 Tuxedo ->配置新的Jolt 連接緩沖池...
①進入選項卡的General(常規),輸入參數:
Name: JoltPool
Minimum Pool Size: 1
Maximum Pool Size: 2
Recv Timeout: 0
點擊Apply應用按紐
②進入選項卡的Addresses(地址),輸入參數:
Primary Addresses: //192.168.0.166:9878
Failover Addresses: //192.168.0.166:9878
點擊Apply應用按紐
③進入Targets欄:
選中myserver
點擊Apply應用按紐.
已部署的資源 ->啟動和關閉 分別配置StartUp,ShutDown的Class
①進入Configuration(設置)
在ClassName:中輸入: bea.jolt.pool.servlet.weblogic.PoolManagerStartUp,
其它采用默認值。
②進入Targets(目標)欄:
選中myserver,點擊Apply應用按紐.
①進入Configuration(設置)
在ClassName:中輸入: bea.jolt.pool.servlet.weblogic.PoolManagerShutDown,
其它采用默認值。
②進入Targets(目標):
選中myserver,點擊Apply應用按紐.
到這里config.xml文件就設置完了,下面需要編輯startWebLogic.cmd,加入對jolt jar的引用,否則jolt
是啟動失敗的。在echo CLASSPATH=%CLASSPATH%前加入以下代碼,設置CLASSPATH,這里classpath跟外部環境
變量是兩碼事。
set CLASSPATH=%CLASSPATH%;E:\bea\tuxedo9.0\udataobj\jolt\jolt.jar;E:\bea\tuxedo9.0\udataobj\jolt\joltwls.jar;E:\bea\tuxedo9.0\udataobj\jolt\joltjse.jar
設置完后,重啟服務,在Eclipse管理WebLogic服務時如果出現啟動關閉不成功,多試幾次就可以了。
在啟動的console界面里如果出現以下內容,就說明jolt pool啟動成功!
<2006-6-1 下午09時12分55秒 CST> <Notice> <WebLogicServer> <BEA-000327> <Starting WebLogic Admin Server "webServer" for domain "WebServer">
Jolt pool deployed for webServer
<2006-6-1 下午09時13分13秒 CST> <Notice> <Security>...
------------------------
八、Eclipse3.1編寫Servlet代碼
------------------------
首先需要在所建工程->右鍵->Properties->Java BuildPath ->Library->Add External jars ..添加jolt的jar包
這里需要三個jar包,如下:
E:\bea\tuxedo9.0\udataobj\jolt\jolt.jar
E:\bea\tuxedo9.0\udataobj\jolt\joltjse.jar
E:\bea\tuxedo9.0\udataobj\jolt\joltwls.jar
添加jar完后,建立一個主頁面index.jsp和一個Servlet。關于Eclipse3.1配置Servlet在《Eclipse3.1 Web開發配置》
一文也有說明。這里Servlet名為liwei.java,具體內容如下:
index.jsp
<body>
<form id=form1 name="form1" action=liwei method=post>
<input type="text" name="STRING" value="1">
<input type=submit value=submit>
</form>
</body>
說明:name要是STRING,用來傳遞參數,action是liwei.java即Servlet。
liwei.java
public class liwei extends javax.servlet.http.HttpServlet
{
//聲明管理連接池的變量
private bea.jolt.pool.servlet.ServletSessionPoolManager bool_mgr = (bea.jolt.pool.servlet.ServletSessionPoolManager) bea.jolt.pool.SessionPoolManager.poolmgr;
public void init(javax.servlet.ServletConfig config) throws javax.servlet.ServletException
{
//初始化servlet
super.init(config);
}
public void destroy() {
//關閉servlet
bool_mgr = null;
}
protected void doGet(javax.servlet.http.HttpServletRequest request, javax.servlet.http.HttpServletResponse response)
throws javax.servlet.ServletException, java.io.IOException
{
bea.jolt.pool.servlet.ServletResult result;
//設置頁面類型,如果沒有charset,顯示漢字會亂碼
response.setContentType("text/html;charset=UTF-8");
java.io.PrintWriter out =response.getWriter();
out.println("<html>");
out.println("<body>");
//System.out.println("TEST________________________1");
//獲取在WebLogic服務定義好的連接池,JoltPool
bea.jolt.pool.servlet.ServletSessionPool pool_session = (bea.jolt.pool.servlet.ServletSessionPool)
bool_mgr.getSessionPool("JoltPool");
if (pool_session == null) {
out.println("獲取Tuxedo服務失敗。"+
"<br>"+
"確認Tuxedo服務已啟動且配置正確。"+
"</font></body></html>");
out.close();
return;
}
System.out.println(pool_session);
String sendvalue;
sendvalue=request.getParameter("STRING");
System.out.println(sendvalue);
// 調用服務
try
{
System.out.println("OK!");
//調用服務DBREAD
result = pool_session.call("DBREAD", request);
out.println("傳遞的參數 = " + sendvalue);
out.println("Tuxedo服務成功調用。 ");
//跟據傳遞的變量STRING值,獲取返回值
out.println("返回值:"+result.getValue("STRING", ""));
}
catch (bea.jolt.pool.SessionPoolException e)
{
// 連接池繁忙
out.println("此時請求不能被處理。\n"+
"錯誤信息: "+e.getMessage()+"\n"+
"可能的原因:1.無效的連接池 2.連接池已關閉");
}
catch (bea.jolt.pool.ServiceException e)
{
// 服務出錯,這里主要是Tuxedo的服務配置,jrepository文件出錯
e.printStackTrace();
out.println("錯誤信息:"+
"Error message:"+e.getMessage()+
"Error number:"+e.getErrno());
}
catch (bea.jolt.pool.ApplicationException e)
{
// 應用程序出錯
result = (bea.jolt.pool.servlet.ServletResult) e.getResult();
out.println("錯誤代碼:"+result.getApplicationCode());
}
catch (Exception e)
{
out.println("意外錯誤:"+e);
}
out.println("</body></html>\n");
out.close();
}
protected void doPost(javax.servlet.http.HttpServletRequest request, javax.servlet.http.HttpServletResponse response)
throws javax.servlet.ServletException, java.io.IOException
{
this.doGet(request,response);
}
}
------------------------
九、RUN
------------------------
Run on server ,點擊Submit,顯示 傳遞的參數 = 1 Tuxedo服務成功調用。 返回值:aaaaaaa !
=======================
Java通過Jolt訪問Tuxedo服務-補充說明
草木瓜
2006-6-2
一、頁面參數文件說明以及通過WebLogic調用Tuxedo服務
《Java通過Jolt訪問Tuxedo服務》一文是在Eclipse環境下開發調用Tuxedo服務。
其中在index.asp和liwei.java中有這么幾句語句:
index.asp
<form id=form1 name="form1" action=liwei method=post>
<input type="text" name="STRING" value="1">
<input type=submit value=submit>
liwei.java
//跟據傳遞的變量STRING值,獲取返回值
out.println("返回值:"+result.getValue("STRING", ""));
這兩段的STRING是不可以隨便替換的,這必須與E:\bea\tuxedo9.0\udataobj\jolt\repository
下jrepository文件描述的服務參數相一致!且必須為大寫!即:
add SVC/DBREAD:vs=1:ex=1:bt=STRING:\
bp:pn=STRING:pt=string:pf=167772161:pa=rw:ep: //這里面定義的參數就是STRING
add PKG/SIMPSERV:DBREAD:
下面用WebLogic對Tuxedo服務調用再詳細的舉例說明。
WebLogic通過jolt調用Tuxedo服務,有了上文的前提就顯得很容易,說白了只是Servlet與Jsp的一點
小轉換。除了最后一步在Eclipse3.1編寫Servlet代碼,其他的前提步驟是必須的。WebLogic要使用
Jolt接口,同樣需要jolt,joltjse,joltwls三個jar包,將它們Copy到WEB-INF下的lib文件夾即可。
以下是完整的示例,參數名用大寫的TEST。
index.jsp
---------------------------------
<form action="_test/testTuxedo.jsp" method="post">
<p>
<input type="text" value="1" name="TEST" id="text1"><input type="submit" value="tuxedo">
</p>
</form>
testTuxedo.jsp
---------------------------------
<body>
<p>
<%
bea.jolt.pool.servlet.ServletSessionPoolManager bool_mgr = (bea.jolt.pool.servlet.ServletSessionPoolManager) bea.jolt.pool.SessionPoolManager.poolmgr;
bea.jolt.pool.servlet.ServletResult result;
//獲取在WebLogic服務定義好的連接池
bea.jolt.pool.servlet.ServletSessionPool pool_session = (bea.jolt.pool.servlet.ServletSessionPool)
bool_mgr.getSessionPool("JoltPool");
if (pool_session == null) {
out.println("獲取Tuxedo服務失敗。"+
"<br>"+
"確認Tuxedo服務已啟動且配置正確。");
out.close();
return;
}
// 調用服務
try
{
result = pool_session.call("DBREAD", request);
System.out.println("OK!");
out.println("傳遞的參數 = " + sendvalue);
out.println("Tuxedo服務成功調用。 ");
out.println("返回值:"+result.getValue("TEST", ""));
}
catch (bea.jolt.pool.SessionPoolException e)
{
// 連接池繁忙
out.println("此時請求不能被處理。\n"+
"錯誤信息: "+e.getMessage()+"\n"+
"可能的原因:1.無效的連接池 2.連接池已關閉");
}
catch (bea.jolt.pool.ServiceException e)
{
// 服務出錯
e.printStackTrace();
out.println("Error:"+
"Error message:"+e.getMessage()+
"Error number:"+e.getErrno());
}
catch (bea.jolt.pool.ApplicationException e)
{
// 應用程序出錯
result = (bea.jolt.pool.servlet.ServletResult) e.getResult();
out.println("錯誤代碼:"+result.getApplicationCode());
}
catch (Exception e)
{
out.println("意外錯誤:"+e);
}
%>
</p>
</body>
二、典型的服務應用
Oracle服務器 192.168.0.111
Tuxedo服務器 192.168.0.66
Web服務器
通過Web客戶端訪問Web服務器,調用Tuxedo服務訪問數據庫
1.配置Tuxedo服務器的Oracle連接字符串(TNSNAME)。注意Oracle服務器的防火墻
WINDB =
(DESCRIPTION =
(ADDRESS_LIST =
(ADDRESS = (PROTOCOL = TCP)(HOST = 192.168.0.111)(PORT = 1521))
)
(CONNECT_DATA =
(SERVICE_NAME = wincn)
)
)
2.配置Tuxedo的jrepository文件
3.配置Tuxedo的Config文件,JSR服務的IP與端口要與本地IP一致。
JSL SRVGRP=JSLGRP SRVID=301
CLOPT="-A -- -n //192.168.0.66:9988 -M 10 -x 10 -m 2"
4.配置Web服務器的WebServer,config.xml中ip與端口即為Tuxedo服務器的JSR服務IP與端口
注意Tuxedo服務器的防火墻。
<JoltConnectionPool FailoverAddresses="http://192.168.0.66:9988"
MaximumPoolSize="2" MinimumPoolSize="1" Name="JoltPool"
PrimaryAddresses="http://192.168.0.66:9988"
SecurityContextEnabled="false" Targets="webServer"/>
Windows下Tuxedo的安裝與配置-數據庫
草木瓜 2005-5-18
一、準備數據庫環境
這里使用的是Linux+Oracle9的虛擬機數據庫環境。本機配置Tuxedo服務器。在上篇無數據庫配置
基礎上,配置Tuxedo服務器連接Oracle理解起來就相對簡單了。這里采用XA方式連接數據庫。
二、準備客戶端,服務端的應用程序
這里是自已寫的代碼。
client.c
#include <stdio.h>
#include <atmi.h> /* TUXEDO Header File */
main(int argc, char *argv[])
{
char *sendbuf;
long sendlen=1024;
int ret;
if(argc != 2) {
(void) fprintf(stderr, "args not exist\n");
exit(1);
}
/* 與服務器建立連接 */
if (tpinit((TPINIT *) NULL) == -1)
{
(void) fprintf(stderr, "Tpinit failed\n");
exit(1);
}
/* 分配發送緩沖 */
sendbuf = (char *) tpalloc("STRING", NULL, sendlen);
if (sendbuf== (char *)NULL)
{
(void) fprintf(stderr,"Error allocating send buffer\n");
tpterm();
exit(1);
}
(void) strcpy(sendbuf, argv[1]);
(void) fprintf(stdout, "InputValue: %s\n", argv[1]);
/* 向服務發送請求 */
ret = tpcall("DBSERV", (char *)sendbuf, 0L, (char **)&sendbuf, &sendlen, 0L);
if(ret == -1) {
(void) fprintf(stderr, "Can't send request to service DBREAD\n");
(void) fprintf(stderr, "Tperrno = %d\n", tperrno);
tpfree(sendbuf);
tpterm();
exit(1);
}
(void) fprintf(stdout, "Returned string is: %s\n", sendbuf);
/* Free Buffers & Detach from System/T */
tpfree(sendbuf);
tpterm();
return(0);
}
server.pc 這里用到了ProC的一些方法
#include <stdio.h>
#include <ctype.h>
#include <atmi.h> /* TUXEDO Header File */
#include <userlog.h> /* TUXEDO Header File */
EXEC SQL INCLUDE sqlca;
EXEC SQL BEGIN DECLARE SECTION;
VARCHAR ora_no[2];
VARCHAR ora_value[10];
EXEC SQL END DECLARE SECTION;
DBREAD(TPSVCINFO *rqst)
{
strcpy(ora_no.arr,(char *)rqst->data);
ora_no.len=strlen(ora_no.arr);
ora_no.arr[ora_no.len]='\0';
userlog("ERRSRV: %s",ora_no.arr);
EXEC SQL select name into :ora_value from tuxedo_test where id=:ora_no;
if(sqlca.sqlcode!=0)
{
userlog("ERRSRV: select name from tuxedo_test where id=, sqlcode=%ld \n",sqlca.sqlcode);
tpreturn(TPFAIL, 0, rqst->data, 0L, 0);
}
strcpy(rqst->data,ora_value.arr);
tpreturn(TPSUCCESS, 0, rqst->data, 0L, 0);
}
三、編譯客戶端,服務端代碼
buildclient -o client -f client.c -v
對pc文件,須首先編譯為c,然后再編譯為服務。在proc編譯的過程,會出現link錯誤,這是因為tuxedo本身
帶的sqlca.h與oracle proc沖突,將C:\bea\tuxedo9.0\include\sqlca.h改名即可。
proc server.pc include=%TUXDIR%/include
buildserver -o server -f server.c -r Oracle_XA -s DBREAD -v
四、配置Tuxedo的RM文件
本地Tuxedo9.0安裝路徑為C:\bea\tuxedo9.0。
打開C:\bea\tuxedo9.0\udataobj路徑下的rm文件。找到Oracle_XA:這句,可以注釋掉,然后增加下面內容。
Oracle_XA;xaosw;E:\oracle\ora92\rdbms\XA\ORAXA9.LIB E:\oracle\ora92\precomp\lib\orasql9.lib
注:本機如果沒有裝服務版的Oracle,可能找不到對應庫文件,可從服務器端復制過來即可。
這兩個lib是用于編譯tms文件的,tuxedo通過TMS_ORA9i與Oracle數據庫進行XA通訊。
修改完rm文件,運行命令buildtms -o C:\bea\tuxedo9.0\bin\TMS_ORA9i -r Oracle_XA編譯生成TMS_ORA9i。
五、修改ubbconfig文件
在*GROUP下添加下面語句。liwei/liwei@linux是連接數據庫的tns配置。TMSCOUNT=2表示啟動兩個TMS服務。
OPENINFO="Oracle_XA:Oracle_XA+Acc=P/liwei/liwei+SqlNet=linux+SesTm=600+MaxCur=5+LogDir=."
TMSNAME="TMS_ORA9i" TMSCOUNT=2
另外在*MACHINES添加日志的處理,語句如下。
TLOGDEVICE = "F:\Liwei\Tuxedo\dbread\TLOG"
TLOGNAME = TLOG
TLOGSIZE = 100
因為編譯的服務文件名是server,*SERVERS下改為server
因為生成的服務是DBREAD,所以*SERVICES下也要改成DBREAD。
修改后文件如下:
#Liwei
*RESOURCES
IPCKEY 123456
DOMAINID liweiapp
MASTER lw
MAXACCESSERS 5
MAXSERVERS 5
MAXSERVICES 5
MODEL SHM
LDBAL N
*MACHINES
LWYM
LMID = lw
TUXDIR = "C:\bea\tuxedo9.0"
TUXCONFIG = "F:\Liwei\Tuxedo\dbread\tuxconfig"
APPDIR = "F:\Liwei\Tuxedo\dbread"
TLOGDEVICE = "F:\Liwei\Tuxedo\dbread\TLOG"
TLOGNAME=TLOG
TLOGSIZE = 100
#ULOGPFX = "F:\Liwei\Tuxedo\dbread\ULOG"
*GROUPS
GROUP1 LMID=lw GRPNO = 1
OPENINFO="Oracle_XA:Oracle_XA+Acc=P/liwei/liwei+SqlNet=linux+SesTm=600+MaxCur=5+LogDir=."
TMSNAME="TMS_ORA9i" TMSCOUNT=2
*SERVERS
DEFAULT:
CLOPT="-A"
server SRVGRP=GROUP1 SRVID=1
*SERVICES
DBREAD
編譯日志后不能立刻tmboot運行,需要先用tmadmin創建TLOG。方法如下:
C:\>tmadmin
>crdl -b 500 -z F:\Liwei\Tuxedo\dbread\TLOG
>crlog -m lw
注:lw是ubbconfig里面的LMID。
六、Oracle的設置
Linux:
sqlplus /nolog
conn sys/*** as sysdba
執行xaview.sql 創建v$xatrans$和 v$pending_xatrans$兩個視圖
@...../rdbms/admin/xaview.sql
并把兩個視圖的select權限授給連接用戶如liwei。
grant select on v$xatrans$ to liwei with grant option;
grant select on v$pending_xatrans$ to liwei with grant option;
最后
grant select any table to liwei;
七、運行tmboot
你會發現有個TMS_ORA9i啟動不起來,沒關系,將*RESOURCES max系列的設大點,tmshutdown,并且
結束掉tuxipc,重新編譯config然后tmboot就ok了。
client 1
執行就會返回數據庫結果了。
Windows下Tuxedo的安裝配置-數據庫補充
草木瓜 2006-5-28
一、序
《Windows下Tuxedo的安裝配置-數據庫》一文中介紹了通過XA方法連接數據庫,步驟比較多,當然也可以采
用另一種方法,在服務程序里面直接寫入連接數據庫的命令。
二、服務端程序
小作修改
EXEC SQL BEGIN DECLARE SECTION;
VARCHAR ora_no[2];
VARCHAR ora_value[10];
VARCHAR ora_cn[30]; //新增
EXEC SQL END DECLARE SECTION;
EXEC SQL INCLUDE sqlca;
//新增以下內容,tpsvinit,tpsrdone是tuxedo默認構造和析構函數。
tpsvrinit()
{
strcpy(ora_cn.arr,"liwei/liwei@windb");
ora_cn.len = strlen(ora_cn.arr);
ora_cn.arr[ora_cn.len]='\0';
EXEC SQL CONNECT :ora_cn;
return(0);
}
tpsrvdone()
{
EXEC SQL COMMIT WORK RELEASE;
}
三、配置文件
注釋掉與XA相關項,由于客戶端與服務器是同一臺機器,WSL要不要無所謂。這里也注釋掉。
*GROUPS
GROUP1 LMID=lw GRPNO = 1
#OPENINFO="Oracle_XA:Oracle_XA+Acc=P/liwei/liwei+SqlNet=linux+SesTm=600+MaxCur=5+LogDir=."
#TMSNAME="TMS_ORA9i" TMSCOUNT=2
*SERVERS
server SRVGRP=GROUP1 SRVID=1
#WSL SRVGRP=GROUP1 SRVID =300
#CLOPT="-A -- -n //192.168.98.166:5898 -d/dev/tcp -m1 -M5 -x 10"
*SERVICES
DBREAD
四、編譯服務端的命令
修改如下:
proc server.pc include=%TUXDIR%\include
buildserver -o server -f server.c -s DBREAD -v
如果在編譯過程中出現error LNK2001: unresolved external symbol _sqlcxt類似的錯誤,那是因為
找不到orasql9.lib文件。設置環境變量lib,加上e:\oracle\ora92\precomp\lib,修改命令:
buildserver -o server -f server.c -s DBREAD -v -l orasql9.lib
五、編譯config文件,運行tmboot
六、補充說明
Tuxedo配置一般如下步驟:
1 設置環境變量。
2 準備服務端客戶端程序。
3 服務端客戶端編譯(buildclient buildserver)。
4 準備tuxedo的config文件。
5 編譯config文件(tmload)。
6 如果config文件包含日志,必須通過tmadmin生成日志文件(crdl,crlog),如出錯須將原日志文件刪除。
7 啟動tuxedo服務(tmboot)。
進入linux系統,在linux系統dos輸入頁面中輸入tmadmin
進入tmadmin的監管環境,輸入下面的命令即可
啟動tmadmin
tmboot -y
1查看服務信息psr
(1) 命令: printserver 簡寫 psr
(2) psr [-m machine] [-g groupname] [-i srvid] [-q qaddress]
-m machine LMID為 machine的所有服務進程
-g groupname 組名為groupname的所有服務進程
-I srvid SRVID為srvid的服務進程
-q qaddress 消息隊列為qaddress的所有SERVERS查看server的信息
(3) 結果示例:
Prog Name Queue Name Grp Name ID RqDone Load Done Current Service
--------- ---------- -------- -- ------ --------- ---------------
rz_Ecsb 00004.04000 APGP2 4000 0 0 ( IDLE )
BBL 70020 simple 0 1 50 ( IDLE )
IFMTMS APGP2_TMS APGP2 30001 1 50 ( IDLE )
ftpserv32 00002.00001 FTPGP 1 60 3000 ( IDLE )
結果說明:
列號 描述
1. 服務的可執行文件名
2. 服務連接的隊列名
3. 組名
4. 服務的數字id
5. 服務已經處理的請求數(該SERVER的所有service的負載因子總和)
6. 服務處理的全部請求的參數和,如果當前沒有service被調用,則為IDLE
2查看交易信息psc
(1) 命令: printservice 簡寫: psc
psc [-m machine] [-g groupname] [-I srvid] [-q qaddress]
[-s service] [-a {0|1|2}]
-s service 顯示名為sevice的service信息
-a {0|1|2} 顯示系統的隱含的service
其他參數與psr命令相同
(2) 結果示例:
Service Name Routine Name Prog Name Grp Name ID Machine # Done Status
------------ ------------ ------- -------- -- ------- ------ ------
416701 rz_Ecsb rz_Ecsb APGP2 4000 simple 0 AVAIL
416601 rz_Ecsb rz_Ecsb APGP2 4000 simple 0 AVAIL
416501 rz_Ecsb rz_Ecsb APGP2 4000 simple 0 AVAIL
(3) 結果說明:
列號 描述
1. Service Name :服務名
2. Routine Name :函數名(采用TUXEDO服務的別名機制,一個函數可以對應多個服務名)
3. Prog Name :service 所在的SERVER名
4. Grp Name :組名
5. ID :server的ID號
6. Machine :server所在的LMID
7. # Done :service被調用的次數
8. Status :service的狀態。AVAIL表示可用
3查看隊列信息pq
(1) 命令: printqueue 簡寫:pq [PADRESS]
(2) 結果示例:
pq 00004.05062
Prog Name Queue Name # Serve Wk Queued # Queued Ave. Len Machine
--------- ------------ ------ --------- -------- -------- -------
CCS_GEDAIPC_50 00004.05062 1 0 0 0.0 simple
(3) 結果說明:
列號 描述
1. Prog Name :隊列連接的服務的可執行文件名
2. Queue Name :字符隊列名,是RQADDR參數或一個隨機值
3. #Serve :連接的服務數
4. Wk Queued :當前隊列的所有請求的參數和
5. #Queued :實際請求數
6. Ave.Len :平均隊列長度
7. Machine :隊列所在機器的LMID
4查看客戶端信息pclt
(1) 命令: printclient 簡寫:pclt
-m machine 顯示LMID號為machine上的客戶端連接
-u username 顯示用戶名為username 的客戶端連接
-c ctlname 顯示用戶進程為ctlname的客戶端連接
(2) 結果示例:
LMID User Name Client Name Time Status Bgn/Cmmt/Abrt
---------- --------------- --------------- -------- ------- -------------
simple ccsmis WSH 17:42:47 IDLE 0/0/0
simple ccsmis tmadmin 0:44:28 IDLE 0/0/0
(3) 結果說明:
列號 描述
1. 已經登錄的客戶端機器的LMID
2. 用戶名,由tpinit()提供的
3. 客戶端名,由tpinit()提供的
4. 客戶端連接后經過的時間
5. 客戶端狀態
6. IDLE——表示客戶端目前沒有任何交易在工作
7. IDLET——表示客戶端啟動了一個交易
8. BUSY——表示客戶端在工作中
9. BUSYT——表示客戶端正在交易控制下工作
10. 啟動/提交/中斷的交易數
5查看部分統計信息bbs
(4) 命令: bbstats 簡寫:bbs
> bbs
Current Bulletin Board Status:
Current number of servers: 335
Current number of services: 2324
Current number of request queues: 27
Current number of server groups: 11
Current number of interfaces: 0
6觀察某個節點的進程信息default
(5) 命令:default –m
> default -m SITE13
SITE13> psr
Prog Name Queue Name Grp Name ID RqDone Load Done Current Service
--------- ---------- -------- -- ------ --------- ---------------
BBL 30004.00000 SITE13 0 22827 1141350 ..ADJUNCTBB
BRIDGE 836437 SITE13 1 0 0 ( IDLE )
GWADM 00021.00019 BGWGRP1+ 19 0 0 ( IDLE )
GWTDOMAIN 00021.00020 BGWGRP1+ 20 123826 0
GWADM 00022.00021 BGWGRP2+ 21 0 0 ( IDLE )
GWTDOMAIN 00022.00022 BGWGRP2+ 22 0 0 ( IDLE )
GWADM 00025.00027 GWGRP1_+ 27 4 200 ( IDLE )
7查看消息發送狀態pnw
(6) 命令:printnetwork 簡寫 pnw
> pnw SITE12
SITE12 Connected To: msgs sent msgs received
SITE14 61904 62319
SITE13 61890 62288
SITE11 15972 13564
8退出管理模式q
(7) 命令: quit 簡寫:q
C++ constructors are called to initialize class objects when those objects are created, and destructors are invoked when class objects are destroyed. For automatic (that is, local, non-static) variables that contain constructors and destructors, the constructor is called when the variable comes into scope and the destructor is called when the variable goes out of scope. However, when you call the tpreturn() or tpforward() function, the compiler performs a non-local goto (using longjmp(3)) such that destructors for automatic variables are not called. To avoid this problem, write the application so that you call tpreturn() or tpforward() from the service routine directly (instead of from any functions that are called from the service routine). In addition, one of the following should be true: