1. 程式人生 > >1109:雜湊演算法(下)

1109:雜湊演算法(下)

目錄

帶著問題來學習:

一、雜湊演算法在分散式系統中的應用

1.負載均衡

1.1.需求

1.2.常規解決方案

1.3.完美解決方案

2.資料分片

2.1.如何統計“搜尋關鍵詞”出現的次數?

2.2.如何快速判斷圖片是否存在相簿中?

3.分散式儲存

3.1.什麼是分散式儲存?

3.2.遇到的問題是什麼?

3.3.解決方案是什麼?

二、思考


帶著問題來學習:

雜湊演算法在分散式系統中有哪些應用?負載均衡、資料分片、分散式儲存

雜湊演算法是如何解決這些分散式問題的?

一、雜湊演算法在分散式系統中的應用

1.負載均衡

1.1.需求

如何實現一個會話粘滯(session sticky)的負載均衡演算法?也就是說,在一次會話中的所有請求都路由到同一個伺服器上。

1.2.常規解決方案

①維護一張對映關係表,這張表的內容是客戶端IP或者會話ID與伺服器編號的對映關係。

②客戶端每次發出的請求都要先在對映表中查詢應該路由到的伺服器編號,然後在請求編號對應的伺服器。

③這種方案簡單直觀,但存在幾個弊端:

其一,若客戶端很多,對映表可能會很大,比較浪費記憶體空間;

其二,客戶端下線、上線,伺服器擴容、縮容都會導致對映失效,這樣維護表的成本就會很大。

1.3.完美解決方案

通過雜湊演算法對客戶端IP或會話ID計算雜湊值,將取得的雜湊值與伺服器列表的大小進行取模運算,最終得到的值就是應該被路由到的伺服器編號。這樣,就可以把同一個IP過來的請求都路由到同一個後端伺服器上。

2.資料分片

2.1.如何統計“搜尋關鍵詞”出現的次數?

①需求描述

假如我們有1T的日誌檔案,這裡面記錄了使用者的搜尋關鍵詞,我們想要快速統計出每個關鍵詞被搜尋的次數,該怎麼做呢?

②問題分析

這個問題有兩個難點,第一個是搜尋的日子很大,沒辦法放到一臺機器的記憶體中。第二個是隻用一臺機器來處理這麼巨大的資料,處理時間會很長。

③解決方案

先對資料進行分片,然後採用多臺(比如n臺)機器進行處理。具體做法:從搜尋記錄的日誌檔案中依次讀取每個關鍵詞,並通過雜湊函式計算該關鍵詞的雜湊值,然後跟機器的臺數n取模,最終得到值就是該關鍵詞應該被分到的機器編號,這樣相同的關鍵詞一定會被分配到同一臺機器上,資料分配完成後,由多臺機器並行進行統計,最後合併起來就是最終結果。

實際上,這裡的處理過程也是 MapReduce 的基本設計思想。

2.2.如何快速判斷圖片是否存在相簿中?

①需求描述

假設現在我們的相簿中有1億張圖片,如何快速判斷圖片是否在相簿中?基本方式是給每個圖片去唯一表示(或者資訊摘要),然後構建散列表。

②問題分析

很顯然,在單臺機器上構建散列表示行不通的,因為單臺機器的記憶體有限,而1億張圖片構建散列表遠遠超過了單臺機器的記憶體上限。

②解決方案

準備n臺機器,讓每臺機器只維護一部分圖片對應的散列表。我們每次從相簿中讀取一個圖片,計算唯一標識,然後與機器個數n求餘取模,得到的值就對應要分配的機器編號,然後將這個圖片的唯一表示和圖片路徑發往對應的機器構建散列表。

當我們要判斷一個圖片是否在相簿中時,我們通過同樣的雜湊演算法,計算這個圖片的唯一表示,然後與機器個數n求餘取模。假設得到的值是k,那就去編號為k的機器構建的散列表中查詢。

如何估算給1億張圖片構建散列表大約需要多少臺機器?

散列表中每個資料單元包含兩個資訊,雜湊值和圖片檔案的路徑。假設我們通過 MD5 來計算雜湊值,那長度就是 128 位元,也就是 16 位元組。檔案路徑長度的上限是 256 位元組,我們可以假設平均長度是 128 位元組。如果我們用連結串列法來解決衝突,那還需要儲存指標,指標只佔用 8 位元組。所以,散列表中每個資料單元就佔用 152 位元組(這裡只是估算,並不準確)。

假設一臺機器的記憶體大小為 2GB,散列表的裝載因子為 0.75,那一臺機器可以給大約 1000 萬(2GB*0.75/152)張圖片構建散列表。所以,如果要對 1 億張圖片構建索引,需要大約十幾臺機器。在工程中,這種估算還是很重要的,能讓我們事先對需要投入的資源、資金有個大概的瞭解,能更好地評估解決方案的可行性。

實際上,針對這種海量資料的處理問題,我們都可以採用多機分散式處理。藉助這種分片的思路,可以突破單機記憶體、CPU 等資源的限制。

3.分散式儲存

3.1.什麼是分散式儲存?

①現在網際網路面對的都是海量資料、海量使用者。我們為了提高資料讀取、寫入能力,一般都採用分散式方式來儲存資料,比如分散式快取。

②由於資料量太大,需要將資料分佈到多臺機器上。那如何決定將哪個資料放到哪個機器上呢?可以利用資料分片的思想,即通過雜湊演算法對資料取雜湊值,然後對機器個數取模,這個最終值就是應該儲存的快取機器編號。

3.2.遇到的問題是什麼?

如果資料持續增多,原來的機器數量已經不能滿足需求,就需要增加機器,這時就麻煩了,因為所有的資料都需要重新雜湊值進行再次分配。這就相當於,快取中的資料一下子都失效了,所有的資料請求都會穿透快取,直接去請求資料庫。這樣就可能發生雪崩效應,壓垮資料庫。

3.3.解決方案是什麼?

①這時,需要一種方法,使得新加入一個機器後,並不需要做大量的資料搬移。那就是在分散式系統中應用非常廣泛的一致性雜湊演算法。

②一致性雜湊演算法的基本思想是什麼呢?為了說清楚這個問題,我們假設有k個機器,資料的雜湊值範圍是[0-MAX],我們將整個範圍劃分成m個小區間(m遠大於k),每個機器複雜m/k個小區間。當有新機器加入的時候,我們就將某幾個小區間的資料,從原來的機器中搬移到新的機器中。這樣,既不用全部重新雜湊、搬移資料,也保持了各個機器上資料量的均衡。

二、思考

1.雜湊演算法在分散式系統中有哪些應用?雜湊演算法是如何解決這些分散式問題的?

2.這兩節我總共講了七個雜湊演算法的應用。實際上,我講的也只是冰山一角,雜湊演算法還有很多其他的應用,比如網路協議中的 CRC 校驗、Git commit id等等。除了這些,你還能想到其他用到雜湊演算法的地方嗎?