自拍偷在线精品自拍偷,亚洲欧美中文日韩v在线观看不卡

九張圖,帶你了解一致性哈希原理

開發(fā) 前端
一致性哈希算法在1997年由麻省理工學院提出(參見擴展閱讀[1]),設計目標是為了解決因特網(wǎng)中的熱點(Hot spot)問題,初衷和CARP十分類似。

[[434665]]

假設我們現(xiàn)在做一個簡單的文件緩存服務,由于文件數(shù)過多,我們先使用3臺機器用來存儲文件。

為了由文件名(假設文件名稱不重復)能得到存儲的機器,考慮先對文件名做hash運算,接著對3取余,得到的余數(shù)即為所在機器的編號。

​這套系統(tǒng)運行了很久,后來文件數(shù)量慢慢增多,3臺機器存不下了,現(xiàn)在我們考慮擴充到4臺。

這個時候,我們的算法更新為hash(文件名)%5。

那么使用該算法獲取abc.txt文件所在的緩存機器時,在其hash值為10的時候,將會映射到0號機器上,而之前是存儲在1號機器上的,這個時候就會重新將文件存儲到0號機器上,或者將1號機器上的文件遷移到0號機器上。

因此,增加了兩臺機器后,導致了緩存失效。

我們使用代碼來大致確定一下緩存失效的比例:

  1. public static void main(String[] args) { 
  2.       //緩存失效計數(shù) 
  3.       int count = 0; 
  4.       //假設一共有10000份文件 
  5.       for (int i = 0; i < 10000; i++) { 
  6.           //文件名稱 
  7.           String fileName = "file#" + i; 
  8.           int hashCode = fileName.hashCode(); 
  9.           //原來的存儲位置 
  10.           int oldSite = hashCode % 3; 
  11.           //增加兩臺機器后,現(xiàn)在的存儲位置 
  12.           int newSite = hashCode % 5; 
  13.  
  14.           if (oldSite != newSite) { 
  15.               count++; 
  16.           } 
  17.       } 
  18.  
  19.       System.out.println(count); 
  20.   } 

​運行后發(fā)現(xiàn),超過80%的緩存都會失效。

也就是說,無論是增加機器還是減少機器,都會使得緩存大面積的失效,這是我們不愿意見到的結果,那么有沒有一種新的算法呢?

一致性哈希算法,就應運而生了。該算法可以使得增減機器時,大幅度減少失效的緩存數(shù)量。

首先這里有個圓,你可以看做是從0到2^32-1頭尾相連的環(huán)。

​我們先對一臺機器的ip做哈希運算,再對2^32取模,即hash(ip)%2^32,得到了數(shù)字肯定在環(huán)上。

假設我們使用的哈希算法得到的哈希值返回值是int類型,則本身相當于已經(jīng)取過模。

因此我們標記出三臺機器在環(huán)上的位置

​這個時候,需要將文件映射到環(huán)上,使用一樣的哈希函數(shù),即hash(文件名)。假設這里有4個文件,我們在環(huán)上標記出文件的位置。

​那現(xiàn)在怎么確定文件在哪臺機器上存儲呢?

很簡單,從當前文件開始,順時針找到第一個機器,即為文件的存儲位置。

​假設這個時候機器2宕機,我們將機器2從環(huán)上移除,觀察一下文件3的變化

​當機器2宕機時,文件3將重新指向機器3。

也就是說,當機器2宕機時,原本映射到機器1與機器2之間位置的文件,將會被重新映射到機器3。

​因此,一致性哈希能夠大幅度降低緩存失敗的范圍,不至于“牽一發(fā)而動全身”。

不知道大家有沒有看出來,在上圖中,幾臺機器在環(huán)上的分布比較均勻,這是一種非常理想的情況。

然而現(xiàn)實可能并不是這樣,假設3臺機器經(jīng)過映射后,彼此之間非??拷?。

​當機器數(shù)量特別少的時候,經(jīng)過映射后,節(jié)點在環(huán)上分布不均勻,導致大部分文件全部落在同一臺機器上,也就是存在數(shù)據(jù)傾斜問題。

如圖所示,4個文件全部存儲在了機器1上。倘若有一天,機器1承載不住大量的文件訪問掛了,這些文件將會立即轉移到機器2上。機器2同樣也會承載不住,最后就會造成整個系統(tǒng)的連鎖崩潰。

既然問題的根本在于機器數(shù)量少,那我們可以增加機器啊!

但機器是一種實際存在的物理資源,不可能說增加就增加,老板也不讓啊!

這個時候,我們可以復制現(xiàn)有的物理機器,形成一些虛擬節(jié)點,通過以物理節(jié)點的ip加上后綴序號來實現(xiàn)。

​當虛擬節(jié)點以同樣的算法映射到環(huán)上之后,文件1最終將會落到機器2上。

理論上,虛擬節(jié)點越多,越能做到相對的均勻分布。

