分布式存儲初認識——竹子整理


  背景:隨着計算機網絡技術的發展和普及,出現了越來越多像”淘寶“,”京東“等大型電子商務網站。這類網站都保存有大量圖片資源。用戶在訪問這些站點網頁時,網頁中圖片信息占到頁面數據流量的大部分。由於受客戶端瀏覽器限制,無法從一台服務器上同時下載頁面中的所有圖片信息,因此即使服務器又很高帶寬,用戶的放棄問速度還是會受到很大影響,由於圖片保存在物理硬盤上,訪問圖片需要頻繁進行I/O操作,因此當並發用戶數越來越多的時候,I/O操作就會成為整個系統的性能瓶頸。

  對於大型的網站系統來說,由於擁有雄厚的資金,可以使用NFS,CDN,Lighttpd等技術(好吧,除了CDN,在JS中稍微有點認識,其他都沒聽過),提高用戶的訪問速度。但這些技術需要龐大的資金支持,對於處於創業初期中等規模的商務網站,由於缺少必要的資金支持,因此無法采用這些技術提升網站的訪問速度。今天我們講一個適用於中等規模商務網站的海量圖片數據分布式動態存儲及負載均衡的解決方案。該方案只需增加很少的硬件成本,即可提升網站的訪問速度,並且可以根據需要動態調整圖片服務器的數量及圖片的存儲目錄,確保系統具有可擴展性和伸縮性。

  系統架構設計需滿足一下4點要求:

  

   以上只是為了隨筆的完整性而收錄,好了,直接進入技術階段。

  本隨筆就以圖片為例,對分布式存儲進行一個簡單的介紹。流程是這樣的:

  存儲階段:用戶上傳圖片-->web服務器接收-->存儲到另一台圖片服務器上

  請求階段:用戶請求圖片-->web服務器從數據庫獲取圖片信息,請求對應圖片服務器-->對應圖片服務器進行I/O操作獲取圖片返回

  以上過程,我都盡量簡化了。不要在乎細節~

  好了,先說說存儲階段,粗一看很容易理解,不過具體實施起來,就需考慮實現所需的技術了,其中的關鍵就是web服務器接收圖片后如何存儲到圖片服務器上。這里(筆者玩.net)有這么幾種技術(評論可以補充):

  【1】、將數據進行數據流操作后,即變成bytu[],通過webClient,來進行兩個站點間的數據傳輸。  

byte[] fileByte = 將圖片處理成byte[];
string imageUrl = "http://192.168.2.41:8899/UploadImage.ashx?Id=1&Ext=png";
WebClient wc = new WebClient();
wc.UploadData(imageUrl , fileByte);

  

//圖片服務器接收(這里用的是一般處理程序)
int imageId = Convert.ToInt32( context.Request["Id"]);
string ext = context.Request["Ext"];
//這兩個就組成了我們圖片的名稱,當然名稱如何組成可以你自己定
using(FileStream fs = File.OpenWrite("D:/"+imageId+ext))
{
  //獲取傳輸過來的Byte[]
  //context.Request.InputStream:web服務器wc.UploadData的第二個參數的數據流
  context.Request.InputStream.CopyTo(fs);    
}

 

  【2】、通過在圖片服務器中設置一個小的web站點,然后建立一個webService,web服務器通過這個開放的服務進行數據傳輸,同理,用我們的wcf,webapi也可以實現。這個懂的自然懂,不懂的可以查閱下資料哈,也不是一兩行代碼能解釋的。

  【3】、我們的web服務器與圖片服務器放置在一起的話,其實就可以是個局域網,這樣一來,我們直接可以將圖片服務器的某個文件夾進行”共享“,這樣我們的web服務器直接就可以進行I/O操作。

  目前為止,我們存儲階段的流程是走通了,但是問題來了:

  Q1:如果我們有多台圖片服務器呢?

  A1:首先,我們應該抓住問題重點,多台服務器,多台怎么了,造成什么問題了?回頭看上面【1】的代碼,會有哪些變動?就四行代碼,很容易看出,多台服務器的區別就是我們的IP變多個了,我們應該用哪個呢?多台的存在肯定是一台不夠用,所以我們需要讓它們雨露均沾對吧。由此,引出了上文背景的一個詞兒:負載均衡。好了,不賣關子,其實很簡單,不就是對IP這個字符串數組進行管理嘛,首先建個表,記錄我們的IP以及服務器狀態(可用不可用之類),其他的字段可以任意擴展。然后我們將圖片數據流傳輸前,就先用隨機算法獲取我們數據表中的IP,然后WebClient或其他技術,傳輸即可。

  注意點:圖片服務器對圖片進行存儲完后,需對web服務器說一聲,我這邊存完了,好讓web服務器進行后續操作,如將圖片信息保存入數據庫,字段應該有:圖片Id,圖片所在的圖片服務器IP,存儲路徑,時間等。怎么”說一聲“呢,很簡單,如果傳輸用的 webClient的話,”說一聲“也用這個不就行了。隨便在web服務器定義個接口,可以也是一般處理程序,然后定義個接收字段,約束下即可。如果是用wcf,則更簡單,方法定義為回調函數即可(我好啰嗦啊,不是怕你們看不懂,是怕我自己日后看不懂~)

  說完存儲階段,下面的請求階段就很簡單了。

  用戶請求圖片-->web服務器從數據庫獲取圖片信息,請求對應圖片服務器-->對應圖片服務器進行I/O操作獲取圖片返回

  請求圖片,肯定是帶着Id來的,這樣我們就從圖片信息數據表中查詢出對應信息,主要是存儲該圖片的對應圖片服務器的IP,存儲路徑。然后WebClient等技術請求即可。額,好像完事兒了,確實很簡單。

  好了,一堆文字,看着煩。用圖片總結下:

  

兩張表的設計:

  

  補充:上面提到的滿足負載均衡的算法,這里給個小例子:
  
var list = db.ImageServerInfo.Where<ImageServerInfo>(c=>c.State==1).ToList();
int serverCount = list.Count();
Random r = new Random();
int i = r.Next();
int j = i%r;
//獲取狀態為1(normal)的圖片服務器總數,隨機數去對其取余。得到的就是我們的隨機索引,於是就可通過list[j]去獲取ServerId,然后再去獲取ServerIP


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM