成人免费xxxxx在线视频软件_久久精品久久久_亚洲国产精品久久久_天天色天天色_亚洲人成一区_欧美一级欧美三级在线观看

17條避坑指南,獲贊5K+,這是一份來自谷歌工程師的數(shù)據(jù)庫經(jīng)驗(yàn)貼

開發(fā) 開發(fā)工具 數(shù)據(jù)庫運(yùn)維
在這篇文章中,她總結(jié)了 17 條這樣的經(jīng)驗(yàn)教訓(xùn),希望為剛接觸數(shù)據(jù)庫的小白提供一份避坑指南。目前,這一指南已在 medium 上收獲了 5k+ 贊。

 「ACID 有很多含義」、「每個(gè)數(shù)據(jù)庫具有不同的一致性和隔離性」、「嵌套事務(wù)可能有害」…… 這些都是谷歌云工程師 Jaana Dogan 曾經(jīng)踩過的坑。在這篇文章中,她總結(jié)了 17 條這樣的經(jīng)驗(yàn)教訓(xùn),希望為剛接觸數(shù)據(jù)庫的小白提供一份避坑指南。目前,這一指南已在 medium 上收獲了 5k+ 贊。

[[325835]]

絕大多數(shù)計(jì)算機(jī)系統(tǒng)都具有某種狀態(tài),而且很可能還依賴于一個(gè)存儲系統(tǒng)。我對數(shù)據(jù)庫的知識也是逐漸累積起來的,但在累積的過程中,我們的設(shè)計(jì)錯誤曾導(dǎo)致過數(shù)據(jù)丟失和中斷問題。在嚴(yán)重依賴數(shù)據(jù)的系統(tǒng)中,數(shù)據(jù)庫是系統(tǒng)設(shè)計(jì)的目標(biāo)和權(quán)衡的核心。盡管我們不可能忽略數(shù)據(jù)庫的工作方式,但應(yīng)用開發(fā)者可以預(yù)見或?qū)嶋H經(jīng)歷的問題往往都只是冰山一角。在本系列文章中,我將分享一些我專門找到的對不擅長數(shù)據(jù)庫領(lǐng)域的開發(fā)者很有用的見解:

  1. 如果 99.999% 的時(shí)間里網(wǎng)絡(luò)沒有問題,那你確實(shí)很幸運(yùn)。
  2. ACID 有很多含義。
  3. 每個(gè)數(shù)據(jù)庫具有不同的一致性和隔離性。
  4. 當(dāng)你無法搞定鎖時(shí),就使用樂觀鎖。
  5. 除了臟讀和數(shù)據(jù)丟失,還存在其它異常。
  6. 我的數(shù)據(jù)庫和我在排序方面并不總是一致的。
  7. 應(yīng)用層面的分片可以存在于該應(yīng)用之外。
  8. AUTOINCREMENT 可能有害。
  9. 過時(shí)的數(shù)據(jù)可能有用而且是無鎖的。
  10. 任何時(shí)鐘源之間都會發(fā)生時(shí)鐘偏移。
  11. 延遲(latency)有很多含義。
  12. 評估每個(gè)事務(wù)的性能需求。
  13. 嵌套事務(wù)可能有害。
  14. 事務(wù)不應(yīng)維持應(yīng)用狀態(tài)。
  15. 查詢計(jì)劃器能提供有關(guān)數(shù)據(jù)庫的一切信息。
  16. 在線遷移可能很復(fù)雜,但卻可以實(shí)現(xiàn)。
  17. 數(shù)據(jù)庫顯著增長時(shí)會引入不可預(yù)測性。

如果 99.999% 的時(shí)間里網(wǎng)絡(luò)沒有問題,那你確實(shí)很幸運(yùn)。

人們至今仍在論辯如今的網(wǎng)絡(luò)連接技術(shù)有多可靠以及由于網(wǎng)絡(luò)中斷而導(dǎo)致系統(tǒng)停機(jī)的情況有多頻繁。可行的研究很有限,而且這些研究往往由擁有使用定制硬件的專用網(wǎng)絡(luò)的大型組織以及特定人員所主導(dǎo)。

憑借 99.999% 的服務(wù)可用性,谷歌僅把 Spanner(谷歌散布在全球的數(shù)據(jù)庫)出現(xiàn)的問題中的 7.6% 歸因于網(wǎng)絡(luò)連接,盡管該公司稱其專用網(wǎng)絡(luò)是這種可用性背后的核心原因。Bailis 和 Kingsbury 2014 年的調(diào)查向 Peter Deutsch 于 1994 年提出的分布式計(jì)算的謬誤(Fallacies of Distributed Computing)之一發(fā)起了挑戰(zhàn)。網(wǎng)絡(luò)真的可靠嗎?

我們并沒有來自巨頭企業(yè)之外的調(diào)查結(jié)果或在公共互聯(lián)網(wǎng)上的調(diào)查結(jié)果。主要電信提供商也沒有足夠的數(shù)據(jù),讓人無法了解他們的客戶端遇到的問題有多少可追溯到網(wǎng)絡(luò)問題。我們常會遇到大型云提供商的網(wǎng)絡(luò)堆棧中斷的情況,這可能導(dǎo)致部分互聯(lián)網(wǎng)下線幾個(gè)小時(shí),但只有影響力很高的事件才會影響到大量可見客戶端。網(wǎng)絡(luò)中斷可能影響范圍很大,但不是每個(gè)案例都會產(chǎn)生嚴(yán)重影響。云客戶端也不一定需要詳細(xì)了解他們遇到的問題。當(dāng)出現(xiàn)中斷時(shí),不可能識別出這是否是由提供商導(dǎo)致的網(wǎng)絡(luò)錯誤。對他們而言,第三方服務(wù)都是黑箱。如果不是主要提供商,是不可能估計(jì)出影響有多大的。

