99热99这里只有精品6国产,亚洲中文字幕在线天天更新,在线观看亚洲精品国产福利片 ,久久久久综合网

歡迎加入QQ討論群258996829
麥子學(xué)院 頭像
蘋果6袋
6
麥子學(xué)院

快速擴(kuò)展MySQL數(shù)據(jù)量的方法步驟詳解?

發(fā)布時(shí)間:2016-11-02 22:20  回復(fù):0  查看:2909   最后回復(fù):2016-11-02 22:20  

很多時(shí)候由于MySQL技術(shù)導(dǎo)致的災(zāi)難性的后果,同時(shí)大量用于讀的MySQL從屬服務(wù)器,產(chǎn)生了大量令人惱火的Bug,特別是緩存。為了解決這個(gè)問題我們就需要重新架構(gòu)整個(gè)存儲(chǔ)模型,今天和大家分享的就是如何快速擴(kuò)展MySQL數(shù)據(jù)容量的相關(guān)操作,希望可以幫助大家更好的學(xué)習(xí)MySQL ,一起來看看吧。

業(yè)務(wù)需求

·系統(tǒng)總體要非常穩(wěn)定,便于操作,便于拓展。我們想讓數(shù)據(jù)庫能從開始小存儲(chǔ)量,能隨著業(yè)務(wù)發(fā)展而拓展;

·Pin友生成的內(nèi)容必須能永久訪問;

·(支持)請(qǐng)求的N個(gè)Pin在板塊中以確定的順序(像按照創(chuàng)建時(shí)間倒序,或是按照用戶特定的排序)(顯示)。對(duì)于喜歡的Pin友,發(fā)PinPin友列表等,也必須以特定的順序;

·為了簡(jiǎn)單,更新一般而言要保證最好的性能,為了獲取最終一致性,需要額外的東西,如分布式事物日志。這是一個(gè)有趣(但不太容易)的事情!

設(shè)計(jì)原理與筆記

  由于我們想要的這些數(shù)據(jù)是橫跨多個(gè)數(shù)據(jù)庫的,我們不能使用數(shù)據(jù)庫的join,外鍵或者收集所有數(shù)據(jù)的索引,不過他們可以被用于不能橫跨數(shù)據(jù)庫的子查詢。

  我們也需要支持負(fù)載均衡我們的數(shù)據(jù)。我們厭惡來回移動(dòng)數(shù)據(jù),尤其是逐項(xiàng)移動(dòng),因?yàn)槿菀壮鲥e(cuò),也容易讓系統(tǒng)變得不必要的復(fù)雜。如果我們必須移動(dòng)數(shù)據(jù),最好移動(dòng)一整個(gè)虛擬節(jié)點(diǎn)到物理節(jié)點(diǎn)。

  為了實(shí)現(xiàn)快速成型,我們需要一個(gè)簡(jiǎn)單可用的解決方案,并且在我們的分布式數(shù)據(jù)平臺(tái)上,節(jié)點(diǎn)要非常穩(wěn)定。

  所有的數(shù)據(jù)都需要被備份到從節(jié)點(diǎn)進(jìn)行高可用,并為 MapReduce 轉(zhuǎn)存到 S3。 在生產(chǎn)中,我們只與主節(jié)點(diǎn)交互。在生產(chǎn)中,你不能在從節(jié)點(diǎn)上讀/寫。從節(jié)點(diǎn)是滯后的,它會(huì)引發(fā)奇怪的bug。如果你共享數(shù)據(jù),一般來說在生產(chǎn)中與從節(jié)點(diǎn)交互是沒有優(yōu)勢(shì)的。

  最終,我們需要一個(gè)好的方式來生成一個(gè)統(tǒng)一且唯一的IDUUID)分配給所有我們的對(duì)象。

我們?nèi)绾吻蟹謹(jǐn)?shù)據(jù)

無論我們?nèi)绾螛?gòu)建系統(tǒng),都需要滿足我們的業(yè)務(wù)要求并保證系統(tǒng)穩(wěn)定,具有高性能,易于維護(hù)。換言之,我們需要系統(tǒng)不糟糕 ,因此我們選擇成熟的技術(shù)-MySQL作為我們構(gòu)建系統(tǒng)的基礎(chǔ)。我們有意避免使用具有自動(dòng)擴(kuò)展功能的新技術(shù),例如MongoDBCassandra Membase等,因?yàn)樗麄冞€不夠成熟(并且他們會(huì)以無法預(yù)知的方式崩潰)。

悄悄話:我依舊建議初創(chuàng)公司避免使用花哨的新事物——嘗試使用完全能夠正常運(yùn)行的MySQL。相信我,我有很多錯(cuò)誤的實(shí)踐(創(chuàng)傷)來證明這一點(diǎn)。

