乾貨 | 攜程圖片服務架構
作者簡介:胡健,攜程框架高階研發經理,目前負責多媒體服務的構建和研發工作。
近些年攜程業務突飛猛進,使用者遍及世界各地。公司對使用者體驗也越來越重視,每一個小的功能改動、頁面改版的背後,都有大量的A/B實驗提供保障。與此同時,與使用者體驗息息相關的媒體檔案的應用質量也被放到重要位置,如圖片載入延時、成功率、清晰度等資料。
本文將分享攜程圖片服務架構,包括 服務架構的演變過程,以及在生產上實際遇到的一些問題,避免大家重複踩坑。
一、服務架構
1、初始階段
攜程圖片的服務架構主要經歷了三次比較大的調整。早些年為了滿足業務快速上線的需求,我們做了簡單實現,架構如下:
這個架構開發工作量不大,因為當時業務對圖片尺寸的需求單一,也沒有複雜的圖片組合處理需求,因此有大量圖片都被Squid快取住,快取命中率很高,取圖速度非常快。
圖片裁剪命令的執行,則由業務釋出的時候上傳處理。儲存通過NFS讓整個Nginx服務叢集共享。直到移動端流量開始爆發的時候,這個架構有點力不從心。
首先,同一張原圖需要裁剪出大量不同尺寸的小圖片,佔用了大量儲存資源。其次,業務圖片越來越多加上大量不同尺寸的小圖片的出現,導致Squid快取命中率變差,大量流量穿透到NFS上,I/O迅速變為瓶頸。
從監控看,當時的NFS Read I/O一直處於高水位水平,告警更是24小時不斷,回源流量的上升也導致Squid服務叢集開始變得不穩定,經常需要重啟。鑑於這些問題,我們做了下面架構上的調整。
2、發展階段
用Varnish替換了Squid,作為快取和反向代理服務。
從實際監控情況看,同等壓力下Varnish的表現比Squid更穩定,Varnish虛擬記憶體swap機制比Squid自己管理的更好,因此效能上更優,並且Varnish配置方便,對運維友好。
當然Squid也有更適合的使用場景,選擇Varnish是因為在當前場景下更符合我們的需求。
為了解決Varnish節點當機會引發大量快取資料失效,LB上對URL做了一致性Hash,這樣能儘量減少快取失效帶來的其他節點資料的遷移,同時也解決了Varnish利用率的問題。
Nginx內嵌Lua指令碼用於在圖片訪問的時候直接對圖片進行處理,而不是上傳的時候處理,這樣很多不同尺寸的小圖不用在儲存上保留,儲存上少了大量I/O,並且減少儲存量的同時也會減輕運維的壓力。
從訪問效率看,因為圖片需要實時處理,服務響應延時相比上一個版本有大幅上升,平均延時大概在300毫秒左右。但是這個影響實際對端的影響有限。
首先,國內CDN普遍質量較好,95%以上的圖片資源訪問都會被CDN擋掉,正常情況下回源流量不會太大。其次,我們Varnish叢集命中率大概在40~50%之間,所以整體圖片實時處理壓力佔整體流量約1%~2%之間,這些流量訪問延時會上升300毫秒左右是完全能夠接受的。
儲存用FastDFS替換了NFS,當時Ceph還不像現在那麼穩定,FastDFS的特性又能夠滿足我們需求,並且架構簡單,原始碼能完全掌控。事實證明,FastDFS叢集完全支撐了每天數億次的原圖讀寫操作,並多次在多機房DR演練中完成各項指標。
當時這個架構的核心是Lua的圖片處理模組,Coroutine的效能非常好,當有大量圖片回源請求的時候,CPU不會浪費線上程的context switch上,開發也很直白,在I/O操作的時候不需要用非同步方式編碼,並且Lua的執行在Nginx裡足夠高效。
這裡唯一的缺點是Lua擴充套件性相對較弱,很多模組需要自己寫,比如對接我們自己的監控系統的時候就遇到難題。
隨著業務的發展,使用者對圖片的處理要求越來越高,多重濾鏡的應用,需要在Lua裡實現很多功能,並且很多基礎資料結構都要自己寫或者依賴第三方,不僅開發工作量大,穩定性和正確性的驗證也需要花費不少的精力。
是不是還有一種技術方案可替代,既能享受協程帶來的簡單,高效。又能兼顧擴充套件性和完善的功能包,不用重複造輪子。
1、具有1-5工作經驗的,面對目前流行的技術不知從何下手,
需要突破技術瓶頸的。
2、在公司待久了,過得很安逸,但跳槽時面試碰壁。需要在短時間內進修、跳槽拿高薪的。
3、如果沒有工作經驗,但基礎非常紮實,對java工作機制,用設計思想,常用java開發框架掌握熟練的。
4、覺得自己很牛B,一般需求都能搞定。但是所學的知識點沒有系統化,很難在技術領域繼續突破的。
- 群號:高階架構群 ⑥⑨⑦⑤⑦⑨⑦⑤① 備註好資訊!
6.阿里Java高階大牛直播講解知識點,分享知識,
3、現階段
我們選擇了Golang做為當前版本的開發語言,架構如下:
採用多程式單協程圖片處理模型。圖片庫主要依賴的是GraphicsMagick,和少部分ImageMagick,通過封裝cgo呼叫實現。
Golang呼叫cgo會申明一個進入syscall的指令,意味著排程器會建立一個M去執行goroutine。因此當有大量併發呼叫,並且圖片處理足夠慢,比如一張畫素特別大的原圖,就會引發大量執行緒同時存在,造成不必要context switch,CPU load看上去很高,實際效率很低。
因此我們通常會通過Master程式fork出和CPU相等數量的Worker程式做圖片處理,每個程式只有一個協程來處理圖片,每個程式會建立一個可配置的buffer用於儲存原圖的blob, 這樣能最大化利用單協程的利用率。
採用這種架構當時主要還為了規避GM本身的一個問題,參考我們向作者提交的issue:
https://sourceforge.net/p/graphicsmagick/mailman/graphicsmagick-help/?viewmonth=201708 .
問題描述是setjmp函式和longjmp函式在某些作業系統非執行緒安全,作者需要一個全域性鎖來保證執行緒安全。因此多執行緒呼叫本身是低效的。
這個問題在java或者.net封裝的GM也會存在。上一個版本的Lua不存在這個問題,因為Nginx本身會fork多個Worker程式進行圖片處理,並且只可能存在一個正在執行的協程。事實上Linux執行這兩個函式本身是執行緒安全的,作者可以通過build的時候來決定是不是需要加上執行緒安全的flag。在發表本文的時候,作者已經在最新的release中修復了這個bug。
這裡的Nginx不僅僅用來做LB,因為Nginx能提供很豐富的指令碼,可以省去很多開發工作量,並且當有獲取原圖的需求,可以通過Nginx sendfile直接從儲存取回,節省不必要的系統開銷。
LB演算法並不是簡單的RR,我們會根據每個程式的CPU消耗,以及原影象素,buffer消耗等維度動態算出各程式的負載量,如果Nginx RR到一個負載非常大的程式,可以通過返回重定向狀態碼讓Nginx重新跳轉,這裡可能會出現幾次網路跳轉,但是因為是Loopback,網路上的消耗相對圖片處理的消耗可以忽略不計。
Master程式用來管理Worker程式,當有Worker意外Crash,則會重新拉起一個Worker程式,始終保持和CPU數量一致。 Master程式的健康安全會定期Report給監控系統做告警。
二、 小結
當前的圖片服務架構,支撐了攜程每天上億次原圖處理,平均圖片處理延時控制在200毫秒以內,圖片處理失敗率小於萬分之一,從釋出至今節點沒有出現當機現象,偶爾Worker程式有效能問題和Crash也通過日誌和分析工具逐一解決。
如上所述,攜程圖片服務架構經歷了三次改版,從一開始沒有設計複雜的架構,只是為了解決碰到實際問題而重構,到後來根據遇到的問題,不斷調整,也說明了沒有完美的架構,只有適合的架構。
當然,要提供穩定圖片服務,架構是一方面,也必須有其他技術上的支援,比如圖片本身質量和尺寸的優化,盜鏈和版權問題,端到端的實時監控和預警機制,不良內容識別,產品圖片管理和編輯功能,以及海外使用者圖片訪問加速問題。這些問題每個都能寫下不少篇幅的文章,有時間再和小夥伴分享。
目前,攜程圖片服務已在github上開源了小部分功能,開源地址: https://github.com/ctripcorp/nephele
後續會逐步完善,歡迎PR。
高階架構群:697579751(大牛交流群)沒有開發經驗勿擾!
相關文章
- 乾貨 | 攜程線上風控系統架構架構
- 乾貨 | 攜程酒店實時數倉架構和案例架構
- 近萬服務例項穩定執行 0 故障,攜程微服務架構是如何落地的?微服務架構
- 【虹科乾貨】設計微服務架構的原則微服務架構
- 乾貨篇:超多內容微服務架構實戰微服務架構
- 乾貨 | 攜程日誌系統治理演進之路
- 乾貨:軟體架構詳解架構
- 服務架構學習與思考(12):從單體架構到微服務架構的演進歷程架構微服務
- 單體架構&微服務架構&中臺服務架構架構微服務
- 乾貨帖 | TDSQL-A核心架構揭秘SQL架構
- 乾貨 | 廣告系統架構解密架構解密
- 乾貨:軟體架構分析詳解架構
- ImageMagick+OpenResty構建圖片處理服務REST
- 乾淨架構在 Web 服務開發中的實踐架構Web
- Android-圖片壓縮(二)-純乾貨Android
- 2018服務端架構師技術圖譜服務端架構
- 面向服務的架構架構
- 微服務架構—服務降級微服務架構
- 乾貨:阿里大牛淺談MySQL架構體系阿里MySql架構
- 「乾貨分享」用友雲微服務架構下配置檔案管理利器:配置中心微服務架構
- 乾貨 | 資料為王,攜程國際火車票的 ShardingSphere 之路
- 乾貨 | 攜程一次Redis遷移容器後Slowlog“異常”分析Redis
- 整合spring cloud雲服務架構 - commonservice-eureka 專案構建過程SpringCloud架構
- 乾貨分享丨攜程國際業務動態實時標籤處理平臺實踐
- 【虹科乾貨】Lambda資料架構和Kappa資料架構——構建現代資料架構架構APP
- 「技術乾貨」Pontus-用友雲限流服務
- 微服務架構之「 服務註冊 」微服務架構
- (七)整合spring cloud雲服務架構 - common-service 專案構建過程SpringCloud架構
- (八)整合spring cloud雲服務架構 - commonservice-eureka 專案構建過程SpringCloud架構
- 乾貨 | 攜程酒店排序推薦廣告高效可靠資料基座--填充引擎排序
- SpringCloud構建微服務架構-Hystrix服務降級SpringGCCloud微服務架構
- 按照業務領域畫資料架構圖 業務架構 資料架構架構
- Spring Cloud雲服務架構 - 企業分散式微服務雲架構構建SpringCloud架構分散式微服務
- 使用C#建立安裝Windows服務程式(乾貨)C#Windows
- 整合華為運動健康服務乾貨總覽健康服務
- 用 Hystrix 構建高可用服務架構架構
- 微服務 架構圖 參考微服務架構
- Spring Cloud雲服務架構 - 雲架構程式碼結構構建SpringCloud架構