Mysql全局ID生成方法

  生產系統隨着業務增加總會經歷一個業務量由小變大的過程,可擴展性是考量數據庫系統高可用性的一個重要指標;在單表/數據庫數據量過大,更新量不斷飆漲時,MySQL DBA每每會對業務系統提出sharding的方案。既然要sharding,那麼不可避免的要討論到sharding key問題,在有些業務系統中,必須保證sharding key全局惟一,好比存放商品的數據庫等,那麼如何生成全局惟一的ID呢,下文將從DBA的角度介紹幾種常見的方案。mysql

  一、使用CAS思想redis

  什麼是CAS協議sql

  Memcached於1.2.4版本新增CAS(Check and Set)協議類同於Java併發的CAS(Compare and Swap)原子操做,處理同一item被多個線程更改過程的併發問題數據庫

  CAS的基本原理編程

  基本原理很是簡單,一言以蔽之,就是「版本號」,每一個存儲的數據對象,都有一個版本號。緩存

  咱們能夠從下面的例子來理解:服務器

  不採用CAS,則有以下的情景:併發

  •第一步,A取出數據對象X;性能

  •第二步,B取出數據對象X;線程

  •第三步,B修改數據對象X,並將其放入緩存;

  •第四步,A修改數據對象X,並將其放入緩存。

  結論:第四步中會產生數據寫入衝突。

  採用CAS協議,則是以下的情景。

  •第一步,A取出數據對象X,並獲取到CAS-ID1;

  •第二步,B取出數據對象X,並獲取到CAS-ID2;

  •第三步,B修改數據對象X,在寫入緩存前,檢查CAS-ID與緩存空間中該數據的CAS-ID是否一致。結果是「一致」,就將修改後的帶有CAS-ID2的X寫入到緩存。

  •第四步,A修改數據對象Y,在寫入緩存前,檢查CAS-ID與緩存空間中該數據的CAS-ID是否一致。結果是「不一致」,則拒絕寫入,返回存儲失敗。

  這樣CAS協議就用了「版本號」的思想,解決了衝突問題。(樂觀鎖概念)

  其實這裏並非嚴格的CAS,而是使用了比較交換原子操做的思想。

  生成思路以下:每次生成全局id時,先從sequence表中獲取當前的全局最大id。而後在獲取的全局id上作加1操做,加1後的值更新到數據庫,如加1後的值爲203,表名是users,數據表結構以下:

  sql語句

  sql語句的 and gid 203 是爲了保證併發環境下gid的值只增不減。

  若是update語句的影響記錄條數爲0說明,已經有其餘進程提早生成了203這個值,並寫入了數據庫。須要重複以上步驟重新生成。

  代碼實現以下:

  二、使用全局鎖

  在進行併發編程時,通常都會使用鎖機制。其實,全局id的生成也是解決併發問題。

  生成思路以下:

  在使用redis的setnx方法和memcace的add方法時,若是指定的key已經存在,則返回false。利用這個特性,實現全局鎖

  每次生成全局id前,先檢測指定的key是否存在,若是不存在則使用redis的incr方法或者memcache的increment進行加1操做。這兩個方法的返回值是加1後的值,若是存在,則程序進入循環等待狀態。循環過程當中不斷檢測key是否還存在,若是key不存在就執行上面的操做。

  代碼以下:

  三、redis和db結合

  使用redis直接操做內存,可能性能會好些。可是若是redis死掉後,如何處理呢?把以上兩種方案結合,提供更好的穩定性。

  代碼以下:

  四、Flicker的解決方案

  由於mysql自己支持auto_increment操做,很天然地,咱們會想到藉助這個特性來實現這個功能。Flicker在解決全局ID生成方案裏就採用了MySQL自增加ID的機制(auto_increment + replace into + MyISAM)。一個生成64位ID方案具體就是這樣的:

  先建立單獨的數據庫(eg:ticket),而後建立一個表:

  當咱們插入記錄後,執行SELECT * from Tickets64,查詢結果就是這樣的:

  在咱們的應用端須要作下面這兩個操做,在一個事務會話裏提交:

  這樣咱們就能拿到不斷增加且不重複的ID了。

  到上面爲止,咱們只是在單臺數據庫上生成ID,從高可用角度考慮,

  接下來就要解決單點故障問題:Flicker啓用了兩臺數據庫服務器來生成ID,

  經過區分auto_increment的起始值和步長來生成奇偶數的ID。

  最後,在客戶端只須要經過輪詢方式取ID就能夠了。

  •優勢:充分藉助數據庫的自增ID機制,提供高可靠性,生成的ID有序。

  •缺點:佔用兩個獨立的MySQL實例,有些浪費資源,成本較高。

  以上內容是小編給你們分享的Mysql全局ID生成方法,但願你們喜歡。

相關文章
相關標籤/搜索