TCPCopy顧名思義,就是一個能夠將tcp流量複製的工具(其實也能夠複製UDP)。有了這樣一個工具,咱們就能夠真實的複製線上流量,而後將這些流量複製到咱們的測試服務器上。這樣就能夠很容易模擬線上真實用戶的訪問,作一些功能上的,性能上的測試。並且通過實際測試發現TCPCopy對線上機器的資源消耗也是極低的。緩存
藉助這麼一個工具,咱們能夠比較容易的實現一些比較有意思的功能。好比咱們如今咱們的應用都已經服務化了,那麼咱們在一次需求變動以後,或者一次性能優化以後,咱們如何最快的知道該服務功能是否正確,性能優化是否達到指望呢?固然,咱們可使用一些性能壓測工具模擬大量請求,可是有的時候來自線上真實的流量或許能最真實的反應實際狀況。性能優化
OK,那咱們可使用TCPCopy將線上流量複製到線下測試環境。在咱們使用這種方式的時候,又發現另一個問題。咱們不少時候進行引流的時候,只但願複製部分服務的流量。好比咱們想將下單服務的引入進來,但並不想將支付訂單的流量也引入進來,由於這樣咱們可能須要搭建一個很複雜的環境。另外, 有的時候咱們只想針對單個服務進行測試,這樣的話只複製單個服務或符合條件的流量,能夠更好的隔離咱們的測試,隔離其餘服務對咱們測試指望的影響。基於這些緣由,咱們就不能直接的將TCPCopy的全部流量所有直接的引入測試環境。爲此咱們開發了一個proxy -- DubboCopy(由於我廠的服務框架是基於Alibaba開源的Dubbo)。服務器
下面第一個圖是使用TCPCopy的原始結構:網絡
使用DubboCopy以後的結構:負載均衡
DubboCopy的目的主要有:框架
1. 下降服務流量複製的使用門檻tcp
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是否有變化多是其中最關鍵的一點。
對於功能測試,最直接的多是服務的響應數據是否有異常等,不過也能夠進一步作到響應數據與線上服務的響應數據進行對比(這一點目前還未實現)。
有了這兩方面的數據,咱們就覆蓋了服務流量複製到結果收集兩個環節,能作到一個比較有效的線上環境模擬的工具了。
那麼問題來了,你們的線上模擬環境是怎麼實現的呢?或者對這個工具感興趣,有什麼新需求的都歡迎來聊聊。