日日操夜夜添-日日操影院-日日草夜夜操-日日干干-精品一区二区三区波多野结衣-精品一区二区三区高清免费不卡

公告:魔扣目錄網為廣大站長提供免費收錄網站服務,提交前請做好本站友鏈:【 網站目錄:http://www.ylptlb.cn 】, 免友鏈快審服務(50元/站),

點擊這里在線咨詢客服
新站提交
  • 網站:51998
  • 待審:31
  • 小程序:12
  • 文章:1030137
  • 會員:747

上兩篇講到了我們的系統在面臨大并發讀取的時候,采用了讀寫分離主從復制(數據庫讀寫分離方案,實現高性能數據庫集群)的方案去應對,后來又面臨了大并發寫入的時候,系統數據庫采用了分庫分表的方案(數據庫分庫分表方案,優化大量并發寫入所帶來的性能問題),通過垂直拆分以及水平拆分的方式,將數據分到多個庫和多個表中去應對的,即現在是這樣的一套分布式存儲結構

數據庫分庫分表后,我們怎么保證ID全局唯一

 

數據庫分庫分表那篇也講到了,使用了分庫分表勢必會帶來和我們之前使用不大相同的問題。今天,我將其中一個和我們開發息息相關的問題提出來進行講解,也就是我們開發中所使用的的主鍵的問題。我們知道,以前我們單庫的時候,主鍵唯一ID是自增的,現在好了,我們的數據被分到多個庫的多個表里面了,如果我們還是使用之前的主鍵自增策略,那么這樣就會出現兩個數據插入到了兩個不同的表會出現相同的ID值,這時我們該怎么去使用呢?

對于什么是主鍵,主鍵該怎么選,今天不做講解,我相信大家可能比我還精通,我們今天主要是講唯一主鍵ID在分布式存儲系統下怎么生成,保證ID的唯一性且符合我們業務需要,才是我們開發人員最關心的實戰。

UUID

這個時候,你可能會說,自增用不了,那我就是用UUID嘛,這個UUID生成出來的就是唯一的。的確,在我以前在一個公司中的確接觸到是使用UUID來生成唯一主鍵ID的,而且性能還可以。但是,我想提一點的就是,當這個ID和我們業務交集不相關的時候是可以使用UUID生成主鍵的。比如,一般我們業務是需要用來做查詢的,而且最好是單調遞增的,這樣我們的UUID就很不適合了。

主鍵ID單調遞增有什么好處呢?

1,就拿我們用戶關注航班這個模塊來說,我們查看某個航班關注用戶按照時間的先后進行排序。因為現在的ID是時間上有序的,所以現在我們就可以按照ID來進行排序了,同時這樣對于有些并不是要存儲時間的業務來說,會減少不少的存儲空間。

2,有序的ID可以提升數據寫入的性能

我們知道主鍵其實在數據庫中就是一種索引,而索引在MySQL數據庫的B+數據結構中是順序存儲的,所以每次插入的時候就是遞增排序的,直接追加到后面就行。如果是無序的話,則每次插入數據之前還得查找它應該所在的位置,這無疑就會增加數據的異動等相關的開銷,如下圖:

數據庫分庫分表后,我們怎么保證ID全局唯一

 

如上圖所示,如果我們生成的ID是有序的,那這個 50 就直接插在尾部就行了,如果是無序的話,突然生成了一個 26,我們還得先找到 26 需要存放的位置,然后還要對其后面數據進行挪位置。

3,UUID不具備業務相關性

我們現在開發的項目都是依據公司業務開展的,而我們的唯一ID一般都是和業務有關系的,比如,有些訂單ID中帶上了時間的維度、機房的維度以及業務類型等維度。也就是為了我方便進行定位是那種業務的訂單,才會這么設計的,是不是。

而UUID是由32位的16進制數字組成的字符串,不僅在存儲空間上造成浪費,更不具備我們業務相關性。那我們該怎么解決呢?其實twitter提出來的Snowflake 算法就能很好滿足我們現在的要求,滿足了主鍵ID的全局唯一性、單調遞增性,也可以滿足我們的業務相關。所以,我們現在使用的唯一ID生成方式就是使用Snowflake算法,這個算法其實很簡單。下面我們來對其進行講解,并對其相應改造使其能用到我們的開發業務中來。

Snowflake 算法原理

Snowflake 是由 64 比特bit二進制數字組成的,一共分為4大部分:

  • 1位默認不使用
  • 41位時間戳
  • 10位機器ID
  • 12位序列號
數據庫分庫分表后,我們怎么保證ID全局唯一

 

  1. 我們從上圖中可以看出snowflake算法的第二部分的41位時間戳,大概可以支撐2^41/1000/60/60/24/365 年,也就是大約有69年。我們設計一個系統用69年應該是足夠了吧。
  2. 10位的機器ID我們可以怎么使用呢?我們可以劃分成大概2到3位IDC,也就是可以支撐4到8個IDC機房;然后劃分7到 8 位的機器ID,即可以支撐128~256臺機器。
  3. 12位的序號,就代表每個節點每毫秒可以生成4096個ID序號。

