Ticket 服务: 一种经济的分布式唯一主键生成方案
生活随笔
收集整理的這篇文章主要介紹了
Ticket 服务: 一种经济的分布式唯一主键生成方案
小編覺得挺不錯的,現在分享給大家,幫大家做個參考.
2019獨角獸企業重金招聘Python工程師標準>>>
MySQL分庫分表早已經不是什么新鮮話題了。甚至已經成了說到MySQL就會說到的話題。在一張表中,MySQL提供了原生的自增主鍵實現。但是在這樣的分布式系統中,怎么保證數據在多張表上的ID是唯一的呢? Flickr提出了一個方案,將文章簡單翻譯一下給大家,方便大家閱讀。嫌棄我翻譯水平太爛的,請移步原文: http://code.flickr.net/2010/02/08/ticket-servers-distributed-unique-primary-keys-on-the-cheap/ --------------------------------------------- 我就是分割線?分割線就是我 ?----------------------------------------- 這篇文章是“ 在Flickr里使用,廣泛使用,擴展MySQL”系列文章的第一彈。 Ticket服務本身其實沒什么好說的,但他是Flickr系統里一個重要的組成部分。是我們接下來要談到的話題的核心,就像sharding和主主復制一樣。Ticket服務器給我們提供了一個生成全局(Flickr范圍內)唯一的整數的服務,這個整數用來作為我們分布式系統中的主鍵使用。為什么(需要這樣一種機制)?
Sharding(或者叫 data partition)(譯者注:數據分片)是使我們的數據存儲能力能夠水平擴展的方案。我們不是將我們所有的數據都存在一個物理的數據庫上,相反,我們有很多數據庫,每個數據庫存儲一部分數據,然后我們將壓力負載均衡到這些數據庫上去。但在某些情況下,我們需要在不同的數據庫之間進行數據合并,所以我們需要主鍵是全局唯一的。另外,我們的數據庫sharding是基于主主復制的。這意味著我們需要保證,在一個分片內,主鍵也是唯一的,這樣才能避免主鍵沖突(重復)。我們當然希望能夠和其他人一樣,使用MySQL的自增字段來生成主鍵。但是,這種方案在跨多個物理或邏輯數據庫時,沒有辦法保證唯一性。(使用)GUIDs(行不行)?
看來,我們就是需要一個全局唯一的id,那為什么不用GUID(譯者注: GUID=Globally Unique Identifier 全局唯一標示)呢?最大的原因就是GUID太大了,而且他在MySQL中索引效果太差了。為了保證我們的MySQL足夠快,我們將所有要查詢的條件都索引起來,然后只在索引鍵上做查詢。所以,索引的大小就成了一個關鍵性的指標。如果你不能將你的索引全部都放到內存里,那你的數據庫就不可能足夠快。而且,Ticket服務給我們的ID是有序的。這個特點給我們做業務報表和做調試的時候帶來了很大的方便性,而且我們還可以再上面做一些緩存的優化方案。(使用)一致性哈希(行不行)?
像? Amazon’s Dynamo和其他一些系統,在數據存儲上面提供了一致性哈希環來解決GUID和分片的問題。這種方案更適合于寫廉價的應用場景(比如:? LSMTs),而MySQL是一種針對隨機讀取專門做過優化的系統。集中式自增
我們不能讓MySQL的自增跨數據庫工作,那如果我們只用一個數據庫呢?假設在有人上傳圖片的時候,我們都往這個數據庫庫中插入一條數據,然后用這個表的自增主鍵值作為我們所有數據庫的唯一主鍵。 在目前每秒60+張圖片上傳的情況下,這張表很快就會變得奇大無比。就算在中央數據庫中我們只存儲圖片的id,而不存儲其他任何信息,這張表也很快就會大到無法管理的地步。更何況圖片的評論,收藏,分組,標簽等等等等也都需要唯一ID。REPLACE INTO
大約小十年前,MySQL在ANSI SQL標準上做了一個非標準的 “REPLACE INTO”擴展。雖然后來有 “INSERT ON DUPLICATE KEY UPDATE”更好的解決了這類問題,但REPLACE INTO現在仍然能用。 REPLACE和INSERT很像。除了在新插入的行中主鍵或唯一所以中的值在表中已經存在的情況下,會先刪除老的那行數據,再插入新的這行數據。 這樣的話,我們就可以通過更新(replace)數據庫中的某一行來獲取一個新的自增主鍵ID了。來個總結
一個Flickr Ticket服務器是一個只包含一個數據庫獨立的數據庫服務器。然后這個數據庫里包含了一些類似Ticket32和Ticket64的表(分別用于提供32位整型主鍵和64位長整型主鍵)。 Tickets64 的Sckeme大概像這樣: CREATE TABLE `Tickets64` (`id` bigint(20) unsigned NOT NULL auto_increment,`stub` char(1) NOT NULL default '',PRIMARY KEY (`id`),UNIQUE KEY `stub` (`stub`) ) ENGINE=MyISAM SELECT * from Tickets64 返回的一行數據大概像這樣: +-------------------+------+ | id | stub | +-------------------+------+ | 72157623227190423 | a | +-------------------+------+ 當我們需要一個新的64位的主鍵的時候,我們可以通過執行下面的SQL得到: REPLACE INTO Tickets64 (stub) VALUES ('a'); SELECT LAST_INSERT_ID();單點問題
你絕對不愿意看到你的ID服務器因為單點問題掛掉。我們實現“高可用”的方法是跑兩個Ticket服務。但在兩個機器之間進行寫入/更新的復制是會有問題的,由于必要的鎖的存在,會嚴重降低整個網站的性能。我們的做法是將ID生成的職責均分到兩個服務上,一個生成奇數,一個生成偶數。設置如下: TicketServer1: auto-increment-increment = 2 auto-increment-offset = 1TicketServer2: auto-increment-increment = 2 auto-increment-offset = 2 然后我們使用輪詢的方式去輪流訪問這兩個服務器,來達到負載均衡的目的和應對停機的情況。如果有一邊不能保持同步了(停機了),那最多就是可能會有連續的幾十萬個奇數(或者偶數)的ID。但這不會有任何副作用。更多的隊列
在Ticket服務器中,除了Ticket32和Ticket64這樣的兩張表,我們其實還有其他更多的表。我們的圖片,賬號, 離線任務,組等等都有自己獨立的ID隊列。離線任務有它自己獨立的ID隊列是因為它太多了,然后我們又不希望有不必要的因素導致隊列增長(譯者注:前面提到,ID的大小一定程度上反應了業務的數據量)。分組和賬號有他們自己的ID隊列是因為我們很少拿他們來做比較。圖片有自己的ID隊列是因為我們要保證切換之后要和之前單表的自增ID保持同步,因為之前的自增id我們可以很方便的知道我們總共上傳了多少張圖片。就是這樣
雖然,這個方案看起來不是特別優雅。但令人震驚的是從2006年1月13號我們上線到現在,在生產環境跑的都非常好。這個設計已經成為我們Flickr工程師的一個設計理念——“ 在最壞的情況下也能工作”的一個典型代表了。轉載于:https://my.oschina.net/laichendong/blog/283796
總結
以上是生活随笔為你收集整理的Ticket 服务: 一种经济的分布式唯一主键生成方案的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 程序员,请不要抢系统管理员的饭碗
- 下一篇: [c#基础]堆和栈