IM開發基礎知識補課(二):如何設計大量圖片檔案的服務端儲存架構?
友情提示:正文內容整理自架構師丁浪的技術分享,部分觀點可作拋磚引玉之用,可能並非最佳實踐,歡迎留言指正。
1、前言
一個完善的IM系統中通常充斥著大量的圖片內容,包括:使用者頭像、圖片訊息、相簿、圖片表情等等,那麼在做服務端架構設計時該如何儲存這些圖片呢?
本文分享的是典型Web應用中大量圖片的服務端儲存加構的演進過程,但基本的技術原理和架構思路對於IM系統而言同樣適用,所以在閱讀時可以根據自已IM的實際架構情況,酌情吸取適合您的內容即可。文中部分觀點可作拋磚引玉之用,可能並非最佳實踐,請勿迷信之。
實際上:舊式的PC端IM中,諸如圖片訊息這種業務形態,可能是通過長連線直接推送過去(所謂的實時圖片傳輸嘛),這種情況理論上是不需要服務端儲存的。但現今的主流移動端IM,基於行動網路抖動大、 不穩定的特性和隨時隨地社交分享的現實,已很少使用實時傳輸這種技術手段。現在主流IM都是本文所述的這種:通過Http短連線從雲(也就是服務端)“拉取”,這種方式的好處是:隨時隨地分享、對網路穩定性要求低(只要上傳者一次上傳,服務端可長時間儲存,下一個閱讀者通過URL按需隨讀隨取即可,再次分享時只要分享URL而無需再次完整傳輸整個圖片)。
以此類推:IM系統中,實際上還存在其它類似於圖片的小檔案儲存需求,比如:語音留言訊息中的AMR短音訊檔案(有些IM中為了音質可能使用的是AAC音訊格式,比如易信)、短視訊功能中的小視訊檔案等,這些檔案的儲存和使用跟圖片檔案基本類似,所以考慮到通用性,如果能把這些小檔案儲存也納入到圖片的儲存架構中,對於整體系統架構來說(尤其儲存部分)就顯的更通用。所以本文中雖然以圖片儲存為切入點,但您實際上完全可以套用到基它小檔案的儲存上哦。
學習交流:
– 即時通訊開發交流群:320837163[推薦]
– 移動端IM開發入門文章:《新手入門一篇就夠:從零開發移動端IM》
(本文同步釋出於:http://www.52im.net/thread-1356-1-1.html)
2、相關文章
▼ 跟IM資料儲存架構有關的文章,有如下幾篇,或許對你有用:
《騰訊原創分享(一):如何大幅提升行動網路下手機QQ的圖片傳輸速度和成功率》
▼ IM開發乾貨系列文章適合作為IM開發熱點問題參考資料(本文是其第11篇):
《IM訊息送達保證機制實現(一):保證線上實時訊息的可靠投遞》
《一種Android端IM智慧心跳演算法的設計與實現探討(含樣例程式碼)》
如果您是IM開發初學者,強烈建議首先閱讀《新手入門一篇就夠:從零開發移動端IM》。
3、單機時代的圖片伺服器架構(集中式)
初創時期由於時間緊迫,開發人員水平很有限。
所以通常就直接在website檔案所在的目錄下,建立1個upload子目錄,用於儲存使用者上傳的圖片檔案:
[1] 如果按業務再細分,可以在upload目錄下再建立不同的子目錄來區分,例如:uploadQA,uploadFace等
[2] 在資料庫表中儲存的也是“upload/qa/test.jpg”這類相對路徑;
[3] 使用者的訪問方式如下:http://www.yourdomain.com/upload/qa/test.jpg
程式上傳和寫入方式:
程式設計師A通過在web.config中配置物理目錄D:Webyourdomainupload 然後通過stream的方式寫入檔案;
程式設計師B通過Server.MapPath等方式,根據相對路徑獲取物理目錄 然後也通過stream的方式寫入檔案。
結果就是:
優點:實現起來最簡單,無需任何複雜技術,就能成功將使用者上傳的檔案寫入指定目錄。儲存資料庫記錄和訪問起來倒是也很方便;
缺點:上傳方式混亂,嚴重不利於網站的擴充套件。
針對上述最原始的架構,主要面臨著如下問題:
隨著upload目錄中檔案越來越多,所在分割槽如果出現容量不足,則很難擴容。只能停機後更換更大容量的儲存裝置,再將舊資料匯入;
在部署新版本(部署新版本前通過需要備份)和日常備份website檔案的時候,需要同時操作upload目錄中的檔案,如果考慮到訪問量上升,後邊部署由多臺Web伺服器組成的負載均衡叢集,叢集節點之間如果做好檔案實時同步將是個難題。
4、叢集時代的圖片伺服器架構(實時同步)
一個傳統的Web服務端站點下面,新建一個名為upload的虛擬目錄,由於虛擬目錄的靈活性,能在一定程度上取代物理目錄,併相容原有的圖片上傳和訪問方式。
使用者的訪問方式依然是:
http://www.yourdomain.com/upload/qa/test.jpg
優點:配置更加靈活,也能相容老版本的上傳和訪問方式。因為虛擬目錄,可以指向本地任意碟符下的任意目錄。這樣一來,還可以通過接入外接儲存,來進行單機的容量擴充套件。
缺點:部署成由多臺Web伺服器組成的叢集,各個Web伺服器(叢集節點)之間(虛擬目錄下的)需要實時的去同步檔案,由於同步效率和實時性的限制,很難保證某一時刻各節點上檔案是完全一致的。
基本架構如下圖所示:
從上圖可看出,整個Web伺服器架構已經具備“可擴充套件、高可用”了,主要問題和瓶頸都集中在多臺伺服器之間的檔案同步上。
上述架構中只能在這幾臺Web伺服器上互相“增量同步”,這樣一來,就不支援檔案的“刪除、更新”操作的同步了。
早期的想法是,在應用程式層面做控制,當使用者請求在web1伺服器進行上傳寫入的同時,也同步去呼叫其它web伺服器上的上傳介面,這顯然是得不償失的。所以我們選擇使用Rsync類的軟體來做定時檔案同步的,從而省去了“重複造輪子”的成本,也降低了風險性。
同步操作裡面,一般有比較經典的兩種模型,即推拉模型:所謂“拉”,就是指輪詢地去獲取更新,所謂推,就是發生更改後主動的“推”給其它機器。當然,也可以採用加高階的事件通知機制來完成此類動作。
在高併發寫入的場景中,同步都會出現效率和實時性問題,而且大量檔案同步也是很消耗系統和頻寬資源的(跨網段則更明顯)。
5、叢集時代的圖片伺服器架構改進(共享儲存)
沿用虛擬目錄的方式,通過UNC(網路路徑)的方式實現共享儲存(將upload虛擬目錄指向UNC)。
使用者的訪問方式1:
http://www.yourdomain.com/upload/qa/test.jpg
使用者的訪問方式2(可以配置獨立域名):
http://img.yourdomain.com/upload/qa/test.jpg
支援UNC所在server上配置獨立域名指向,並配置輕量級的web伺服器,來實現獨立圖片伺服器。
優點: 通過UNC(網路路徑)的方式來進行讀寫操作,可以避免多伺服器之間同步相關的問題。相對來講很靈活,也支援擴容/擴充套件。支援配置成獨立圖片伺服器和域名訪問,也完整相容舊版本的訪問規則。
缺點:但是UNC配置有些繁瑣,而且會造成一定的(讀寫和安全)效能損失。可能會出現“單點故障”。如果儲存級別沒有raid或者更高階的災備措施,還會造成資料丟失。
基本架構如下圖所示:
在早期的很多基於Linux開源架構的網站中,如果不想同步圖片,可能會利用NFS來實現。事實證明,NFS在高併發讀寫和海量儲存方面,效率上存在一定問題,並非最佳的選擇,所以大部分網際網路公司都不會使用NFS來實現此類應用。當然,也可以通過Windows自帶的DFS來實現,缺點是“配置複雜,效率未知,而且缺乏資料大量的實際案例”。另外,也有一些公司採用FTP或Samba來實現。
上面提到的幾種架構,在上傳/下載操作時,都經過了Web伺服器(雖然共享儲存的這種架構,也可以配置獨立域名和站點來提供圖片訪問,但上傳寫入仍然得經過Web伺服器上的應用程式來處理),這對Web伺服器來講無疑是造成巨大的壓力。所以,更建議使用獨立的圖片伺服器和獨立的域名,來提供使用者圖片的上傳和訪問。
6、獨立圖片伺服器/獨立域名的好處
圖片訪問是很消耗伺服器資源的(因為會涉及到作業系統的上下文切換和磁碟I/O操作)。分離出來後,Web/App伺服器可以更專注發揮動態處理的能力。
獨立儲存,更方便做擴容、容災和資料遷移;
瀏覽器(相同域名下的)併發策略限制,效能損失;
訪問圖片時,請求資訊中總帶cookie資訊,也會造成效能損失;
方便做圖片訪問請求的負載均衡,方便應用各種快取策略(HTTP Header、Proxy Cache等),也更加方便遷移到CDN;
……
我們可以使用Lighttpd或者Nginx等輕量級的web伺服器來架構獨立圖片伺服器。
7、我們當前的圖片伺服器架構
當前圖片伺服器架構採用分散式檔案系統+CDN。
在構建當前的圖片伺服器架構之前,可以先徹底撇開web伺服器,直接配置單獨的圖片伺服器/域名。
但面臨如下的問題:
舊圖片資料怎麼辦?能否繼續相容舊圖片路徑訪問規則?
獨立的圖片伺服器上需要提供單獨的上傳寫入的介面(服務API對外發布),安全問題如何保證?
同理,假如有多臺獨立圖片伺服器,是使用可擴充套件的共享儲存方案,還是採用實時同步機制?
直到應用級別的(非系統級) DFS(例如FastDFS HDFS MogileFs MooseFS、TFS)的流行,簡化了這個問題:執行冗餘備份、支援自動同步、支援線性擴充套件、支援主流語言的客戶端api上傳/下載/刪除等操作,部分支援檔案索引,部分支援提供Web的方式來訪問。
考慮到各DFS的特點,客戶端API語言支援情況(需要支援C#),文件和案例,以及社群的支援度,我們最終選擇了FastDFS來部署。
唯一的問題是:可能會不相容舊版本的訪問規則。如果將舊圖片一次性匯入FastDFS,但由於舊圖片訪問路徑分佈儲存在不同業務資料庫的各個表中,整體更新起來也十分困難,所以必須得相容舊版本的訪問規則。架構升級往往比做全新架構更有難度,就是因為還要相容之前版本的問題。(給飛機在空中換引擎可比造架飛機難得多)
解決方案如下:
首先,關閉舊版本上傳入口(避免繼續使用導致資料不一致)。將舊圖片資料通過rsync工具一次性遷移到獨立的圖片伺服器上(即下圖中描述的Old Image Server)。在最前端(七層代理,如Haproxy、Nginx)用ACL(訪問規則控制),將舊圖片對應URL規則的請求(正則)匹配到,然後將請求直接轉發指定的web 伺服器列表,在該列表中的伺服器上配置好提供圖片(以Web方式)訪問的站點,並加入快取策略。這樣實現舊圖片伺服器的分離和快取,相容了舊圖片的訪問規則並提升舊圖片訪問效率,也避免了實時同步所帶來的問題。
整體架構如圖:
8、使用第3方CDN的方案
基於FastDFS的獨立圖片伺服器叢集架構,雖然已經非常的成熟,但是由於國內“南北互聯”和IDC頻寬成本等問題(圖片是非常消耗流量的),我們最終還是選擇了商用的CDN技術,實現起來也非常容易,原理其實也很簡單,我這裡只做個簡單的介紹。
將img域名cname到CDN廠商指定的域名上,使用者請求訪問圖片時,則由CDN廠商提供智慧DNS解析,將最近的(當然也可能有其它更復雜的策略,例如負載情況、健康狀態等)服務節點地址返回給使用者,使用者請求到達指定的伺服器節點上,該節點上提供了類似Squid/Vanish的代理快取服務,如果是第一次請求該路徑,則會從源站獲取圖片資源返回客戶端瀏覽器,如果快取中存在,則直接從快取中獲取並返回給客戶端瀏覽器,完成請求/響應過程。
由於採用了商用CDN服務,所以我們並沒有考慮用Squid/Vanish來自行構建前置代理快取。
上面的整個叢集架構,可以很方便的做橫向擴充套件,能滿足一般垂直領域中大型網站的圖片服務需求(當然,像taobao這樣超大規模的可能另當別論)。經測試,提供圖片訪問的單臺Nginx伺服器(至強E5四核CPU、16G記憶體、SSD),對小靜態頁面(壓縮後大概只有10kb左右的)可以扛住幾千個併發且毫無壓力。當然,由於圖片本身體積比純文字的靜態頁面大很多,提供圖片訪問的伺服器的抗併發能力,往往會受限於磁碟的I/O處理能力和IDC提供的頻寬。Nginx的抗併發能力還是非常強的,而且對資源佔用很低,尤其是處理靜態資源,似乎都不需要有過多擔心了。可以根據實際訪問量的需求,通過調整Nginx的引數,對Linux核心做調優,加入分級快取策略等手段能夠做更大程度的優化,也可以通過增加伺服器或者升級伺服器配置來做擴充套件,最直接的是通過購買更高階的儲存裝置和更大的頻寬,以滿足更大訪問量的需求。
值得一提的是,在“雲端計算”流行的當下,也推薦高速發展期間的網站,使用“雲端儲存”這樣的方案,既能幫你解決各類儲存、擴充套件、備災的問題,又能做好CDN加速。最重要的是,價格也不貴。
總結,有關圖片伺服器架構擴充套件,大致圍繞這些問題展開:
容量規劃和擴充套件問題;
資料的同步、冗餘和容災;
硬體裝置的成本和可靠性(是普通機械硬碟,還是SSD,或者更高階的儲存裝置和方案);
檔案系統的選擇。根據檔案特性(例如檔案大小、讀寫比例等)選擇是用ext3/4或者NFS/GFS/TFS這些開源的(分散式)檔案系統;
圖片的加速訪問。採用商用CDN或者自建的代理快取、web靜態快取架構;
舊圖片路徑和訪問規則的相容性,應用程式層面的可擴充套件,上傳和訪問的效能和安全性等。
附錄:更多IM開發文章
[1] 有關IM架構設計:
《一套海量線上使用者的移動端IM架構設計實踐分享(含詳細圖文)》
《騰訊QQ1.4億線上使用者的技術挑戰和架構演進之路PPT》
《IM開發基礎知識補課(二):如何設計大量圖片檔案的服務端儲存架構?》
>> 更多同類文章 ……
[2] 有關IM安全的文章:
《即時通訊安全篇(一):正確地理解和使用Android端加密演算法》
《即時通訊安全篇(四):例項分析Android中金鑰硬編碼的風險》
《即時通訊安全篇(五):對稱加密技術在Android平臺上的應用實踐》
《傳輸層安全協議SSL/TLS的Java平臺實現簡介和Demo演示》
《理論聯絡實際:一套典型的IM通訊協議設計詳解(含安全層設計)》
《微信新一代通訊安全解決方案:基於TLS1.3的MMTLS詳解》
《來自阿里OpenIM:打造安全可靠即時通訊服務的技術實踐分享》
《Web端即時通訊安全:跨站點WebSocket劫持漏洞詳解(含示例程式碼)》
>> 更多同類文章 ……
[3] IM開發綜合文章:
《IM開發基礎知識補課:正確理解前置HTTP SSO單點登陸介面的原理》
《IM訊息送達保證機制實現(一):保證線上實時訊息的可靠投遞》
《開源IM工程“蘑菇街TeamTalk”的現狀:一場有始無終的開源秀》
《QQ音樂團隊分享:Android中的圖片壓縮技術詳解(上篇)》
《QQ音樂團隊分享:Android中的圖片壓縮技術詳解(下篇)》
《騰訊原創分享(一):如何大幅提升行動網路下手機QQ的圖片傳輸速度和成功率》
《騰訊原創分享(二):如何大幅壓縮行動網路下APP的流量消耗(上篇)》
《騰訊原創分享(二):如何大幅壓縮行動網路下APP的流量消耗(下篇)》
《如約而至:微信自用的移動端IM網路層跨平臺元件庫Mars已正式開源》
《基於社交網路的Yelp是如何實現海量使用者圖片的無失真壓縮的?》
>> 更多同類文章 ……
(本文同步釋出於:http://www.52im.net/thread-1356-1-1.html)
相關文章
- IM開發基礎知識補課(三):快速理解服務端資料庫讀寫分離原理及實踐建議服務端資料庫
- 架構設計基礎知識整理架構
- 知識乾貨:基礎儲存服務新手體驗營
- 基礎儲存知識
- IM開發基礎知識補課(十):大型IM系統有多難?萬字長文,搞懂異地多活!
- IM開發基礎知識補課(四):正確理解HTTP短連線中的Cookie、Session和TokenHTTPCookieSession
- IM開發基礎知識補課:正確理解前置HTTPSSO單點登陸介面的原理HTTP
- [雲原生微服務架構](十)微服務架構的基礎知識微服務架構
- .Net之使用Jquery Ajax通過FormData物件非同步提交圖片檔案到服務端儲存並返回儲存的圖片路徑jQueryORM物件非同步服務端
- Java併發程式設計——基礎知識(二)Java程式設計
- Oracle架構的基礎知識Oracle架構
- 儲存基礎知識白皮書
- 基於滴滴雲的棋牌遊戲服務端架構設計遊戲服務端架構
- 淘寶圖片儲存系統架構架構
- 圖片服務架構演進架構
- oracle架構的基礎知識(轉)Oracle架構
- ASP儲存遠端圖片檔案到原生程式碼
- Python基礎知識架構Python架構
- 服務端指南 資料儲存篇 | MySQL(03) 如何設計索引服務端MySql索引
- SpringCloud Alibaba實戰(3:儲存設計與基礎架構設計)SpringGCCloud架構
- 雲端計算學習路線課程大綱資料:儲存基礎知識
- 基礎知識1——資料物理,邏輯儲存結構
- SecureFiles LOBs基礎知識之儲存篇
- 系統架構設計面試指南(02)-MQ和檔案儲存架構面試MQ
- 二、javase基礎知識總結(從檔案 I/O開始)Java
- 基於AWS的檔案同步服務系統架構架構
- 服務計算基礎知識 UDDI SOAP WSDL特性 SOA 設計原則
- 如何進行雲端儲存架構框架設計?架構框架
- 開發基礎知識
- 微服務架構 spring boot 那些最基礎的知識點微服務架構Spring Boot
- 儲存基礎(二)
- 乾貨 | 攜程圖片服務架構架構
- 將圖片檔案儲存到Oracle的儲存過程Oracle儲存過程
- 面向服務的整車E/E架構(SOA)設計開發諮詢服務架構
- 【轉】mysql儲存圖片技術決定:儲存二進位制檔案還是隻儲存圖片相對路徑,圖片放在硬碟上面?MySql硬碟
- oracle架構的基礎知識(入門級)Oracle架構
- 網路開發基礎服務端001服務端
- 【VMware vSAN】全新vSAN 8 ESA快速儲存架構配置檔案服務並建立檔案共享。架構