如何改造

我們現在已經知道了Snowflake 算法的核心原理,并且知道了其有64位的二進制數據,那我們就可以根據自己業務進行改造以更好的來為我們業務服務。一般不同的公司對其進行改造的方式都不盡相同,但是道理都是一樣的。我們可以這么做:

  1. 我們是減少序列號的位數,增加機器ID的位數,是為了用來支撐我們單IDC的更多機器。
  2. 將我們業務ID加入進去用來區分我們不同的業務。比如,1位0 + 41位時間戳 + 6位IDC(64個IDC) + 6位業務信息(支撐64種業務) + 10位自增序列(每毫秒1024個ID)
數據庫分庫分表后,我們怎么保證ID全局唯一

 

如此,我們就可以在單機房部署這么一個統一ID發號器,然后用Keeplive 保證高可用(對于高可用不熟悉的回去看看哈「高可用」你們服務器掛了怎么辦,我們是這樣做的)可以將不同的業務模塊ID加入進去,這樣的好處是即使哪個業務出問題了,我只看ID號我就分析出來,比如,我看到現在ID號有我的訂單ID業務,我就去看訂單模塊。

開發如何使用

現在我們知道Snowflake 算法原理了,還知道了我們可以進行改造了。那我們開發人員該怎么去使用,來為我們業務生成統一的唯一ID呢?

1,直接嵌入到業務代碼

嵌入業務代碼的意思就是,這個snowflake算法就部署在和我們業務相同的服務器上,這樣我們代碼使用的時候,就不用了跨網絡調用,性能相對比較好。但是也是有缺點的,因為我們的業務機器肯定是很多的,這就意味著我們發號器算法需要更多的機器ID位數。同時,太多的業務服務器我們會很難保證業務機器id的唯一性,這里就需要引用zookeeper一致性組件來保證每次機器重啟都能能獲得唯一的機器ID。

2,獨立部署成發號器服務

也就是說,我們將其作為單獨的服務部署到單獨的機器上,已對外提供服務。這樣就是多了網絡的傳輸,不過影響不大,比如,我可以將其部署成一個主備的方式對外提供發號服務,機器ID可以用作序列號使用,這樣也就是會有更多的自增序號,有部分大廠就是以這樣單獨的服務提供出來的。

開發中避坑大法

1,雖然snowflake很優秀,但是它是基于系統時間的,萬一我們系統的時間不準怎么辦,就會造成我們的ID會重復。那我們的做法就是,要利用系統的對時功能,一旦發現時間不一致,就暫停發號器,等到時鐘準了在啟用。

2,還有一個坑比較關鍵,也是常發生的,就是當我們的QPS并發不高的時候,比如每毫秒只生成一個ID號,這樣就是直接結果是,每次生成的ID末尾都是1,這樣我們分庫分表就會出現問題呀對吧,因為我們用這個ID去分庫分表呀,會造成數據不均勻,是吧,忘記了去復習哈(數據庫分庫分表方案,優化大量并發寫入所帶來的性能問題)那我們怎么解決呢?

我們可以將時間戳記錄從毫秒記錄改為秒記錄,這樣我一秒可以發好多個號了

生成的序列號起始號隨機啟動,比如這一秒起始號是10,我下一秒隨機了變成了28,這樣就更加分散開了。

總結,今天我們針對分庫分表之后帶來的第一個直接影響我們開發的問題,就是主鍵ID唯一性的問題,然后說到了使用Snowflake算法去解決,并且對其原理和使用進行了詳細的講解,同時,還將其在使用中遇到的坑給講出來了,也對其進行了填坑分析,讓大家直接避免遇到同樣的問題。當然生成唯一ID有多種,我們根據業務選擇合適我們自己的就好,你們是基于什么方式生成的可以也可以告訴大家。

分享到:
標簽:分庫分表
用戶無頭像

網友整理

注冊時間:

網站:5 個   小程序:0 個  文章:12 篇

  • 51998

    網站

  • 12

    小程序

  • 1030137

    文章

  • 747

    會員

趕快注冊賬號,推廣您的網站吧!
最新入駐小程序

數獨大挑戰2018-06-03

數獨一種數學游戲,玩家需要根據9

答題星2018-06-03

您可以通過答題星輕松地創建試卷

全階人生考試2018-06-03

各種考試題,題庫,初中,高中,大學四六

運動步數有氧達人2018-06-03

記錄運動步數,積累氧氣值。還可偷

每日養生app2018-06-03

每日養生,天天健康

體育訓練成績評定2018-06-03

通用課目體育訓練成績評定