goreplay 使用經驗

2021-09-20 09:17:02 字數 4133 閱讀 9708

測試 http 服務,為了覆蓋更多的場景,可以考慮錄製線上流量,在測試環境進行重放。之前用 tcpcopy 比較多,最近遇到一些需求,需要在 http 層做一些過濾,例如只錄製指定 url 的請求。

經過調研,發現 goreplay,其前稱是 gor,很適合這個場景,有以下優點。

支援 http 層面的流量過濾,可以只挑選我們感興趣的流量。

支援請求放大,用於效能測試。

免 root 執行,抓包並不需要 root 許可權,同樣的方法適用於 tcpdump,其實 goreplay 和 tcpdump 一樣,都用 libpcap 來抓包。

$ sudo setcap "cap_net_raw,cap_net_admin+eip" ./goreplay
抓取 80 埠的 http 請求,只抓請求 url 是 /api/v1 的,並輸出到終端。這個比 tcpdump 更直觀,列印到終端的是我們熟悉的 http 協議。

第一行是 goreplay 自定義的 header,平常使用可以不必理會,不是實際抓到的包,從第二行開始才是實際抓到的包。

$ ./goreplay --input-raw :80 --http-allow-url '/api/v1' --output-stdout
抓取 80 埠的所有請求,並儲存到檔案。實際會分批儲存為 request_0.gor,request_1.gor 這種檔名。

$ ./goreplay --input-raw :80 --output-file 'request.gor'
重放請求,例如 host2.com 是我們的新機房網域名稱。這種重放,會根據請求的時間戳,按照抓取時的請求順序重放。

例如抓取的時候,第一秒 10 個請求,第二秒 20 個請求,那麼重放的時候,也會按照這個順序。並且讀完 request.gor 檔案,就會停止。

上面我們看到了 goreplay 自定義的 header,其第三個字段,是乙個納秒級的時間戳,根據這個來保證重放的順序和速率。

$ ./goreplay --input-file 'request.gor' --output-http ''
如果是效能測試,可以不考慮請求的順序和速率,並且要求無限迴圈。

# --input-file 從檔案中獲取請求資料,重放的時候 100x 倍速

# --input-file-loop 無限迴圈,而不是讀完這個檔案就停止

# --output-http 傳送請求到

# --output-http-workers 併發 100 發請求

# --stats --output-http-stats 每 5 秒輸出一次 tps 資料

$ ./goreplay --input-file 'request.gor|10000%' --input-file-loop --output-http '' --output-http-workers 100 --stats --output-http-stats

更多的命令列引數及用法,可以檢視 goreplay 原始碼的 settings.go 檔案。

其輸出的 stats 含義,可以看看 這個帖子 的解釋。

使用過程中遇到的坑。

如果 http 請求不符合規範,可能會抓不到包。遇到過 http 請求頭裡面的 content-length 不等於實際的 body 大小,goreplay 認為其請求未結束。

input-file 是單 goroutine 在跑,會有效能瓶頸。測試的時候,讀取的 rps 在 1.7w - 1.8w 左右,如果壓測需求大於這個,需要開多個程序同時跑。

goreplay 是用 golang 編寫的,抓包的時候呼叫 gopacket,後者通過 cgo 來呼叫 libpcap。從編譯開始,從原始碼層面學習一下其實現。

tl;dr

由於 goreplay 使用了第三方 c **,不能使用 go 的交叉編譯功能來跨平台編譯。只能在 linux 下編譯 linux 使用的可執行檔案。

在 redhat 系髮型版下,可以使用 yum 來安裝依賴。

$ sudo yum install libpcap libpcap-devel
或者從原始碼編譯 libpcap。

# 安裝依賴

$ sudo yum install gcc flex byacc bison

$ wget && tar xzf libpcap-1.8.1.tar.gz

$ cd libpcap-1.8.1

$ ./configure

$ sudo make install

cd 到 goreplay 的原始碼目錄,執行命令。

# 純靜態編譯

$ go build -ldflags '-extldflags "-static"'

如果編譯成功,在當前目錄會生成乙個 goreplay 檔案,試執行一下。

[vagrant@localhost goreplay]$ ./goreplay

version:

2018/06/08 08:06:22 required at least 1 input and 1 output

不依賴任何庫。

[vagrant@localhost goreplay]$ ldd goreplay

not a dynamic executable

乙個合法的可執行檔案。

[vagrant@localhost goreplay]$ file goreplay

goreplay: elf 64-bit lsb executable, x86-64, version 1 (gnu/linux), statically linked, for gnu/linux 2.6.32, buildid[sha1]=e334de401c00057ca56a33c0136dc5c86debee61, not stripped

如果遇到以下編譯錯誤。

collect2: error: ld returned 1 exit status需要安裝 glibc 的靜態庫。

$ sudo yum install glibc-static.x86_64
如果不是通過 go get 來獲取 goreplay,而是通過 git clone 下來的,那麼會缺少一些第三方庫的依賴,通過 go get 命令補充就好。

$ go get github.com/shopify/sarama
input 和 output 是 goreplay 對資料流的抽象,在原始碼目錄有很多 input_***.go 和 output_***.go,實現了 goreplay 的核心功能。

在啟動的時候,會解析命令列引數中指定的 input 和 output,接著啟動 emitter,從 input 中讀資料,寫到 output 中。

emitter.go 中核心**如下:

for _, in := range plugins.inputs
多個 input 之間是並行的,但單個 input 到多個 output,是序列的。所有 input 都實現了 io.reader 介面,output 都實現了 io.writer 介面。所以閱讀**時,input 的入口是 read() 方法,output 的入口是 write() 方法。

抓包是核心功能,也算是一種 input 的型別。不過 goreplay 的實現中,實現上和 http 協議繫結的很死。我參考 goreplay 的**,實現了 goreplay-udp,用法上和 goreplay 保持一致。

UltraEdit使用經驗

都是些很簡單的技巧,不過是自己摸索出來,記錄一下。我用的版本是ultraedit 32 13.00a 簡體中文版。1 去重 如果文字中的資料是一行一行的,有重複的內容,去重的方法是 檔案 排序 高階排序 選項,選中 刪除重複 2 查詢後亂碼 將檔案另存為 utf 16 格式的文字。頁要設定成 高階 ...

tokyotyrant 使用經驗

1 關於rcc引數 如果執行ttserver的時候,帶上了rcc引數。那麼在資料同步過程中,如果有一條資料執行錯誤,那麼同步就會停下來,直到有人工干預。反之,如果沒有rcc引數,同步會繼續進行,但是在日誌中,會報乙個error級別的錯誤。建議,不帶rcc引數執行ttserver,同時監控ttserv...

AspectJ使用經驗

aspectj使用經驗 author hongsoft public aspect monitoraspect private static dateformat sdf new dateformat yyyy mm dd hh mm ss log logg logfactory.getlog mo...