摘要: Tengine是由淘寶網發起的Web服務器項目。它在Nginx的基礎上,針對大訪問量網站的需求,提供更強大的流量負載均衡能力、全站HTTPS服務、安全防攻擊、鏈路追蹤等衆多高級特性。團隊的核心成員來自於淘寶、搜狗等互聯網企業,從2011年12月開始,Tengine成爲一個開源項目,團隊在積極地開發和維護着它,最終目標是打造一個高效、穩定、安全、易用的Web平臺。html
Tengine是由淘寶網發起的Web服務器項目。它在Nginx的基礎上,針對大訪問量網站的需求,提供更強大的流量負載均衡能力、全站HTTPS服務、安全防攻擊、鏈路追蹤等衆多高級特性。團隊的核心成員來自於淘寶、搜狗等互聯網企業,從2011年12月開始,Tengine成爲一個開源項目,團隊在積極地開發和維護着它,最終目標是打造一個高效、穩定、安全、易用的Web平臺。前端
阿里雲CDN如今服務超過24萬家客戶,Tengine做爲接入層提供高性能Web Server服務,是CDN系統最核心的組件之一。不管是來自阿里集團內部仍是外部客戶的流量服務,幾乎都是由Tengine承載。能夠絕不誇張地說,Tengine的服務質量直接影響着國內外無數大中小型Web站點的服務質量和業務存活,因此,維護Tengine的穩定性一直是咱們團隊的最高優先級目標之一。通過了多年淘寶、天貓等大型網站雙十一活動的洗禮,Tengine的性能和穩定性已經獲得了很好的驗證。python
有一句俗語:「上帝說要有光,因而便有了光。「阿里雲高級開發工程師墨颺說,「Tengine在作工具化的時候,也基本沿襲了這樣的思路。在作開發以前,咱們會系統性地思考:咱們須要面對什麼樣的場景,會碰到什麼樣的問題,須要怎樣的調試技巧和工具,是否能夠解決更多此類問題,因而,咱們的工具便會在這樣的思路下逐漸成型和完善。同時,在服務客戶的過程當中,咱們也會遇到各類新場景新問題,爲了定位和解決問題,咱們也會針對性地提出解決方案,沉澱出更多調試技巧和工具。做爲一線開發團隊,咱們一路走來積累了很是多調試技巧、工具化的經驗。」nginx
本文由阿里雲CDN團隊的研發同窗笑臣和墨颺帶來,從Tengine的內存調試、核心結構、upstream、coredump四個部分展開,爲你們整理和分享一些實踐經驗。git
內存調試——精準定位問題
Tengine做爲C語言開發的應用,在內存的使用中會碰到一些問題,第一部分將重點介紹內存調試方面的相關內容。github
從下圖能夠清晰的看出,Tengine內存分佈能夠從三個維度來理解:底層實現、抽象層、應用層。後端
1、底層實現
Tengine底層實現依賴操做系統的內存分配機制,常見的內存分配器包括jemalloc(FreeBSD)、ptmalloc(glic)、tcmalloc(Google),luajit則使用內置的dlmalloc庫。Tengine在每一個鏈接accept後會malloc一塊內存,做爲整個鏈接生命週期內的內存池, 當HTTP請求到達的時候,又會malloc一塊當前請求階段的內存池, 所以對malloc的分配速度有必定的依賴關係。jemalloc的性能是ptmalloc的兩倍以上,咱們在使用Tengine的時候默認採用jemalloc。jemalloc在追蹤實際內存分配時可使用「malloc_stats_print」來查看內部細節,幫助定位內存泄露等問題。
2、nginx pool調試
在底層內存分配工具沒法定位問題時,咱們須要從抽象層分析出了什麼問題。
Tengine做爲nginx 的fork,在使用nginx pool方面與官方nginx基本沒什麼區別,它的內存池管理機制在HTTP請求的任一階段均可能被調用來分配內存,咱們能夠從內存分配的真實函數調用來統計內存分配的佔用量、歷史數量、當前數量、large alloc等。mod_debug_pool已經在Tengine社區開源,有興趣能夠自行查閱文檔,它的原理是經過hook ngx_create_pool函數來記錄__func__/__LINE__,在須要排查問題時能夠展現歷史數據,從抽象層定位內存泄露等問題。安全
3、lua內存統計
lua/luajit是另外一個很是成熟的開源項目,在nginx生態系統中,lua-nginx-module容許lua/luajit以虛擬機形式內嵌到nginx提供強大的腳本能力,咱們在阿里雲CDN海量業務開發中大量使用到lua/luajit。在調試luajit內存佔用時,能夠經過collectgarbage來展現總內存佔用量,經過掃描gc object,能夠統計global_State中全部gc對象,OpenResty社區也提供了GDB工具來輸出gc對象的數量和內存佔用。服務器
4、共享內存調試
Tengine是多進程服務模型,其進程間的通訊主要依賴操做系統共享內存機制,隨着業務的發展共享內存的使用頻率愈來愈高,如何去定位、調試共享內存,是一個比較嚴峻的問題,且業內缺乏相關工具。咱們在調試共享內存問題時,沉澱和開源了mod_slab_stat工具,在Tengine社區能夠查閱詳細的文檔,該工具統計和展現了每一個zone的內存分配細節,包括page、slab和alloc num等,突出業務通訊內容塊分佈狀況等。該工具適用於ngx shm,基於ngx slab的stub stats模塊是個例外。網絡
以上,從底層實現、抽象層、應用層三個維度,能夠定位到絕大部分Tengine系統和業務的內存問題,包括一些內存的調試技巧。
核心結構——調試與解決故障
Tengine做爲高性能服務器被普遍應用,它的核心框架和核心數據結構決定了其承載服務的質量。針對所遇到的CDN用戶上報故障的工單,好比請求異常、訪問慢等,如何從Tengine核心結構去調試、定位和解決問題,是本部分要介紹的內容。
Tengine主要的核心結構包括鏈接、請求和計時器等。鏈接承載着請求,以鏈接池的形式提供前端、後端網絡服務,其異步事件驅動的特性是Tengine高性能網絡服務的基石,而其事件模型又和計時器牢牢關聯,這些核心結構組成了Tengine的核心框架。
要調試和定位Tengine網絡問題,須要從鏈接、請求、計時器等多角度思考,從讀寫請求狀態、解析請求階段、應答輸出階段、建連等多維度採集,從而獲得更詳細的全局監控數據。
Tengine在nginx stub status工具基礎上,開發了tsar工具(已開源),來展現更細粒度的歷史資源監控,包括應用層QPS、HTTPS和網絡層的accept、讀寫等待等。基於reqstatus的域名級監控,能夠針對任意粒度域名級來統計請求數、鏈接數和5xx、4xx等狀態碼數量,還包括鏈接的複用狀況等。
有了tsar和reqstatus工具,咱們能夠從全局來分析Tengine系統的服務和性能狀態,可是,這夠了麼?CDN系統中,咱們會遇到一些問題,好比:爲啥tengine/nginx訪問慢?是由於客戶端慢、後端慢、仍是nginx自己hang住?如何去衡量「慢「?咱們須要對請求時間進一步細分。
Tengine新增了responsefirstbytetime、upstream_response_time、writewaittime、upstream_read_wait_time等變量來記錄從請求進入到響應結束整個請求流程中的包括不限於應答首字節、後端應答首字節、socket讀寫等待時間總和等關鍵指標。
Tengine在衡量和監控請求卡頓時,將events cycle內event平均處理時間和events cycle內timer平均處理時間綜合來定位單cycle平均耗時長的異常,常見的問題如同步IO(磁盤負載高時寫log卡頓)、CPU密集型執行流(lua實現的CPU密集型邏輯)。
有些時候,咱們沒法從全局資源監控角度定位問題,這時候能夠從ngx_cycles->connections[]來查詢當前執行的請求或鏈接結構信息,經過gdb腳原本掃描worker內當前鏈接信息,查看和調試是否有請求堆積或鏈接泄露等問題。mod_debug_conn(待開源)工具是上述調試技巧的沉澱,它還能夠幫助咱們查看請求/鏈接的內存佔用、分析鏈接和請求上的各種信息。
同時,Tengine的計時器(timer)在異步業務場景中有重要做用,經過掃描計時器紅黑樹,分析每一個event timer,咱們能夠調試和定位異步操做中的問題。有時候咱們在平滑升級tengine服務時,worker一直處於shutting down狀態沒法退出,其實即是由於一直存在timer致使的。也能夠經過hook ngx.timer.at函數來統計lua-nginx-module中的timer caller次數,解決timer超限的報錯等。
回源監控
CDN是內容分發網絡的簡稱,其分發的內容來自用戶源站,負責回源的upstream模塊是Tengine最重要組成部分之一,使Tengine跨越單機的限制,完成網絡數據的接收、處理和轉發。這部分主要介紹upsteam的一些調試技巧和回源資源監控的內容,以及相應的實例分享。
在上面的章節中,咱們已經分析過如何依靠Tengine提供的關鍵指標來衡量和監控請求卡頓,那麼,咱們一樣能夠提出問題:如何去分析請求代理或回源失敗?是由於客戶端主動斷連、後端異常仍是請求超時?如何去分析真實的緣由,從而實時監控回源失敗,這也是常常困擾CDN用戶和開發人員的難題。
從Tengine的請求處理流程分析,客戶端在完成TCP三次握手後,比較常見的錯誤是:一、客戶端異常斷開鏈接;二、客戶端主動斷開鏈接;三、等待讀寫客戶端超時。在Tengine讀取請求內容後,解析客戶端請求失敗如請求行/請求頭等協議出錯,在upstream模塊回源時,也可能發生鏈接後端失敗、後端異常斷開鏈接、後端主動斷開鏈接、等待讀寫後端超時、解析後端應答頭失敗等錯誤,咱們能夠從Tengine的錯誤日誌查看對應的報錯信息,在此基礎上,咱們從ngx_http_upstream_connect、ngx_http_upstream_send_request、ngx_http_upstream_process_header、ngx_http_upstream_process_body_in_memory等回源關鍵函數切入,提供error flag來監控真實的客戶端/回源失敗緣由,將錯誤統計輸出至訪問日誌、reqstatus工具等,關聯和分析域名/請求級別的回源失敗問題,保障CDN服務的穩定性。
如今,咱們有了回源的關鍵指標變量和error flag,能夠依靠一些調試技巧來分享一個upstream問題實例。如圖所示,當客戶端請求經過Tengine upstream回源時,咱們可能碰到這樣的問題:
讀源站,讀滿buffer
發送buffer size數據給客戶端,全發完了
循環上述兩步驟…
繼續讀源站,讀出若干數據,且源站已讀完
發送部分給客戶端,未發完(客戶端卡或者其餘緣由)
再次讀upstream,讀出again(顯然,由於以前源站數據讀完了)
繼續發送數據給客戶端,未發完(客戶端卡或者其餘緣由)
upstream回源先超時了,這個時候$error_flag代表等待讀源站超時,可是事實是這樣嗎?
咱們提供了完整的復現方法,如圖所示:
站在上帝視角,很明顯能夠看到實際上是客戶端問題,可是回源採集的關鍵指標:errorflag、upstream_read_wait_time、$write_wait_time,卻告訴咱們是源站出錯致使的問題,數據不會欺騙咱們,那麼問題到底在哪裏?
上述調試的一些技巧和回源監控,幫助咱們理解upstream模塊的原理:
一、upstream有2個計時器,前端的和後端的;
二、Tengine/Nginx即便寫客戶端寫不進去,只要proxy buf沒滿也會嘗試讀後端,若是後端數據讀完了,會讀出EAGAIN;
三、後端計時器較短先超時了,關閉請求,此時每每認爲後端出錯,真實狀況是客戶端出錯;
這個特殊實例,在某些場景下,甚至在不少的生成環境中,都是比較常見但卻每每被忽視的問題,在幫助提高用戶體驗和服務質量的目標下,即便是nginx核心代碼不易發現的bug,在完善的調試工具和回源監控下,同樣無所遁形。有興趣的同窗能夠搜索nginx郵件列表來詳細瞭解問題背景,雖然nginx 官方由於一些緣由沒有合入該patch,咱們在Tengine中也作了單獨的優化策略。
Coredump
coredump是Tengine這類C開發的應用程序比較常見的問題,隨着業務的迅猛發展,coredump每每會變得愈來愈大,甚至愈來愈頻繁,咱們從空間、數量、自動分析等角度層層遞進來優化Tengine的coredump。
「cat /proc/PID/coredump_filter」這行指令幫助咱們瞭解Linux操做系統coredump機制所支持的內存形態,包括私有內存、共享內存等。咱們在使用Tengine時能夠去除共享內存,下降coredump文件大小。同時,也能夠限制必定時間內crash寫coredump文件的次數,防止磁盤IO太高或磁盤空間被佔滿,Tengine提供了「worker_core_limit」指令(待開源)來限制至分鐘/小時/天級別。
如今咱們已經從空間和數量角度優化了coredump,方便了調試。那麼是否能夠自動化完成分析,提高定位問題的速度?答案是確定的。
咱們經過gdb python腳原本自動分析coredump文件,從中提取獲得觸發問題的請求的host、URL、headers等,有了這些信息,就能夠不斷復現來快速調試和定位問題。可是有時候,coredump棧並不能告訴咱們完整的現場,而在crash時,Tengine丟失了日誌中的請求信息,咱們將這些信息記錄在環形內存中,經過coredump文件將環形緩衝數據輸出到文件,環環相扣,完整的現場,真相只有一個。
原理:http://nginx.org/en/docs/ngx_...
過後諸葛只能查漏補缺,咱們須要提早發現問題,實時流量拷貝工具應運而生。http_copy是Tengine的擴展模塊,能夠實時放大轉發本機的流量(HTTP請求),能夠配置放大流量到指定地址和端口,也可設置放大的倍數和併發量等,更能夠經過源站健康檢查來自動關停流量,避免過大流量對Tengine和源站的正常服務形成影響。
在流量壓測/流量拷貝時,不須要真實返回響應的內容,減小帶寬消耗,drop_traffic工具添加body filter直接丟棄數據,或者截獲c->send_chain/c->send函數直接丟棄數據,在調試時發現問題而不產生問題。
以上就是阿里雲CDN團隊對於Tengine的內存調試與資源監控方面的一些實踐經驗,但願對於正在使用開源Tengine的同窗有一些幫助。
Tengine官網:http://tengine.taobao.org
Tengine Github:https://github.com/alibaba/te...
阿里雲CDN:https://www.aliyun.com/produc...
最後,阿里雲CDN團隊正在招聘志同道合的夥伴,歡迎加入~