【我們為什麼挑選這篇文章】首圖跟文章內容是顛倒過來的,這次獲得勝利的是代表 MySQL 的海豚,落敗的則是 Postgres SQL 的大象。如果你對 Uber 從轉用 MySQL 的細節有所疑惑,可以到他們的部落格觀看,內有細部的實作細節。(中文版本)
而你有特別喜歡的資料庫嗎?我想文章作者說的很正確:兩個資料庫各有各的優勢和實用場景,並沒有一種比另一種有壓倒性優勢的存在。端看你所需要的環境與要求來做選擇。
如果你對相關的議題有興趣,可以到 Ant Yi-Feng Tzeng,Muzik Online 的 Chief Engineer,其臉書頁面上有許多探討 MySQL 與 Postgres SQL 的文章。
(責任編輯:Matthew Chen)
前兩天 Uber post 了一篇文章:為什麼 Uber 轉向使用 MySQL,說他們從 Postgres SQL 轉到使用 MySQL 了。blog 寫的不錯,科普了一些 DB indexing 和 replication 的基本常識。當時轉給一個朋友看,朋友說,其實 Uber 2013 年才發了一篇文章說他們從 MySQL 轉 Postgres SQL。遂去找來看了。看完後尋思下,其實兩篇文章背後的情況,兩次轉型的文章背後的原因,也就可以揣測一二了。
作為兩大主流開源數據庫,MySQL 和 Postgres 的「戰爭」從來沒有停止過,雖然硝煙不似程序語言之間的鬥爭那麼濃烈。你可以去 Quora 或者 Stack Overflow 上搜相關的 MySQL vs Postgres 帖子,特別多。我的感覺是,各有各的優勢和實用場景,並沒有一種比另一種有壓倒性優勢的存在。
對於大部分程序員來說,公司用哪個 DB,基本不太輪到你來做決定。
你加入一個公司的時候,除非是創業公司,或者你是 CTO、VP、Director 級別的,否則大部分的技術選型都應該早已經塵埃落定了的。尤其是 DB,一旦選擇,再遷移的代價就很大。所以除非有了顛覆性的優勢或者問題,很少有公司會去費時費力做這種大的遷移。而不論是選型還是轉型,一個不可忽略的因素,就是你招到的工程師更能駕馭哪一種技術,或者有話語權的決策者們傾向於哪一種技術。這其實和程序語言的選型多少有著異曲同工的類似。
其實 Uber 兩次高調轉型,類似的事情在 Square 也發生過。雖然 Square 最早是使用 MySQL,但是在大概在 2012 年間,因為 Postgres 的各種優勢(如對 geospatial 數據及搜索的支持等),以及當時幾位比較 senior 的工程師的大力倡導,很多新的 service 都嘗試性地選擇了使用 Postgres。所以當時公司的架構是 MySQL 和 Postgres 並存。對於那時候的我而言,不過是有機會學習、了解、和比較兩個不同的技術。兩者各有特點,有些東西在 MySQL 裡似乎更方便,另一些則反之。總有方案去實現,並沒有覺得非要哪一種才行。
- DB 若安好,便是晴天。
一個公司,如果 DB 從來不出問題,那肯定是因為沒有業務或者流量。所有的技術,都有它設計的應用場景。除了一些 happy case,就一定有坑。能夠盡可能地避免這些坑,或者在出問題的時候能夠最快修復,就成了至關重要的因素。Square 兩種 DB 並存的期間,公司裡 Postgres 的牛人寥寥無幾。但是 MySQL 的專家,卻有幾個極為靠譜的。大部分工程師,並不是數據庫專家,Postgres 和 MySQL 的相對優勢,對我們而言,都比不過出問題的時候有人解惑或者救火來的重要。何況一個公司維繫兩套同類的數據庫系統本身就是個負擔。因此,這些使用 Postgres 的 service 後來又都慢慢轉成 MySQL 了。
因為我們做支付的需要強 transactional 的支持,所以不太會用 NoSQL 類型的,主要用的還是 MySQL 或者 Postgres。雖說數據庫相關的知識和技術,現在工作中因為用得多,慢慢也了解了不少,但如果真的線上出了問題,自己還是不太擺得平。好在每個公司都會有一些數據庫大牛,有的公司叫做 DBA。很多中小公司並沒有專職的 DBA,都是做系統的人監管。有幾位私交甚好。加上自己平時系統里相關問題也經常需要請教,所以一來二去知道了好些好玩的事情。
對數據庫大牛我一向是抱景仰的態度的。公司只要稍具規模,數據庫這塊做不好,基本也就沒啥好玩的了。這一塊不出問題也罷,一出問題,基本就是見血封喉,網站直接掛掉。那麼平時最常見的都有哪些問題呢?
首先就是選型。
每個公司因為業務的不同,數據庫系統應用場景不一樣,哪一種最合適就不一樣。沒有哪一個系統一定是最好的。比如做支付的一定要強事務性、一致性的支持,而很多社交平台更多時候其實是需要高可用;有的業務 writes 特別 heavy,有的業務更重要的是 reads;有些業務可以只關心最近幾天的數據,因此可以 tradeoff 老數據讀寫的低效,有的卻要頻頻 access 歷史數據;有些業務可以通過加 index 解決 query 效率,有些卻只能通過加緩存等等。。這也是為什麼很多公司有多個數據庫系統並存,以最優化對每個場景和業務的支持。
選型錯了,基本就掉在坑裡了,也沒有頻頻踩坑一說了。
另外一個就是相關架構。
什麼意思呢?這裡包括數據庫上層的 cache 系統的設計,程序語言對 DB connection 的處理,proxy layer(如果存在)的功能,以及和 binlog 等相關的 data pipeline 的搭建。當然,也包括數據庫系統的分區、備份等的具體設計。
很多公司早期所有的 table 都在一個 DB 裡面,因為各種 connection pool 和 throughput 的限制,這其實基本沒法 scale。
能夠合理的安排不同 table 的分離,讓數據相關的留在一起,不相關的或者不太相關的放在另一個 DB 裡。類似這些很簡單的道理,很多時候卻可以很大程度上緩解 scalability 的問題。
而平時我們遇到的最多的問題,還是 human mistake.
再好的系統,使用姿勢不對,也是枉然。何況並不是所有的工程師都是數據庫專家。
- 人為錯誤分成兩種
一種是 DB operation 中犯的錯誤。這種概率比較低,但是通常危害卻最大。幾乎所有的公司都會有類似的傳奇,常見的版本有:
1.某某工程師或無意或有意,「不小心」 刪掉了數據庫某 core table 中所有的數據。不是開玩笑,這種事 Facebook 也發生過,還是一個朋友。好在後來恢復了。這事也成了他的工程師歷史上光輝的一筆。
2.某某工程師做 online schema change 的時候,不小心有一步誤操作。結果數據庫被 lock 長達幾個小時。該公司網站也就掛了好幾個小時。
3.最後這個版本聽國內一個大公司的朋友說的,細節還真是不記得了。只是記得兩台服務器,做 master slave switch 還是什麼的時候,拔錯了一個電源插頭,然後 …… 就沒有然後了。
另一種是程序員程序裡或者腳本裡犯的錯誤。這個就很常見了。舉個很簡單的例子。我們知道 Ruby on Rails 對數據庫的 access 基本是通過 Active Record 來完成的。Active Record 可以通過一個 connection pool 來限制每個 application 到 DB 的 connection。如果某一個程序或者腳本中的 query 是查詢沒有被 index 的數據,而導致 full table scan,加上一些 web server 的並行的實現,很經常就會有整個 DB 的所有 connection 被佔用,連 kill query 都沒法執行。只能人肉的去做一些類似重啟的操作。還有更常見的,就是程序裡的 N+1 query。這些都很無語,但若說你從沒遇到過,那可能是 …… 呵呵。
最後一種,也就是自然流量增長或者流量突增造成的數據庫訪問瓶頸。
只要是數據庫,就有 throughput 的限制。只要你的業務在增長,總有一天數據庫訪問就會達到一個上限。所以在這個預警到來前,就要做各種 horizontal 或者 vertical 的 scale 來不斷提升這個上限。或者是通過緩存等其他機制來對訪問量進行分流。這裡面可以做的東西就多了。覺得可以單獨寫一篇了。
另一種就是類似 DDoS、Marketing 等等帶來的各種流量的突增。如果是有計劃的 Marketing 等,就需要提前做好各種戰鬥準備。如果是惡意攻擊,那就只能靠各種防禦工程(如 IP blocking 等等)擋掉這些訪問來保證數據庫正常工作了。
最後,推薦一個 DBA 寫的博客網站內容很精彩,有技術有情懷。文章寫的比我好多了。
(本文經合作夥伴 36kr 授權轉載,並同意 TechOrange 編寫導讀與修訂標題,原文標題為:《矽谷資深工程師帶你聊聊數據庫那些事》。圖片來源。)
──
- 延伸閱讀
NoSQL 資料庫的春天:MongoDB 獲得 1.5 億美元融資,它背後的故事是什麼?
資料科學的第一堂課:面對海量資料,該怎麼著手處理?
當金融交易遇上資料科學——買股票,我們到底該相信第四台名嘴還是「資料」?