對比一下主要玩家公布的系統(tǒng)報(bào)告,如果可能導(dǎo)致中斷的潛在問題中僅有一小部分是網(wǎng)絡(luò)問題,那么可以說你是相當(dāng)幸運(yùn)的。網(wǎng)絡(luò)連接仍面臨著許多常規(guī)問題,比如硬件故障、拓?fù)渥兓?、管理配置更改和電源故障。但我最近看到一個(gè)新聞,發(fā)現(xiàn)鯊魚撕咬也是一個(gè)現(xiàn)實(shí)存在的問題——已經(jīng)出現(xiàn)過鯊魚撕咬海底光纜的案例。

ACID 有很多含義

ACID 表示原子性(atomicity)、一致性(consistency)、隔離性(isolation)、持久性(durability)。ACID 是數(shù)據(jù)庫事務(wù)(database transaction)需要向用戶確保有效的屬性——即使在出現(xiàn)崩潰、錯誤、硬件故障等情況時(shí)也需要保證這些屬性。如果沒有 ACID 或類似的保證,應(yīng)用開發(fā)者將難以區(qū)分他們自己的職責(zé)與數(shù)據(jù)庫能夠提供的保證。大多數(shù)關(guān)系事務(wù)數(shù)據(jù)庫都會盡力符合 ACID 指標(biāo),但 NoSQL 運(yùn)動等新方法催生了許多沒有 ACID 事務(wù)的數(shù)據(jù)庫,這些這些事務(wù)的實(shí)現(xiàn)成本比較高。

在我剛進(jìn)入這一行業(yè)時(shí),我們的技術(shù)主管當(dāng)時(shí)討論過 ACID 是否已是一個(gè)過時(shí)的概念??梢院侠淼卣f,ACID 可視為一種定義寬松的描述,而不是嚴(yán)格的實(shí)現(xiàn)標(biāo)準(zhǔn)?,F(xiàn)如今,我發(fā)現(xiàn) ACID 最有用的地方是它提供了問題的類別(以及可能的解決方案的類別)。

并非每個(gè)數(shù)據(jù)庫都符合 ACID,而在符合 ACID 的數(shù)據(jù)庫中,ACID 的解讀方式也可能不同。為什么 ACID 會有不同的實(shí)現(xiàn)方式?一個(gè)原因是在實(shí)現(xiàn) ACID 時(shí),需要權(quán)衡的東西太多了。數(shù)據(jù)庫在做廣告宣傳時(shí)可能會說自己符合 ACID,但在許多邊緣案例上仍可能有不同的解釋或在處理不太可能發(fā)生的事件時(shí)的方法不同。為了適當(dāng)?shù)乩斫夤收夏J胶驮O(shè)計(jì)權(quán)衡,開發(fā)者至少可以在高層面上了解數(shù)據(jù)庫實(shí)現(xiàn)各項(xiàng)功能的方式。

一個(gè)眾所周知的爭議問題是 MongoDB 在第 4 版后有多符合 ACID。MongoDB 很長時(shí)間都不支持日志功能,盡管默認(rèn)情況下其也不會更頻繁地(每 60 秒)將數(shù)據(jù)文件提交到磁盤。考慮以下情況,一個(gè)應(yīng)用執(zhí)行兩次寫入(w1 和 w2)。MongoDB 能夠在第一次寫入時(shí)保留更改,但無法在寫入 w2 時(shí)保留這項(xiàng)更改,因?yàn)檫@會出現(xiàn)由硬件故障所致的崩潰。

17条避坑指南,获赞5K+,这是一份来自谷歌工程师的数据库经验贴

MongoDB 在寫入物理磁盤前崩潰而導(dǎo)致數(shù)據(jù)丟失的示意圖

將數(shù)據(jù)提交到磁盤的過程具有較高的成本,而通過避免提交,它們可以宣稱在寫入方面表現(xiàn)出色,但這樣就犧牲了持久性。如今,MongoDB 已經(jīng)有了日志功能,但臟寫(dirty writes)仍然可能影響數(shù)據(jù)的持久性,因?yàn)樗鼈兡J(rèn)是每 100 ms 提交一次。對于日志及這些日志所表示的更改的持久性,也可能會出現(xiàn)同樣的情況,不過這種風(fēng)險(xiǎn)要小得多。

每個(gè)數(shù)據(jù)庫具有不同的一致性和隔離性

在 ACID 屬性中,一致性和隔離性的不同實(shí)現(xiàn)細(xì)節(jié)的范圍是最廣的,因?yàn)槠渖婕暗臋?quán)衡因素更多。一致性和隔離性都是實(shí)現(xiàn)成本較高的屬性。為了保持?jǐn)?shù)據(jù)一致,它們需要協(xié)調(diào)而且正得到越來越多的討論。當(dāng)必須以水平方式擴(kuò)展數(shù)據(jù)中心時(shí)(尤其是對于不同的地區(qū)),這些問題會變得更加困難。因?yàn)榇藭r(shí)可用性會下降且網(wǎng)絡(luò)分區(qū)會越來越普遍,這會導(dǎo)致很難實(shí)現(xiàn)高層面的一致性。CAP 定理為這一現(xiàn)象給出了更普適的解釋。需要指出的是,即使有一些不一致性,一般應(yīng)用也能處理,或者程序開發(fā)者對這一問題有足夠的認(rèn)知,讓他們能為該應(yīng)用添加用于處理這一情況的邏輯,從而無需過于依賴他們的數(shù)據(jù)庫。

