欧美三区_成人在线免费观看视频_欧美极品少妇xxxxⅹ免费视频_a级毛片免费播放_鲁一鲁中文字幕久久_亚洲一级特黄

動手寫一個OpenVPN的wrapper來優化OpenVPN性能

系統 5360 0
OpenVPN,一個讓人想說愛你不容易的VPN,曾經耗費了我大量精力的VPN,其性能,...最終還是不咋地!以下是一個大致的統計數據:
純千兆環境,4核心至強3.0GHZ處理器,OpenVPN使用BF-CBC加密,SHA1摘要,OpenVPN不綁定特定CPU,帶寬可達20-30MB/s;
純千兆環境,4核心至強3.0GHZ處理器,OpenVPN不加密,不摘要,OpenVPN不綁定特定CPU,帶寬可達40-45MB/s;
純千兆環境,4核心至強3.0GHZ處理器,OpenVPN不加密,不摘要,OpenVPN綁定特定CPU,帶寬可達45-55MB/s;
純千兆環境,4核心至強3.0GHZ處理器,OpenVPN使用BF-CBC加密,不摘要,OpenVPN綁定特定CPU,帶寬可達35-40MB/s;
純千兆環境,綁定OpenVPN到特定CPU,該CPU會跑滿,帶寬無法提升受制于CPU;
純千兆環境,不綁定OpenVPN到特定CPU,沒有一個CPU跑滿,帶寬無法提升受制于OpenVPN的單進程模型以及操作系統多處理器調度開銷;
百兆環境,無論如何,OpenVPN的加密隧道帶寬基本接近物理網卡的百兆帶寬。

既然是OpenVPN的軟件模型遠遠跟不上硬件的提升,那么就要想辦法以量取勝,辦法是運行多個OpenVPN進程,每一個CPU上綁定一個,通過Linux的內核接口可以很容易做到這一點:
1.首先mount一個cpuset,創建3個set
    mount -t cpuset none /mnt
mkdir /mnt/{vpn1,vpn2,vpn3}
  
2.簡單配置一個cpuset
    echo 0 > /mnt/vpn1/cpus
echo 0 > /mnt/vpn1/mems
echo 1 > /mnt/vpn2/cpus
echo 0 > /mnt/vpn2/mems
echo 2 > /mnt/vpn3/cpus
echo 0 > /mnt/vpn3/mems
  
3.以不同端口號和虛擬網段啟動3個不同的OpenVPN進程
    openvpn --config cfg1 --port 1234 --server 121.121.0.0 255.255.0.0
openvpn --config cfg2 --port 2234 --server 122.122.0.0 255.255.0.0
openvpn --config cfg3 --port 3234 --server 123.123.0.0 255.255.0.0
  
4.綁定上述3個openvpn進程到不同的cpuset
    i=1;for pid in $(ps -e|grep openvpn|awk -F ' ' '{print $1}');do echo $pid > /mnt/vpn$i/tasks; ((i=i+1)); done
  
5.將多個客戶端連接在這不同的三個OpenVPN進程上,拉取大文件,測試OpenVPN服務器的tap0-tap2的總流量
經過上述配置后,新的統計數據如下:
純千兆環境,4核心至強3.0GHZ處理器,OpenVPN使用BF-CBC加密,SHA1摘要,帶寬可達35-40MB/s;
純千兆環境,4核心至強3.0GHZ處理器,OpenVPN不加密,不摘要,帶寬可達75-80MB/s;
純千兆環境,4核心至強3.0GHZ處理器,OpenVPN使用BF-CBC加密,不摘要,帶寬可達50-55MB/s;
純千兆環境,3個CPU會跑滿,帶寬無法再提升受制于CPU;
純千兆環境,將物理網卡中斷(同時也是協議棧接收處理的軟中斷)釘在第四個CPU上,上述值再有5左右的提升。