下面以代碼的形式,來驗證一下。

  1. public class Main { 
  2.  
  3.     //真實節(jié)點 
  4.     private static final String[] ipArray = new String[]{"192.168.1.1""192.168.1.2""192.168.1.3""192.168.1.4"}; 
  5.     //哈希環(huán)(哈希值->真實節(jié)點ip) 
  6.     private static final TreeMap<Long, String> circle = new TreeMap<>(); 
  7.  
  8.     //指定倍數(shù)初始化哈希環(huán) 
  9.     private static void initCircle(int mul) { 
  10.         //映射真實節(jié)點 
  11.         for (String ip : ipArray) { 
  12.             circle.put(hash(ip), ip); 
  13.             //按照倍數(shù)映射虛擬節(jié)點 
  14.             for (int i = 1; i <= mul; i++) { 
  15.                 String virtual = ip + "#" + i; 
  16.                 circle.put(hash(virtual), ip); 
  17.             } 
  18.         } 
  19.     } 
  20.  
  21.     //獲取指定文件存儲的機器ip 
  22.     private static String getIpByFileName(String fileName) { 
  23.         long hash = hash(fileName); 
  24.         Long higherKey = circle.higherKey(hash); 
  25.         if (higherKey == null) { 
  26.             //返回哈希環(huán)中的第一個ip 
  27.             return circle.get(circle.firstKey()); 
  28.         } 
  29.         //返回比文件名稱的哈希值大的最小ip 
  30.         return circle.get(higherKey); 
  31.     } 
  32.  
  33.     //統(tǒng)計落在每個節(jié)點上的文件總數(shù)(ip->文件總數(shù)) 
  34.     private static Map<String, Long> count(long fileCount) { 
  35.         //(ip,文件總數(shù)) 
  36.         Map<String, Long> map = new HashMap<>(); 
  37.  
  38.         for (long i = 1; i <= fileCount; i++) { 
  39.             String ip = getIpByFileName("file#" + i); 
  40.             Long ipCount = map.get(ip); 
  41.             map.put(ip, (ipCount == null ? 0 : ipCount) + 1); 
  42.         } 
  43.  
  44.         return map; 
  45.     } 
  46.  
  47.     //打印各個ip存儲的文件數(shù)占總數(shù)的百分比 
  48.     private static void print(int fileCount) { 
  49.         Map<String, Long> map = count(fileCount); 
  50.  
  51.         for (String ip : ipArray) { 
  52.             Long ipCountL = map.get(ip); 
  53.             long ipCount = ipCountL == null ? 0 : ipCountL; 
  54.  
  55.             double result = ipCount * 100 / (double) fileCount; 
  56.             //保留一位小數(shù) 
  57.             String format = String.format("%.1f", result); 
  58.             System.out.println(ip + ":" + format + "%"); 
  59.         } 
  60.     } 
  61.  
  62.     // 32位的 Fowler-Noll-Vo 哈希算法 
  63.     // https://en.wikipedia.org/wiki/Fowler–Noll–Vo_hash_function 
  64.     private static Long hash(String key) { 
  65.         final int p = 16777619; 
  66.         long hash = 2166136261L; 
  67.         for (int idx = 0, num = key.length(); idx < num; ++idx) { 
  68.             hash = (hash ^ key.charAt(idx)) * p; 
  69.         } 
  70.         hash += hash << 13; 
  71.         hash ^= hash >> 7; 
  72.         hash += hash << 3; 
  73.         hash ^= hash >> 17; 
  74.         hash += hash << 5; 
  75.  
  76.         if (hash < 0) { 
  77.             hash = Math.abs(hash); 
  78.         } 
  79.         return hash; 
  80.     } 
  81.  
  82.     public static void main(String[] args) { 
  83.         //初始化哈希環(huán) 
  84.         initCircle(1000000); 
  85.         //文件總數(shù)10000個 
  86.         print(10000); 
  87.     } 
  88.  

 當倍數(shù)為0時:

  1. 192.168.1.1:0.0% 
  2. 192.168.1.2:0.0% 
  3. 192.168.1.3:100.0% 
  4. 192.168.1.4:0.0% 

 相當于沒有虛擬節(jié)點,可以看到極度不均勻,傾斜嚴重。

當倍數(shù)為100時:

  1. 192.168.1.1:28.4% 
  2. 192.168.1.2:22.4% 
  3. 192.168.1.3:34.6% 
  4. 192.168.1.4:14.6% 

 傾斜改善了!但仍然不滿足

當倍數(shù)為10000時:

  1. 192.168.1.1:24.6% 
  2. 192.168.1.2:25.9% 
  3. 192.168.1.3:23.3% 
  4. 192.168.1.4:26.3% 

 基本上算是比較均勻了

大膽點,我們把倍數(shù)調(diào)到1百萬,文件數(shù)也調(diào)到1百萬

  1. 192.168.1.1:25.0% 
  2. 192.168.1.2:24.9% 
  3. 192.168.1.3:25.0% 
  4. 192.168.1.4:25.1% 

  可見所有ip下存儲的文件總數(shù)非常均勻!​

 

責任編輯:姜華 來源: 今日頭條
相關推薦

2021-09-15 07:46:42

哈希一致性哈希算法

2021-02-05 08:00:48

哈希算法?機器

2021-02-02 12:40:50

哈希算法數(shù)據(jù)

2023-12-12 08:00:50

節(jié)點哈希算法

2020-07-20 08:30:37

算法哈希分布式系統(tǒng)

2020-06-28 07:39:44

Kafka分布式消息

2016-12-19 18:41:09

哈希算法Java數(shù)據(jù)

2021-07-27 08:57:10

算法一致性哈希哈希算法

2023-06-25 09:44:00

一致性哈希數(shù)據(jù)庫

2020-10-26 19:25:23

CPU緩存Cache

2021-08-13 07:56:13

Raft算法日志

2020-11-24 09:03:41

一致性MySQLMVCC

2022-03-22 09:54:22

Hash算法

2023-06-26 07:17:48

負載均衡策略Dubbo

2023-12-20 08:11:02

Redis節(jié)點通信

2021-10-14 10:00:46

MYSQL開發(fā)數(shù)據(jù)

2017-07-25 14:38:56

數(shù)據(jù)庫一致性非鎖定讀一致性鎖定讀

2018-07-05 09:41:08

一致性哈希算法

2019-11-01 09:13:37

算法哈希緩存

2023-12-05 14:44:01

點贊
收藏

51CTO技術棧公眾號