數(shù)據(jù)庫往往會提供多種不同的隔離層,這樣應(yīng)用開發(fā)者就可以基于自己的權(quán)衡策略來選擇最具成本效益的。當(dāng)隔離更弱時(shí),速度可能更快,但也可能導(dǎo)致數(shù)據(jù)競爭(data race)。當(dāng)隔離更強(qiáng)時(shí),不會出現(xiàn)某些潛在的數(shù)據(jù)競爭,但速度會更慢,而且還可能出現(xiàn)爭用(contention)情況,這甚至可能將數(shù)據(jù)庫的速度拖慢到中斷的程度。

17条避坑指南,获赞5K+,这是一份来自谷歌工程师的数据库经验贴

現(xiàn)有并發(fā)模型及它們之間的關(guān)系概況

SQL 標(biāo)準(zhǔn)僅定義了 4 種隔離層級,但理論上和實(shí)踐中的層級都更多。jepson.io 很好地總結(jié)了現(xiàn)有并發(fā)模型的情況:https://jepsen.io/consistency。舉個(gè)例子,谷歌的 Spanner 使用了時(shí)鐘同步來保證外部可串行化,即使這是一種更嚴(yán)格的隔離層,但標(biāo)準(zhǔn)隔離層中卻并沒有這樣的定義。

SQL 標(biāo)準(zhǔn)中提及的隔離層級包括:

  • 可串行化(最嚴(yán)格,成本最高):可串行化執(zhí)行(serializable execution)得到的效果與這些事務(wù)的某些序列執(zhí)行的效果一樣。序列執(zhí)行(serial execution)是指在每個(gè)事務(wù)執(zhí)行完成之后再執(zhí)行下一個(gè)事務(wù)。關(guān)于可串行化執(zhí)行,需要注意的一點(diǎn)是:由于解釋的差異性,它往往被實(shí)現(xiàn)為快照隔離(snapshot isolation),比如 Oracle,而快照隔離并不在 SQL 標(biāo)準(zhǔn)中。
  • 可重復(fù)的讀取:當(dāng)前事務(wù)中未提交的讀取對當(dāng)前事務(wù)來說是可見的,但其它事務(wù)做出的改變(比如新插入的行)不是可見的。
  • 已提交的讀取:未提交的讀取對事務(wù)來說不可見。只有已提交的寫入是可見的,但可能出現(xiàn)幻象讀?。╬hantom read)。如果另一個(gè)事務(wù)插入和提交了新的行,則當(dāng)前事務(wù)在查詢時(shí)可以看到它們。
  • 未提交的讀取(最不嚴(yán)格,成本最低):允許臟讀(dirty read),事務(wù)可以看到其它事務(wù)做出的尚未提交的更改。在實(shí)踐中,這個(gè)層級可用于返回近似聚合結(jié)果,比如對一個(gè)表格的 COUNT(*) 查詢。

可串行化層級出現(xiàn)數(shù)據(jù)競爭的情況最少,但成本也最高,而且會讓系統(tǒng)出現(xiàn)最多爭用。其它隔離層級的成本更低一些,但也更可能出現(xiàn)數(shù)據(jù)競爭問題。某些數(shù)據(jù)庫允許自行設(shè)置隔離層級,某些數(shù)據(jù)庫則在這方面更為固執(zhí)一點(diǎn),并不一定支持所有這些層級。

而就算數(shù)據(jù)庫宣稱自己支持這些隔離層級,但只要仔細(xì)檢查一下它們的行為,就可以了解這些數(shù)據(jù)庫實(shí)際究竟是怎么做的。

17条避坑指南,获赞5K+,这是一份来自谷歌工程师的数据库经验贴

每個(gè)數(shù)據(jù)庫在不同隔離層級上的并發(fā)異常概況

Martin Kleppmann 的 hermitage 項(xiàng)目總結(jié)了不同的并發(fā)異常,并說明了一個(gè)數(shù)據(jù)庫在不同的隔離層級上能否處理這樣的異常:https://github.com/ept/hermitage 。Kleppmann 的研究表明數(shù)據(jù)庫設(shè)計(jì)者會以不同的方式解釋隔離層級。

當(dāng)你無法搞定鎖時(shí),就使用樂觀鎖

鎖的成本非常高,不僅是因?yàn)樗鼈儠閿?shù)據(jù)庫引入更多爭用,而且還需要你的應(yīng)用服務(wù)器與數(shù)據(jù)庫之間存在一致的連接。網(wǎng)絡(luò)分區(qū)可能會更顯著地影響排它鎖(exclusive lock),這會導(dǎo)致難以識別和解決的死鎖(deadlock)。如果有些案例無法很好地使用排它鎖,可以選擇樂觀鎖(optimistic locking)。

樂觀鎖這種方法是指當(dāng)讀取某行時(shí)會記錄版本號、上次修改的時(shí)間戳或其校驗(yàn)和(checksum)。然后你可以在更改記錄之前檢查原子方面并無修改的版本。

  1. UPDATE products 
  2. SET name = 'Telegraph receiver', version = 2 
  3. WHERE id = 1 AND version = 1 

如果另一項(xiàng)更新之前已經(jīng)修改了這一行,那么對 products 表的更新將影響 0 行。如果沒有更早的更新,則它會影響 1 行,則我們可以說更新成功了。

除了臟讀和數(shù)據(jù)丟失,還存在其它異常

當(dāng)我們在探討數(shù)據(jù)一致性時(shí),我們主要關(guān)注的是可能導(dǎo)致臟讀和數(shù)據(jù)丟失的競爭問題。但數(shù)據(jù)方面的異常并不止這兩種。