可見,多個處理進程會帶來帶寬的大幅提升。實際上上述的方案完全可以通過虛擬網卡bondding或者多VPN進程共享虛擬網卡的方式做到,然而這些配置都不簡單,有時還要修改虛擬網卡的驅動程序,可擴展性很不好,因此簡單的以多OpenVPN實例來說明問題是再好不過的了,如需bonding方案或者shared-tap方案,請參考《 關于OpenVPN文章的目錄 》。
雖然上述方案解決了部分性能問題,然而配置還是比較復雜,能不能通過一個wrapper將上述的操作包裝起來呢?既能做到多實例并行-綁定特定CPU,又能做到OpenVPN客戶端動態自動獲取OpenVPN服務器端口號和虛擬網段。這需要增加一個層次,就是在OpenVPN連接之前增加一個“端口/虛擬網段”協商的層。該包裝器的使用如下:
服務器端:openvpn-wrapper -t server -p 1111 -v /usr/sbin/openvpn -c /home/zy/cfg ....
客戶端:openvpn-wrapper -t client -p 1111 -a 192.168.1.23 -v /usr/sbin/openvpn -c /home/zy/cfg-client
參數意義如下:
-t:類型,分為server和client,和openvpn一樣
-p:wrapper服務器監聽的TCP端口號
-v:openvpn的路徑
-c:openvpn配置文件的路徑,該文件中沒有那些自動協商出來的配置,比如openvpn的端口,虛擬網段等等。

openvpn-wrapper的代碼結構如下:
    struct vpn_opt {
    char vpn_path[255]; //openvpn的路徑
    char cfg_path[255]; //openvpn配置文件路徑,配置文件不含server指令和port指令
    int port_base;      //起始端口號
    int num_process;    //openvpn進程數量
    int num_cpu;        //CPU數量
    int sintr_cpu;      //單獨分配的處理物理網卡軟中斷的CPU
};

struct vpn_opt vopt;
int vpn_servers()
{
    int pid;
    int ps = vopt.num_process;
    //創建ps個openvpn服務器進程
    while (ps--) {
        pid = fork();
        if (pid == 0) {
            //每一個openvpn服務器進程綁定在一個CPU上
            sched_setaffinity(getpid(), ..., ps%vopt.num_cpu);
            execve(vopt.vpn_path --config vopt.cfg_path --port vopt.port_base+ps --server $不同虛擬網段...);
        } else if (pid > 0) {
        } else {
        }
    }
}
 
int accept_clients()
{
    //創建TCP服務器,接收client請求,回送端口信息
    //端口調度算法:
    //1.輪轉調度:N個客戶端按照先后順序在vopt.num_process個進程之間輪轉
    //2.空閑優先:紀錄M個VPN進程之間的負載情況或client連接數,取最小值
    //3.其它的算法...

    //對應客戶端的wrapper先連接這個TCP server,得到VPN端口信息后調用exec啟動
    //openvpn客戶端進程。
}
 
int main(int argc, char **argv)
{
    char c;
    while ((c = getopt (argc, argv, "")) != -1)
        switch (c)
        {
        case 'v':
            strcpy(vopt.vpn_path, optarg);
            break;
        case 'c':
            strcpy(vopt.cfg_path, optarg);
            break;
        //可供配置的其它參數,比如CPU數量,中斷處理均衡等
        default:
            abort ();
    }
    //下述參數必須由命令行提供:
    //vopt.port_base = 61195;
    //vopt.num_process = 2;
    //vopt.num_cpu = 2;
    vpn_servers();
    accept_clients();
}
  
