若是從應用層面進行復制,好比基於服務器的請求複製,實現起來相對簡單,但也存在着若干缺點:
1)請求複製從應用層出發,穿透整個協議棧,這樣就容易擠佔應用的資源,好比寶貴的鏈接資源 ,
2)測試跟實際應用耦合在一塊兒,容易影響在線系統,
3)也所以很難支撐壓力大的請求複製,
4)很難控制網絡延遲。
而基於底層數據包的請求複製,能夠作到無需穿透整個協議棧,路程最短的,能夠從數據鏈路層抓請求包,從數據鏈路層發包,路程通常的,能夠在IP層抓請求包,從IP層發出去,無論怎麼走,只要不走TCP,對在線的影響就會小得多。這也就是 TCPCopy 的基本思路。
從傳統架構的 rawsocket+iptable+netlink,到新架構的 pacp+route,它經歷了三次架構調整,現現在的 TCPCopy 分爲三個角色:
- Online Server(OS):上面要部署 TCPCopy,從數據鏈路層(pcap 接口)抓請求數據包,發包是從IP層發出去;
- Test Server(TS):最新的架構調整把 intercept 的工做從 TS 中 offload 出來。TS 設置路由信息,把 被測應用 的須要被捕獲的響應數據包信息路由到 AS;
- Assistant Server(AS):這是一臺獨立的輔助服務器,原則上必定要用同網段的一臺閒置服務器來充當輔助服務器。AS 在數據鏈路層截獲到響應包,從中抽取出有用的信息,再返回給相應的 OS 上的 tcpcopy 進程。
請配合下圖1理解:
圖1 三個角色的數據流轉方式
Online Server 上的抓包:
tcpcopy 的新架構在 OS 上抓請求數據包默認採用 raw socket input 接口抓包。王斌則推薦採用 pcap 抓包,安裝命令以下:
./configure --enable-advanced --enable-pcap
make
make install
這樣就能夠在內核態進行過濾,不然只能在用戶態進行包的過濾,並且在 intercept 端或者 tcpcopy 端設置 filter(經過 -F 參數,相似 tcpdump 的 filter),達到起多個實例來共同完成抓包的工做,這樣可擴展性就更強,適合於超級高併發的場合。
爲了便於理解 pcap 抓包,下面簡單描述一下 libpcap 的工做原理。 nginx
一個包的捕捉分爲三個主要部分: git
- 面向底層包捕獲,
- 面向中間層的數據包過濾,
- 面向應用層的用戶接口。
這與 Linux 操做系統對數據包的處理流程是相同的(網卡->網卡驅動->數據鏈路層->IP層->傳輸層->應用程序)。包捕獲機制是在數據鏈路層增長一個旁路處理(並不干擾系統自身的網絡協議棧的處理),對發送和接收的數據包經過Linux內核作過濾和緩衝處理,最後直接傳遞給上層應用程序。以下圖2所示: github
圖2 libpcap的三部分
Online Server 上的發包:
如圖1所示,新架構和傳統架構同樣,OS 默認使用 raw socket output 接口發包,此時發包命令以下:
./tcpcopy -x 80-測試機IP:測試機應用端口 -s 服務器IP -i eth0
其中 -i 參數指定 pcap 從哪一個網卡抓取請求包。
此外,新架構還支持經過 pcap_inject(編譯時候增長--enable-dlinject)來發包。
Test Server 上的響應包路由:
須要在 Test Server 上添加靜態路由,確保被測試應用程序的響應包路由到輔助測試服務器,而不是回包給 Online Server。
Assistant Server 上的捕獲響應包:
輔助服務器要確保沒有開啓路由模式 cat /proc/sys/net/ipv4/ip_forward,爲0表示沒有開啓。
輔助服務器上的 intercept 進程經過 pcap 抓取測試機應用程序的響應包,將頭部抽取後發送給 Online Server 上的 tcpcopy 進程,從而完成一次請求的複製。
0x02,實做:仿真測試的拓撲
下面將列出本次仿真測試的線上環境拓撲圖。
環境以下:
- Online Server
- 4個生產環境 Nginx
- 172.16.***.110
- 172.16.***.111
- 172.16.***.112
- 172.16.***.113
- Test Server
- Assistant Server
拓撲如圖3所示:
圖3 壓測環境拓撲
它的數據流轉順序以下圖4所示:
圖4 壓測環境的數據流轉順序
0x03,實做:操做步驟
下面分別列出在 Online Server/Test Server/Assistant Server 上的操做步驟。
3.1 Online Server 上的操做:
下載並安裝 tcpcopy 客戶端;
git clone http://github.com/session-replay-tools/tcpcopy
./configure
make && make install
安裝完成後的各結構目錄:
Configuration summary
tcpcopy path prefix: "/usr/local/tcpcopy"
tcpcopy binary file: "/usr/local/tcpcopy/sbin/tcpcopy"
tcpcopy configuration prefix: "/usr/local/tcpcopy/conf"
tcpcopy configuration file: "/usr/local/tcpcopy/conf/plugin.conf"
tcpcopy pid file: "/usr/local/tcpcopy/logs/tcpcopy.pid"
tcpcopy error log file: "/usr/local/tcpcopy/logs/error_tcpcopy.log"
運行 tcpcopy 客戶端,有幾種可選方式:
./tcpcopy -x 80-172.16.***.52:80 -s 172.16.***.53 -d #全流量複製
./tcpcopy -x 80-172.16.***.52:80 -s 172.16.***.53 -r 20 -d #複製20%的流量
./tcpcopy -x 80-172.16.***.52:80 -s 172.16.***.53 -n 2 -d #放大2倍流量
3.2 Test Server 上的操做:
添加靜態路由:
route add -net 0.0.0.0/0 gw 172.16.***.53
3.3 Assistant Server 上的操做:
下載並安裝 intercept 服務端;
git clone http://github.com/session-replay-tools/intercept
./configure
make && make install
安裝完成後的各結構目錄:
Configuration summary
intercept path prefix: "/usr/local/intercept"
intercept binary file: "/usr/local/intercept/sbin/intercept"
intercept configuration prefix: "/usr/local"
intercept configuration file: "/usr/local/intercept/"
intercept pid file: "/usr/local/intercept/logs/intercept.pid"
intercept error log file: "/usr/local/intercept/logs/error_intercept.log"
運行 intercept 服務端;
./intercept -i eth0 -F 'tcp and src port 80' -d
圖5 生產環境和鏡像環境數據傳輸流程圖
對照上圖5,再簡單解釋一下工做原理:
- TCPcopy 從數據鏈路層 copy 端口請求,而後更改目的 ip 和目的端口。
- 將修改過的數據包傳送給數據鏈路層,而且保持 tcp 鏈接請求。
- 經過數據鏈路層從 online server 發送到 test server。
- 在數據鏈路層解封裝後到達 nginx 響應的服務端口。
- 等用戶請求的數據返回結果後,回包走數據鏈路層。
- 經過數據鏈路層將返回的結果從 test server 發送到 assistant server。注:test server 只有一條默認路由指向 assistant server。
- 數據到達 assistant server 後被 intercept 進程截獲。
- 過濾相關信息將請求狀態發送給 online server 的 tcpcopy,關閉 tcp 鏈接。
0x04,可能會遇到的問題
王斌本身講:要想用好 tcpcopy,須要熟悉系統知識,包括如何高效率抓包,如何定位系統瓶頸,如何部署測試應用系統,如何抓包分析。常見問題有:1)部署測試系統不到位,耦合線上系統,2)忽視系統瓶頸問題,3)不知道如何定位問題,4)資源不到位,資源緊張引起的問題 。
1)ip_conntrack
2014年6月,微博的唐福林曾說:「Tcpcopy 引流工具是線上問題排查的絕佳之選,但使用者不多有人去關注開啓 tcpcopy 服務時,同時會開啓 ip_conntrack 內核模塊,這個模塊負責追蹤全部 tcp 連接的狀態,並且它的內部存儲有長度限制,一旦超過,全部新建連接都會失敗。」
王斌則
迴應說:「開啓 tcpcopy,自身不會去開啓 ip_conntrack 內核模塊。開不開啓 ip_conntrack 內核模塊,是用戶本身決定的,跟 tcpcopy 不要緊。」他
還建議:「
當鏈接數量很是多的時候,自己就應該關閉 ip_conntrack,不然嚴重影響性能。至於 tcpcopy,默認是從 ip 層發包的,因此也會被 ip_conntrack 干涉,文檔中也有描述,其實也能夠採用 --enable-dlinject 來發包,避開ip層的ip_conntrack。若是沒有報「ip_conntrack: table full, dropping packet」,通常無需去操心ip_conntrack。」以及「線上鏈接很少的場合,開啓 ip_conntrack 並無問題。線上鏈接比較多的場合,最好關閉 ip_conntrack,或者對線上應用系統端口設置 NOTRACK,至少我周圍的系統都是這樣的,這是爲性能考慮,也是一種好的運維習慣。」
2)少許丟包
如何發現 TCPCopy 丟包多仍是少呢?
王斌本身稱,在某些場景下,pcap 抓包丟包率會遠高於 raw socket 抓包,所以最好利用 pf_ring 來輔助或者採用 raw socket 來抓包。
丟包率須要在測試環境中按照定量請求發送進行對比才能展開計算,另外還須要對日誌內容進行分析,有待測試。