【大型網站技術實踐】初級篇:海量圖片的分散式儲存設計與實現
一、研究背景:效能與資金,二者可兼得乎?
1.1 那麼問題來了?
隨著網際網路的發展,許多大中型的網站都儲存了大量的圖片資源,使用者在訪問這些圖片資源異常豐富的網站(如淘寶、京東等電子商務網站)時,網頁中的圖片資訊佔據了頁面資料流量的很大部分,那麼問題也來了:
(1)由於受客戶端瀏覽器限制,無法從一臺伺服器上同時下載頁面中所有圖片資訊;
PS:當一個網頁被瀏覽時,Web伺服器與瀏覽器建立連線,每個連線表示一個併發。當頁面包含多個圖片時,Web伺服器與瀏覽器會產生多個連線,同時傳送文字和圖片以提高瀏覽速度。因此,頁面中圖片越多Web伺服器受到的壓力也就越大。同時由於受到瀏覽器本身的併發連線數限制(2個~6個併發
),意味著頁面上有多於併發連線數限制的圖片時,也不能並行地把所有圖片同時下載和顯示。
(2)由於圖片儲存在物理伺服器上,訪問圖片需要頻繁進行I/O操作:因此當併發使用者數越來越多時,I/O操作就會成為整個系統的效能瓶頸;
(3)由於受作業系統的限制,一個目錄中能存放的圖片檔案數量也是有限的:隨著圖片資源不斷增加,如何有效管理和維護圖片也是一個難題;
1.2 山東濟南找藍翔?
(1)對於少數大型網站系統,由於自身具有雄厚的資金和人力資源,可採用NFS、CDN、Lighttpd、反向代理、負載均衡等技術提高使用者訪問速度;但是,這些技術需要龐大的資金來支援。
(2)對於多數中小型網站系統,有木有一種方案適用於中等規模商務網站的海量圖片資料分散式動態儲存及負載均衡的解決方案?該方案可否只需增加很少的硬體成本,即可提升網站的訪問速度,並且可以根據需要動態調整圖片伺服器的數量及圖片的儲存目錄,確保系統具有可擴充套件性和伸縮性。
SUMMARY:需求永遠是那麼美好,使用最少的money幹盡量多的事情!正在我們決定放棄開發崗位去藍翔學挖掘機技術的時候,我們突然發現有那麼多的技術先驅已經給我們指明瞭道路。
二、架構設計:構建圖片伺服器叢集
對於小型網站,由於資料規模小,可以把網站所有頁面和圖片統一存放在一個主目錄下,這樣的網站對系統架構、效能要求都很簡單。但大中型網站都儲存有海量級的圖片檔案,所採用的技術更是涉及廣泛,從硬體到軟體、程式語言、資料庫、Web伺服器、防火牆等各個領域都有較高要求。因此,有必要設立單獨的圖片伺服器來專門存放圖片,把圖片資料的流量從Web伺服器上分離開,這樣的架構可以有效緩解Web伺服器的I/O效能瓶頸
2.1 系統設計目標
基於以上的考慮,我們希望的設計目標是:
(1)圖片能進行分散式儲存;
(2)圖片伺服器能實現負載均衡;
(3)能根據使用者訪問量及網站圖片資料量的增加能動態新增圖片伺服器節點;
(4)圖片伺服器節點的動態調整對網站使用者而言是透明的,並且不會中斷系統的正常執行;
其中,(1)和(2)是針對系統的高可用和伸縮性,而(3)和(4)則是針對系統的高可用和可擴充套件而言的。
2.2 系統架構設計
系統整體架構如上圖所示:包括客戶端、Web伺服器、資料庫伺服器、圖片伺服器叢集4個部分。
(1)Web伺服器部署網站的Web頁面,用於響應客戶端使用者的請求。當用戶瀏覽網頁時,Web伺服器響應請求並訪問資料庫伺服器,獲得網頁中所有圖片的URL路徑,然後生成頁面並返回給客戶端;
(2)客戶端接收該頁面並根據頁面中的圖片URL路徑自動從不同的圖片伺服器下載並顯示相應圖片。
(3)資料庫伺服器用於記錄所有圖片的編號以及圖片的存放位置等資訊,同時需要記錄所有圖片伺服器的配置及當前狀態資訊。
(4)圖片伺服器叢集用於存放網站的所有圖片資訊,該叢集的伺服器數量可以根據需要動態增加或刪減。
三、系統實現:一種簡單且價廉可用的方案
3.1 資料庫設計與實現:兩張簡單的表
Web伺服器需要及時掌握所有圖片伺服器的狀態和資訊才能動態決定把圖片儲存到哪一臺圖片伺服器。因此,需要把所有的圖片伺服器的狀態資訊全部紀錄到資料庫伺服器中,記錄圖片伺服器資訊和狀態的表格式如下圖所示:可以清楚地看出,圖片伺服器資訊表中記錄了圖片伺服器的ID、名稱、URL、最大儲存數量、當前已存數量以及伺服器的狀態(True:可用,False:不可用),每個圖片伺服器下會有多個圖片資訊記錄,因此它們是一對多的關係。
(1)圖片伺服器狀態資訊表建表語句:
CREATE TABLE [dbo].[ImageServerInfo]( [ServerId] [int] IDENTITY(1,1) NOT NULL, [ServerName] [nvarchar](32) NOT NULL, [ServerUrl] [nvarchar](100) NOT NULL, [PicRootPath] [nvarchar](100) NOT NULL, [MaxPicAmount] [int] NOT NULL, [CurPicAmount] [int] NOT NULL, [FlgUsable] [bit] NOT NULL, CONSTRAINT [PK_ImageServerInfo] PRIMARY KEY CLUSTERED ( [ServerId] ASC )WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY] ) ON [PRIMARY]
(2)圖片記錄資訊表建表語句:
CREATE TABLE [dbo].[ImageInfo]( [Id] [int] IDENTITY(1,1) NOT NULL, [ImageName] [nvarchar](100) NOT NULL, [ImageServerId] [int] NOT NULL, CONSTRAINT [PK_ImageInfo] PRIMARY KEY CLUSTERED ( [Id] ASC )WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY] ) ON [PRIMARY] GO ALTER TABLE [dbo].[ImageInfo] WITH CHECK ADD CONSTRAINT [FK_ImageInfo_ImageServerInfo] FOREIGN KEY([ImageServerId]) REFERENCES [dbo].[ImageServerInfo] ([ServerId]) GO ALTER TABLE [dbo].[ImageInfo] CHECK CONSTRAINT [FK_ImageInfo_ImageServerInfo] GO
3.2 檔案上傳與瀏覽系統實現:一個ASP.Net MVC應用程式
這裡我們使用一個ASP.NET MVC應用程式部署在Web伺服器上,這個應用程式作為Web網站向客戶提供上傳和瀏覽的服務。因此,它最重要的功能就是:
一、接收使用者上傳的檔案,並轉交給圖片伺服器的相關處理程式進行處理和儲存;
二、取得所有圖片伺服器中儲存的有效圖片路徑,返回給客戶端瀏覽器,再由客戶端瀏覽器對圖片路徑向圖片伺服器叢集進行請求;
3.2.1 設計Controller
public class HomeController : Controller { IImageServerInfoRepsitory _imageServerInfoRepository; public HomeController() { // 這裡可以藉助IoC實現依賴注入 this._imageServerInfoRepository = new ImageServerInfoRepository(); } #region 01.Action:上傳頁面 // // GET: /Home/ public ActionResult Index() { return View(); } #endregion #region 02.Action:上傳圖片 public ActionResult Upload() { HttpPostedFileBase file = Request.Files["fileUpload"]; if (file.ContentLength == 0) { return Content("<script type=\"text/javascript\">alert(\"您還未選擇要上傳的圖片!\");location.href=\"/Home/Index\";</script>"); } // 獲取上傳的圖片名稱和副檔名稱 string fileFullName = Path.GetFileName(file.FileName); string fileExtName = Path.GetExtension(fileFullName); if (!CommonHelper.CheckImageFormat(fileExtName)) { return Content("<script type=\"text/javascript\">alert(\"上傳圖片格式錯誤,請重新選擇!\");location.href=\"/Home/Index\";</script>"); } // 獲取可用的圖片伺服器集合 List<ImageServerInfo> serverList = this._imageServerInfoRepository .GetAllUseableServers(); if(serverList.Count == 0) { return Content("<script type=\"text/javascript\">alert(\"暫時沒有可用的圖片伺服器,請稍後再上傳!\");location.href=\"/Home/Index\";</script>"); } // 獲取要儲存的圖片伺服器索引號 int serverIndex = CommonHelper.GetServerIndex(serverList.Count); // 獲取指定圖片伺服器的資訊 string serverUrl = serverList[serverIndex].ServerUrl; int serverID = serverList[serverIndex].ServerId; string serverFullUrl = string.Format("http://{0}/FileUploadHandler.ashx?serverId={1}&ext={2}", serverUrl, serverID, fileExtName); // 藉助WebClient上傳圖片到指定伺服器 WebClient client = new WebClient(); client.UploadData(serverFullUrl, CommonHelper.StearmToBytes(file.InputStream)); return Content("<script type=\"text/javascript\">alert(\"上傳圖片操作成功!\");location.href=\"/Home/Index\";</script>"); } #endregion #region 03.Action:顯示圖片 public ActionResult Show() { var imageServerList = this._imageServerInfoRepository.GetAllUseableServers(); ViewData["ImageServers"] = imageServerList; return View(); } #endregion }
(1)圖片上傳的過程比較複雜,首先Web伺服器接收客戶端的訪問請求並訪問資料庫,在Web端需要取得所有可用的圖片伺服器的集合,這裡使用到了一個GetAllUseableServers方法,它的實現如下:可以看出,我們需要判斷FlgUsable標誌為true以及CurPicAmount當前儲存量小於MaxPicAmount最大儲存量這兩個條件。如果有宕機或不可用的情況,需要管理員將那一行的FlgUsable設定為false。
public List<ImageServerInfo> GetAllUseableServers() { List<ImageServerInfo> serverList = db.ImageServerInfo .Where<ImageServerInfo>(s => s.FlgUsable == true && s.CurPicAmount < s.MaxPicAmount) .ToList(); return serverList; }
(2)這裡用到了一個GetServerIndex的方法,它的實現如下:從圖片伺服器狀態資訊表篩選出可用的圖片伺服器集合記作C,並獲取集合的總記錄數N。然後用隨機函式產生一個隨機數R1,用R1與N進行取餘運算記作I=R1%N。則C[I]即為要儲存圖片的圖片伺服器。這個方法基本保證了我們的圖片伺服器的負載是一個比較均衡的比例。(當然,我們可以設計一個更加高效的,類似於一致性雜湊演算法的雜湊函式)
#region 01.獲取伺服器索引號 /// <summary> /// 01.獲取伺服器索引號 /// </summary> /// <param name="serverCount">伺服器數量</param> /// <returns>索引號</returns> public static int GetServerIndex(int serverCount) { Random rand = new Random(); int randomNumber = rand.Next(); int serverIndex = randomNumber % serverCount; return serverIndex; } #endregion
(3)最後,Web端程式藉助了WebClient將伺服器ID、副檔名以及圖片的位元組流轉交給了具體的圖片伺服器處理程式:Web端程式的工作就到此結束,但是這裡木有采用非同步,因此需要等待圖片伺服器的工作結束。
WebClient client = new WebClient(); client.UploadData(serverFullUrl, CommonHelper.StearmToBytes(file.InputStream));
PS:由於B/S架構本身技術限制,圖片無法通過Web伺服器直接上傳到不同的圖片伺服器中。因此,這裡需要藉助類似於WebClient、HttpWebRequest等類向具體的圖片伺服器傳送Http請求,或者是通過在圖片伺服器上部署Web Service,以便Web伺服器通過呼叫該服務執行圖片的儲存操作。
3.2.2 設計View
(1)上傳頁面:
@{ Layout = null; } <!DOCTYPE html> <html> <head> <meta name="viewport" content="width=device-width" /> <title>Index</title> <link href="~/Resources/css/mystyle.css" rel="stylesheet" /> <script src="~/Resources/js/jquery-1.8.0.min.js"></script> <script type="text/javascript"> $(function () { $("#btnUpload").click(function () { $("#loading").show(); }); }); </script> </head> <body> <div id="mainarea"> <fieldset> <legend id="title">圖片上傳系統</legend> <form method="post" action="/Home/Upload" enctype="multipart/form-data"> <table> <tr> <td> <input id="fileSelect" type="file" name="fileUpload" /></td> <td> <input id="btnUpload" type="submit" value="上傳圖片" /></td> </tr> <tr> <td id="tiparea" colspan="2"> <div id="loading"> <img class="imgstyle" src="~/Resources/image/ico_loading2.gif" /> 正在上傳中,請稍候... </div> </td> </tr> </table> </form> </fieldset> <p id="footer">Copyright © 2014 Edison Chou</p> </div> </body> </html>
在form標籤中不要忘了:enctype="multipart/form-data"
(2)瀏覽頁面:
@{ Layout = null; } @using MyImageDFS.Model; <!DOCTYPE html> <html> <相關推薦
【大型網站技術實踐】初級篇:海量圖片的分散式儲存設計與實現
一、研究背景:效能與資金,二者可兼得乎? 1.1 那麼問題來了? 隨著網際網路的發展,許多大中型的網站都儲存了大量的圖片資源,使用者在訪問這些圖片資源異常豐富的網站(如淘寶、京東等電子商務網站)時,網頁中的圖片資訊佔據了頁面資料流量的很大部分,那麼問題也來了:
【Unix/Linux程式設計實踐】檔案系統:編寫pwd
知識點 目錄是一個包含檔名與i-節點對的列表的檔案。 ”檔案在目錄中“的含義:目錄中存放的只是檔案在i-節點表的入口,而檔案的內容則儲存在資料區中。例如,“檔案x在目錄a中”意味著在目錄a中有一個指向檔案x的i-節點的連結,這個連結所附加的檔名為x。 pw
jQuery技術內幕:深入解析jQuery架構設計與實現原理
源碼 att root 功能 技術內幕 瀏覽器 sel 緩存 callbacks jQuery源碼(jquery-1.7.1.js)的總體結構:(function( window, undefined ) {// 構造jQuery對象 var jQuery = (fun
Hadoop技術內幕:深入解析MapReduce架構設計與實現原理 (大資料技術叢書).epub
【下載地址】 《Hadoop技術內幕:深入解析MapReduce架構設計與實現原理》內容簡介:“Hadoop技術內幕”共兩冊,分別從原始碼的角度對“Common+HDFS”和“MapReduce的架構設計和實現原理”進行了極為詳細的分析。《Hadoop技術內幕:深入解析M
SM2演算法第二十五篇:ECDSA數字簽名演算法原理與實現
---------------------------------------------轉載原因------------------------------------------------- 這邊部落格中有關 EC_KEY_set_private_key和EC_KEY_set_public_key
《大型網站技術架構:核心原理與案例分析》【PDF】下載
優化 均衡 1.7 3.3 架設 框架 應用服務器 博客 分布式服務框架 《大型網站技術架構:核心原理與案例分析》【PDF】下載鏈接: https://u253469.pipipan.com/fs/253469-230062557 內容簡介 本書通過梳理大型網站技
【Python爬蟲學習實踐】基於Beautiful Soup的網站解析及數據可視化
為我 enc lambda ech 和我 find weather acc 節點 在上一次的學習實踐中,我們以Tencent職位信息網站為例,介紹了在爬蟲中如何分析待解析的網站結構,同時也說明了利用Xpath和lxml解析網站的一般化流程。在本節的實踐中,我們將以中國天氣網
讀大型網站技術架構---第一篇---第一章---架構演化過程
最近開始讀此書,主要為了增加自己知識的廣度,首要目的是即使自己沒有參與過此類專案,但是也能知道在某些場景或者某些架構處理時應該往哪些方向思考。 大型網站系統特點 1.高併發,大流量 2.高可用 3.海量資料 4.使用者分佈廣泛,網路情況複雜 5.安全環境惡劣 6.需求
讀大型網站技術架構---第二篇---第四章---架構優化
此書第二章主要針對架構方面怎麼實現一些具體的優化手段,4.1節主要描述的是效能測試方面的,暫時不想去關注效能測試方面的知識。主要關注一下其他地方的優化手段。 4.2 Web前端效能優化 Web前端指網站業務邏輯之前的部分,包括瀏覽器載入,網站試圖模型,圖片服務,CND服務。
讀大型網站技術架構---第一篇---第三章---架構要素
大型網站的架構要素分為5個大類,有5個大類的一些標準。 1.效能 網站的效能優化手段有很多,主要分為下面幾種: 1.1 瀏覽器端: 瀏覽器快取,使用頁面壓縮,合理佈局頁面,減少Cookie傳輸手段,CDN; 1.2 應用伺服器端: 伺服器本地快取和分散式快取,加速請求處理
讀大型網站技術架構---第一篇---第二章---架構模式
關於大型網站架構模式,我覺得只要看看阿里的就足夠了,它成功了,所以它的架構模式就是指路明燈以及行業的正確架構模式,所以關於架構其實現在即使你沒有參與進去,但是模式就是那樣。 1.分層 分層是一種常見的架構模式,主要是將系統在橫向維度上切分成幾個部分,每個部分負責相對比較單一的職責,然後通
讀大型網站技術架構---第二篇---第五章---架構高可用
網站的可用性的度量和考核 可用性度量 網站不可用被稱作網站故障,QQ的可用性是4個9,即QQ服務99.99%可用,也就是一年中大約最多53分鐘不可用。 網站不可用時間 = 故障修復時間點 - 故障發現時間點; 網站年度可用性指標 = (1 - 網站不可用時間/年度總時間)* 10
【大型網站架構】架構演化
基本成型的大型網站架構: 使用分散式伺服器(多個應用伺服器,使用一個負載均衡排程伺服器進行排程),使用分散式快取伺服器,分散式檔案伺服器,資料庫使用讀寫分離,寫入主資料庫,讀取從資料庫,主從資料庫之間會進行資料複製: (本文的圖片是從其他地方偷來的,不是很清晰,但基本能看。) 使用者
【configure】如何用automake、autoconf指令生成configure並建立自己的linux tar.gz安裝包【初級篇:簡單建立-測試】
$ tree 2048-c/ 2048-c/ ├── 2048.c ├── 2048.h └── main.c 0 directories, 3 files 然後進入資料夾,執行autoscan生成configure.scan檔案 $ cd 2048-c/ $ ls
《大型網站技術架構:核心原理與案例分析》讀書筆記 - 第2篇 架構
第2篇 架構 4 瞬時響應:網站的高效能架構 34 4.1 網站效能測試 35 效能測試是效能優化的前提和基礎,也是效能優化結果的檢查和度量標準。 4.1.1 不同視角下的網站效能 35 使用者:直觀感受到的快慢 開發:應用程式本身 運維:基礎設施效能和資源利用率 4.1.2 效
【Android-資料報表】初級篇[讓Highcharts報表顯示在Android螢幕]
Highcharts 報表是至今我發現做得最好的報表之一。當然,可能還有更好的我沒發現。 此次我們就說說怎麼讓Highcharts顯示在Android裝置上。 首先可以在官網檢視文件[官方文件]此次
關於大型網站技術演進的思考(八)--儲存的瓶頸終篇(8)
在開始本篇主要內容前,我們一起看看下面的幾張截圖,首先是第一張圖,如下圖所示: 這是一家電商網站的首頁,當我們第一次開啟這個首頁,網站會彈出一個強制性的對話方塊,讓使用者選擇貨物配送的地址,如果是淘寶和京東的話,那麼這個選擇配貨地址的選項是在商品裡,如下圖是淘寶的選擇配送地點: 下
《大型網站技術架構:核心原理與案例分析》-- 讀書筆記 (5) :網購秒殺系統
案例 並發 刷新 隨機 url 對策 -- 技術 動態生成 1. 秒殺活動的技術挑戰及應對策略 1.1 對現有網站業務造成沖擊 秒殺活動具有時間短,並發訪問量大的特點,必然會對現有業務造成沖擊。對策:秒殺系統獨立部署 1.2 高並發下的應用、
《大型網站技術架構》讀書筆記之六:永無止境之網站的伸縮性架構
映射 應對 方法 訂閱 知識 位置 n+1 轉換 bsp 此篇已收錄至《大型網站技術架構》讀書筆記系列目錄貼,點擊訪問該目錄可獲取更多內容。 首先,所謂網站的伸縮性,指不需要改變網站的軟硬件設計,僅僅通過改變部署的服務器數量就可以擴大或者縮小網站的服務處理能力。在整個互聯
關於大型網站技術演進的思考(五)--存儲的瓶頸(5)
做了 技術分享 表數 例子 執行 同時 設備 系統重啟 拆分 原引:http://www.cnblogs.com/sharpxiajun/p/4265853.html 上文裏我遺留了兩個問題,一個問題是數據庫做了水平拆分以後,如果我們對主鍵的設計采取一種均勻分布的策略,那麽