線下的傳統壓力測試,難以模拟真實流量,尤其難以模拟正常流量混雜着各色異常流量。是以,線下壓得好好的系統,上線後可能某天突然雪崩,說好能支撐 5 倍流量的系統重構,也許流量一翻倍就徹底挂了。
但辦法總比問題多。
系統重構或重要變更上線前,可以拷貝線上真實流量,實時模拟線上流量,甚至可以放大真實流量,進行壓力測試,以評估系統承載能力。
反過來也可以這樣,如果線上跑着跑着發現有性能瓶頸,但線下環境難以複現,還不如把真實流量拷貝到線下重放,畢竟線下環境便于上各種排查手段,重放幾遍都行,直到找到問題。
如何實時拷貝線上真實流量呢?TCPCopy
2010年,網易技術部的王斌在王波的工作基礎上開發了 TCPCopy - A TCP Stream Replay Tool。2011年9月開源。目前版本号是 1.0.0。很多公司的模拟線上測試都是基于 TCPCopy 做的,如一淘。
TCPCopy 是一種請求複制(複制基于 TCP 的 packets)工具 ,通過複制線上資料包,修改 TCP/IP 頭部資訊,發送給測試伺服器,達到欺騙測試伺服器的TCP 程式的目的,進而為欺騙上層應用打下堅實基礎。
TCPCopy是如何工作的
基于 Server 的請求回放領域,一般分為離線回放和線上實時複制兩種。
其中請求實時複制,一般可以分為兩類:
1)基于應用層的請求複制 ,
2)基于底層資料包的請求複制。
如果從應用層面進行複制,比如基于伺服器的請求複制,實作起來相對簡單,但也存在着若幹缺點:
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 程序。
tcpcopy項目位址:https://github.com/session-replay-tools/tcpcopy
Online Server 上的抓包:
tcpcopy 的新架構在 OS 上抓請求資料包預設采用 raw socket input 接口抓包。王斌則推薦采用 pcap 抓包,安裝指令如下:
yum install libpcap-devel
git clone git://github.com/session-replay-tools/tcpcopy.git
cd tcpcopy
./configure
make
make install
這樣就可以在核心态進行過濾,否則隻能在使用者态進行包的過濾,而且在 intercept 端或者 tcpcopy 端設定 filter(通過 -F 參數,類似 tcpdump 的 filter),達到起多個執行個體來共同完成抓包的工作,這樣可擴充性就更強,适合于超級高并發的場合。
為了便于了解 pcap 抓包,下面簡單描述一下 libpcap 的工作原理。
一個包的捕捉分為三個主要部分:
面向底層包捕獲,
面向中間層的資料包過濾,
面向應用層的使用者接口。
這與 Linux 作業系統對資料包的處理流程是相同的(網卡->網卡驅動->資料鍊路層->IP層->傳輸層->應用程式)。包捕獲機制是在資料鍊路層增加一個旁路處理(并不幹擾系統自身的網絡協定棧的處理),對發送和接收的資料包通過Linux核心做過濾和緩沖處理,最後直接傳遞給上層應用程式。如下圖2所示:
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 程序,進而完成一次請求的複制。
實驗
1.機器别表
192.168.0.11 -- onlie server
192.168.0.12 -- test server
192.168.0.13 -- Assistant server
2.online server操作
安裝tcpcopy
啟動TCPCOPY
./sbin/tcpcopy -x 80-192.168.0.12:80 -s 192.168.0.13 -c 192.168.0.11
-x 參數指定本機哪個端口的流量轉發到哪台機器的哪個端口,格式為localip:80-targetip:port
-s 參數指定Assistant server -c 指定本機
可以添加-n參數來放大流量,比如說 -n 2 代表放大2倍流量
可以添加-r參數來複制一部分流量。比如說,-r 20 代表複制20%的流量
可以添加-d參數來讓tcpcopy背景運作
3.test server操作
route add host 192.168.0.11 gw 192.168.0.13
這一步很重要,之前我就是因為這個路由設定不正确,一直沒搭建成功
4.Assistant server操作
安裝intercept
git clone git://github.com/session-replay-tools/intercept.git
cd intercept
啟動intercept
./sbin/intercept -i eth0 -F tcp and src port 80 -d
-i 指定網卡
-F 指定copy的是tcp還是udp
-d 代表背景運作
我這裡預設online server還有test server都啟動了nginx。當你通路online server上的http服務的時候。你會發現test server上也有通路log存在。可以通過監控test server上的負載,來判斷機器的運作情況