(點選上方公眾號,可快速關註)
英文:stackoverflow,翻譯:宋鑫
3gods.com/database/MySQL-Sharding-Approaches.html
翻譯一個stackoverflow上的問答,關於分庫分表的缺點的,原文連結:
《MySQL sharding approaches?》
https://stackoverflow.com/questions/5541421/mysql-sharding-approaches
問題:
什麼是最好的MySQL分庫分表方案?我想到的有:
1、應用層切分?
2、MySQL代理層切分?
3、提供查詢資料庫分片的中心服務?
你們知道任何這方面有趣的專案或者工具嗎?
回答:
最好的切分MySQL的方式就是:除非萬不得已,否則不要去乾它。
當你寫一個應用時,你通常都想要最快的開發速度。只有必要時,你才開始最佳化延時,提高吞吐量,
你切分資料庫的原因無非因為資料庫的讀或者寫:
-
資料庫寫
寫操作永久的超過了伺服器的磁碟負載;太多寫入導致副本同步永遠的落後了。
-
資料庫讀
讀取到的資料量太大以至於稱爆記憶體;並且大多數讀操作開始直擊磁碟而不是從記憶體中讀取資料。
只有這時,你才需要考慮做資料庫切分。
當你開始切分後,你開始以下麵幾種方式支付代價:
你的SQL陳述句不再是宣告式的(declarative)
一般的,你用SQL陳述句告訴資料庫你要什麼資料,然後讓最佳化器最佳化SQL,並將SQL轉化成資料獲取程式。
這很棒,因為它非常靈活,而且寫這些轉化程式很無聊,嚴重影響開發速度。
分散式環境下,你將A節點的表和B節點的表進行join,甚至有些表的資料大到超過一個節點,在A節點和B節點將資料join起來,然後將B節點和C節點join後的資料再次聚合。你開始寫單方面的hash應用程式來解決這個問題(或者你可以再造MySQL的叢集),這表示結果你得到一大堆的非宣告式的SQL,而且讓程式以一種面向過程的方式開始工作。
你招致了大量的網路延時
一般的,一條SQL查詢陳述句可以本地解決並且透過最佳化器以最小的耗時解決這個查詢問題。
在分散式環境下,查詢陳述句必須要透過KV對映,訪問多個網路節點(希望是批次訪問,而不是每個Key都來一次網路往返),或者將WHERE條件放在他們將被執行的節點上。
但是即使在最好的情況下,涉及到多個網路訪問都會更加複雜。特別是MySQL的最佳化器完全不知道網路延時的情況。
你失去了SQL的許多強大能力
好吧,這或許沒那麼重要,但是外來鍵約束,其他保證資料完整性的SQL機制,對於跨多個節點是無能為力的。
MySQL沒有API保證非同步查詢傳回順序結果
當相同型別的資料存放在多個節點上(比如使用者資料存放在A,B,C節點上),水平查詢需要訪問所有節點,資料訪問時間直接因以節點數線性增長。除非多個節點是以並行方式訪問,然後再以Map-Reduce的方式聚合。
前提是需要提供非同步通訊的API,但這並不存在於MySQL提供的功能中。可選的方案是在子行程中增加很多的forking和連線。
總結
當你開始做資料庫分庫分表,資料結構和網路拓撲明顯影響到應用的效能。
為了執行良好,你的應用需要當心這些事情,所以只有應用層的切分才有意義。
如果需要自動切分,問題會更多(比如決定那個節點的那個列作為hash主鍵),或者
你想要手動進行切分,xyz使用者去這個主庫上,abc去和def去到那個主庫上。
業務功能上的切分有些好處,如果做對了,這對絕大部分開發人員是透明的。因為所有相關的表都存放在本地。
這讓程式的透明性可以從宣告式的SQL中儘量受益,並且有更少的網路延時,因為跨節點的網路訪問被保持到最小化。
業務功能上的切分的缺點是:它不能準許單個表的資料膨脹過大,這需要設計者的特別註意。
業務功能切分的好處是:針對一個並沒有太多改變的程式碼庫,它相對而言非常簡單。
Booking.com在過去幾年進行過幾次業務功能上的分庫分表,並且一直工作的很好。
看完本文有收穫?請轉發分享給更多人
關註「資料分析與開發」,提升資料技能