舉個(gè)例子,還有一種異常是寫偏序(write skew)。寫偏序更難以識別認(rèn)定,因?yàn)槲覀儾粫鲃拥厝ゲ檎疫@個(gè)問題。導(dǎo)致寫偏序的原因不是發(fā)生在寫入上的臟讀或數(shù)據(jù)丟失,而是因?yàn)閿?shù)據(jù)上的邏輯約束損壞。

比如,假設(shè)一個(gè)監(jiān)控應(yīng)用需要一個(gè)人類操作員始終處于待命狀態(tài)。

  1. BEGIN tx1;                      BEGIN tx2;SELECT COUNT(*) 
  2. FROM operators 
  3. WHERE oncall = true
  4. 0                               SELECT COUNT(*) 
  5.                                 FROM operators 
  6.                                 WHERE oncall = TRUE; 
  7.                                 0UPDATE operators                UPDATE operators 
  8. SET oncall = TRUE               SET oncall = TRUE 
  9. WHERE userId = 4;               WHERE userId = 2;COMMIT tx1;         

在上面的情況中,如果這些事務(wù)中有兩個(gè)成功提交,就會出現(xiàn)寫偏序。即使此時(shí)沒有出現(xiàn)臟讀或數(shù)據(jù)丟失,數(shù)據(jù)也失去了完整性,因?yàn)槠渲付藘蓚€(gè)待命的人。

可串行化隔離、模式設(shè)計(jì)或數(shù)據(jù)庫約束有助于消除寫偏序。開發(fā)者需要在開發(fā)過程中識別這樣的異常,以避免生產(chǎn)過程中出現(xiàn)數(shù)據(jù)異常。話雖如此,識別代碼庫中的寫偏序卻非常之難。尤其是在大型系統(tǒng)中,如果負(fù)責(zé)基于同一表格構(gòu)建功能的不同團(tuán)隊(duì)之間沒有溝通且沒有互相檢查他們存取數(shù)據(jù)的方式,那么就會出現(xiàn)這種問題。

我的數(shù)據(jù)庫和我在排序方面并不總是一致的

數(shù)據(jù)庫提供的一大核心能力是排序保證,但排序結(jié)果可能會出乎應(yīng)用開發(fā)者的預(yù)料。數(shù)據(jù)庫查閱事務(wù)的順序就是它們接收這些事務(wù)的順序,而不是開發(fā)者查看它們時(shí)的程序設(shè)計(jì)順序。事務(wù)執(zhí)行的順序難以預(yù)測,尤其是在高容量的并發(fā)系統(tǒng)中。

在開發(fā)時(shí),尤其是在使用非阻塞軟件庫進(jìn)行開發(fā)時(shí),較差的樣式和可讀性可能會導(dǎo)致用戶認(rèn)為事務(wù)是按順序執(zhí)行的,即使它們可能以任何順序抵達(dá)數(shù)據(jù)庫。下面的程序看起來像是 T1 和 T2 將按順序調(diào)用,但如果這些函數(shù)是非阻塞的,則它們將立即帶著 promise 返回,調(diào)用的順序?qū)⑷Q于它們在數(shù)據(jù)庫中接收到的時(shí)間。

  1. result1 = T1() // results are actually promises 
  2. result2 = T2() 

如果需要原子性(以便完全提交或放棄所有操作)且序列很重要,則 T1 和 T2 中的操作應(yīng)該運(yùn)行在單個(gè)數(shù)據(jù)庫事務(wù)中。

應(yīng)用層面的分片可以存在于該應(yīng)用之外

分片(Sharding)是一種水平劃分?jǐn)?shù)據(jù)庫的方法。有的數(shù)據(jù)庫可以自動地對數(shù)據(jù)進(jìn)行水平分區(qū),有的數(shù)據(jù)庫則不支持這種功能或做得不好。當(dāng)數(shù)據(jù)架構(gòu)師 / 開發(fā)者可以預(yù)測訪問數(shù)據(jù)的方式時(shí),他們可能會在用戶區(qū)域創(chuàng)建水平分區(qū),而不是將這項(xiàng)工作委托給他們的數(shù)據(jù)庫。這種方式稱為應(yīng)用級分片(application-level sharding)。

應(yīng)用級分片這個(gè)名稱往往會給人帶來一種錯誤印象,讓人以為這種分片應(yīng)該存在于應(yīng)用服務(wù)之中。分片功能可以實(shí)現(xiàn)為數(shù)據(jù)庫的前面一層。取決于數(shù)據(jù)增長和架構(gòu)迭代情況,分片的要求可能會變得非常復(fù)雜。如果能在無需重新部署應(yīng)用服務(wù)器的前提下對某些策略進(jìn)行迭代,則會大有裨益。

應(yīng)用服務(wù)器與分片服務(wù)分離的架構(gòu)示例

如果將分片作為一個(gè)單獨(dú)的服務(wù),你就能更好地在不重新部署應(yīng)用服務(wù)器的前提下迭代分片策略。Vitess 就是應(yīng)用級分片系統(tǒng)的一個(gè)例子。Vitess 為 MySQL 提供了水平分片,并允許客戶端通過 MySQL 協(xié)議連接它;Vitess 會將數(shù)據(jù)分片到多個(gè)互相之間無聯(lián)系的 MySQL 節(jié)點(diǎn)上。

AUTOINCREMENT 可能有害

