LF模式是个坑,ZeroIce中间件让你体会这个痛
LF模式是個(gè)坑,一個(gè)小小的失誤就可能使你的網(wǎng)絡(luò)處理癱瘓,Ice就很好地展現(xiàn)了出來(lái),換句話(huà)說(shuō),Ice中間件或是LF模式就是一個(gè)坑,如果你一不小心。
LF模式的官方論文中,論述了此模式用于高性能網(wǎng)絡(luò)并發(fā)模式,使用的是系統(tǒng)的隱式隊(duì)列,也就是Reactor復(fù)用多路IO,(如果是select的話(huà),還是會(huì)將事件收集到一個(gè)顯式隊(duì)列),每次只有一條線(xiàn)程可以有一次機(jī)會(huì)成為leader訪(fǎng)問(wèn)這個(gè)隊(duì)列,從隊(duì)列取出事件后放棄leader,同時(shí)喚醒另一線(xiàn)程(如果還有follower線(xiàn)程的話(huà));注意這時(shí)的線(xiàn)程既不是leader也不是follower,它就可以處理事件,一般就是同步非阻塞讀寫(xiě),然后處理這個(gè)請(qǐng)求(通常來(lái)說(shuō)就是dispatchFromThisThread)。當(dāng)上面的工作結(jié)束就,才會(huì)作為follower等待成為leader,如果沒(méi)有l(wèi)eader的話(huà)就會(huì)馬上成為leader。在這種模式中,稱(chēng)為L(zhǎng)F模式有點(diǎn)誤導(dǎo),因?yàn)閷?shí)際上是三種狀態(tài),LPF,Leader,Process,Follower,狀態(tài)機(jī)為 L->P->F->L->...。Follower狀態(tài)的線(xiàn)程阻塞等待著Leader離開(kāi)Leader狀態(tài)去Process,從而喚醒可能的Follower狀態(tài)的線(xiàn)程。被喚醒的Follower線(xiàn)程狀態(tài)變?yōu)長(zhǎng)eader,成為線(xiàn)程池中唯一當(dāng)前有權(quán)操作隊(duì)列的線(xiàn)程,要么阻塞在空隊(duì)列,要么取出隊(duì)列一個(gè)事件離開(kāi)Leader狀態(tài)去Process。線(xiàn)程池線(xiàn)程當(dāng)Process完事件后才會(huì)狀態(tài)變?yōu)镕ollower,或者阻塞等待Leader的喚醒,或者自動(dòng)成為L(zhǎng)eader。狀態(tài)機(jī)就為 L(block on event queue)->P->F->(block on followers queue)->L ...。在這種模式下的線(xiàn)程池中,最多只有一個(gè)線(xiàn)程在Leader狀態(tài),并且只有這個(gè)Leader線(xiàn)程可以阻塞在IO事件隊(duì)列,其它線(xiàn)程要么在Process狀態(tài)處理事件,要么就是在Follower狀態(tài)等待成為下一個(gè)Leader。當(dāng)沒(méi)有IO事件的時(shí)候,就只有一個(gè)線(xiàn)程在Leader狀態(tài)阻塞在IO事件隊(duì)列,其它線(xiàn)程都結(jié)事了事件的處理,并在Follower狀態(tài)阻塞等待Leader線(xiàn)程釋放信號(hào)。
通常用來(lái)襯托LF模式的,就是sync/async模式,并且都會(huì)舉例Manager-Workers線(xiàn)程池。Manager負(fù)責(zé)將隊(duì)列的事件指派到空閑Worker線(xiàn)程進(jìn)行處理。Worker線(xiàn)程被喚醒處理完事件后再次阻塞等待Manager喚醒。當(dāng)沒(méi)有事件的時(shí)候,Manager阻塞在事件隊(duì)列,Worker線(xiàn)程阻塞等待Manager線(xiàn)程喚醒。這種線(xiàn)程池有一個(gè)固定線(xiàn)程去阻塞在事件隊(duì)列。并且每次Manager喚醒Worker都要通過(guò)堆來(lái)傳遞事件。(Manager從事件隊(duì)列取出一個(gè)事件寫(xiě)入到堆內(nèi)存,Worker從堆內(nèi)存讀到自己的棧,然后處理?xiàng)I系倪@個(gè)事件;而Leader從事件隊(duì)列將一個(gè)事件讀到自己的棧,再就喚醒其它Follower,然后處理?xiàng)I系倪@個(gè)事件。)當(dāng)Manager線(xiàn)程不負(fù)責(zé)Reactor復(fù)用多路IO的情況,在空閑時(shí)發(fā)生了一次IO事件必須跨線(xiàn)程寫(xiě)入Manager線(xiàn)程的事件隊(duì)列,并喚醒Manager線(xiàn)程,然后Manager線(xiàn)程喚醒Worker線(xiàn)程去處理事件。而LF模式線(xiàn)程池,Leader從系統(tǒng)的多路IO復(fù)用分離函數(shù)中返回,喚醒一個(gè)Follower,然后自己去處理事件。這樣一比較就是Manager-Workers線(xiàn)程池進(jìn)行了兩次線(xiàn)程喚醒,而LF模式線(xiàn)程池只有一個(gè)線(xiàn)程喚醒(這里必須要公正,Leader是之前就被喚醒經(jīng)歷消耗了一次切換),事件在Manager-Workers線(xiàn)程池需要多次拷貝。
那么為什么LF模式不心就會(huì)踩坑,而Ice的設(shè)計(jì)就讓體會(huì)這個(gè)坑。
問(wèn)題在于如果LF模式線(xiàn)程池的線(xiàn)程進(jìn)行Process阻塞等待IO響應(yīng),而所有的線(xiàn)程都在Process過(guò)程中阻塞等待IO響應(yīng),更重要這些被等待的IO應(yīng)用在這個(gè)線(xiàn)程池的Reactor,就會(huì)再也沒(méi)有線(xiàn)程成為L(zhǎng)eader去多路IO分離函數(shù)中讀取IO事件。這時(shí)候這個(gè)LF線(xiàn)程池就會(huì)癱瘓不工作。Ice中間件會(huì)讓你深深體會(huì)這種痛。Ice采用ActiveObject模式進(jìn)行OBR對(duì)象代理請(qǐng)求。控制線(xiàn)程調(diào)用proxy請(qǐng)求返回一個(gè)future,阻塞等待future。Communicator的clientThreadPool負(fù)責(zé)Reactor,收到請(qǐng)求的response后就向future發(fā)信號(hào),從而喚醒這個(gè)response對(duì)應(yīng)的future阻塞住的控制線(xiàn)程。這種情況下使用ORB對(duì)象代理請(qǐng)求的線(xiàn)程與網(wǎng)絡(luò)Reactor線(xiàn)程池獨(dú)立,負(fù)責(zé)Reactor的LF線(xiàn)程池不會(huì)被其它邏輯影響。但是在LF線(xiàn)程池中進(jìn)行ORB對(duì)象代理請(qǐng)求呢?問(wèn)題就來(lái)了。你的LF線(xiàn)程池隨時(shí)都可能癱瘓掉,只要你不小心。極端地,LF線(xiàn)程池只有一個(gè)線(xiàn)程,這個(gè)線(xiàn)程在Process事件時(shí),進(jìn)行了ORB對(duì)象代理請(qǐng)求,阻塞等待future。Good Job!! 這個(gè)線(xiàn)程池中唯一的線(xiàn)程就永遠(yuǎn)不會(huì)再有機(jī)會(huì)成為L(zhǎng)eader去取出遠(yuǎn)端的response的IO事件,去喚醒這個(gè)阻塞住線(xiàn)程的future了。這還不容易解決,都說(shuō)是線(xiàn)程池,那會(huì)只有一個(gè)線(xiàn)程的呢。我們讓這個(gè)LF線(xiàn)程池添加到兩個(gè)線(xiàn)程,第一個(gè)線(xiàn)程取出事件喚醒第二個(gè)線(xiàn)程,然后自己處理事件時(shí),進(jìn)行了ORB對(duì)象代理請(qǐng)求,阻塞等待future;第二個(gè)線(xiàn)程成為L(zhǎng)eader阻塞在多路IO分離函數(shù),并在遠(yuǎn)端response到來(lái)時(shí),從分離函數(shù)返回,得以喚醒了阻塞第一個(gè)線(xiàn)程的future。但是很不幸,第二個(gè)線(xiàn)程在等待到response到來(lái)之前,收到其它IO事件,而處理這個(gè)事件卻進(jìn)行了ORB對(duì)象代理請(qǐng)求,阻塞等待future。汗,LF線(xiàn)程池都被阻塞在future,future又等待IO事件。再往下演繹,不論LF線(xiàn)程池有多少線(xiàn)程,只要你的處理邏輯中進(jìn)行了同步阻塞的ORB對(duì)象代理請(qǐng)求,都會(huì)使你的Ice網(wǎng)絡(luò)處理癱瘓,癱瘓的原因是LF線(xiàn)程池癱瘓了。Ice的Server端線(xiàn)程池默認(rèn)就在當(dāng)前線(xiàn)程進(jìn)行請(qǐng)求的dispatch,如果你在實(shí)現(xiàn)你的服務(wù)的時(shí)候必須依賴(lài)其它ORB對(duì)象代理請(qǐng)求時(shí),你就要小心了,你可能因?yàn)檫@樣而阻塞掉所有Communicator的Server端LF線(xiàn)程池,至使網(wǎng)絡(luò)Reactor癱瘓。如果你使用了bidirection connection來(lái)提供callback的飼服,要是你在callback的實(shí)現(xiàn)中依賴(lài)了其它ORB對(duì)象代理請(qǐng)求時(shí),你同樣也要小心了,你可能因?yàn)檫@樣而阻塞掉所有Communicator的Client端LF線(xiàn)程池,至使網(wǎng)絡(luò)Reactor癱瘓。Ice為了避免,會(huì)默認(rèn)為每個(gè)連接加上一個(gè)計(jì)時(shí)器,讓連接自動(dòng)斷開(kāi)。但是我們還是有應(yīng)用場(chǎng)合希望連接長(zhǎng)九不斷開(kāi),關(guān)閉這種機(jī)制,這時(shí)就要小心了。再者就是,即使你所有的ORB對(duì)象請(qǐng)求代理都用異步方式(ami,amd)進(jìn)行編程,但是悲劇的是你無(wú)法干涉到你依賴(lài)的其它人函數(shù)沒(méi)有進(jìn)行同步阻塞的ORB對(duì)象代理請(qǐng)求。
轉(zhuǎn)載于:https://www.cnblogs.com/bbqzsl/p/7462606.html
總結(jié)
以上是生活随笔為你收集整理的LF模式是个坑,ZeroIce中间件让你体会这个痛的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: python 替换字符串
- 下一篇: js中this的指向问题