大型互聯網應用去Oracle改造經驗總結——全局id生成服務設計和實現

ID的特性

id是惟一標識一條數據的,它通常沒有什麼業務含義,是系統內部的標識,那麼它每每有這樣一些特性。 mysql


  • 全局惟一性。這個是強制的,每每id會被設置成主鍵,確定不容許重複。
  • 順序性。這個通常不強制,可是某些業務可能會依賴id進行排序,表示數據建立的前後順序。
  • 簡單高效性。非強制特性。id每每會被做爲主鍵,若是過於複雜,則對查詢效率很差。
  • 連續性。這個是指產生的id是連續的。


全局id生成服務解決方案

總結一下,大概有下面這幾種。 redis

數據庫自增實現

這種放方案是這樣的,仍是利用MySQL數據庫自身的autoincrement特性實現的,只不過每一個分庫(或者分表)的起始值不一樣,增加步長等於分庫數量,這樣各分庫的ID就不會出現重複的。這種實現方案的特色是這樣。 算法

優勢: sql

  • 實現較簡單。
  • 可保證單庫的嚴格順序性。
  • 簡單高效。
  • 可靠性高。

缺點: 數據庫

  • 併發性受數據庫限制。
  • 分庫變化以後維護複雜。
  • 靈活性差。

客戶端應用實現

客戶端實現,就是在應用程序中經過一種算法來生成一個全局惟一的ID,這個算法的選擇很是關鍵。好比 snowflake 算法。 安全

優勢: 網絡

  • 實現較簡單。
  • 性能高。
  • 可靠性最高。

缺點: 併發

  • 生產的ID每每較爲複雜。
  • 不合適的算法可能產生重複值。
  • 生成的id的有序性差。
  • id生成的可控性差。
  • 與現有數據生成的id不兼容,改動較大。

獨立服務實現

經過一個微服務來實現全局id生成服務,這個微服務的實現要作到不能生成重複值,盡肯能保持有序,生成的值儘量簡單。這種方案的特色是。 運維

優勢: 微服務

  • 可確保全局惟一。
  • 生成的值簡單高效。
  • 靈活性大。
  • 分庫變化影響不大。

缺點:

  • 連續性不嚴謹。
  • 開發運維複雜。
  • 增長網絡調用性能損耗。
  • 可用性嚴重依賴微服務。

總結

咱們最終選擇了「獨立服務實現」方案來生成全局惟一id,下面詳細介紹這種方案的設計和實現。

全局id生成微服務設計和實現

設計圖

該方案是這樣的。

該服務由三級ID隊列組成,分別是MySQL數據庫,H2嵌入式數據庫,內存隊列。下面分別介紹着三級的詳細設計。

MySQL數據庫ID隊列設計實現

該便是由一張sequence表組成,這個表就三個字段,分別是:

seqName:序列名,經過這個來獲取ID值。

currentValue:當前值,這個是一直增加的。這個值的安全增加才能保障不生成重複的值。

increment:增加步長。

該表的表引擎必須是innodb,以支持行鎖。

該表實際上模擬實現了Oracle數據的sequence特性。

這個表自己也能夠支持分庫分表,以提高它的擴展性,不過我以爲多數場景是不須要的,可是若是是大規模集中部署則須要支持該特性。

支持單個或者批量獲取ID,得到到對應的id以後就將currentValue值日後增長。

H2內存數據庫id隊列

爲了作到徹底不依賴於MySQL數據庫,咱們引入了h2內存數據庫,它的表結構很是簡單,就是每一個sequence是一張表,表中就一個字段ID,而且它是主鍵。

當服務啓動的時候若數據庫中沒有足夠的ID,則會從mysql數據中補充大量的id插入到表中。這樣h2數據庫就可以支持長時間的提供服務。而且有後臺線程不斷的向h2的id隊列中補充id,避免沒有讀取的時候纔去補充id,下降性能。

內存ID隊列

內存id隊列纔是正式提供id獲取服務的,由於它直接從內存隊列中返回隊首的id值,則能夠保障極高的性能。它也會在須要補充的時候從H2內存數據庫隊列中補充必定數量的ID,也有後臺線程定時補充。它的實現是基於BlockingDeque的。

實現

經過多級隊列咱們發現有不少邏輯是通用的,咱們是能夠抽象出一個實現自動補全隊列和範圍限定的全能隊列的,咱們命名爲AutoSuppliedAndBoundedQueue。它將一些實現了一些公共特性。包括這些內容。


  • 限制隊列數。
  • 有上級隊列。
  • 能夠自動長上級隊列補充數據。

這樣就有很是強的可擴展性,咱們能夠用redis實現,也能夠再增長几級隊列,增長的級數越多,整體可靠性增長,可是複雜度也就越高。須要根據實際狀況來設計。

特色


該id生成服務具備這樣的特色。


  • 極高的性能。在獲取id的時候徹底是無鎖設計,直接從準備好的數據中讀取。
  • 極高的可用性。MySQL數據不可用,徹底不影響可用性。
  • 極高的可擴展性。MySQL數據庫支持分庫分表擴展,服務實例能夠任意增長。
相關文章
相關標籤/搜索