有了這個wrapper,就可以將之直接替代openvpn了,但是對于大網對大網的拓撲,如此混亂的虛擬網段讓客戶端怎么管理呢?這可以通過將所有的配置全部集中在OpenVPN服務器端來解決,客戶端需要怎么配置全由服務器端來推送,涉及到自定義信息的推送,請參考push setenv-safe這個指令。如果涉及到全網互通的路由配置,你就不能單靠OpenVPN的client-to-client了,還要在不同的虛擬子網之間配置路由,怎么辦呢?還記得ICMP Redirect嗎?統一配置默認網關(注意單加物理網段互通的路由)該虛擬網段的OpenVPN服務器的虛擬IP,如果目標屬于同一個OpenVPN實例管轄,那么tap模式下OpenVPN服務器會直接發送ICMP Redirect,如果不是由同一個OpenVPN實例管轄,那么確保OpenVPN服務器上擁有管轄目標網段的OpenVPN實例即可,一切都可以靠單點路由配置搞定。
總之一,將配置集中于一個點,最終由同一個人來配置,這樣最不容易引起混亂,剩下的全部由機器來做。能推送下去的盡量推送下去,做到單點配置。OpenVPN提供了豐富的可推送的配置,實在滿足不了的可以使用setenv-safe這個。
總之二,優化無極限,如果你單看多個OpenVPN實例運行帶來了性能提升就沾沾自喜了,那么你就會錯過綁定單個實例到一個CPU上帶來的進一步性能提升,如果你有幸看到了這一點,不要停步,看看top輸出,你會發現軟中斷可能在和OpenVPN搶奪CPU,因此你會進入/proc/interrupts看個究竟,于是你可以通過設置/proc/irq/smp_affinity文件來分離中斷,突然,你看到了以下信息:
95: 18250769 193538 28997 45831 0 0 0 0 IR-PCI-MSI-edge eth3-TxRx-1
96: 4115 0 0 0 0 0 0 0 IR-PCI-MSI-edge eth3-TxRx-2
97: 52535493 0 0 0 0 0 0 0 IR-PCI-MSI-edge eth3-TxRx-3
98: 75459635 0 0 0 0 0 0 0 IR-PCI-MSI-edge eth3-TxRx-4
99: 4115 0 0 0 0 0 0 0 IR-PCI-MSI-edge eth3-TxRx-5
100: 44074216 0 0 0 0 0 0 0 IR-PCI-MSI-edge eth3-TxRx-6
101: 20545603 0 0 0 0 0 0 0 IR-PCI-MSI-edge eth3-TxRx-7
于是你不得不拿起千兆以太網卡的手冊看看多隊列相關的內容。這樣完了嗎?虛擬網卡帶寬之和已經接近物理網卡的千兆帶寬了--98MB/s,不要止步,記得Linux有一個renice命令,提升一下OpenVPN的優先級試一下...105MB/s。我想還可以更好,只是時間來不及了...出事了!
如果你只是看到了這,那么你可能錯過了一件大事。重新看上面的eth3-TxRx-1信息,然后思考結果。當我將每一個OpenVPN綁定于特定的不同CPU之后,所有的網卡TxRx隊列卻還只是由一個CPU處理,這就形成了一個多對一的關系,考慮如下的拓撲:
動手寫一個OpenVPN的wrapper來優化OpenVPN性能
服務器端每一個VPN進程由一個單獨的CPU來處理,它們很顯然都會將包發往網卡ETH3,而該網卡ETH3的中斷卻只由一個CPU來處理,不管是發送中斷還是接收中斷。能不能均分一下任務呢?在均分之前,先要想一個方案。我有8個CPU核心,分別處于兩個封裝上,每個封裝4個核心,于是我啟動6個VPN實例,分別綁定在編號(從0開始)為1,2,3,4,5,6的CPU上,然后讓CPU0和CPU1各自處理一半的軟中斷(大多數是接收中斷的軟中斷),這是因為一個封裝內部的Cache親和性以及CPU核心親和性要比屬于不同封裝的核心好很多,因此兩個封裝中各自都有一個核心處理軟中斷,可以高效地將數據踢給綁定于同一封裝核心的VPN實例。測試下來雖然性能提升不顯著,但是畢竟有了3MB/s的提升。
說了這么多,所謂的OpenVPN的優化都是在OpenVPN外部進行的,要知道其本身也有很多的參數可以調節性能,比如sndbuf和rcvbuf以及txqueuelen這三個參數,如果rcvbuf和sndbuf不一致相差太多的話,會造成UDP以及ICMP的大量丟包,雖然TCP能調節自身的速率,但是當rcvbuf小到比TCP管道最細的部位還要小的時候,丟包就顯著了,比如rcvbuf是M,而TCP的慢啟動閥值為N,且N遠大于M,這就會導致TCP頻繁大量丟包,然后慢啟動,然后再丟包,再慢啟動...此時要么調小慢啟動閥值,要么調小TCP發送緩沖區,對于Linux則是tcp_wmem,不過最好的辦法就是調整sndbuf和rcvbuf,將其調整為一樣大,并且適當比TCP管道更寬一些,讓TCP可以在其中自由發揮流控以及擁塞控制,而不是將OpenVPN模擬成一段及其惡劣的線路,如果你將sndbuf設置成了30000,將rcvbuf設成了1234567,那么雖然TCP也能進入VPN隧道,但是這條隧道太惡劣了,有效速率將會很低很低。
可是還有個小問題,為何不把中斷均分到VPN實例所在的CPU呢?這是可行的,然而必須用測試結果說話,有一點可以確定的是,如果那樣的話,雖然可能會得益于千兆網卡的DCA,然而VPN實例和軟中斷將會搶奪CPU,搶奪的激烈程度不僅僅受制于CPU的性能,還要受制于時間的串行性的本質,畢竟同一時刻一個CPU只能做一件事,因此有時候,你用top發現每一個CPU都沒有泡滿,然而性能卻反而因為中斷均分而下降了,值得注意的是,Cache親和性雖然很重要,但是相比訪問同一個核心的Cache的開銷,訪問同一顆封裝的Cache的開銷也不會差太多,畢竟現代超猛的多核心處理器的每個封裝,甚至封裝之間都有共享Cache的。于是這又扯到了一級Cache,二級Cache,...內存,磁盤,網絡等存儲設備的大小和層次問題了...
通過測試終端的TCP重傳次數計算,上述的結果非常不錯,優化無極限,如果考慮到一路統一MTU,那將必須又是一個優化切入點,另外還有e1000e千兆網卡驅動的很多參數還沒有調整,另外,如果你的CPU核心在綁了一個OpenVPN實例且滿數據跑時top顯示其idle百分比仍然很高,那么就在其上綁定兩個或者多個OpenVPN實例,總之,CPU利用率達到90%以上并不是壞事,而是好事,這個和桌面系統是完全不同的...
如果CPU跑不滿,先別急著綁多個VPN實例,還有一招,那就是壓縮,在OpenVPN配置中增加comp-lzo即可,非常簡單,理論和測試結果均證明,啟用壓縮可以大大減少丟包率,且使得吞吐量得到大幅提高。最基本的一點,對于TCP而言,我覺得多個OpenVPN載荷包打包壓縮要比單個載荷包單獨壓縮效果更好些,OpenVPN隧道一端對多個TCP包進行壓縮,另一端簡單進行解壓縮,隧道途中,壓縮包中載荷數據包順序決不會亂掉,因此也就使得串行的協議比如TCP的順序性得到了加強,多包加密隧道不但封裝了數據加密了數據,還帶著串行的TCP數據走過了最坎坷的一段路使它們不會亂序。下圖說明了這一點:
動手寫一個OpenVPN的wrapper來優化OpenVPN性能
但是,即使是單包壓縮,也會使隧道傳輸速率提高,因為隧道內的數據包尺寸減小了,更有利于傳輸(轎車要比卡車快...?),同時通過調節中途設備的網卡驅動參數還能將隧道傳輸速率進一步提高,舉個例子,Intel千兆網卡就有可以調節的參數使它更有利于小包的收發,或者更有利于大包的收發,或者折中。MTU導致的IP分段也是使用壓縮的重要理由。壓縮可以將包壓小,如果傳輸文件,發送數據塊而不是小包的可能性較大(相反的則是ssh之類的延遲敏感的程序,它們一般使用小包通信),那么起始端可能根據網卡的MTU來截取數據包,然而OpenVPN在用戶態使用socket為其進行封裝,肯定會超過MTU值,因此OpenVPN的封裝對于端到端的MTU發現是不可見的,所以IP分段并沒有發生在端到端的載荷包上,而是發生在OpenVPN的數據傳輸本身。通過抓包,發現大量:
10:07:26.243655 IP (tos 0x0, ttl 64, id 50897, offset 0, flags [+], proto UDP (17), length 1500)
172.16.2.1.61195 > 172.16.2.2.43050: UDP, length 1529
10:07:26.243659 IP (tos 0x0, ttl 64, id 50897, offset 1480, flags [none], proto UDP (17), length 77)
172.16.2.1 > 172.16.2.2: udp

