久久久久久久视色,久久电影免费精品,中文亚洲欧美乱码在线观看,在线免费播放AV片

<center id="vfaef"><input id="vfaef"><table id="vfaef"></table></input></center>

    <p id="vfaef"><kbd id="vfaef"></kbd></p>

    
    
    <pre id="vfaef"><u id="vfaef"></u></pre>

      <thead id="vfaef"><input id="vfaef"></input></thead>

    1. 站長(zhǎng)資訊網(wǎng)
      最全最豐富的資訊網(wǎng)站

      MySQL 如何利用分片來(lái)解決 500 億數(shù)據(jù)的存儲(chǔ)問(wèn)題

      MySQL  如何利用分片來(lái)解決 500 億數(shù)據(jù)的存儲(chǔ)問(wèn)題

      這是一個(gè)關(guān)于我們?cè)诙鄠€(gè) MySQL 服務(wù)器上分割數(shù)據(jù)的技術(shù)研究。我們?cè)?2012 年年初完成了這個(gè)分片方法,它仍是我們今天用來(lái)存儲(chǔ)核心數(shù)據(jù)的系統(tǒng)。

      在我們討論如何分割數(shù)據(jù)之前,讓我們先了解一下我們的數(shù)據(jù)。心情照明,巧克力草莓,星際迷航語(yǔ)錄……

      Pinteres 是你感興趣的所有東西的發(fā)現(xiàn)引擎。從數(shù)據(jù)的角度來(lái)說(shuō),Pinterest 是世界上最大的人類興趣圖集。有超過(guò) 500 億的 Pin 被 Pin 友們保存在 10 億塊圖板上。 用戶再次 Pin,喜歡其他人的 Pin(粗略地說(shuō)是一個(gè)淺顯的復(fù)制品),關(guān)注其他 Pin 友,畫板和興趣,然后查看主頁(yè)上所訂閱 Pin 友的所有資訊。 太好了! 現(xiàn)在讓它擴(kuò)大規(guī)模!

      成長(zhǎng)的痛

      在 2011 年我們?nèi)〉昧顺晒Α?在 一些 評(píng)估報(bào)告里,我們的發(fā)展比其他的初創(chuàng)公司要快得多。在 2011 年 9 月,我們每一項(xiàng)基礎(chǔ)設(shè)備都超出了負(fù)載。我們應(yīng)用了一些 NoSQL 技術(shù),所有這些技術(shù)都導(dǎo)致了災(zāi)難性的后果。 同時(shí),大量用于讀的 MySQL 從服務(wù)器產(chǎn)生了大量令人惱火的 bugs,特別是緩存。我們重構(gòu)了整個(gè)數(shù)據(jù)存儲(chǔ)模式。為了使之有效,我們仔細(xì)制定了我們的要求。

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

      我們的全部系統(tǒng)需要非常穩(wěn)定,易于操作和易于擴(kuò)展。 我們希望支持?jǐn)?shù)據(jù)庫(kù)能從開始的小存儲(chǔ)量,能隨著業(yè)務(wù)發(fā)展而擴(kuò)展。

      所有 Pin 友 生成的內(nèi)容在網(wǎng)站上必須隨時(shí)可以訪問(wèn)。

      支持以確定的順序請(qǐng)求訪問(wèn) N 個(gè) Pin 在畫板中展示(像按照創(chuàng)建的時(shí)間,或者按照用戶特定的順序)。對(duì)于喜歡的 Pin 友和 Pin 友的 Pin 列表等也能按照特定的順序展示。

      為了簡(jiǎn)單起見,更新一般要保證最好的效果。為了獲取最終一致性,你需要一些額外的東西,如分布式 事務(wù)日志。這是一件有趣并(不)簡(jiǎn)單的事情。

      解決思路及要點(diǎn)備注

      解決方案由于需要將海量的數(shù)據(jù)切片分布到多個(gè)數(shù)據(jù)庫(kù)實(shí)例上,不能使用關(guān)系數(shù)據(jù)庫(kù)的連接、外鍵或索引等方法整合整個(gè)數(shù)據(jù)。想想就知道,關(guān)聯(lián)的子查詢不能跨越不同的數(shù)據(jù)庫(kù)實(shí)例。

      我們的方案需要負(fù)載平衡數(shù)據(jù)訪問(wèn)。我們?cè)骱迶?shù)據(jù)遷移,尤其是逐個(gè)記錄進(jìn)行遷移,因關(guān)系的復(fù)雜性,這樣非常容易發(fā)生錯(cuò)誤且加重系統(tǒng)不必要的復(fù)雜性。如果必須要遷移數(shù)據(jù),最好是邏輯節(jié)點(diǎn)集的整體遷移。

      為了達(dá)到方案實(shí)施的可靠迅速,我們需要在我們的分布式數(shù)據(jù)平臺(tái)上使用最易于實(shí)現(xiàn)、最健壯的技術(shù)方案。

      每個(gè)實(shí)例上的所有的數(shù)據(jù)將被完全復(fù)制到一個(gè)從實(shí)例上,作為數(shù)據(jù)備份。我們使用的是高可用性的 MapReduce (分布式計(jì)算環(huán)境) 的 S3 。我們前端的業(yè)務(wù)邏輯訪問(wèn)后臺(tái)數(shù)據(jù),只訪問(wèn)數(shù)據(jù)庫(kù)的 主實(shí)例。永遠(yuǎn)不要讓您的前端業(yè)務(wù)去讀寫訪問(wèn)從實(shí)例 。因?yàn)樗c 主實(shí)例 數(shù)據(jù)同步存在延遲,會(huì)造成莫名其妙的錯(cuò)誤,一旦將數(shù)據(jù)切片并分布,沒(méi)有一絲理由讓你前端業(yè)務(wù)從 從實(shí)例 上讀寫數(shù)據(jù)。

      最后,我們需要精心設(shè)計(jì)一個(gè)優(yōu)秀的方案生成和解析我們所有數(shù)據(jù)對(duì)象的 全局唯一標(biāo)識(shí)( UUID ) 。

      我們的切片方案

      不管怎樣,我們需要設(shè)計(jì)符合我們需求的,健壯的,性能優(yōu)良和可維護(hù)的數(shù)據(jù)分布解決方案。換句話說(shuō),它不能稚嫩(未經(jīng)廣泛驗(yàn)證)。因此,我們的基礎(chǔ)設(shè)計(jì)建立在 MySQL 之上,參見 we chose a mature technology(選擇成熟技術(shù)) 。設(shè)計(jì)之初,我們自然會(huì)跳開不用那些號(hào)稱具有自動(dòng)分布(auto-scaling)新技術(shù)能力的數(shù)據(jù)庫(kù)產(chǎn)品,諸如 MongoDB,Cassandra 和 Membase 之類的產(chǎn)品,因?yàn)樗鼈兯坪鯇?shí)施簡(jiǎn)單卻適用性太差(常常發(fā)生莫名其妙的錯(cuò)誤導(dǎo)致崩潰)。

      旁白:強(qiáng)烈建議從底層基礎(chǔ)入手,避免時(shí)髦新鮮的東東 — 扎扎實(shí)實(shí)把 MySQL 學(xué)好用好。相信我,字字都是淚。

      MySQL 是成熟、穩(wěn)定并且就是好使的關(guān)系型數(shù)據(jù)庫(kù)產(chǎn)品。不僅我們用它,包括許多知名大公司也使用它作為后臺(tái)數(shù)據(jù)支撐,存儲(chǔ)著海量的數(shù)據(jù)。(譯注:大概幾年前,由于 MySQL 隨著 SUN 被 Oracle 的收購(gòu),歸到 Oracle 名下。許多公司,如 google,facebook 等由于擔(dān)心 MySQL 的開源問(wèn)題,紛紛轉(zhuǎn)到由 MySQL 原作者開發(fā)的另一個(gè)開源數(shù)據(jù)庫(kù) MariaDB 下)MySQL 支持我們對(duì)數(shù)據(jù)庫(kù)要求按序數(shù)據(jù)請(qǐng)求,查詢指定范圍數(shù)據(jù)及行(記錄)級(jí)上的事務(wù)處理的技術(shù)要求。MySQL 有一堆功能特性,但我們不需要那些。由于 MySQL 本身是個(gè)單體解決方案,可我們卻要把我們的數(shù)據(jù)切片。(譯注:此處的意思是,一個(gè)單實(shí)例管理海量的數(shù)據(jù),勢(shì)必造成性能問(wèn)題?,F(xiàn)在把一個(gè)海量整體數(shù)據(jù)切片成一個(gè)個(gè)單體數(shù)據(jù)集,需要一個(gè)強(qiáng)有力的技術(shù)解決方案,把一個(gè)個(gè)的單體整合成一個(gè)整體,提高性能還不出錯(cuò))下面是我們的設(shè)計(jì)方案:

      我們起始使用 8 臺(tái) EC2 服務(wù)器,每臺(tái)服務(wù)器都運(yùn)行一個(gè) MySQL 實(shí)例:

      MySQL  如何利用分片來(lái)解決 500 億數(shù)據(jù)的存儲(chǔ)問(wèn)題

      每個(gè) MySQL 服務(wù)器各自以 主 – 主備份( master-master replicated )到 1 臺(tái)冗余主機(jī)作為災(zāi)難恢復(fù)。我們前臺(tái)業(yè)務(wù)只從主服務(wù)實(shí)例讀 / 寫數(shù)據(jù) 。我建議你也這么做,它簡(jiǎn)化許多事情,避免延遲故障。(譯注:主 – 主備份( master-master replicated ) 是 MySQL 數(shù)據(jù)庫(kù)本身提供的功能,指兩臺(tái)機(jī)器互做備份的一種模式,相對(duì)其它模式,如 主 – 從備份,兩臺(tái)機(jī)器數(shù)據(jù)完全一致,后臺(tái)同步,每臺(tái)機(jī)器有自己?jiǎn)为?dú) IP 都可訪問(wèn),可并發(fā)讀 / 寫訪問(wèn)。但原文作者一再?gòu)?qiáng)調(diào)的是雖然這兩臺(tái)互為冗余使用 主 – 主備份,都可訪問(wèn)。但你邏輯上區(qū)分 主 – 從,永遠(yuǎn)只從其中一個(gè)進(jìn)行讀 / 寫。例如,圖中所示, MySQL001A 和 MySQL001B 間 主 – 主備份,但你只從 MySQL001A 進(jìn)行讀 / 寫訪問(wèn)。另:他們使用了 16 臺(tái)機(jī)器,另 8 臺(tái)做從機(jī)的可能不是 EC2 也未必)

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

      MySQL  如何利用分片來(lái)解決 500 億數(shù)據(jù)的存儲(chǔ)問(wèn)題

      注意每個(gè)數(shù)據(jù)庫(kù)是如何唯一地命名為 db00000,db00001,直到 dbNNNN。每個(gè)數(shù)據(jù)庫(kù)都是我們數(shù)據(jù)庫(kù)的分片。我們做了一個(gè)設(shè)計(jì),一旦一塊數(shù)據(jù)被分配到一個(gè)分片中,它就不會(huì)移出那個(gè)分片。但是,你可以通過(guò)將分片移動(dòng)到其他機(jī)器來(lái)獲得更大的容量(我們將在后面討論這一點(diǎn))。

      我們維護(hù)著一個(gè)配置數(shù)據(jù)庫(kù)表,此表中記錄這切片數(shù)據(jù)庫(kù)在哪臺(tái)機(jī)器上:

      [ {“range”: (0,511), “master”: “MySQL001A”, “slave”: “MySQL001B”}, {“range”: (512, 1023), “master”: “MySQL002A”, “slave”: “MySQL002B”},  ... {“range”: (3584, 4095), “master”: “MySQL008A”, “slave”: “MySQL008B”} ]

      這個(gè)配置表僅當(dāng)遷移切片數(shù)據(jù)庫(kù)或替換主機(jī)時(shí)修改。例如,一個(gè)主實(shí)例主機(jī)宕掉了,我們會(huì)提升它的從實(shí)例主機(jī)為主實(shí)例,然后盡快頂替一個(gè)新機(jī)器當(dāng)從實(shí)例主機(jī)。配置腳本保留在 ZooKeeper 上,當(dāng)出現(xiàn)上述修改時(shí),通過(guò)腳本發(fā)送到維護(hù)切片服務(wù)的機(jī)器上進(jìn)行配置改變。(譯注:可發(fā)現(xiàn)原作者一直強(qiáng)調(diào)的,前端業(yè)務(wù)僅從邏輯主實(shí)例讀寫數(shù)據(jù)的好處)。

      每個(gè)切片數(shù)據(jù)庫(kù)保持相同的數(shù)據(jù)庫(kù)表及表結(jié)構(gòu),諸如,有 pins ,boards ,users_has_pins ,users_likes_pins ,pin_liked_by_user 等數(shù)據(jù)庫(kù)表。 在布署時(shí)同步構(gòu)建。

      分布數(shù)據(jù)到切片服務(wù)器設(shè)計(jì)方案

      我們組合 切片 ID(shard ID) 、數(shù)據(jù)類型標(biāo)識(shí)和 局部 ID(local ID) 形成 64 位的 全局唯一標(biāo)識(shí)(ID) 。切片 ID(shard ID) 占 16 個(gè)位(bit), 數(shù)據(jù)類型標(biāo)識(shí)占 10 個(gè)位(bit), 局部 ID(local ID) 占 36 個(gè)位 (bit)。 明眼人馬上會(huì)發(fā)現(xiàn),這才 62 位。我過(guò)去的分布及整合數(shù)據(jù)經(jīng)驗(yàn)告訴我,保留幾位留做擴(kuò)展是無(wú)價(jià)寶。因此,我保留了 2 位(設(shè)為 0)。(譯注:這里解釋一下,根據(jù)后面的運(yùn)算和說(shuō)明,任何對(duì)象的唯一標(biāo)識(shí) ID 是 64 位,最高 2 位始終為 0,之后是 36 位的局部標(biāo)識(shí),之后是 10 位類型標(biāo)識(shí),最后是 16 位的切片標(biāo)識(shí)。局部標(biāo)識(shí)可表示 2^36 達(dá) 600 多億個(gè) ID 。數(shù)據(jù)類型可表示 2^10 達(dá) 1024 個(gè)對(duì)象類型,切片標(biāo)識(shí)可細(xì)分成 2^16 達(dá) 65536 個(gè)切片數(shù)據(jù)庫(kù)。前面說(shuō)的方案切了 4096 個(gè)切片數(shù)據(jù)庫(kù))

      ID = (shard ID << 46) | (type ID << 36) | (local ID<<0) 以 Pin: https://www.pinterest.com/pin/241294492511... 為例,讓我們解構(gòu)這個(gè) Pin 對(duì)象的 全局 ID 標(biāo)識(shí) 241294492511762325 : Shard ID = (241294492511762325 >> 46) & 0xFFFF = 3429 Type ID  = (241294492511762325 >> 36) & 0x3FF = 1 Local ID = (241294492511762325 >>  0) & 0xFFFFFFFFF = 7075733

      可知這個(gè) Pin 對(duì)象在 3429 切片數(shù)據(jù)庫(kù)里。 假設(shè) Pin 對(duì)象 數(shù)據(jù)類型標(biāo)識(shí)為 1,它的記錄在 3429 切片數(shù)據(jù)庫(kù)里的 pin 數(shù)據(jù)表中的 7075733 記錄行中。舉例,假設(shè)切片 3429 數(shù)據(jù)庫(kù)在 MySQL012A 中,我們可利用下面語(yǔ)句得到其數(shù)據(jù)記錄:(譯注:這里原作者泛泛舉例,若按其前面方案例子來(lái)說(shuō),3429 應(yīng)在 MySQL007A 上)

      conn = MySQLdb.connect(host=”MySQL012A”) conn.execute(“SELECT data FROM db03429.pins where local_id=7075733”)

      有兩種類型的數(shù)據(jù):對(duì)象或關(guān)系。對(duì)象包含對(duì)象本身細(xì)節(jié)。 如 Pin 。

      存儲(chǔ)對(duì)象的數(shù)據(jù)庫(kù)表

      對(duì)象庫(kù)表中的每個(gè)記錄,表示我們前端業(yè)務(wù)中的一個(gè)對(duì)象,諸如:Pins(釘便簽), users(用戶),boards(白板)和 comments(注釋),每個(gè)這樣的記錄在數(shù)據(jù)庫(kù)表中設(shè)計(jì)一個(gè)標(biāo)識(shí) ID 字段(這個(gè)字段在表中作為記錄的 自增主鍵「auto-incrementing primary key」 ,也就是我們前面提到的 局部 ID「 local ID」 ),和一個(gè) blob 數(shù)據(jù)字段 — 使用 JSON 保存對(duì)象的具體數(shù)據(jù) –。

      CREATE TABLE pins (   local_id INT PRIMARY KEY AUTO_INCREMENT,   data TEXT,   ts TIMESTAMP DEFAULT CURRENT_TIMESTAMP ) ENGINE=InnoDB;

      舉例,一個(gè) Pin 對(duì)象形狀如下:

      {“details”: “New Star Wars character”, “l(fā)ink”: “http://webpage.com/asdf”, “user_id”: 241294629943640797, “board_id”: 241294561224164665, …}

      創(chuàng)建一個(gè) Pin 對(duì)象,收集所有的數(shù)據(jù)構(gòu)成 JSON blob 數(shù)據(jù)。然后,確定它的 切片 ID「 shard ID」 (我們更樂(lè)意把 Pin 對(duì)象的切片數(shù)據(jù)放到跟其所在 白板「 board」 對(duì)象相同的切片數(shù)據(jù)庫(kù)里,這不是強(qiáng)制設(shè)計(jì)規(guī)則)。Pin 對(duì)象的數(shù)據(jù)類型標(biāo)識(shí)為 1。連接到 切片 ID 指示的切片數(shù)據(jù)庫(kù),插入(insert)Pin 對(duì)象的 JOSON 數(shù)據(jù)到 Pin 對(duì)象數(shù)據(jù)庫(kù)表中,MySQL 操作成功后將會(huì)返回 自增主鍵「auto-incrementing primary key」 給你,這個(gè)作為此 Pin 對(duì)象的 局部 ID「 local ID」?,F(xiàn)在,我們有了 shard 、類型值、local ID 這些必要信息,就可以構(gòu)建出此 Pin 對(duì)象的 64 位 ID 。(譯注:原作者提到的,他們的前端業(yè)務(wù)所用到的每種對(duì)象都保存在一個(gè)對(duì)象數(shù)據(jù)庫(kù)表里,每個(gè)對(duì)象記錄都通過(guò)一個(gè)全局唯一 ID 去找到它,但這個(gè)全局唯一 ID 并不是數(shù)據(jù)庫(kù)表中的 局部 ID,由于切片的緣故。原作者一直在講這個(gè)設(shè)計(jì)及其原理。這樣設(shè)計(jì)的目的為了海量數(shù)據(jù)切片提高性能,還要易用,可維護(hù),可擴(kuò)展。后面,作者會(huì)依次講解到)

      編輯一個(gè) Pin 對(duì)象,使用 MySQL 事務(wù)「transaction」 在 Pin 對(duì)象的數(shù)據(jù)記錄上 讀出 — 修改 — 寫回「read-modify-write」 Pin 對(duì)象的 JOSON 數(shù)據(jù)字段:

      > BEGIN > SELECT blob FROM db03429.pins WHERE local_id=7075733 FOR UPDATE [修改 json blob] > UPDATE db03429.pins SET blob=’<修改后的 blob>’ WHERE local_id=7075733 > COMMIT

      編輯一個(gè) Pin 對(duì)象,您當(dāng)然可以直接刪除這個(gè)對(duì)象在 MySQL 數(shù)據(jù)庫(kù)表中的數(shù)據(jù)記錄。但是,請(qǐng)仔細(xì)想一下,是否在對(duì)象的 JSON 數(shù)據(jù)上加個(gè)叫做「 active」的域,把剔除工作交由前端中間業(yè)務(wù)邏輯去處理或許會(huì)更好呢。

      (譯注:學(xué)過(guò)關(guān)系數(shù)據(jù)庫(kù)的應(yīng)知道,自增主鍵在記錄表中是固實(shí),在里面刪除記錄,會(huì)造成孔洞。當(dāng)多了,勢(shì)必造成數(shù)據(jù)庫(kù)性能下降。數(shù)據(jù)庫(kù)只負(fù)責(zé)保存數(shù)據(jù)和高性能地查詢、讀寫數(shù)據(jù),其數(shù)據(jù)間的關(guān)系完全靠設(shè)計(jì)精良的對(duì)象全局 ID 通過(guò)中間件邏輯去維護(hù) 這樣的設(shè)計(jì)理念一直貫穿在作者的行文中。只有理解了這點(diǎn)您才能抓住這篇文章的核心)

      關(guān)系映射數(shù)據(jù)庫(kù)表

      關(guān)系映射表表示的是前端業(yè)務(wù)對(duì)象間的關(guān)系。諸如:一個(gè)白板(board)上有哪些釘便簽(Pin), 一個(gè)釘便簽(Pin)在哪些白板(board)上等等。表示這種關(guān)系的 MySQL 數(shù)據(jù)庫(kù)表包括 3 個(gè)字段:一個(gè) 64 位的「from」ID, 一個(gè) 64 位的「to」ID 和一個(gè)順序號(hào)。每個(gè)字段上都做索引方便快速查詢。其記錄保存在根據(jù)「from」字段 ID 解構(gòu)出來(lái)的切片 ID 指示出的切片數(shù)據(jù)庫(kù)上。

      CREATE TABLE board_has_pins (   board_id INT,   pin_id INT,   sequence INT,   INDEX(board_id, pin_id, sequence) ) ENGINE=InnoDB;

      (譯注:這里的關(guān)系映射指前端業(yè)務(wù)對(duì)象間的關(guān)系用數(shù)據(jù)庫(kù)表來(lái)運(yùn)維,并不指我上節(jié)注釋中說(shuō)到的關(guān)系數(shù)據(jù)庫(kù)的關(guān)系映射。作者開篇就講到,由于切片,不能做關(guān)系數(shù)據(jù)庫(kù)表間的關(guān)系映射的,如一對(duì)一,一對(duì)多,多對(duì)多等關(guān)系關(guān)聯(lián))

      關(guān)系映射表是單向的,如 board_has_pins(板含便簽)表方便根據(jù) board (白板)ID 查詢其上有多少 Pin(釘便簽)。若您需要根據(jù) Pin(釘便簽)ID 查詢其都在哪些 board(白板)上,您可另建個(gè)表 pin_owned_by_board(便簽屬于哪些白板)表,其中 sequence 字段表示 Pin 在 board 上的順序號(hào)。(由于數(shù)據(jù)分布在切片數(shù)據(jù)庫(kù)上,我們的 ID 本身無(wú)法表示其順序)我們通常將一個(gè)新的 Pin 對(duì)象加到 board 上時(shí),將其 sequence 設(shè)為當(dāng)時(shí)的系統(tǒng)時(shí)間。sequence 可被設(shè)為任意整數(shù),設(shè)為當(dāng)時(shí)的系統(tǒng)時(shí)間,保證新建的對(duì)象的 sequence 總是大于舊對(duì)象的。這是個(gè)方便易行的方法。您可通過(guò)下面的語(yǔ)句從關(guān)系映射表中查詢對(duì)象數(shù)據(jù)集:

      SELECT pin_id FROM board_has_pins  WHERE board_id=241294561224164665 ORDER BY sequence  LIMIT 50 OFFSET 150

      語(yǔ)句會(huì)查出 50 個(gè) pin_ids(便簽 ID ), 隨后可用這些對(duì)象 ID 查詢其具體信息。

      我們只在業(yè)務(wù)應(yīng)用層進(jìn)行這些關(guān)系的映射,如 board_id -> pin_ids -> pin objects (從 白板 ID -> 便簽 IDs -> 便簽對(duì)象)。 這種設(shè)計(jì)一個(gè)非常棒的特性是,您可以分開緩存這些關(guān)系映射對(duì)。例如,我們緩存 pin_id -> pin object (便簽 ID -> 便簽對(duì)象)關(guān)系映射在 memcache(內(nèi)存緩存)集群服務(wù)器上,board_id -> pin_ids (白板 ID -> 便簽 IDs)關(guān)系映射緩存在 redis 集群服務(wù)器上。這樣,可以非常適合我們優(yōu)化緩存技術(shù)策略。

      增大服務(wù)能力

      在我們的系統(tǒng)中,提升服務(wù)處理能力主要三個(gè)途徑。最容易的是升級(jí)機(jī)器(更大的空間,更快的硬盤速度,

      贊(0)
      分享到: 更多 (0)
      網(wǎng)站地圖   滬ICP備18035694號(hào)-2    滬公網(wǎng)安備31011702889846號(hào)