十年網(wǎng)站開發(fā)經(jīng)驗 + 多家企業(yè)客戶 + 靠譜的建站團(tuán)隊
量身定制 + 運(yùn)營維護(hù)+專業(yè)推廣+無憂售后,網(wǎng)站問題一站解決
現(xiàn)在全鏈路越來越火,各大廠商也紛紛推出了自己的全鏈路壓測測試方案。特別是針對全鏈路壓測流量模型,各家方案都有所不同。最近我看了一些這方面的資料,有一些感悟。分享給大家。
創(chuàng)新互聯(lián)于2013年創(chuàng)立,先為麥蓋提等服務(wù)建站,麥蓋提等地企業(yè),進(jìn)行企業(yè)商務(wù)咨詢服務(wù)。為麥蓋提企業(yè)網(wǎng)站制作PC+手機(jī)+微官網(wǎng)三網(wǎng)同步一站式服務(wù)解決您的所有建站問題。
全鏈路壓測流量模型的梳理呢,這里就先不講了,各家公司自有司情在。因為主要是全鏈路壓測模型的實現(xiàn),其實實現(xiàn)也對應(yīng)了流量模型的梳理結(jié)果。
業(yè)界常用的三種方一種:是基于業(yè)務(wù)模型的實現(xiàn),一種是基于真實流量的錄制回放,最后一種是灰度分流。
這個是一種比較常用的方式。首先要對公司業(yè)務(wù)模型進(jìn)行梳理,也就是說對公司的業(yè)務(wù)鏈路進(jìn)行梳理。這里的業(yè)務(wù)鏈路可能會比較復(fù)雜,不是像很多案例中到的了就非常流行暢的一條鏈路,中間很有可能會出現(xiàn)各種各樣的支路。如果圖圖形化展示的話,某一條鏈路應(yīng)該就是一個樹形結(jié)構(gòu)。樹形結(jié)構(gòu)的開始是用戶的入口頁一般就是入口頁面的登陸,或者說是首頁接口。樹形結(jié)構(gòu)的右側(cè)是用戶的出口,這里根據(jù)業(yè)務(wù)模型不同,用戶的出口會非常的多,所以大多數(shù)來時候來講,這就是一個分叉的樹形結(jié)構(gòu)。
要對這樣的流量模型進(jìn)行實現(xiàn)。是比較困難的。首先要梳理出這樣的業(yè)務(wù)模型,就不太容易,再加上接口的相互調(diào)用啊,數(shù)據(jù)之間的相互依賴又可能是復(fù)雜程度增加一個量級。所以一般的實現(xiàn)方式就是做歸攏。將比較復(fù)雜的樹形結(jié)構(gòu)簡單化,或者干脆將以個業(yè)務(wù)聯(lián)絡(luò)分解成n個列有鏈路。然后分別實現(xiàn)。最終將流量匯聚,就變成了整個業(yè)務(wù)鏈路的流量模型實現(xiàn)。
在業(yè)務(wù)模型實現(xiàn)這個方向,各家都有不同的實現(xiàn)方式啊,基本上就分為工具以及腳本實現(xiàn)。我自己不怎么用工具做過接口的性能測試,全都是使用java和groovy腳本去實現(xiàn)的。首先,我會實現(xiàn)一個基于接口的業(yè)務(wù)測試框架,將每一個接口封裝成一個方法。接口的參數(shù)即是這個方法的參數(shù)。然后將每一個用戶封裝成一個對象。將用戶的各種信息變成這個對象的屬性。然后用戶在請求不同的接口的時候?qū)τ脩舻膶傩赃M(jìn)行賦值這樣就達(dá)到了一個參數(shù)傳遞的目的。然后通過調(diào)用不同的方法,我們就可以實現(xiàn)對不同接口的請求。通過控制參數(shù)或者說接口請求的頻率,我們就可以達(dá)到控制當(dāng)前用戶。在整個業(yè)務(wù)鏈的走向。
基于流量錄制和回放,這個是最容易實現(xiàn)的方式。也是最容易貼近真實情況的方式。哦,我接觸到的主要有一個回放模型,就是用golang語言寫的goreply。go語言的性能是非常好的,用于性能測試足夠滿足用戶的需求。大多數(shù)公司都會選擇在原生引擎的基礎(chǔ)上做一些封裝。然后對對業(yè)務(wù)進(jìn)行一些兼容,最主要的還是適配流量來源。通常流量的來源是通過日志文件來獲取的,但是我看行業(yè)內(nèi)也有通過一些固定的流量存儲分析引擎去完成。這里的技術(shù)我不是太熟,也就不多分享啦。
我覺得基于流量錄制回放這種模式有一個比較難以解決的問題:流量的不可見性。一般來說,錄制流量會非常大。介于幾十萬上百萬之間。這么規(guī)模大的流量,是很難對他進(jìn)行可視化的。常遇到的一個問題,就是對于一些請求量非常小的接口。錄制的時候可能會錄丟。還有一種就是錄制流量的時間范圍不會太廣。那么錄制出來的流量文件只能反映錄制時的流量模型,并不能反映其他錄制時間段的流量模型。如果某個服務(wù)的流量是根據(jù)時間變化的。那么就需要對多個時間段都錄制流量,然后進(jìn)行合并。由于流量的不可見性,所以對流量的模型進(jìn)行分析,就會顯得比較麻煩。
這是我在某個會議上看到大佬分享的一個方案?;叶却蠹衣牭目赡鼙容^多的是灰度發(fā)布。就是將服務(wù)或者app更新范圍限制在某些一批人,或者說某個地理范圍。這里講的灰度分流,其實核心上差不多,就是將線上的一部分流量轉(zhuǎn)到某些機(jī)器上。以實現(xiàn)對這些機(jī)器所在服務(wù)的一些壓測。這種方案?;诰€上流量完成,所以幾乎不需要測試。投入過多的資源進(jìn)行開發(fā)實現(xiàn)。這種方案有點兒基于業(yè)務(wù)模型和基于流量錄制取了一個中間態(tài)。既能保證流量的真實有效性。又可以避免開發(fā)測試腳本帶來的負(fù)擔(dān)。
這種方式對于公司的架構(gòu),主或者說是分流的實現(xiàn)來說,技術(shù)難度是比較高的。因為他用的全都是用戶的真實數(shù)據(jù),所以一旦出現(xiàn)問題的話,這個問題影響范圍不太可控,而且比較嚴(yán)重。對于接收灰度分流流量的機(jī)器來說,壓測流量完全真實。但是他也無法避免基于流量錄制,回放同樣的問題。就是流量的不可見性以及流量與時間可能存在于一個關(guān)聯(lián)關(guān)系并不是線性的。甚至這一點流量的灰度分流還不如流量的錄制與回放。我想這也是。我身邊接觸到的公司,都沒有采用這種方案的原因吧。
很多朋友可能知道Go語言的優(yōu)勢在哪,卻不知道Go語言適合用于哪些地方。
1、 Go語言作為服務(wù)器編程語言,很適合處理日志、數(shù)據(jù)打包、虛擬機(jī)處理、文件系統(tǒng)、分布式系統(tǒng)、數(shù)據(jù)庫代理等;網(wǎng)絡(luò)編程方面。Go語言廣泛應(yīng)用于Web應(yīng)用、API應(yīng)用、下載應(yīng)用等;除此之外,Go語言還可用于內(nèi)存數(shù)據(jù)庫和云平臺領(lǐng)域,目前國外很多云平臺都是采用Go開發(fā)。
2、 其實Go語言主要用作服務(wù)器端開發(fā)。其定位是用來開發(fā)"大型軟件"的,適合于很多程序員一起開發(fā)大型軟件,并且開發(fā)周期長,支持云計算的網(wǎng)絡(luò)服務(wù)。Go語言能夠讓程序員快速開發(fā),并且在軟件不斷的增長過程中,它能讓程序員更容易地進(jìn)行維護(hù)和修改。它融合了傳統(tǒng)編譯型語言的高效性和腳本語言的易用性和富于表達(dá)性。
3、 Go語言成功案例。Nsq:Nsq是由Go語言開發(fā)的高性能、高可用消息隊列系統(tǒng),性能非常高,每天能處理數(shù)十億條的消息;
4、 Docker:基于lxc的一個虛擬打包工具,能夠?qū)崿F(xiàn)PAAS平臺的組建。
5、 Packer:用來生成不同平臺的鏡像文件,例如VM、vbox、AWS等,作者是vagrant的作者
6、 Skynet:分布式調(diào)度框架。
7、 Doozer:分布式同步工具,類似ZooKeeper。
8、 Heka:mazila開源的日志處理系統(tǒng)。
9、 Cbfs:couchbase開源的分布式文件系統(tǒng)。
10、 Tsuru:開源的PAAS平臺,和SAE實現(xiàn)的功能一模一樣。
11、 Groupcache:memcahe作者寫的用于Google下載系統(tǒng)的緩存系統(tǒng)。
12、 God:類似redis的緩存系統(tǒng),但是支持分布式和擴(kuò)展性。
13、 Gor:網(wǎng)絡(luò)流量抓包和重放工具。
以上的就是關(guān)于go語言能做什么的內(nèi)容介紹了。
網(wǎng)關(guān)=反向代理+負(fù)載均衡+各種策略,技術(shù)實現(xiàn)也有多種多樣,有基于 nginx 使用 lua 的實現(xiàn),比如 openresty、kong;也有基于 zuul 的通用網(wǎng)關(guān);還有就是 golang 的網(wǎng)關(guān),比如 tyk。
這篇文章主要是講如何基于 golang 實現(xiàn)一個簡單的網(wǎng)關(guān)。
轉(zhuǎn)自: troy.wang/docs/golang/posts/golang-gateway/
整理:go語言鐘文文檔:
啟動兩個后端 web 服務(wù)(代碼)
這里使用命令行工具進(jìn)行測試
具體代碼
直接使用基礎(chǔ)庫 httputil 提供的NewSingleHostReverseProxy即可,返回的reverseProxy對象實現(xiàn)了serveHttp方法,因此可以直接作為 handler。
具體代碼
director中定義回調(diào)函數(shù),入?yún)?http.Request,決定如何構(gòu)造向后端的請求,比如 host 是否向后傳遞,是否進(jìn)行 url 重寫,對于 header 的處理,后端 target 的選擇等,都可以在這里完成。
director在這里具體做了:
modifyResponse中定義回調(diào)函數(shù),入?yún)?http.Response,用于修改響應(yīng)的信息,比如響應(yīng)的 Body,響應(yīng)的 Header 等信息。
最終依舊是返回一個ReverseProxy,然后將這個對象作為 handler 傳入即可。
參考 2.2 中的NewSingleHostReverseProxy,只需要實現(xiàn)一個類似的、支持多 targets 的方法即可,具體實現(xiàn)見后面。
作為一個網(wǎng)關(guān)服務(wù),在上面 2.3 的基礎(chǔ)上,需要支持必要的負(fù)載均衡策略,比如:
隨便 random 一個整數(shù)作為索引,然后取對應(yīng)的地址即可,實現(xiàn)比較簡單。
具體代碼
使用curIndex進(jìn)行累加計數(shù),一旦超過 rss 數(shù)組的長度,則重置。
具體代碼
輪詢帶權(quán)重,如果使用計數(shù)遞減的方式,如果權(quán)重是5,1,1那么后端 rs 依次為a,a,a,a,a,b,c,a,a,a,a…,其中 a 后端會瞬間壓力過大;參考 nginx 內(nèi)部的加權(quán)輪詢,或者應(yīng)該稱之為平滑加權(quán)輪詢,思路是:
后端真實節(jié)點包含三個權(quán)重:
操作步驟:
具體代碼
一致性 hash 算法,主要是用于分布式 cache 熱點/命中問題;這里用于基于某 key 的 hash 值,路由到固定后端,但是只能是基本滿足流量綁定,一旦后端目標(biāo)節(jié)點故障,會自動平移到環(huán)上最近的那么個節(jié)點。
實現(xiàn):
具體代碼
每一種不同的負(fù)載均衡算法,只需要實現(xiàn)添加以及獲取的接口即可。
然后使用工廠方法,根據(jù)傳入的參數(shù),決定使用哪種負(fù)載均衡策略。
具體代碼
作為網(wǎng)關(guān),中間件必不可少,這類包括請求響應(yīng)的模式,一般稱作洋蔥模式,每一層都是中間件,一層層進(jìn)去,然后一層層出來。
中間件的實現(xiàn)一般有兩種,一種是使用數(shù)組,然后配合 index 計數(shù);一種是鏈?zhǔn)秸{(diào)用。
具體代碼
1. 介紹
最近在研究一些消息中間件,常用的MQ如RabbitMQ,ActiveMQ,Kafka等。NSQ是一個基于Go語言的分布式實時消息平臺,它基于MIT開源協(xié)議發(fā)布,由bitly公司開源出來的一款簡單易用的消息中間件。
官方和第三方還為NSQ開發(fā)了眾多客戶端功能庫,如官方提供的基于HTTP的nsqd、Go客戶端go-nsq、Python客戶端pynsq、基于Node.js的JavaScript客戶端nsqjs、異步C客戶端libnsq、Java客戶端nsq-java以及基于各種語言的眾多第三方客戶端功能庫。
1.1 Features
1). Distributed
NSQ提供了分布式的,去中心化,且沒有單點故障的拓?fù)浣Y(jié)構(gòu),穩(wěn)定的消息傳輸發(fā)布保障,能夠具有高容錯和HA(高可用)特性。
2). Scalable易于擴(kuò)展
NSQ支持水平擴(kuò)展,沒有中心化的brokers。內(nèi)置的發(fā)現(xiàn)服務(wù)簡化了在集群中增加節(jié)點。同時支持pub-sub和load-balanced 的消息分發(fā)。
3). Ops Friendly
NSQ非常容易配置和部署,生來就綁定了一個管理界面。二進(jìn)制包沒有運(yùn)行時依賴。官方有Docker image。
4.Integrated高度集成
官方的 Go 和 Python庫都有提供。而且為大多數(shù)語言提供了庫。
1.2 組件
1.3 拓?fù)浣Y(jié)構(gòu)
NSQ推薦通過他們相應(yīng)的nsqd實例使用協(xié)同定位發(fā)布者,這意味著即使面對網(wǎng)絡(luò)分區(qū),消息也會被保存在本地,直到它們被一個消費(fèi)者讀取。更重要的是,發(fā)布者不必去發(fā)現(xiàn)其他的nsqd節(jié)點,他們總是可以向本地實例發(fā)布消息。
NSQ
首先,一個發(fā)布者向它的本地nsqd發(fā)送消息,要做到這點,首先要先打開一個連接,然后發(fā)送一個包含topic和消息主體的發(fā)布命令,在這種情況下,我們將消息發(fā)布到事件topic上以分散到我們不同的worker中。
事件topic會復(fù)制這些消息并且在每一個連接topic的channel上進(jìn)行排隊,在我們的案例中,有三個channel,它們其中之一作為檔案channel。消費(fèi)者會獲取這些消息并且上傳到S3。
nsqd
每個channel的消息都會進(jìn)行排隊,直到一個worker把他們消費(fèi),如果此隊列超出了內(nèi)存限制,消息將會被寫入到磁盤中。Nsqd節(jié)點首先會向nsqlookup廣播他們的位置信息,一旦它們注冊成功,worker將會從nsqlookup服務(wù)器節(jié)點上發(fā)現(xiàn)所有包含事件topic的nsqd節(jié)點。
nsqlookupd
2. Internals
2.1 消息傳遞擔(dān)保
1)客戶表示已經(jīng)準(zhǔn)備好接收消息
2)NSQ 發(fā)送一條消息,并暫時將數(shù)據(jù)存儲在本地(在 re-queue 或 timeout)
3)客戶端回復(fù) FIN(結(jié)束)或 REQ(重新排隊)分別指示成功或失敗。如果客戶端沒有回復(fù), NSQ 會在設(shè)定的時間超時,自動重新排隊消息
這確保了消息丟失唯一可能的情況是不正常結(jié)束 nsqd 進(jìn)程。在這種情況下,這是在內(nèi)存中的任何信息(或任何緩沖未刷新到磁盤)都將丟失。
如何防止消息丟失是最重要的,即使是這個意外情況可以得到緩解。一種解決方案是構(gòu)成冗余 nsqd對(在不同的主機(jī)上)接收消息的相同部分的副本。因為你實現(xiàn)的消費(fèi)者是冪等的,以兩倍時間處理這些消息不會對下游造成影響,并使得系統(tǒng)能夠承受任何單一節(jié)點故障而不會丟失信息。
2.2 簡化配置和管理
單個 nsqd 實例被設(shè)計成可以同時處理多個數(shù)據(jù)流。流被稱為“話題”和話題有 1 個或多個“通道”。每個通道都接收到一個話題中所有消息的拷貝。在實踐中,一個通道映射到下行服務(wù)消費(fèi)一個話題。
在更底的層面,每個 nsqd 有一個與 nsqlookupd 的長期 TCP 連接,定期推動其狀態(tài)。這個數(shù)據(jù)被 nsqlookupd 用于給消費(fèi)者通知 nsqd 地址。對于消費(fèi)者來說,一個暴露的 HTTP /lookup 接口用于輪詢。為話題引入一個新的消費(fèi)者,只需啟動一個配置了 nsqlookup 實例地址的 NSQ 客戶端。無需為添加任何新的消費(fèi)者或生產(chǎn)者更改配置,大大降低了開銷和復(fù)雜性。
2.3 消除單點故障
NSQ被設(shè)計以分布的方式被使用。nsqd 客戶端(通過 TCP )連接到指定話題的所有生產(chǎn)者實例。沒有中間人,沒有消息代理,也沒有單點故障。
這種拓?fù)浣Y(jié)構(gòu)消除單鏈,聚合,反饋。相反,你的消費(fèi)者直接訪問所有生產(chǎn)者。從技術(shù)上講,哪個客戶端連接到哪個 NSQ 不重要,只要有足夠的消費(fèi)者連接到所有生產(chǎn)者,以滿足大量的消息,保證所有東西最終將被處理。對于 nsqlookupd,高可用性是通過運(yùn)行多個實例來實現(xiàn)。他們不直接相互通信和數(shù)據(jù)被認(rèn)為是最終一致。消費(fèi)者輪詢所有的配置的 nsqlookupd 實例和合并 response。失敗的,無法訪問的,或以其他方式故障的節(jié)點不會讓系統(tǒng)陷于停頓。
2.4 效率
對于數(shù)據(jù)的協(xié)議,通過推送數(shù)據(jù)到客戶端最大限度地提高性能和吞吐量的,而不是等待客戶端拉數(shù)據(jù)。這個概念,稱之為 RDY 狀態(tài),基本上是客戶端流量控制的一種形式。
efficiency
2.5 心跳和超時
組合應(yīng)用級別的心跳和 RDY 狀態(tài),避免頭阻塞現(xiàn)象,也可能使心跳無用(即,如果消費(fèi)者是在后面的處理消息流的接收緩沖區(qū)中,操作系統(tǒng)將被填滿,堵心跳)為了保證進(jìn)度,所有的網(wǎng)絡(luò) IO 時間上限勢必與配置的心跳間隔相關(guān)聯(lián)。這意味著,你可以從字面上拔掉之間的網(wǎng)絡(luò)連接 nsqd 和消費(fèi)者,它會檢測并正確處理錯誤。當(dāng)檢測到一個致命錯誤,客戶端連接被強(qiáng)制關(guān)閉。在傳輸中的消息會超時而重新排隊等待傳遞到另一個消費(fèi)者。最后,錯誤會被記錄并累計到各種內(nèi)部指標(biāo)。
2.6 分布式
因為NSQ沒有在守護(hù)程序之間共享信息,所以它從一開始就是為了分布式操作而生。個別的機(jī)器可以隨便宕機(jī)隨便啟動而不會影響到系統(tǒng)的其余部分,消息發(fā)布者可以在本地發(fā)布,即使面對網(wǎng)絡(luò)分區(qū)。
這種“分布式優(yōu)先”的設(shè)計理念意味著NSQ基本上可以永遠(yuǎn)不斷地擴(kuò)展,需要更高的吞吐量?那就添加更多的nsqd吧。唯一的共享狀態(tài)就是保存在lookup節(jié)點上,甚至它們不需要全局視圖,配置某些nsqd注冊到某些lookup節(jié)點上這是很簡單的配置,唯一關(guān)鍵的地方就是消費(fèi)者可以通過lookup節(jié)點獲取所有完整的節(jié)點集。清晰的故障事件——NSQ在組件內(nèi)建立了一套明確關(guān)于可能導(dǎo)致故障的的故障權(quán)衡機(jī)制,這對消息傳遞和恢復(fù)都有意義。雖然它們可能不像Kafka系統(tǒng)那樣提供嚴(yán)格的保證級別,但NSQ簡單的操作使故障情況非常明顯。
2.7 no replication
不像其他的隊列組件,NSQ并沒有提供任何形式的復(fù)制和集群,也正是這點讓它能夠如此簡單地運(yùn)行,但它確實對于一些高保證性高可靠性的消息發(fā)布沒有足夠的保證。我們可以通過降低文件同步的時間來部分避免,只需通過一個標(biāo)志配置,通過EBS支持我們的隊列。但是這樣仍然存在一個消息被發(fā)布后馬上死亡,丟失了有效的寫入的情況。
2.8 沒有嚴(yán)格的順序
雖然Kafka由一個有序的日志構(gòu)成,但NSQ不是。消息可以在任何時間以任何順序進(jìn)入隊列。在我們使用的案例中,這通常沒有關(guān)系,因為所有的數(shù)據(jù)都被加上了時間戳,但它并不適合需要嚴(yán)格順序的情況。
2.9 無數(shù)據(jù)重復(fù)刪除功能
NSQ對于超時系統(tǒng),它使用了心跳檢測機(jī)制去測試消費(fèi)者是否存活還是死亡。很多原因會導(dǎo)致我們的consumer無法完成心跳檢測,所以在consumer中必須有一個單獨的步驟確保冪等性。
3. 實踐安裝過程
本文將nsq集群具體的安裝過程略去,大家可以自行參考官網(wǎng),比較簡單。這部分介紹下筆者實驗的拓?fù)?,以及nsqadmin的相關(guān)信息。
3.1 拓?fù)浣Y(jié)構(gòu)
topology
實驗采用3臺NSQD服務(wù),2臺LOOKUPD服務(wù)。
采用官方推薦的拓?fù)?,消息發(fā)布的服務(wù)和NSQD在一臺主機(jī)。一共5臺機(jī)器。
NSQ基本沒有配置文件,配置通過命令行指定參數(shù)。
主要命令如下:
LOOKUPD命令
NSQD命令
工具類,消費(fèi)后存儲到本地文件。
發(fā)布一條消息
3.2 nsqadmin
對Streams的詳細(xì)信息進(jìn)行查看,包括NSQD節(jié)點,具體的channel,隊列中的消息數(shù),連接數(shù)等信息。
nsqadmin
channel
列出所有的NSQD節(jié)點:
nodes
消息的統(tǒng)計:
msgs
lookup主機(jī)的列表:
hosts
4. 總結(jié)
NSQ基本核心就是簡單性,是一個簡單的隊列,這意味著它很容易進(jìn)行故障推理和很容易發(fā)現(xiàn)bug。消費(fèi)者可以自行處理故障事件而不會影響系統(tǒng)剩下的其余部分。
事實上,簡單性是我們決定使用NSQ的首要因素,這方便與我們的許多其他軟件一起維護(hù),通過引入隊列使我們得到了堪稱完美的表現(xiàn),通過隊列甚至讓我們增加了幾個數(shù)量級的吞吐量。越來越多的consumer需要一套嚴(yán)格可靠性和順序性保障,這已經(jīng)超過了NSQ提供的簡單功能。
結(jié)合我們的業(yè)務(wù)系統(tǒng)來看,對于我們所需要傳輸?shù)陌l(fā)票消息,相對比較敏感,無法容忍某個nsqd宕機(jī),或者磁盤無法使用的情況,該節(jié)點堆積的消息無法找回。這是我們沒有選擇該消息中間件的主要原因。簡單性和可靠性似乎并不能完全滿足。相比Kafka,ops肩負(fù)起更多負(fù)責(zé)的運(yùn)營。另一方面,它擁有一個可復(fù)制的、有序的日志可以提供給我們更好的服務(wù)。但對于其他適合NSQ的consumer,它為我們服務(wù)的相當(dāng)好,我們期待著繼續(xù)鞏固它的堅實的基礎(chǔ)。