AUTOINCREMENT(自動遞增)是生成主鍵(primary key)的一種常用方法。數(shù)據(jù)庫被用作 ID 生成器以及數(shù)據(jù)庫中有 ID 生成指定表格的情況其實(shí)并不少見。但使用自動遞增生成主鍵的方式其實(shí)并不理想,原因有幾點(diǎn):

  • 在分布式數(shù)據(jù)庫系統(tǒng)中,自動遞增很困難。為了生成 ID,需要使用全局鎖才行。而如果你可以生成 UUID,那么就不需要數(shù)據(jù)庫節(jié)點(diǎn)之間有任何合作。使用鎖的自動遞增可能導(dǎo)致爭用,并可能導(dǎo)致分布式情況中插入性能顯著下降。MySQL 等一些數(shù)據(jù)庫可能需要特定的配置和更多的注意才能正確地完成 master-master 復(fù)制。這樣的配置容易混亂而且可能導(dǎo)致寫入中斷。
  • 某些數(shù)據(jù)庫有基于主鍵的分區(qū)算法。按順序排布的 ID 可能導(dǎo)致無法預(yù)測的熱點(diǎn),從而使得某些分區(qū)過于繁忙,另一些則一直空閑。
  • 訪問數(shù)據(jù)庫中某行的最快方式是通過主鍵。如果你有更好的標(biāo)識記錄的方式,那么順序 ID 可能會讓表中最顯著的列成為無意義的值。請盡可能地選擇全局獨(dú)一的自然主鍵(比如用戶名)。

請考慮自動遞增 ID 與 UUID 對索引、分區(qū)和分片的影響,然后再決定哪種方式對你而言最好。

過時(shí)的數(shù)據(jù)可能有用而且是無鎖的

多版本并發(fā)控制(MVCC)能實(shí)現(xiàn)我們上面簡要討論過的很多一致性。Postgres 和 Spanner 等一些數(shù)據(jù)庫使用 MVCC 以讓每個(gè)事務(wù)都能看到一個(gè)快照,即該數(shù)據(jù)庫的一個(gè)更舊版本。參照快照的事務(wù)仍然可以串行化以實(shí)現(xiàn)一致性。當(dāng)讀取一個(gè)舊快照時(shí),實(shí)際讀取的是過時(shí)的數(shù)據(jù)。

但即使讀取的是稍微過時(shí)的數(shù)據(jù),也會很有用處,比如當(dāng)在生成數(shù)據(jù)分析結(jié)果或計(jì)算近似聚合值時(shí)。

讀取過時(shí)數(shù)據(jù)的第一大優(yōu)勢是延遲(尤其是當(dāng)你的數(shù)據(jù)庫分布在不同的地區(qū)時(shí))。MVCC 數(shù)據(jù)庫的第二大優(yōu)勢是其允許只讀事務(wù)是無鎖的。在需要大量讀取的應(yīng)用中,一個(gè)優(yōu)勢是用過時(shí)的數(shù)據(jù)也是可行的。

17条避坑指南,获赞5K+,这是一份来自谷歌工程师的数据库经验贴

即便太平洋另一端有某個(gè)數(shù)據(jù)的最新版本,但也可以從本地讀取 5 秒前的過時(shí)副本。

數(shù)據(jù)庫會自動清除舊版本,而在某些情況下,數(shù)據(jù)庫也支持按需清理。舉個(gè)例子,Postgres 允許用戶按需執(zhí)行 VACUUM 操作或每隔一段時(shí)間自動執(zhí)行 VACUUM,而 Spanner 則是通過運(yùn)行一個(gè)垃圾收集器來丟棄時(shí)間超過 1 小時(shí)的版本。

任何時(shí)鐘源之間都會發(fā)生時(shí)鐘偏移

在計(jì)算領(lǐng)域,隱藏得最好的秘密是所有時(shí)間 API 都在說謊。我們的機(jī)器并不能準(zhǔn)確地知道當(dāng)前的時(shí)間是多少。我們的計(jì)算機(jī)全都包含一個(gè)用以產(chǎn)生計(jì)時(shí)信號的石英晶體。但石英晶體并不能準(zhǔn)確計(jì)時(shí)和計(jì)算時(shí)間偏移量,要么比實(shí)際時(shí)鐘快,要么就更慢。一天的偏移量甚至可達(dá) 20 秒。為了準(zhǔn)確,我們的計(jì)算機(jī)時(shí)間必須不時(shí)地與實(shí)際時(shí)間保持同步。

NTP 服務(wù)器可用于同步,但同步本身卻可能由于網(wǎng)絡(luò)的原因而出現(xiàn)延遲。與同一數(shù)據(jù)中心的 NTP 服務(wù)器同步?jīng)r且需要時(shí)間,與公共 NTP 服務(wù)器同步更是可能產(chǎn)生更大的偏移。

原子鐘和 GPS 時(shí)鐘是更好的確定當(dāng)前時(shí)間的信息源,但它們的部署成本更高,而且需要復(fù)雜的設(shè)置,不可能在每臺機(jī)器上都安裝。由于存在這些限制條件,數(shù)據(jù)中心通常使用的是多層方法。即在使用原子鐘和 / 或 GPS 時(shí)鐘提供準(zhǔn)確計(jì)時(shí)的同時(shí),再通過輔助服務(wù)器將時(shí)間信息廣播給其它機(jī)器。這意味著所有機(jī)器都與實(shí)際的當(dāng)前時(shí)間存在一定程度的偏移。

不僅如此,應(yīng)用和數(shù)據(jù)庫往往搭建在不同的機(jī)器中,甚至還可能位于不同的數(shù)據(jù)中心。因此,不僅分散在不同機(jī)器上的不同數(shù)據(jù)庫節(jié)點(diǎn)之間無法統(tǒng)一時(shí)間,應(yīng)用服務(wù)器時(shí)鐘和數(shù)據(jù)庫節(jié)點(diǎn)時(shí)鐘也無法統(tǒng)一。

