TCPCopy顧名思義,就是一個可以將tcp流量復制的工具(其實也可以復制UDP)。有了這樣一個工具,我們就可以真實的復制線上流量,然后將這些流量復制到我們的測試服務器上。這樣就可以很容易模擬線上真實用戶的訪問,做一些功能上的,性能上的測試。而且經過實際測試發現TCPCopy對線上機器的資源消耗也是極低的。
借助這么一個工具,我們可以比較容易的實現一些比較有意思的功能。比如我們現在我們的應用都已經服務化了,那么我們在一次需求變更之后,或者一次性能優化之后,我們如何最快的知道該服務功能是否正確,性能優化是否達到期望呢?當然,我們可以使用一些性能壓測工具模擬大量請求,但是有的時候來自線上真實的流量或許能最真實的反應實際情況。
OK,那我們可以使用TCPCopy將線上流量復制到線下測試環境。在我們使用這種方式的時候,又發現另外一個問題。我們很多時候進行引流的時候,只希望復制部分服務的流量。比如我們想將下單服務的引入進來,但並不想將支付訂單的流量也引入進來,因為這樣我們可能需要搭建一個很復雜的環境。另外, 有的時候我們只想針對單個服務進行測試,這樣的話只復制單個服務或符合條件的流量,可以更好的隔離我們的測試,隔離其他服務對我們測試期望的影響。基於這些原因,我們就不能直接的將TCPCopy的所有流量全部直接的引入測試環境。為此我們開發了一個proxy -- DubboCopy(因為我廠的服務框架是基於Alibaba開源的Dubbo)。
下面第一個圖是使用TCPCopy的原始結構:
使用DubboCopy之后的結構:
DubboCopy的目的主要有:
1. 降低服務流量復制的使用門檻
2. 基於多重維度的服務流量復制
3. 監控各種性能指標,收集服務響應結果
那么下面我們就分幾個部分介紹我們是如何實現的。
降低服務流量復制的使用門檻
其實TCPCopy的使用還是有一些門檻的,有一些網段的限制,需要添加一些路由表等。並且TCPCopy沒有提供rpm包等,如果從零搭建一套流量復制環境,還是要費一番周折。而我們想達到的是一鍵引流,對使用方透明。首先我們自己build了TCPCopy的RPM放入公司的倉庫。然后我們請求OPS協助提供了在線上機器啟停TCPCopy的HTTP接口。這樣一來用戶使用該功能的時候,就基本上感受不到TCPCopy的存在。這里說點題外話:『基礎設施服務化,流程API化』是提高生產效率非常有效的辦法,感謝兄弟部門的協作讓整個流程暢通起來。
另外一點是,因為TCPCopy直接面對的是我們提供的這個proxy,不會直接跟線下測試服務器交互,所以一些配置在proxy上配置,也對使用者透明,繼續降低了使用的復雜度。
可以基於多重維度的服務流量復制
這一點是我們的主要目的。用戶使用該功能的時候,只需要在界面上選擇需要復制的服務,並且指定目標機器。這時DubboCopy就會使用調用接口在線上機器啟動TCPCopy。需要注意的是,我們復制的流量可能來自線上多台機器,而我們的DubboCopy也是部署有多台。那么在調用啟動接口的時候,會使用類似一個負載均衡的方式發送不同的命令到不同的線上機器,將流量均衡的復制到各個DubboCopy。
當TCPCopy將流量復制到proxy后,我們可以部分解析Dubbo的協議,從中提取出服務,方法等信息。有了這些信息我們就可以根據預先配置好的信息選擇要將數據包復制到哪些測試機。DubboCopy是使用Netty開發的,接收到TCPCopy復制過來的流量之后,我們部分的解析出所需信息,然后了解到該請求的長度,讀取指定長度的數據,然后發送到目標機。但是,如果我們想提供這樣一個通用服務,我們需要承載大量線上機器復制過來的流量,但是基於成本考慮我們的DubboCopy不能擴展特別多。那么我們怎么更有效率的處理這個轉發呢?對於這樣一個網絡轉發應用而言,我們的資源消耗主要在網絡,內存和CPU。內網里,一般來說網絡不會成為一個特別大的問題,而且大部分業務服務,數據量並不是特別大(當然也有一些是需要獲取大量的數據)。CPU主要用於處理網絡和協議解析部分。而使用Java編寫這類服務,我最擔心的是內存上。因為該服務需要處理大量的請求數據,GC會不會成為一個很大的問題呢?不過進一步分析我們發現,可以做到幾乎不使用堆內存。Netty讀取的數據可以使用DirectByteBuffer,這樣就分配在堆外了,然后我們也是部分解析請求的數據,這只會占用很少的字節。另外,我們提取的信息其實都是類似服務名,方法名等元數據信息。對於這類信息我們都是可以緩存的。而數據呢?其實我們只需要確定一個請求的數據大小,然后將這個大小的數據原樣的復制過去即可。我們使用Netty的ByteBuf的readSlice,甚至都無須將數據讀取出來,就可以直接將所需數據寫入到發送通道。這樣整個過程,基本上是不怎么消耗堆內內存的,所以GC基本上沒有壓力。而對於堆外內存,Netty 4提供了pool,也能大大降低分配的開銷。在我們的實際測試也表明了堆內存占用極低,GC也不怎么頻繁。
另外,我們將接受數據的Netty Server的worker線程與發送數據的Netty Client的worker線程進行共享,這樣進一步降低了上下文切換的頻率。
監控各種性能指標,收集服務響應結果
實際上,我們進行復制的目的無非就兩點:性能測試和功能測試。
那么對於性能測試來說就是各種性能指標,而服務的RT是否有變化可能是其中最關鍵的一點。
對於功能測試,最直接的可能是服務的響應數據是否有異常等,不過也可以進一步做到響應數據與線上服務的響應數據進行對比(這一點目前還未實現)。
有了這兩方面的數據,我們就覆蓋了服務流量復制到結果收集兩個環節,能做到一個比較有效的線上環境模擬的工具了。
那么問題來了,大家的線上模擬環境是怎么實現的呢?或者對這個工具感興趣,有什么新需求的都歡迎來聊聊。