ForceBot願景前端
一、誕生背景git
伴隨着京東業務的不斷擴張,研發體系的系統也隨之增長,各核心系統環環相扣,尤爲是強依賴系統,上下游關係等緊密結合,其中一個系統出現瓶頸問題,會影響整個系統鏈路的處理性能,直接影響用戶購物體驗。算法
往年的 61八、雙 11 大促備戰至少提早 3 個月時間準備,投入大量的人力物力去作獨立系統的線上壓力評測,帶來的問題就是各個性能壓測團隊工做量很是大,致使壓測任務排期,壓測的數據跟線上對比不夠準確,各個強依賴系統上下游須要在壓測中緊密配合,一不當心就會影響線上。有的在線下測試環境壓測,壓測出的數據更是跟線上差距太大,只能做爲參考。docker
更重要的一個問題是系統容量規劃,每次大促前備戰會必不可少的討論話題就是服務器資源申請擴容問題,各團隊基本都是依據往年經驗和線上資源使用率給出評估量,提出一個擴容量需求,致使各個業務系統每次促銷擴容量很是大。安全
爲了解決以上各類苦惱,2016 年基礎平臺部總體牽頭啓動了 ForceBot 全鏈路壓測(備戰常態化)這個項目,此項目牽扯到全部京東研發體系團隊,各系統必須改造,壓測過來的流量和線上正式流量進行區分標記特殊處理,不能由於壓測流量影響正經常使用戶體驗和污染線上數據等工做。因爲跨團隊協做之多、跨系統協調改造等工做量很是大,挑戰性可想而知!服務器
二、能作什麼網絡
2016年主要實現了訂單前的全部黃金鍊路流程高併發壓測用戶行爲模擬,包括模擬用戶操做:首頁、登錄、搜索、列表、頻道、產品詳情、購物車、結算頁、京東支付等。在黃金鍊路中有各類用戶行爲場景,好比通常用戶首先訪問首頁,在首頁搜索想要產品,翻頁瀏覽,加入購物車、湊單、修改收貨地址、選擇自提等等。架構
各系統壓測量依據往年雙 11 峯值做爲基礎量,在此基礎上動態增長併發壓力;同時要區分對待兩個大的場景,平常流量和大促流量。大促場景下搶購活動集中,交易中心寫庫壓力最大,另外用戶行爲和平常有很大的反差,好比用戶會提早加入購物車,選擇滿減湊單,集中下單等等場景。併發
2016 年啓用的鏈路較短,在 2017 年將實現訂單後生產的全鏈路。框架
三、價值體現
ForceBot 在 2016 年雙 11 替代往年各系統獨自優化及性能壓測備戰狀態,目前全部的備戰數據和各系統性能承載能力、資源規劃等都由 ForceBot 給出直接數據做爲依據。
在軍演壓測過程當中,秒級監控到壓測源、壓測中、京東全部的黃金鍊路系統、接口響應時間、TPS、TP99 等數據,軍演完成後提供豐富的壓測報告,準確的找到各系統併發瓶頸。
同時也承擔了內網單一系統的平常壓測任務,開放給研發和壓測團隊,支撐京東全部的壓測場景統一壓測平臺,對公司內壓測資源的整合和提升利用率。
ForceBot 技術架構
工欲善其事,必先利其器。全鏈路壓測必需要有一套功能強大的軍演平臺,來實現自動化、全鏈路、強壓力的核心目標。
一、第一代性能測試平臺
基於 Ngrinder 作定製開發。 Ngrinder 是一個 Java 語言開源的、分佈式性能測試平臺。它由一個 controller、多個 agent 組成,在 controller 創建測試場景,分發到 agent 進行壓力測試,壓力源將壓測數據上報給 controller。
Ngrinder 基於開源的 Java 負載測試框架 grinder 實現,並對其測試引擎作了功能提高,支持 Python 腳本和 groovy 腳本;同時提供了易用的控制檯功能,包括腳本管理、測試計劃和壓測結果的歷史記錄、定時執行、遞增長壓等功能。
咱們根據京東的業務場景對 Ngrinder 進行了優化,以知足咱們的功能需求。好比:提高 agent 壓力,優化 controller 集羣模式,持久化層的改造,管理頁面交互提高等。
Ngrinder能勝任單業務壓測,但很難勝任全鏈路軍演壓測。分析其緣由是 controller 功能耦合太重,能管理的 agent 數目有限,緣由以下
controller 與 agent 通信是 bio 模式,數據傳輸速度不會很快;
controller 是單點,任務下發和壓測結果上報都通過 controller,當 agent 數量很大時,controller 就成爲瓶頸。
說得通俗點,controller 乾的活又多又慢,總體壓力提高不上去。儘管咱們優化了 controller 集羣模式,能夠同時完成多種測試場景。可是集羣之間沒有協做,每一個 controller 只能單獨完成一個測試場景。由此咱們着手研發全鏈路軍演壓測系統(ForceBot)。
二、ForceBot架構
新平臺在原有功能的基礎上,進行了功能模塊的解耦,剷除系統瓶頸,便於支持橫向擴展。
對 controller 功能進行了拆解,職責變爲單一的任務分配;
由 task service 負責任務下發,支持橫向擴展;
由 agent 註冊心跳、拉取任務、執行任務;
由 monitor service 接受並轉發壓測數據給 JMQ;
由 dataflow 對壓測數據作流式計算,將計算結果保存在 DB 中;
由 git 來保存壓測腳本和類庫。 Git 支持分佈式,增量更新和壓縮
這樣極大的減輕了 controller 的負載壓力,而且提高了壓測數據的計算能力,還能夠獲取更多維度的性能指標。
在此基礎上,還融合進來了集合點測試場景、參數下發、TPS 性能指標等新特性。下面將重點介紹如下幾個功能:
容器部署
爲了快速的建立測試集羣,Agent 採用 Docker 容器經過鏡像方式進行自動化部署。這樣作好處以下
利用鏡像方式,彈性伸縮快捷;
利用 Docker 資源隔離,不影響 CDN 服務;
每一個 Agent 的資源標準化,能啓動的虛擬用戶數固定,應用不須要再作資源調度;
問題:Git 測試腳本如何在各個 Docker 之間共享?
解決方案:採用外掛宿主機的共享磁盤實現。
任務分配
用戶在管理端建立一個測試場景,主要包括:壓力源(分佈在不一樣機房的壓力機)、虛擬用戶數、測試腳本、定時執行時間、process JVM 參數,壓力源,啓動模式,集合點設置,選擇測試腳本。
這個測試場景保存到 db 後,controller 按照時間順序,掃描發現有測試場景了,會根據標籤算法尋找當前存活的空閒的 agent 資源,並計算 agent 的每一個 worker process 啓動的線程數。
任務分配時,要考慮集合點的計算,就是虛擬用戶數在不一樣的時間點不斷變化。目前有兩種方式:毛刺型和階梯型。毛刺型,就是在某個時間點有大量的請求瞬時訪問業務系統,這樣作能夠測試系統的併發能力和吞吐量。階梯型,就是在相等時間間隔,虛擬用戶數等值遞增。
好比:一個測試場景在今天 9 點執行 10000 個虛擬用戶數,執行到 9 點 01 分要虛擬用戶數變爲 20000 個,到 9 點 05 分虛擬用戶數又變爲 40000 個,到 9 點 07 分虛擬用戶數變爲 10000 個,虛擬用戶數像毛刺同樣上下變化。
上面的表格就是對應表結構設計,每一個壓力線會按照順序保存到 db 中。在這張表中,只記錄的持續時間,具體的執行時間是由 controller 根據開始壓測時間累加持續時間逐一計算出來。execType 還包含了緩慢加壓減壓兩種類型,覆蓋了階梯型,默認時間間隔爲 5 秒。
controller 要計算出每一個間隔的執行時間點,遞增的虛擬用戶數。controller 將計算結果分給每一個 agent,保存到 db 中,由 agent 定時來拉取。
動態加壓減壓目前只支持採用 Agent 的增減方式來實現。
問題:因爲購物車是用戶共享的,在壓測下單過程當中,同一個用戶併發操做會出現衝突?
解決方案:爲每一個壓測線程綁定使用不一樣的用戶。在任務分配過程當中,爲每一個 process 進程中的線程分配線程編號。不一樣的線程根據編號,按照映射規則,找到相應的壓測用戶。
心跳任務和下發
task service 爲 agent 提供了任務交互和註冊服務,主要包括 agent 註冊、獲取任務、更新任務狀態。
agent 啓動後就會到 task service 註冊信息,而後每一個幾秒就會有心跳拉取一次任務信息。controller 會根據註冊的信息和最近心跳時間來判斷 agent 是否存活。
agent 拉取任務和執行任務過程當中,會將任務狀態彙報給 task service。controller 會根據任務狀態來判斷任務是否已經結束。
task service 採用了 gRPC 框架,經過接口描述語言生成接口服務。gRPC 是基於 http2 協議,序列化使用的是 protobuf3,Java 語言版採用 netty4 做爲網絡 IO 通信。
使用 gRPC 做爲服務框架,主要緣由有兩點:
服務調用有可能會跨網絡,能夠提供 http2 協議;
服務端能夠認證加密,在外網環境下,能夠保證數據安全。
Agent 實現
agent 職責主要是註冊,獲取任務信息,更新任務狀態,執行和中止 worker process 進程,同時上報壓測數據。通訊協議主要是 gRPC。
Agent 啓動後生成 UUID 做爲當前 Agent 的惟一標識,並向 Task Service 進行註冊。若是 Agent 進程掛掉重啓後,會產生新的 UUID,放棄原來的任務。
Agent 心跳線程每隔 3 秒從 Task Service 拉取任務。獲取到任務後,會把任務扔到隊列裏面,並上報任務接收狀態,不阻塞當前拉取線程。
任務執行線程從隊列獲取任務,若是是啓動新的測試任務,則先從 Git 拉取任務所需的腳本文件和用戶的自定義類庫。而後根據 JVM 參數,設置並啓動 worker process 進程,同時將任務的執行時間,虛擬用戶數,集合點設置信息,壓測腳本信息,以及腳本加載 plugin 所須要的 classpath 傳遞給 worker process。在這裏咱們採用使 Agent 經過 stdout 的方式與 Worker process 對 stdin 的監聽構成一個數據傳輸通道,採用 Stream 的方式將任務的全部信息和數據發送給 Worker process,使 Worker process 能夠獲取到足夠且結構化的數據以完成初始化的工做。
問題:一臺物理機上多個 Docker 實例,如何減小更新測試腳本形成的 git 壓力?
解決方案:測試腳本存放到宿主機共享存儲,更新前,按照測試任務編號進行文件鎖,若是鎖成功則調用 git 更新。同一個測試任務就能夠減小 git 壓力。
問題:如何模擬在某一個瞬間壓力達到峯值?
解決方案:經過集合點功能實現,提早開啓峯值所需足夠數量的線程,經過計算肯定各個時間點上不須要執行任務的線程數量,經過條件鎖讓這些線程阻塞。當壓力須要急劇變化時,咱們從這些阻塞的線程中喚醒足夠數量的線程,使更多的線程在短期進入對目標服務壓測的任務。
數據收集和計算
實現秒級監控。數據的收集工做由 monitor service 完成,也是採用 gRPC 做爲服務框架。Agent 每秒上報一次數據,包括性能,JVM 等值。
monitor service 將數據經 JMQ 發送給 dataflow 平臺,進行數據的流式計算後,產生 TPS,包括 TP999,TP99,TP90,TP50,MAX,MIN 等指標存儲到 ES 中進行查詢展現。
問題:爲了計算總體的 TPS,須要每一個Agent把每次調用的性能數據上報,會產生大量的數據,若是進行有效的傳輸?
解決方案:對每秒的性能數據進行了必要的合併,組提交到監控服務
業務系統改造
一、黃金流程業務
首期識別從用戶瀏覽到下單成功的黃金流程,其包含的核心業務以下:
二、壓測流量識別
壓測流量是模擬真實用戶行爲,要保障在軍演過程當中不能污染線上各類統計等數據,好比:PV UV 訂單量等,更不能影響正經常使用戶下單購物體驗。
首先要對用戶、商品進行打標,以便於各個系統進行測試流量識別。
針對下單壓測,庫存系統須要根據測試用戶和商品提早準備好庫存量。
風控系統須要放行測試用戶和商品的操做。
三、壓測數據存儲
業務系統識別出壓測數據後,根據不一樣的場景,採用兩種方式來存放壓測數據。
打標數據並存儲到生產庫中,壓測的數據能體現生產環境性能。按期清理測試數據。統計報表要過濾掉測試數據。改方案能利用現有資源,須要系統進行較多改造。
構造壓測庫環境,根據壓測流量,把壓測數據存放到壓測庫中進行隔離。改方案須要較多的資源,但系統改造量小。支付系統最大的改造困難就是銀行接口的強依賴,不能用真實的銀行卡扣款和支付,ForceBot的目標不是壓銀行接口,而是壓本身自己的支付系統,因此京東這邊支付團隊目前是本身造了一個假銀行,假接口,經過前端傳遞過來的壓測標識,自動路由到假銀行進行扣款支付;
ForceBot 將來規劃
ForceBot 將來的路還很長,要作的優化、功能也不少,好比有:
無人值守智能壓測,經過監控系統監控到各個被壓系統的性能問題,如遇到系統瓶頸問題聯動 JDOS 系統彈性擴容 docker 資源,擴容到必定量級後發現性能沒有提高,中止此壓測,由 callgraph 自動找到性能系統位置;
人工智能預言:根據大數據人工智能學習計算,在 ForceBot 中設定訂單量目標值(秒級訂單量、日訂單量等),根據平常的軍演數據自動計算出各鏈路系統將要承載的軍演併發量,給出智能評估各系統的瓶頸所在,預測各系統的性能指標和瓶頸問題。
「在線全鏈路壓測,軍演備戰常態化,將是咱們的終極目標。」