谷歌的 TrueTime 為此采用了一種不同的方法。大多數(shù)人認(rèn)為谷歌在時(shí)鐘上的成果可以歸功于他們使用了原子鐘和 GPS 時(shí)鐘,但那其實(shí)僅僅是部分原因。TrueTime 實(shí)際上是這樣工作的:

  • TrueTime 使用了兩個(gè)不同的時(shí)間信號源:GPS 時(shí)鐘和原子鐘。這些時(shí)鐘存在不同的故障模式,因此同時(shí)使用兩者可以提升可靠性。
  • TrueTime 的 API 并不是常規(guī)型的。它會以區(qū)間的形式返回時(shí)間。因此實(shí)際時(shí)間事實(shí)上處于這個(gè)時(shí)間區(qū)間的上界和下界之間。因此,谷歌的分布式數(shù)據(jù)庫 Spanner 就可以等到它確定了當(dāng)前時(shí)間超過了特定時(shí)間之后才執(zhí)行事務(wù)。這種方法會給系統(tǒng)帶來一些延遲,尤其是當(dāng)主機(jī)通告的不確定性很高時(shí);但這種方法能保證正確性,即使數(shù)據(jù)庫分布在全球也是如此。

17条避坑指南,获赞5K+,这是一份来自谷歌工程师的数据库经验贴

使用 TrueTime 的 Spanner 組件,其中 TT.now() 會返回一個(gè)時(shí)間區(qū)間,這樣 Spanner 就可以插入睡眠時(shí)間以確保當(dāng)前時(shí)間已超過特定時(shí)間戳。

當(dāng)當(dāng)前時(shí)間的置信度下降時(shí),Spanner 執(zhí)行操作可能會耗費(fèi)更多時(shí)間。因此,即使不可能獲得精準(zhǔn)的時(shí)鐘,保證時(shí)鐘的置信度對性能而言也是非常重要的。

延遲有很多含義

如果房間里有 10 個(gè)人,你問他們「延遲(latency)」是什么意思,你可能會得到 10 個(gè)不同的答案。在數(shù)據(jù)庫中,延遲通常是指數(shù)據(jù)庫延遲,而非客戶端所感知到的延遲。客戶端感知到的延遲包含數(shù)據(jù)庫延遲和網(wǎng)絡(luò)延遲。在調(diào)試不斷惡化的問題時(shí),分辨客戶端延遲和數(shù)據(jù)庫延遲是非常重要的。在收集和展示指標(biāo)時(shí),往往需要同時(shí)包含這兩種延遲。

評估每個(gè)事務(wù)的性能需求

有時(shí)候,數(shù)據(jù)庫會將它們的讀寫吞吐量和延遲作為性能優(yōu)勢的賣點(diǎn)來進(jìn)行宣傳。盡管這能在評估數(shù)據(jù)庫的性能時(shí)從較高層面上展現(xiàn)主要的限制因素,但為了更全面地進(jìn)行評估,需要單獨(dú)分開評估各個(gè)關(guān)鍵操作的性能,比如每次查詢或每個(gè)事務(wù)的執(zhí)行性能。示例:

  • 為具有給定約束條件的包含 5000 萬行的表格 X 插入新的一行并填充相關(guān)表格時(shí)的吞吐量和延遲。
  • 當(dāng)平均好友數(shù)為 500 時(shí),查詢一個(gè)用戶的好友的好友時(shí)的延遲。
  • 當(dāng)用戶訂閱了 500 個(gè)賬號且每個(gè)小時(shí)有 X 項(xiàng)新輸入時(shí),檢索用戶時(shí)間線前 100 條記錄時(shí)的延遲。

評估和實(shí)驗(yàn)可能包含這樣的關(guān)鍵性案例,直到你有信心你的數(shù)據(jù)庫能夠滿足你的性能需求。另一個(gè)類似的經(jīng)驗(yàn)法則是在收集延遲指標(biāo)和設(shè)置 SLO 時(shí)考慮這種故障情況。

在收集每個(gè)操作的指標(biāo)時(shí)要注意高基數(shù)。如果你需要高基數(shù)的調(diào)試數(shù)據(jù),請使用日志或分布式的跟蹤方法。如果你想了解延遲調(diào)試方法,請參閱《Want to Debug Latency?》(https://medium.com/observability/want-to-debug-latency-7aa48ecbe8f7)。

嵌套事務(wù)可能有害

并非每個(gè)數(shù)據(jù)庫都支持嵌套事務(wù)(nested transactions),但如果支持,那么嵌套事務(wù)可能導(dǎo)致出人意料的程序設(shè)計(jì)錯誤,而且這種錯誤往往不易識別,直到出現(xiàn)了明顯異常才能看清。

如果你想要避免嵌套事務(wù),則可以使用客戶端軟件庫來檢測和避免嵌套事務(wù)。如果你不能避免嵌套事務(wù),則必須注意不要出現(xiàn)意料之外的情況,即當(dāng)提交的事務(wù)因?yàn)樽邮聞?wù)而被意外拋棄時(shí)。