MySQL是成熟的,穩(wěn)定的并且能夠正常運(yùn)行的。不僅我們使用MySQL,還有大量公司在廣泛的使用。MySQL支持我們所需要的數(shù)據(jù)排序、范圍查詢功能并且具備行級(jí)事務(wù)等功能。它還有很多的特性,但是我們不需要或使用這些。盡管MySQL非常適合我們,但MySQL是單一解決方案,因此需要我們對(duì)數(shù)據(jù)進(jìn)行分片。下面是我們的解決方案:

  最開始時(shí)我們有8個(gè)EC2 服務(wù),每個(gè)服務(wù)對(duì)應(yīng)一個(gè)MySQL實(shí)例:

快速擴(kuò)展MySQL數(shù)據(jù)量的方法步驟詳解?

為了應(yīng)對(duì)MySQL服務(wù)崩潰,每一個(gè)MySQL服務(wù)都是應(yīng)用主復(fù)制模式構(gòu)建,即每一個(gè)MySQL服務(wù)都將數(shù)據(jù)備份到一個(gè)備份主機(jī)上。我們的應(yīng)用只讀寫主服務(wù)。我建議你也這樣做。它簡(jiǎn)化了一切操作并且避免了復(fù)制延遲問題。

  每個(gè)MySQL數(shù)據(jù)庫可以有多個(gè)庫:


快速擴(kuò)展MySQL數(shù)據(jù)量的方法步驟詳解?

那這個(gè)Pin對(duì)象保存在3429分片上,它的類型是1(‘Pin’),及它在pin表的所在行是7075733。 舉個(gè)例子,讓我們假設(shè)這個(gè)分片是在MySQL012A.上,我們可能通過下面來訪問到這個(gè)對(duì)象:

 

  這些數(shù)據(jù)有兩個(gè)類型:objects(對(duì)象)和mappings但每個(gè)庫的命名唯一,如db00000, db00001, ,dbNNNNN。 每個(gè)庫都是我們數(shù)據(jù)的一個(gè)分片。我們的決計(jì)決策是一塊數(shù)據(jù)只在一個(gè)分片中,而不會(huì)在其它片中。然而你可以通過增加容量,以便將片移到其它機(jī)器上(后續(xù)將討論這個(gè))。

  我們維護(hù)了一個(gè)配置表,以記錄這些數(shù)據(jù)分片在什么機(jī)器上:

 

  這個(gè)版本僅在我們需要移動(dòng)分片或是替換某臺(tái)機(jī)器時(shí)修改。如果主機(jī)掛掉了,我們可以將某臺(tái)從屬服務(wù)器升級(jí)為主機(jī),然后再加臺(tái)新的從屬服務(wù)器。其配置保存在Zookeeper,更新時(shí),配置發(fā)送到其它維護(hù)分片的MySQL服務(wù)器上。

  每個(gè)分片包含相同的表:pins, boards, users_has_pins, users_likes_pins, pin_liked_by_user等等。后面我會(huì)再詳細(xì)講解。

那怎樣將數(shù)據(jù)部署到這些分片上呢?

  我們創(chuàng)建了一個(gè)64位的ID,包含了分片ID,包含數(shù)據(jù)的類型,及數(shù)據(jù)在那臺(tái)服務(wù)器上(本地ID)。分片ID10位,本地ID36位。精明的專家對(duì)此提示只能加到62位。以前編譯器和芯片設(shè)計(jì)的經(jīng)驗(yàn)已經(jīng)告誡我,預(yù)留位的長(zhǎng)度是很重要的,所以我們有兩個(gè)(設(shè)置為0)。