因此很大一部分開銷花在了IP分段/重組上,故采用壓縮是明智的。一個等價的解決方案是不使用壓縮(畢竟它消耗了CPU),取而代之的是將OpenVPN兩個端點之間的所有鏈路的MTU調大那么一點點(多處一個OpenVPN協議頭以及OpenVPN使用的TCP/UDP頭等協議頭)。
做到這一步,現實意義上已經夠了,剩下的就全屬業余愛好了...
最后要說的是,雖然以上的方式有效的提升了OpenVPN構建的VPN隧道性能,然而卻不能將所有多條隧道的帶寬全部供給一個OpenVPN客戶端,只是說它們的和是一個不小的值,如果想實現單條隧道的帶寬提升,那就需要多實例bonding或者多實例路由負載均衡了。本文所寫的其實不是什么創新,很多Linux發行版自帶的OpenVPN本身就提供了多實例OpenVPN并行的配置,只需要service包裝命令啟動一下即可。

動手寫一個OpenVPN的wrapper來優化OpenVPN性能


更多文章、技術交流、商務合作、聯系博主

微信掃碼或搜索:z360901061

微信掃一掃加我為好友

QQ號聯系: 360901061

您的支持是博主寫作最大的動力,如果您喜歡我的文章,感覺我的文章對您有幫助,請用微信掃描下面二維碼支持博主2元、5元、10元、20元等您想捐的金額吧,狠狠點擊下面給點支持吧,站長非常感激您!手機微信長按不能支付解決辦法:請將微信支付二維碼保存到相冊,切換到微信,然后點擊微信右上角掃一掃功能,選擇支付二維碼完成支付。

