一、工具介紹
Tcpcopy是一個分布式線上壓力測試工具,可以将線上流量拷貝到測試機器,實時的模拟線上環境,達到在程式不上線的情況下實時承擔線上流量的效果,盡早發現bug,增加上線信心。
Tcpcopy是由網易技術部于2011年9月開源的一個項目,現在已經更新到0.4版本。
與傳統的壓力測試工具(如:abench)相比,tcpcopy的最大優勢在于其實時及真實性,除了少量的丢包,完全拷貝線上流量到測試機器,真實的模拟線上流量的變化規律。
二、Tcpcopy的原理
1.流程
現在以nginx作為前端說明tcpcopy的原理:
上圖中左邊是線上前端機,右邊是測試前端機。線上前端機開啟tcpcopy用戶端(tcpcopy程序),測試前端機開啟tcpcopy服務端(interception程序),且兩台機器上都啟動了nginx服務。
Tcpcopy拷貝一次流量通路的步驟如下:
① 一個通路到達線上前端機;
② socket包在ip層被拷貝了一份傳給tcpcopy程序;
③ tcpcopy修改包的目的及源位址,發給測試前端機;
④ 拷貝的包到達測試前端機;
⑤ 測試前端機的nginx處理通路,并傳回結果;
⑥ 傳回結果在ip層被截獲、丢棄,由intercpetion拷貝傳回結果的ip header傳回;
⑦ ip header被發送給線上前端機的tcpcopy程序。
1.代碼分析
1) 首先,在鍊路層或者IP層,在把包交到上一層之前,系統會檢查有沒程序建立了socket(AF_PACKET,SOCK_DGRAM,…) 或socket(AF_INET,SOCK_RAW,…)等類型的套接字(即原始套接字sock_raw),如果有,這個包就會被複制一份并發送到這個 socket的緩沖區。tcpcopy就是通過這種方式來複制通路流量的。上述的兩種抓包方式,前者工作在資料鍊路層,後者工作在IP層。在 tcpcopy中不同版本所使用的抓包函數不同,在0.3版本中是:
int sock = socket(AF_PACKET,SOCK_RAW,htons(ETH_P_IP));
而在0.4版本中,用的是:
int sock = socket(AF_INET,SOCK_RAW,IPPROTO_TCP);
以上兩個函數分别工作在鍊路層和IP層,前者會把進來和出去的包都抓取到,後者隻 抓取到進來的包。
2) Tcpcopy在發送拷貝的資料包的時候,使用了如下socket:
sock = socket(AF_INET, SOCK_RAW,IPPROTO_RAW);
并對這個socket設定了IP_HDRINCL:
setsockopt(sock, IPPROTO_IP, IP_HDRINCL, &n, sizeof(n));
是以網絡層不會再增加ip header. 發送之前更改了包的目的ip和端口:
tcp_header->dest = remote_port;
ip_header->daddr = remote_ip;
最後調用sendto函數發送包到測試前端機:
send_len = sendto(sock,(char *)ip_header,tot_len,0,
(struct sockaddr *)&toaddr,sizeof(toaddr));
3) 在測試前端機上加載了ip_queue子產品,并設定iptables規則:
iptables -I OUTPUT -p tcp –sport 80 -j QUEUE
複制的通路流量到達測試前端機上的nginx,nginx處理并傳回結果,這個結果包在IP層會被前面所設定的iptables規則比對發往目标(target)QUEUE。而QUEUE是由ip_queue子產品實作。下一步這個比對包就會被核心經過netlink socket發往使用者空間的程式(在這是tcpcopy的服務端interception程序)。
netlink socket是核心與使用者程序之間的一種通信機制,是網絡應用程式與核心通信的最常用的接口,可以用來配置網絡的各個方面(比如包的過濾)。
interception用如下方式建立netlink socket:
int sock = socket(AF_NETLINK,SOCK_RAW,NETLINK_FIREWALL);
NETLINK_FIREWALL協定有三種消息類型:IPQM_MODE,IPQM_PACKET,IPQM_VERDICT.
核心通過一個IPQM_PACKET消息将剛才截獲的傳回結果包發送到interception,interception給核心發送一個 IPQM_VERDICT消息告訴核心對這個包的裁決結果(DROP,ACCEPT,etc.)。tcpcopy通過這樣的辦法将測試前端機上nginx 傳回的結果截獲丢棄,并由interception傳回一個ip header.相應代碼實作如下:
拷貝結果包的ip header,發送:
interception向核心發送IPQM_VERDICT消息報告裁決結果:
核心接收到這個包後将packet_id這個包drop或accept。在後文中可以看到從0.4版本開始的tcpcopy利用這個特點保留了一個允許通路的ip清單,因為預設情況下通路測試前端機上nginx服務所得到的結果會在ip層被drop掉,造成在80端口上無法通路nginx。有了這個允許ip清單,即使是刷了iptables規則、起了interception程序,在某些機器上也是可以正常通路測試前端機上的nginx服務的。
三、操作方法
假如有兩台機器:
機器A:線上前端機,ip:61.135.xxx.1;
機器B:測試前端機,ip:61.135.xxx.2;
兩台機器上都起了nginx服務,操作者在兩台機器上都需有sudo權限。
操作步驟:
1. 在B依次執行,
1) 加載ip_queue子產品,modprobe ip_queue;
2) 配置iptables規則,sudo iptables -t filter -I OUTPUT -p tcp –sport 80 -j QUEUE;
3) 啟動tcpcopy服務端,sudo ./interception & ;
2. 在A上執行,
啟動tcpcopy用戶端,sudo ./tcpcopy 61.135.xxx.1 80 61.135.xxx.2 80 &;
如果在A上看到“I am booted”,則表示操作成功,tcpcopy已經開始工作,可以檢視一下機器B上nginx的日志确認。
四、進階用法
1. 級聯
設有線上前端機一台命名A,測試前端機若幹B,C,D,……利用tcpcopy可以将A上的通路流量拷貝到B,B拷貝到C,C拷貝到D,……這樣就将一份流量放大了多倍,可以用來測試引擎的極限承受能力。
2. 同一tcpcopy執行個體内多重複制
從0.4版開始,tcpcopy支援在同一個用戶端執行個體複制多份請求到同一個服務端,啟動的方式如下(比如要複制2份,使用-n這個選項來控制要複制的份數),
sudo ./tcpcopy 61.135.xxx.1 80 61.135.xxx.2 80;
sudo ./tcpcopy 61.135.xxx.1 80 61.135.xxx.2 80 -n 1;
sudo ./tcpcopy 61.135.xxx.1 80 61.135.xxx.2 80 -n 2;
3. 服務端允許通路ip清單
由于配置了iptables規則,使用tcp協定且源端口号為80的包都會被比對放到目标QUEUE去,進而被drop掉,是以這個時候測試前端機上的nginx服務是不可通路的。從0.4版本開始,可以指定一個允許通路ip清單,在清單中的機器上是可以通路測試前端機上的nginx服務的。假如要添加61.135.xxx.3,61.135.xxx.4到允許ip清單,啟動interception時使用如下方式:
sudo ./interception 61.135.xxx.3:61.135.xxx.4;
五、tcpcopy在一淘的應用
一淘引擎在今年2月份時有一次重大的更新,在上線之前,利用tcpcopy把所有前端機的流量拷貝到新的demo前端機上,進行線上模拟實驗。引流示例如下圖:
所有線上前端機都開啟tcpcopy用戶端,由于一直報”Message too long”(這是由于packets長度超過1500造成,每分鐘差不多有50個)刷屏,是以将stderror重定向,
sudo ./tcpcopy ipA 80 ipB 80 2>/dev/null &
在測試前端機上開啟tcpcopy服務端程式interception,并設定iptables規則。
壓了大約有一個星期,期間觀察qps,load等各項名額是否正常。新引擎單個叢集一天的平均qps大約是110,峰值大約240。實驗結果顯示的包丢失率大約是(1822213-1797242)/1822213=1.37%. 後來進一步将多個線上前端機的流量引到一個測試前端,測試新引擎的單叢集極限服務能力,qps能達到1000以上, latency大約40ms,達到了上線要求。
Tcpcopy用戶端和服務端本身占用的資源較少,不影響線上服務。
13991 root 20 0 160m 77m 888 R 7.7 0.3 71:26.24 tcpcopy
7723 root 15 0 42592 38m 324 S 5.8 0.2 12:14.83 interception
%cpu分别占7.7%和5.8%,實體記憶體占用分别是77m和38m.
由于幾乎完全模拟了線上環境,我們對于新引擎上線更有信心,最終上線圓滿成功,實作平穩過渡。現在利用tcpcopy拷貝線上流量作模拟壓測已成為我們日常開發上線流程中的一項内容。
六、附錄
本文轉自 小強測試幫 51CTO部落格,原文連結:http://blog.51cto.com/xqtesting/2068703,如需轉載請自行聯系原作者