自拍偷在线精品自拍偷,亚洲欧美中文日韩v在线观看不卡

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

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

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

[[325835]]

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

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

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

人們至今仍在論辯如今的網(wǎng)絡(luò)連接技術(shù)有多可靠以及由于網(wǎng)絡(luò)中斷而導(dǎo)致系統(tǒng)停機的情況有多頻繁??尚械难芯亢苡邢?,而且這些研究往往由擁有使用定制硬件的專用網(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 年提出的分布式計算的謬誤(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)下線幾個小時,但只有影響力很高的事件才會影響到大量可見客戶端。網(wǎng)絡(luò)中斷可能影響范圍很大,但不是每個案例都會產(chǎn)生嚴重影響。云客戶端也不一定需要詳細了解他們遇到的問題。當出現(xiàn)中斷時,不可能識別出這是否是由提供商導(dǎo)致的網(wǎng)絡(luò)錯誤。對他們而言,第三方服務(wù)都是黑箱。如果不是主要提供商,是不可能估計出影響有多大的。

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

ACID 有很多含義

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

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

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

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

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

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

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

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

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

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

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

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

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

SQL 標準中提及的隔離層級包括:

  • 可串行化(最嚴格,成本最高):可串行化執(zhí)行(serializable execution)得到的效果與這些事務(wù)的某些序列執(zhí)行的效果一樣。序列執(zhí)行(serial execution)是指在每個事務(wù)執(zhí)行完成之后再執(zhí)行下一個事務(wù)。關(guān)于可串行化執(zhí)行,需要注意的一點是:由于解釋的差異性,它往往被實現(xiàn)為快照隔離(snapshot isolation),比如 Oracle,而快照隔離并不在 SQL 標準中。
  • 可重復(fù)的讀取:當前事務(wù)中未提交的讀取對當前事務(wù)來說是可見的,但其它事務(wù)做出的改變(比如新插入的行)不是可見的。
  • 已提交的讀?。何刺峤坏淖x取對事務(wù)來說不可見。只有已提交的寫入是可見的,但可能出現(xiàn)幻象讀取(phantom read)。如果另一個事務(wù)插入和提交了新的行,則當前事務(wù)在查詢時可以看到它們。
  • 未提交的讀?。ㄗ畈粐栏瘢杀咀畹停涸试S臟讀(dirty read),事務(wù)可以看到其它事務(wù)做出的尚未提交的更改。在實踐中,這個層級可用于返回近似聚合結(jié)果,比如對一個表格的 COUNT(*) 查詢。

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

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

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

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

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

當你無法搞定鎖時,就使用樂觀鎖

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

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

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

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

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

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

舉個例子,還有一種異常是寫偏序(write skew)。寫偏序更難以識別認定,因為我們不會主動地去查找這個問題。導(dǎo)致寫偏序的原因不是發(fā)生在寫入上的臟讀或數(shù)據(jù)丟失,而是因為數(shù)據(jù)上的邏輯約束損壞。

比如,假設(shè)一個監(jiān)控應(yīng)用需要一個人類操作員始終處于待命狀態(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ù)中有兩個成功提交,就會出現(xiàn)寫偏序。即使此時沒有出現(xiàn)臟讀或數(shù)據(jù)丟失,數(shù)據(jù)也失去了完整性,因為其指定了兩個待命的人。

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

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

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

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

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

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

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

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

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

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

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

AUTOINCREMENT 可能有害

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

延遲有很多含義

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

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

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

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

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

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

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

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

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

如果將事務(wù)封裝在不同的層中,可能會出現(xiàn)出人意料的嵌套事務(wù)案例,而從可讀性角度來看,其意圖可能將變得難以理解??纯聪旅娴某绦颍?/p>

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

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

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

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

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

  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ù)。這時所要考慮的一個關(guān)鍵事項是選擇合適的范圍??蛻舳嗽谟龅骄W(wǎng)絡(luò)問題時往往會重試事務(wù)。如果一個事務(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é)果究竟如何,在每次運行時都會增加序列號。如果因為網(wǎng)絡(luò)問題而導(dǎo)致提交失敗,則在第二次重試時會使用不同的序列號進行查詢。

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

【本文是51CTO專欄機構(gòu)“機器之心”的原創(chuàng)譯文,微信公眾號“機器之心( 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

勒索軟件攻擊報告

2020-03-23 13:35:59

GitHub代碼開發(fā)者

2011-05-25 16:59:20

前端工程師

2013-05-23 13:32:30

編程攻誠獅工程師

2022-01-17 18:21:09

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

2023-09-01 14:02:25

用戶分析攻略

2024-10-07 20:00:56

2009-03-05 10:28:48

測試工程師箴言offer

2021-02-26 00:46:11

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

2018-01-20 20:46:33

2018-01-29 16:29:35

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

2019-04-12 14:38:04

開發(fā)工具工程師

2019-03-18 08:08:24

知識圖譜技術(shù)

2018-05-15 09:15:03

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

2018-07-29 15:33:04

2024-08-09 08:28:14

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

2019-09-02 22:34:48

2019-07-17 07:07:54

MySQL數(shù)據(jù)庫索引
點贊
收藏

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