ID = (shard ID

  給定這個(gè)Pin: https://www.pinterest.com/pin/241294492511762325/,讓我們開發(fā)剖析這個(gè)Pin ID 241294492511762325:

(映射)。objects包含了具體的數(shù)據(jù),例如Pin的數(shù)據(jù)。

對(duì)象表

  對(duì)象表存儲(chǔ)了如Pin數(shù)據(jù)、用戶數(shù)據(jù)、看板(boards)數(shù)據(jù)以及評(píng)論數(shù)據(jù)。每個(gè)對(duì)象都包含一個(gè)ID列(本地的ID,自增主鍵),和一個(gè)blob字段包含整個(gè)對(duì)象的JSON數(shù)據(jù)。

 

例如一個(gè)Pin數(shù)據(jù):

 

  在創(chuàng)建新Pin的時(shí)候,需要將所有的對(duì)象數(shù)據(jù)收集起來并生成一個(gè)JSON blob。然后,需要確定一個(gè)分片(shardID(我們偏向于選擇與它關(guān)聯(lián)(inserted)的看板的分片ID相同的ID,但是沒有必要)。Pin的類型碼為1。連上數(shù)據(jù)庫并在Pin對(duì)象表中插入JSON數(shù)據(jù)。MySQL會(huì)返回一個(gè)本地自增ID。一旦生成了分片ID、類型碼和本地ID,就可以生成完整的64ID!

  編輯Pin的時(shí)候可以在一個(gè)MySQL事務(wù)中以讀-修改-寫的方式修改JSON數(shù)據(jù):

 

  刪除Pin的時(shí)候可以刪除MySQL中的一行。但是更好的方式是在JSON數(shù)據(jù)中添加一個(gè)‘a(chǎn)ctive’字段,設(shè)置值為false,并且在客戶端上過濾到這些信息。

映射表

  映射表用于建立對(duì)象之間的連接,如看板(board)和Pin之間的連接。MySQL中建立的映射表包含3列,一個(gè)64位的來源對(duì)象ID‘from’、一個(gè)目的對(duì)象ID ‘to’ 以及一個(gè)序列ID ‘sequence’ 。在(from, to, sequence)上建立聯(lián)合索引,并且每條記錄以 ‘from’ 字段的分片ID分片。

 

  映射表中保存單向映射關(guān)系,如看板(board)到Pin的映射表‘board_has_pins’。如果需要反向的映射關(guān)系,需要建立一個(gè)獨(dú)立的反向映射表‘pin_owned_by_board’。‘sequence’ 主要用于排序(分片之間是不可以比較的,因?yàn)楸镜?/span>ID可能相互是沖突的)。當(dāng)插入一個(gè)新的Pin到看板的時(shí)候,通常可以用unix本地的時(shí)間戳作為序列號(hào)(sequence ID = unix timestamp)。序列號(hào)可以是任意的數(shù)字,但是unix時(shí)間戳是一種使新增的列處于更大的數(shù)值的便捷方式,因?yàn)闀r(shí)間是單調(diào)遞增的。查詢映射表的方式如下:

 

  這樣可以返回至多50個(gè)pin_id,再通過它們獲取Pin對(duì)象。

  以上的方法便是一次應(yīng)用層的連接(board_id -> pin_ids -> pin objects)。應(yīng)用層連接的一個(gè)杰出的特性是可以在獨(dú)立于對(duì)象數(shù)據(jù)的情況下緩存映射數(shù)據(jù)。在memcache集群中緩存pin_idpin對(duì)象的映射數(shù)據(jù)的同時(shí)還在Redis集群中緩存board_idpin_ids的映射數(shù)據(jù)。這樣就可以實(shí)現(xiàn)與緩存數(shù)據(jù)更匹配的緩存技術(shù)。

擴(kuò)容

  我們系統(tǒng)有三種主要的擴(kuò)容方式。最簡(jiǎn)單的就是升級(jí)機(jī)器(容量更大、速度更快的硬盤,更多內(nèi)存,任何成為瓶頸的部分)。

第二種方式是開啟新的分片范圍。雖然我們的分片ID16位的(最多64k個(gè)分片),但是一開始我們只創(chuàng)建了4096個(gè)分片。新建的對(duì)象只能存儲(chǔ)在開頭的4k個(gè)分片。某天我們決定添加新的MySQL服務(wù)器用來存儲(chǔ)40968191的分片,并且開始填充數(shù)據(jù)。

最后一種方式是將一些分片移動(dòng)到新的機(jī)器上。例如需要對(duì)MySQL001A(存儲(chǔ)著0511分片)擴(kuò)容是,先新建一對(duì)主從節(jié)點(diǎn)(譯者注:此處原文為“a new master-master pair”,可能為筆誤),命名為最大的編號(hào)(比如MySQL009AMySQL009B),然后開始從MySQL001A復(fù)制數(shù)據(jù)。

快速擴(kuò)展MySQL數(shù)據(jù)量的方法步驟詳解?

當(dāng)復(fù)制完成時(shí),改變配置,使MySQL001A只存儲(chǔ)0255分片,MySQL009A只存儲(chǔ)256511分片。現(xiàn)在每個(gè)服務(wù)器只處理原先一般的數(shù)據(jù)量。


快速擴(kuò)展MySQL數(shù)據(jù)量的方法步驟詳解?

一些優(yōu)點(diǎn)

  如果你曾構(gòu)建過生成UUIDs的系統(tǒng),你會(huì)發(fā)現(xiàn)這個(gè)系統(tǒng)可以輕松地實(shí)現(xiàn)這個(gè)需求!當(dāng)你創(chuàng)建一個(gè)新的對(duì)象并插入到數(shù)據(jù)庫的時(shí)候,會(huì)得到一個(gè)本地ID。這個(gè)本地ID和分片ID、類型ID組合便可得到一個(gè)UUID。

  如果你曾用ALTER命令為MySQL數(shù)據(jù)表添加過字段,你肯定知道這種操作十分緩慢而且十分痛苦。本文的方法不需要任何級(jí)別的MySQL Alter操作。Pinterest的過去三年中,我們可能完成了一次Alter操作。給對(duì)象添加新的字段只需要讓那些服務(wù)知道JSON模式中添加了幾個(gè)新的字段。當(dāng)反序列化一個(gè)JSON對(duì)象的時(shí)候如果沒有某些字段,此時(shí)便可以返回預(yù)設(shè)的默認(rèn)值。如果需要新的映射表,只需要?jiǎng)?chuàng)建一個(gè),然后在需要的時(shí)候填充數(shù)據(jù)就可以。完成這些事情就可以發(fā)布新產(chǎn)品了。