如果將事務(wù)封裝在不同的層中,可能會出現(xiàn)出人意料的嵌套事務(wù)案例,而從可讀性角度來看,其意圖可能將變得難以理解。看看下面的程序:

  1. with newTransaction(): 
  2.     Accounts.create("609-543-222")    with newTransaction(): 
  3.         Accounts.create("775-988-322"
  4.         throw Rollback(); 

以上代碼的結(jié)果是什么?是兩個(gè)事務(wù)都會回滾還是僅回滾內(nèi)部那個(gè)事務(wù)?如果我們當(dāng)時(shí)依賴的多層軟件庫將該事務(wù)的創(chuàng)建過程封裝起來不為我們所見,我們還能識別和改進(jìn)這樣的案例嗎?

假設(shè)一個(gè)具有多項(xiàng)操作(比如 newAccount)的數(shù)據(jù)層已經(jīng)在它們自己的事務(wù)中實(shí)現(xiàn)了。當(dāng)你用更高層的業(yè)務(wù)邏輯(它們運(yùn)行在自己的事務(wù)中)運(yùn)行它們時(shí),會發(fā)生什么?隔離性和一致性又會怎樣?

  1. function newAccount(id string) { 
  2.    with newTransaction(): 
  3.        Accounts.create(id) 

與其耗費(fèi)資源去解決這些仍待解決的問題,還不如不使用嵌套事務(wù)。即使不創(chuàng)建它們自己的事務(wù),你的數(shù)據(jù)層仍可以實(shí)現(xiàn)高層操作。然后,業(yè)務(wù)邏輯會啟動事務(wù),在事務(wù)上運(yùn)行操作,提交或中止。

  1. function newAccount(id string) { 
  2.     Accounts.create(id) 
  3. }// In main application:with newTransaction(): 
  4.     // Read some data from database for configuration. 
  5.     // Generate an ID from the ID service. 
  6.     Accounts.create(id)    Uploads.create(id) // create upload queue for the user. 

   事務(wù)不應(yīng)維持應(yīng)用狀態(tài)

應(yīng)用開發(fā)者可能會想在事務(wù)中使用應(yīng)用狀態(tài)來更新特定的值或調(diào)整查詢參數(shù)。這時(shí)所要考慮的一個(gè)關(guān)鍵事項(xiàng)是選擇合適的范圍??蛻舳嗽谟龅骄W(wǎng)絡(luò)問題時(shí)往往會重試事務(wù)。如果一個(gè)事務(wù)依賴于在其它地方會變化的狀態(tài),那么其可能根據(jù)該問題中數(shù)據(jù)競爭的可能性選擇錯誤的值。事務(wù)應(yīng)注意應(yīng)用中的數(shù)據(jù)競爭。

  1. var seq int64with newTransaction(): 
  2.      newSeq := atomic.Increment(&seq) 
  3.      Entries.query(newSeq)     // Other operations... 

上面的事務(wù)不管最終結(jié)果究竟如何,在每次運(yùn)行時(shí)都會增加序列號。如果因?yàn)榫W(wǎng)絡(luò)問題而導(dǎo)致提交失敗,則在第二次重試時(shí)會使用不同的序列號進(jìn)行查詢。

查詢計(jì)劃器能提供有關(guān)數(shù)據(jù)庫的一切信息

查詢計(jì)劃器(query planner)決定了查詢在數(shù)據(jù)庫中的執(zhí)行方式。它們還會在運(yùn)行之前分析和優(yōu)化這些查詢。計(jì)劃器僅能基于其擁有的信號提供某些可能的估計(jì)。如何確定找到以下查詢的結(jié)果的方法:

  1. SELECT * FROM articles where author = "rakyll" order by title; 

檢索結(jié)果的方法有兩種:

  • 全表掃描:我們可以遍歷表中的每一項(xiàng),然后返回作者名匹配的文章,然后再執(zhí)行排序。
  • 索引掃描:我們可以使用索引來查找匹配的 ID,檢索這些行,再執(zhí)行排序。

查詢計(jì)劃器的作用是確定哪種策略是最佳選擇。不過對于哪些可以預(yù)測,哪些可能導(dǎo)致糟糕的決策,查詢計(jì)劃器僅有有限的信號。數(shù)據(jù)庫管理員(DBA)或開發(fā)者可使用它們來診斷和優(yōu)化表現(xiàn)較差的查詢。當(dāng)數(shù)據(jù)庫升級時(shí),如果新版本的數(shù)據(jù)庫出現(xiàn)了性能問題,那么這個(gè)數(shù)據(jù)庫可以調(diào)節(jié)查詢計(jì)劃器并進(jìn)行自我診斷。慢查詢?nèi)罩?、延遲問題或關(guān)于執(zhí)行時(shí)間的統(tǒng)計(jì)信息等報(bào)告可用于確定需要優(yōu)化的查詢。

查詢計(jì)劃器提供的某些指標(biāo)可能具有較多噪聲,尤其是當(dāng)估計(jì)延遲或 CPU 時(shí)間時(shí)。作為對查詢計(jì)劃器的補(bǔ)充,跟蹤和執(zhí)行路徑工具對診斷這些問題而言可能會更加有用,不過并非每個(gè)數(shù)據(jù)庫都會提供這樣的工具。

在線遷移可能很復(fù)雜,但卻可以實(shí)現(xiàn)

在線或?qū)崟r(shí)遷移的意思是在不停機(jī)且不損害數(shù)據(jù)正確性的同時(shí)從一個(gè)數(shù)據(jù)庫遷移到另一個(gè)數(shù)據(jù)庫。如果是遷移到同樣的數(shù)據(jù)庫 / 引擎,在線遷移會更為簡單;但如果是遷移到性能特性和組織結(jié)構(gòu)要求不同的新數(shù)據(jù)庫,那情況會復(fù)雜得多。