【本文對您有幫助就好】

您的支持是博主寫作最大的動力,如果您喜歡我的文章,感覺我的文章對您有幫助,請用微信掃描上面二維碼支持博主2元、5元、10元、自定義金額等您想捐的金額吧,站長會非常 感謝您的哦!!!

發表我的評論
最新評論 總共0條評論
主站蜘蛛池模板: 天天操夜夜操天天操 | 一本一本大道香蕉久在线精品 | 秋霞理论在线视频 | 精品国产视频 | 欧美综合久久 | 亚洲人成一区二区三区 | 久操成人| 99久久免费国产精品 | 欧美精品第二页 | 久久精品国产一区二区三区不卡 | 欧美一级www | 欧美国产日本高清不卡 | 久久亚洲日本不卡一区二区 | 免费成人福利视频 | 日本黄视频在线观看 | 精品久久久久区二区8888 | 国产成人综合在线观看网站 | 欧美一a一片一级一片 | 精品国产不卡一区二区三区 | 亚洲午夜在线视频 | 99爱国产 | 老版奇米影视 | 二级黄绝大片中国免费视频 | 99久久久无码国产精品 | 久久永久免费中文字幕 | 欧美日韩成人在线观看 | 不卡一区在线观看 | 亚洲综合一二三区 | 亚洲天堂一区二区三区四区 | 欧洲毛片 | 亚洲欧美国产精品久久 | 99热在线播放 | 一级毛片不卡片免费观看 | 久久国产精品久久久久久久久久 | 亚洲精品中文字幕在线观看 | 中文字幕日韩欧美一区二区三区 | 中文字幕在线看 | 欧美一区二区三区四区夜夜大片 | 日本高清视频www | 天天干夜夜爽 | 中文字幕国产日韩 |