取模分片(Mod Shard

  取模分片和 Mod Squad(譯者注:一部電影)是一樣的,唯一的區(qū)別是它們完全不同。

  有一些對(duì)象并不是通過ID查詢的。比如一個(gè)Pin友用Facebook賬號(hào)登錄的時(shí)候,我們需要將FacebookID映射到PinterestID。FacebookID在我們看來就是比特位,所以我們將他們存儲(chǔ)到一個(gè)獨(dú)立的分片系統(tǒng)中,并命名為取模分片。包括其他諸如IP地址、用戶名、郵箱地址等。

  取模分片正如和上文中的分片系統(tǒng)類似,除了它們可以以任何數(shù)據(jù)查詢。對(duì)查詢輸入取hash然后以系統(tǒng)中總分片數(shù)取模。結(jié)果就是數(shù)據(jù)將被存儲(chǔ)或已經(jīng)存儲(chǔ)的位置,如下:

shard = md5(“1.2.3.4") % 4096

  此例中shard 值會(huì)被賦為1524。類似ID分片,需要維護(hù)一個(gè)配置文件,如下:

 

則,查詢一個(gè)IP地址1.2.3.4的方式,如下:

 

  但是會(huì)因此而失去一些ID分片優(yōu)勢(shì),比如空間分布(spacial locality)。一開始就必須創(chuàng)建好所有分片,并且手動(dòng)創(chuàng)建分片ID(并不能自動(dòng)生成)。系統(tǒng)中的所有對(duì)象都最好有一個(gè)不變的ID。只有這樣當(dāng)一個(gè)用戶修改他的用戶名的時(shí)候才不用去更新那些關(guān)于這個(gè)用戶名的引用。

最后的一些想法

  至今為止,這個(gè)系統(tǒng)在Pinterest已經(jīng)在線上使用了3.5年了,似乎還會(huì)一直用下去。實(shí)施這樣一套系統(tǒng)相對(duì)比較直截了當(dāng),但是保持運(yùn)行并將全部數(shù)據(jù)從舊機(jī)器遷移過來還是相當(dāng)困難的。如果你在初創(chuàng)公司并且承受著數(shù)據(jù)增長(zhǎng)的痛苦,然后你構(gòu)建了新的分片機(jī)制,并且考慮構(gòu)建一套集群用于在后臺(tái)執(zhí)行腳本把舊數(shù)據(jù)庫的數(shù)據(jù)遷移到新的分片機(jī)器(提示:可以用pyres)。可以肯定的是,無論你做怎樣的努力,數(shù)據(jù)丟失都是不可避免的(我敢肯定它是系統(tǒng)中的搗蛋鬼),所以要一遍一遍重復(fù)的遷移數(shù)據(jù)直到寫入新系統(tǒng)的遷移數(shù)據(jù)為0或者數(shù)量小到一定程度。

這套系統(tǒng)是最大努力的交付它沒有保證原子性、隔離性和一致性。聽起來很糟糕,但是不用著急,因?yàn)檫@些保證可能并不是必須的。如果需要的話,可以在其他的過程或系統(tǒng)中實(shí)現(xiàn)這些特性,但是你能直接獲得的好處是,這個(gè)系統(tǒng)剛剛好可以正常運(yùn)行。通過簡(jiǎn)潔可以得到好的可靠性,并且運(yùn)行起來相當(dāng)快速。如果你還是擔(dān)心原子性、隔離性和一致性,請(qǐng)聯(lián)系我。我可以幫助你解決這些問題。

  關(guān)于故障恢復(fù)怎么樣呢?我們構(gòu)建了一個(gè)維護(hù)MySQL分片的服務(wù)。我們把分片配置信息存儲(chǔ)到了ZooKeeper。如果一臺(tái)master服務(wù)器宕機(jī)了,可以執(zhí)行一些腳本,將slave升級(jí)為master,然后再開啟一臺(tái)替補(bǔ)服務(wù)器(包括數(shù)據(jù)同步)。直到現(xiàn)在我們也沒有使用自動(dòng)的故障恢復(fù)。

文章來源:開源中國

您還未登錄,請(qǐng)先登錄

熱門帖子

最新帖子

?