本文很短,目的在於confirm一下淩亂的《OpenVPN莫名其妙斷線的問題及其解決》,如果看覺得我比較囉嗦,那麼一定要看看最後一個小節,好在CSDN為每篇文章都自動添加了目錄,可以直接跳轉到最後一節。
1.控制通道
控制通道主宰OpenVPN的SSL握手,密鑰協商以及重協商。因此其健壯性直接影響到隧道是否能夠建立成功。因此最佳化後burst retransmit直接影響惡劣網路環境下的隧道建立過程,使之更容易建立。一旦視窗由於ACK亂序/丟失而爆滿,馬上重傳ID最小的包,期待收到ACK延展視窗!
原則:你丟包我就以多次重發來稀釋掉丟包率,雖然這種方式有點自私,但是惡劣環境中求生是需要自私的。
效果:由於控制通道的資料量有限,因此需要比較極端的方式來展現這個修改是有效,那就是設定以下幾個參數:
ping:設定為5秒,儘可能短,但不要太短
ping-restart:設定成120秒,儘可能和ping拉開距離,這兩個參數保證不會因為ping-restart導致斷開,這樣就將問題全部集中在控制通道了
reneg-sec:將它設定成2,即2秒鐘進行一次密鑰重協商
hand-window:將它設定成15,即15秒內如果SSL通道上的握手,密鑰重協商沒有成功,則算斷開
tran-window:將它設定成5,即hand-window內失敗的話,持續5秒鐘隧道斷開,該參數是可選的
用retry版本和標準版本測試,發現極端情下,標準版本幾乎會瞬間失敗,但是retry版本明顯好很多。
2.資料通道
平時隧道有資料通過的時候,timer總是會reset,沒有資料的時候,就依靠在資料通道發送PING來reset對端的timer。如果ping-restart到期timer都沒有reset,則斷開隧道。因此沒有隧道資料時,更容易斷開!注意,只要隧道建立,密鑰協商好,除了重協商或者推送,控制通道基本空閑。因此影響隧道接通後斷開的因素在ping,ping-restart參數。
3.高丟包率環境二者關係
一旦高丟包率且沒有隧道資料過境,資料通道就會完全依靠PING,如果ping-restart過短,PING在惡劣環境下丟包,則隧道就會斷開,此時會嘗試重建立立隧道,因為此時已經是惡劣環境了,丟包率很高,ACK很容易亂序/丟失,加上OpenVPN在視窗滿時不會馬上重傳,故而隧道久久不能建立。所以是,資料通道斷開反映了網路環境已經惡化,這種惡化進而影響接下來的控制通道的握手和協商,所以針對OpenVPN斷開的問題要雙管齊下,第一拉長ping和ping-restart的距離(但是不能泛PING),第二,如《OpenVPN莫名其妙斷線的問題及其解決》一樣修改OpenVPN的重傳調度邏輯。
4.程式極限
程式員往往希望一廂情願地徹底解決問題!極端的情況就是,因為TCP是保證傳輸的,所以即使網線被剪斷了,程式員還是希望(也僅僅是希望而已)能寫出什麼神秘的代碼來接通網路,也還是希望發現是由於自己代碼寫的不夠好才導致丟包,斷線。但是對於網路工程師,就反過來了,他絲毫不管應用程式如何,上去就是show這show那,檢查網線...有時候還真的就是socket阻塞了。事實上,對於OpenVPN斷線的問題,也有一種處理極限,那就是網路真的不通了,丟包率真的太大了。那怎麼辦,那就只能斷線了,這是我們所解決不了的,我們能做的就是保證損失降低到最小而已,並且告知使用者發生了什麼,讓使用者知道,雖然網路不通了,但是OpenVPN依然在不斷努力中。
5.不修改OpenVPN的防斷方案
不管怎麼說,OpenVPN也是經過很多測試的成熟代碼,它的重傳調度雖然不及時,單是畢竟會重傳!如果有重大問題,早就在社區被修改了。另外要注意的是,大多數時候,控制通道的資料包以及ACK並不是丟了,而是延遲到達,這樣的話,僅僅通過延長逾時時間就可以解決,幸運的是,OpenVPN本身給出了很多逾時時間的配置:
a.增加ping,ping-restart的差值,可以確保不會輕易由於收不到ping而斷開;
b.延長hand-window可以給控制通道的密鑰協商預留足夠的時間;
c.延長tran-window可以進一步在已經發覺要斷和隧道真正斷開之前的這期間,做reneg的最後嘗試;此參數要大於reneg-sec!
...
6.我做的一切都是畫蛇添足,但是...
實際上,當我迴歸看代碼的時候,發現我所做的針對OpenVPN的修改本來就已經實現了,只是我研究其參數配置還沒有細化到一定程度,所以我就自行進行了修改,對於我能找到點子上,並且設計出了一個schedule介面:
voidreliable_schedule_id (struct reliable *rel, time_t timeout, packet_id_type id);
我很欣慰,但是我還是重新實現了已經實現的東西,重造了輪子!這是大多數初中級程式員的典型行為!
我們來看一下以下的這個配置參數:
--tls-timeout n
Packet retransmit timeout on TLS control channel if no acknowledgment from remote within n seconds (default=2).
When OpenVPN sends a control packet to its peer, it will expect to receive an acknowledgement within n seconds or
it will retransmit the packet, subject to a TCP-like exponential backoff algorithm. This parameter only applies
to control channel packets. Data channel packets (which carry encrypted tunnel data) are never acknowledged,
sequenced, or retransmitted by OpenVPN because the higher level network protocols running on top of the tunnel
such as TCP expect this role to be left to them.
預設2秒鐘,如果想讓重傳密集化,那麼設定為1好了,雖然依靠這個參數帶來的是全域意義的重傳逾時配置,但是我相信網路會解決好擁塞問題的。比較下來,我的修改只針對ID最小的包,即僅僅重傳阻礙視窗推進的包,可能更加合理,但是OpenVPN內建的tls-timeout足以解決已經存在的ACK亂序丟失問題了,要拒絕完美,容忍不完美,這才是成事的關鍵!如果要完美,那麼代碼中就會充斥很多的所謂小技巧。
花了大量的時間考慮如何修改OpenVPN的代碼,到頭來卻是代碼回退!