在線遷移有多種模式,下面介紹其中一種:

  • 開始向兩個(gè)數(shù)據(jù)庫執(zhí)行雙寫入(dual writes)。在這一階段,新數(shù)據(jù)庫還不包含所有數(shù)據(jù),但將開始看到新數(shù)據(jù)。一旦這一步得到了保證,你就可以進(jìn)入下一步了。
  • 讓讀取路徑可同時(shí)使用這兩個(gè)數(shù)據(jù)庫。
  • 主要使用新數(shù)據(jù)庫來進(jìn)行讀取和寫入。
  • 停止向舊數(shù)據(jù)庫寫入,但繼續(xù)保持從舊數(shù)據(jù)庫讀取。此時(shí),新數(shù)據(jù)庫仍未包含所有新數(shù)據(jù),而在獲取舊記錄時(shí),可能還需要回退至舊數(shù)據(jù)庫。
  • 這時(shí)候,舊數(shù)據(jù)庫處于只讀狀態(tài)。從舊數(shù)據(jù)庫取出新數(shù)據(jù)庫缺失的值對新數(shù)據(jù)庫進(jìn)行回填。遷移完成后,所有的讀取和寫入路徑都將使用新數(shù)據(jù)庫,舊數(shù)據(jù)庫則從系統(tǒng)中移除。

如果你需要更具體的案例,可以看看 Stripe 的遵循這一模式的遷移策略:https://stripe.com/blog/online-migrations

數(shù)據(jù)庫顯著增長時(shí)會引入不可預(yù)測性

數(shù)據(jù)庫增長會讓你遭遇不可預(yù)測的擴(kuò)展問題。我們對自己數(shù)據(jù)庫的內(nèi)部情況越了解,可能就越難預(yù)測它們的擴(kuò)展情況,還有些事情是我們無法預(yù)測的。

在數(shù)據(jù)庫增大時(shí),之前關(guān)于數(shù)據(jù)規(guī)模和網(wǎng)絡(luò)容量需求的假設(shè)和預(yù)期都將變得過時(shí)。這時(shí)候,為了避免中斷,需要大規(guī)模地重寫組織結(jié)構(gòu)、大規(guī)模地改進(jìn)運(yùn)營、解決容量問題、重新考慮部署方案或遷移到其它數(shù)據(jù)庫。

不要以為了解你當(dāng)前數(shù)據(jù)庫的內(nèi)部情況就萬無一失了,規(guī)模擴(kuò)大還會帶來新的未知。無法預(yù)測的熱點(diǎn)、數(shù)據(jù)不平衡的分布、意料之外的容量和硬件問題、不斷增長的流量和新的網(wǎng)絡(luò)分區(qū)都會讓你重新考慮你的數(shù)據(jù)庫、數(shù)據(jù)模型、部署模型和部署規(guī)模。

【本文是51CTO專欄機(jī)構(gòu)“機(jī)器之心”的原創(chuàng)譯文,微信公眾號“機(jī)器之心( id: almosthuman2014)”】 

戳這里,看該作者更多好文

 

責(zé)任編輯:張燕妮 來源: 51CTO專欄
相關(guān)推薦

2019-04-16 13:57:59

戴爾

2020-06-01 15:04:44

甲骨文自治數(shù)據(jù)庫

2021-10-22 06:04:05

勒索軟件攻擊報(bào)告

2020-03-23 13:35:59

GitHub代碼開發(fā)者

2011-05-25 16:59:20

前端工程師

2013-05-23 13:32:30

編程攻誠獅工程師

2023-09-01 14:02:25

用戶分析攻略

2022-01-17 18:21:09

數(shù)據(jù)庫社交引流

2021-02-26 00:46:11

CIO數(shù)據(jù)決策數(shù)字化轉(zhuǎn)型

2024-10-07 20:00:56

2009-03-05 10:28:48

測試工程師箴言offer

2018-01-20 20:46:33

2019-04-12 14:38:04

開發(fā)工具工程師

2018-01-29 16:29:35

數(shù)據(jù)開發(fā)從業(yè)

2019-03-18 08:08:24

知識圖譜技術(shù)

2018-07-29 15:33:04

2018-05-15 09:15:03

CNN卷積神經(jīng)網(wǎng)絡(luò)函數(shù)

2019-07-17 07:07:54

MySQL數(shù)據(jù)庫索引

2024-08-09 08:28:14

品牌數(shù)據(jù)庫產(chǎn)品

2023-04-28 15:41:08

模型ChatGPT
點(diǎn)贊
收藏

51CTO技術(shù)棧公眾號

主站蜘蛛池模板: 亚洲一区二区国产 | 精品国产乱码久久久久久蜜柚 | 成人免费毛片在线观看 | 99久久99 | 综合精品在线 | 日韩精品一区二区三区老鸭窝 | 亚洲精品乱码久久久久久按摩观 | 在线免费观看毛片 | 国产免费一区二区三区 | 影音先锋中文字幕在线观看 | 国产乱xxav| 国产精品一区二区三区四区 | 国产高清在线精品一区二区三区 | 黄色成人国产 | 亚洲日本一区二区三区四区 | 久久91av| 一区二区三区视频 | 欧美激情综合 | 久久久久免费观看 | 超碰在线97国产 | www.亚洲成人网 | 国产精品一区二区av | 亚洲在线 | 国产精品久久久一区二区三区 | 欧美日韩国产传媒 | 久久高清免费视频 | 精品99在线| 国产一区 日韩 | 色屁屁在线观看 | 成人av播放 | 欧美高清性xxxxhd | 在线观看免费福利 | 羞羞色视频 | 亚洲一区二区三区免费在线观看 | 国产精品一区二区免费看 | v亚洲 | 国产激情在线 | 福利视频一区二区三区 | 激情毛片 | 亚洲精品电影网在线观看 | 91中文字幕在线观看 |