您好,歡迎來電子發(fā)燒友網(wǎng)! ,新用戶?[免費(fèi)注冊]

您的位置:電子發(fā)燒友網(wǎng)>源碼下載>數(shù)值算法/人工智能>

Uber為什么從Postgres遷移到MySQL

大?。?/span>0.6 MB 人氣: 2017-09-30 需要積分:0

  導(dǎo)論

  Uber的早期架構(gòu)由一個單體后端應(yīng)用程序構(gòu)成,該應(yīng)用由Python編寫,Python使用Postgres以實(shí)現(xiàn)數(shù)據(jù)持久化。自那時起,Uber架構(gòu)已發(fā)生巨變,逐步轉(zhuǎn)化為微服務(wù)模式和新的數(shù)據(jù)平臺。特別是在之前一些使用Postgres的案例中,現(xiàn)在則改用Schemaless(一個基于MySQL的全新數(shù)據(jù)庫分片)。本文將探索Postgres的缺陷,解釋遷移到MySQL的基礎(chǔ)上構(gòu)建Schemaless和其它后端服務(wù)的原因。

  Postgres的架構(gòu)

  Postgres有很多局限性:

  寫入架構(gòu)低效數(shù)據(jù)復(fù)制低效表損壞的問題糟糕的從庫MVCC支持新版本更新難度升級

  下文將分析Postgres的表表示法和磁盤上的索引數(shù)據(jù),重點(diǎn)對比MySQL通過其InnoDB存儲引擎呈現(xiàn)相同數(shù)據(jù)的方法,以探索上述缺陷。注意:本文涉及的分析主要基于舊版Postgres 9.2系列。 眾所周知,本文論述的內(nèi)部架構(gòu)在新發(fā)布的Postgres中沒有太大變更。事實(shí)上,至少自Postgres 8.3的發(fā)布開始(距今近十年),Postgres 9.2中磁盤上表示法的基礎(chǔ)設(shè)計就一直沒有做出顯著調(diào)整。

  磁盤上的數(shù)據(jù)格式

  關(guān)系數(shù)據(jù)庫必須執(zhí)行下列關(guān)鍵任務(wù):

  支持插入/更新/刪除功能支持schema變更功能實(shí)現(xiàn)一個多版本并發(fā)控制(MVCC)機(jī)制,促使不同的連接對其所處理的數(shù)據(jù)生成一致性的事務(wù)視圖

  思考其所有特性如何協(xié)同運(yùn)作是設(shè)計數(shù)據(jù)庫在磁盤上呈現(xiàn)數(shù)據(jù)的基礎(chǔ)。

  Postgres的一項核心設(shè)計是行數(shù)據(jù)固定。該固定行在Postgres用語中又名“元組(tuple)”。在Postgres中,元組又通過ctid獲得唯一標(biāo)識。從概念上講,ctid代表元組在磁盤上的位置(例如物理磁盤偏移)。多個ctid可能能夠描述一個單行(例如多個行版本為了MVCC的目的而存在時,或是舊版本行未經(jīng)autovacuum進(jìn)程回收時)。一組元組的組織集合構(gòu)成表,表本身包含索引,索引經(jīng)組合構(gòu)成數(shù)據(jù)結(jié)構(gòu)(通常是B-tree結(jié)構(gòu)),從而將索引字段映射到ctid的有效載荷。

  通常情況下,這些ctid是面向用戶透明的,但了解其運(yùn)行方式有助于理解Postgres表在磁盤上的表架構(gòu)。若要查看行的當(dāng)前ctid,則可向WHERE子句中的欄目列表中添加“ctid”:

  uber@[local] uber=》 SELECTctid, * FROM my_table LIMIT 1; -[ RECORD1]--------+------------------------------ctid | (0,1) 。。.other fields here.。。

  為求布局細(xì)節(jié),先以一個簡單的用戶表為例。Uber針對每個用戶設(shè)置了自動遞增的用戶ID主鍵、用戶姓名和出生年份。同時Uber還設(shè)置了一個基于用戶全名(包括名和姓)的復(fù)合二級索引,和另一個基于用戶出生年份的二級索引。用以創(chuàng)建該表的DDL如下:

  CREATETABLEusers ( id SERIAL, firstTEXT, lastTEXT, birth_year INTEGER, PRIMARYKEY(id) );CREATEINDEX ix_users_first_last ONusers (first, last);CREATEINDEX ix_users_birth_year ONusers (birth_year);

  注意該定義中的三個索引:主鍵索引和兩個二級索引。

  為求例證,將以下面的表格數(shù)據(jù)展開論述,表中數(shù)據(jù)均由歷史上頗具影響力的數(shù)學(xué)家構(gòu)成:

  id

  first

  last

  birth_year

  1 Blaise Pascal 1623

  2 Gottfried Leibniz 1646

  3 Emmy Noether 1882

  4 Muhammad al-Khwārizmī 780

  5 Alan Turing 1912

  6 Srinivasa Ramanujan 1887

  7 Ada Lovelace 1815

  8 Henri Poincaré 1854

  如前所述,表中每一行隱含一個唯一且不公開的ctid。因此,表的內(nèi)部表示如下:

  ctid

  id

  first

  last

  birth_year

  A 1 Blaise Pascal 1623

  B 2 Gottfried Leibniz 1646

  C 3 Emmy Noether 1882

  D 4 Muhammad al-Khwārizmī 780

  E 5 Alan Turing 1912

  F 6 Srinivasa Ramanujan 1887

  G 7 Ada Lovelace 1815

  H 8 Henri Poincaré 1854

  設(shè)置主鍵索引(映射ID到ctid):

  id

  cti

  1 A

  2 B

  3 C

  4 D

  5 E

  6 F

  7 G

  8 H

  B-tree結(jié)構(gòu)的設(shè)置基于id字段,且其每個節(jié)點(diǎn)都保存ctid值。在這個案例中需要注意的是,由于使用自動遞增id,B-tree中的字段順序有時會和表中順序相同,但是也不一定如此。

  二級索引彼此都很相似;主要差異在于字段存儲順序,而字段在B-tree中必須以字典順序排布。(first,last)索引從名開始按字母表順序自上而下排列。

  first

  last

  ctid

  Ada Lovelace G

  Alan Turing E

  Blaise Pascal A

  Emmy Noether C

  Gottfried Leibniz B

  Henri Poincaré H

  Muhammad al-Khwārizmī D

  Srinivasa Ramanujan F

  同樣,birth_year(出生年份)聚集索引以升序排列:

  birth_year

  ctid

  780 D

  1623 A

  1646 B

  1815 G

  1854 H

  1887 F

  1882 C

  1912 E

  綜上所述,不同于自動遞增主鍵的案例,在上面的情境下,各個二級索引中的ctid字段都不是按字母表順序升序排布的。

  假設(shè)需要更新一條表記錄,比如將al-Khwārizmī的出生年份字段更新為另一個預(yù)估值770CE。如前所述,行元組是固定的,因此,為了更新記錄,需要向表中添加一個新元組。該新元組有一個新的非公開ctid,稱之為I。Postgres需要能夠區(qū)分I上的新元組和D上的舊元組。在內(nèi)部,Postgres將一個版本字段和指向前一個元組(如果有的話)的指針存于各個元組。據(jù)此,表的新結(jié)構(gòu)如下:

  ctid

  prev

  id

  first

  last

  birth_year

  A null 1 Blaise Pascal 1623

  B null 2 Gottfried Leibniz 1646

  C null 3 Emmy Noether 1882

  D null 4 Muhammad al-Khwārizmī 780

  E null 5 Alan Turing 1912

  F null 6 Srinivasa Ramanujan 1887

  G null 7 Ada Lovelace 1815

  H null 8 Henri Poincaré 1854

  I D 4 Muhammad al-Khwārizmī 770

  只要al-Khwārizmī存在兩個行版本,則索引必須包含這兩個行的條目。為求簡潔,Uber此處刪除了主鍵索引,只顯示二級索引:

  first

  last

  ctid

  Ada Lovelace G

  Alan Turing E

  Blaise Pascal A

  Emmy Noether C

  Gottfried Leibniz B

  Henri Poincaré H

  Muhammad al-Khwārizmī D

  Muhammad al-Khwārizmī I

  Srinivasa Ramanujan F

  birth_year

  ctid

  770 I

  780 D

  1623 A

  1646 B

  1815 G

  1854 H

  1887 F

  1882 C

  1912 E

  此處將舊版顯示為紅色,新版為綠色。在內(nèi)部,Postgre通過另一個字段保存行版本,以判定哪一個是最新元組。該新增字段幫助數(shù)據(jù)庫決定讓哪一個行元組服務(wù)于一個事務(wù),該事務(wù)可能不被允許查看最新行版本。

  Uber為什么從Postgres遷移到MySQL

  Postgres下,主索引和二級索引都直指磁盤上的元組偏移。若一個元組的位置發(fā)生改變,則必須更新全部索引。

非常好我支持^.^

(1) 100%

不好我反對

(0) 0%

      發(fā)表評論

      用戶評論
      評價:好評中評差評

      發(fā)表評論,獲取積分! 請遵守相關(guān)規(guī)定!

      ?