MySQL架構設計談:從開發規範、選型、拆分到減壓

1、MySQL數據庫開發規範程序員

 

數據庫規範到底有多重要?有過初創公司經歷的朋友應該都深有體會。規範是數據庫運維的一個基石,能有效地減小數據庫出問題的機率,保障數據庫schema的合理設計並方便後續自動化的管理。sql

 

曾經咱們花了大半年時間來作數據庫規範化的工做,例如制定數據庫開發指南、給程序員作培訓等,推動的時候也會遇到一些阻力。但規範以後運維質量會有一個質的提高,也增進了DBA的工做效率。數據庫

 

在開發規範方面,咱們劃分爲開發規範和運維規範兩部分。緩存

 

1、開發規範安全

 

表設計的規範:服務器

 

  • 字段數量建議不超過20-50個網絡

  • 作好數據評估,建議純INT不超過1500萬,含有CHAR的不要超過1000萬。字段類型在知足需求條件下越小越好,儘可能使用UNSIGNED存儲非負整數,由於實際使用時候存儲負數的場景很少。數據結構

  • 將字符轉換成數字存儲。例如使用UNSIGNED INT存儲IPv4 地址而不是用CHAR(15) ,但這種方式只能存儲IPv4,存儲不了IPv6。另外能夠考慮將日期轉化爲數字,如:from_unixtime()、unix_timestamp()。架構

  • 全部字段均定義爲NOT NULL,除非你真的想存儲null。併發

 

索引設計的規範:

 

1)全部表必須有顯式主鍵

 

  • InnoDB表是以主鍵排序存儲的IOT表

  • 儘可能使用短、自增的列作索引

  • 複製結構使用row格式,若是表有主鍵能夠加速複製

  • UNSIGNED INT自增列,也能夠考慮BIGINT

  • TINYINT作主鍵可能致使MySQL Crash

  • 類型轉換會致使查詢效率很低

  • 可用uuid_short()代替uuid(),轉成BIGINT存儲

 

2)合理地創建索引

 

  • 選擇區分度高的列做爲索引

  • 單個索引字段數不超過5,單表索引數量不超過5,避免冗餘索引

  • 創建的索引能覆蓋80%主要的查詢,不求全,解決問題的主要矛盾

  • 複合索引排序問題,多用explain去確認

 

SQL編寫規範:

 

1)避免在數據庫中進行大量計算任務

 

  • 大事務拆成多個事務,分批屢次操做

  • 慎用text、blob大型字段,如要用考慮好拆分方案

  • 頻繁查詢的字典表考慮用Cache抗

 

2)優化join

 

  • 避免大表與大表之間的join,考慮讓小表去驅動大表join

  • 最多容許三表join,最好控制成兩表

  • 控制join後面where選擇的行數

 

3)注重where條件,多用EXPLAIN確認

 

  • where條件的字段,儘可能用區別度高的字段,這樣走索引的性能更好

  • 出現子查詢的SQL,先確認MySQL版本,利用explain確認執行計劃

  • 進行分頁優化;DML時候多個value合併

 

Schema Review:

 

1)字符集問題

 

表字符集選擇UTF8 ,若是須要存儲emoj表情,就改爲UTF8mb4

 

2)Schema設計原則

 

  • 核心表字段數量儘量地少,有大字段要考慮拆分

  • 適當考慮一些反範式的表設計,增長冗餘字段,減小JOIN

  • 資金字段考慮統一*100處理成整型,避免使用decimal浮點類型存儲

  • 日誌類型的表能夠考慮按建立時間水平切割,按期歸檔歷史數據

 

3)Schema設計目標

 

  • 快速實現功能爲主,保證節省資源

  • 平衡業務技術各個方面,作好取捨

  • 不要在DB裏進行大計算,減小複雜操做

 

總體來講,這部分規範仍是很容易遵照的,實現起來也沒有什麼難度,就能取得很好的效果。

 

2、運維規範

 

(1)SQL審覈

 

SQL評審這部分工做相信讓不少的DBA同窗都叫苦連天,人肉審覈不只效率低下,容易出錯,對DBA的自身發展也很是不利,難道咱們來上班就是爲了審覈SQL的嗎?在通過了一段痛苦的人肉審覈以後,咱們接入了去哪兒網開源的Inception,並根據自身的業務特色作了一些調整。固然如今開源的SQL評審軟件已經不少了,你們能夠自由選擇,也能夠自行開發。

 

在審覈與執行上線DDL語句的時候,要注意MySQL官方原生Online DDL和Percona公司的pt-osc之間的一些差別,例如pt-osc在執行時每次都要copy全表,相對來講比較慢,好處是不鎖表,而且有完善的條件檢測和延時負載策略控制。官方Online DDL雖然官方也一直在改進,但生產環境使用還不是很完美,尤爲要注意執行過程當中容易致使MDL鎖。官方Online DDL也有優於pt-osc的地方,好比增刪索引,重命名列等,以下圖所示。

 

 

(2)權限控制

 

MySQL從5.6開始,逐步完善了權限系統,好比MySQL5.6能夠安裝檢查密碼強度的插件,5.7開始增長了密碼過時機制、帳戶鎖定等功能,對SSL這一塊也作了一些優化,8.0版本增長了角色的功能,權限系統已經逐步在向Oracle數據庫靠攏了。在平常運維中,也可使用pt-show-grants工具提升權限審查的力度。應用程序帳號應只賦予SELECT、INSERT、UPDATE權限,DELETE的邏輯改用UPDATE實現,並啓用sql_safe_updates選項。

 

另外一個有效控制權限的方法就是SQL堡壘機,早期咱們經過改造MyWebSQL實現,在Web版客戶端的基礎上加入了一些資源控制策略、審計、語法校驗等功能。後續又使用Python開發了功能更完備的SQL堡壘機,同時支持MySQL、Oracle、Greenplum等數據庫。

 

 

 

SQL堡壘機不只可控制公司內部人員的數據庫權限,追溯各種人員對數據庫的操做,也能避免大查詢或全表更新的狀況發生,支持審計需求,總體運維質量提高了一個臺階。

 

(3)MySQL版本選擇

 

  • MySQL社區版,用戶羣體最大

  • MySQL企業版,收費

  • Percona Server版,新特性多,和MySQL社區版最接近

  • MariaDB版,國內用戶暫時很少

  • 選擇優先級:MySQL社區版> Percona Server > MariaDB > MySQL 企業版

 

對於版本選擇這件事,建議你們仍是跟進官方社區版比較好,目前比較穩定的版本是MySQL5.6,推薦你們使用。有特殊需求的話再選擇MySQL5.七、PXC、TiDB、TokuDB等數據庫。

 

2、MySQL高可用架構選型

 

MySQL高可用方面,目前業界主流依然是基於異步複製的技術,例如Keepalived、MHA、ZooKeeper等,要求數據強一致的場景逐步開始使用分佈式協議,這方面的典型表明有PXC、Group Replication、TiDB。下面咱們就重點來講說keepalived、MHA和PXC這幾種你們用得比較多的架構。

 

1、keepalived高可用架構

 

 

業內使用很是廣泛,它部署容易、方便維護,還節省服務器資源。這種架構的一個好處就是在發生切換後,原Master只需從新拉起來便可恢復高可用,不須要過多幹預。擴展起來也方便,能夠任意掛載只讀庫和災備庫。但它存在的問題也很明顯,好比Keepalived的檢測機制不完善、有腦裂隱患、數據一致性較弱等等。

 

還須要注意主從拓撲的設計。以下圖,只讀庫掛到哪一個Master比較合適?顯然是M2,其它兩種拓撲在發生切換後都會影響到只讀庫的訪問。

 

 

2、MHA

 

 

MHA自誕生以來,就獲得了業內的普遍關注,並迅速流行開來。與keepalived相比,MHA最大的優勢就是在發生故障切換以後,能自動補齊binlog,最大程度保證數據一致性。從服務器能自動切換,無需人工干預,能很是好的工做在讀寫分離的環境下。基於Perl語言的腳本也很是方便進行二次開發。MHA很是適合讀寫壓力比較大的應用。

 

但因爲MHA在工做時須要配置SSH互信,所以選擇這種架構時內網安全必定要作到位。另外也能夠搭配Binlog Server使用。

 

3、PXC

 

 

PXC全稱是Percona XtraDB Cluster,是Percona公司基於Galera協議開發的一個產品。PXC犧牲了CAP裏面的P(Partition Tolerance),保留了C(Consistency )和A(Availability )。這種結構很是適合電商、金融類業務,自PXC和Group Replication出現之後,MySQL完全掃清了進入金融行業的障礙。

 

PXC的優點:

 

  • 同步複製,解決了傳統架構複製延遲和腦裂的問題

  • 數據強一致

  • 多主複製,每一個節點均可以讀寫數據

  • 並行複製,多個事務能夠並行推送到其餘節點

  • 高可用,單點故障不影響集羣可用性

  • 新節點自動部署

  • 與傳統MySQL幾乎徹底兼容

 

使用PXC要注意的問題:

 

  • 不要有大事務

  • 木桶效應,集羣性能取決於性能最差的那個節點

  • 併發效率有損失

  • 網絡要求較高,建議萬兆網絡

  • 多點併發寫時鎖衝突、死鎖問題多

  • 寫沒法擴展,沒法解決熱點更新問題

 

除此以外,還有一類採用DNS/ZooKeeper的高可用架構,這種架構一般都須要自行開發,無通用的方案,比較適合大規模集羣的高可用,這裏咱們不過多贅述。

 

下面簡單回顧一下上述幾種高可用架構:

 

  1. 雙Master架構:很是成熟,使用很廣泛,要注意延遲和數據的一致性。

  2. PXC: 分佈式協議,數據強一致性,併發效率略低,可用性好

  3. MHA:各項指標介於M-M和PXC之間,性能無損失,適合讀寫分離架構。

 

總而言之,沒有最完美的架構,只有最適合的架構。選擇適合本身業務的便可。

 

3、MySQL sharding拆分

 

接下來是第三個議題,MySQL拆分原則和分庫分表設計。

 

首先先提一個問題,爲何要拆,不拆不行嗎?按照咱們的經驗來看,當數據和業務到了必定的規模,都不可避免的要面臨分庫分表的問題。這就好像汽車的發動機同樣,要達到更高的性能,4缸6缸明顯是不夠用的,V八、V12纔是王道。

 

拆分能解決以下幾個問題:

 

  • 單庫併發較大

  • 單庫物理文件太大

  • 單表過大,DDL沒法接受

  • 防止出現性能瓶頸,提高性能

  • 防止出現抖動不穩定現象

 

肯定要進行數據庫的拆分了,應該怎麼拆呢?

 

垂直拆分

 

優勢:

  • 拆分簡單明瞭,拆分規則明確

  • 應用程序模塊清晰,整合容易

  • 數據維護方便易行,容易定位

 

缺點:

  • 表關聯須要改到程序中完成

  • 事務處理變的複雜

  • 熱點表還有可能存在性能瓶頸

  • 過分拆分會形成管理複雜

 

水平拆分

 

優勢:

  • 不會影響表關聯、事務操做

  • 超大規模的表和高負載的表能夠打散

  • 應用程序端改動比較小

  • 拆分能提高性能,也比較易擴展

 

缺點:

  • 數據分散,影響彙集函數的使用

  • 切分規則複雜,維護難度增長

  • 後期遷移較複雜

 

要先分庫仍是先分表?

 

  • 分庫的優勢:實現簡單,庫與庫之間界限分明,便於維護,缺點是不利於頻繁跨庫操做,單表數據量大的問題解決不了。

  • 分表的優勢:能解決分庫的不足點,可是缺點偏偏是分庫的優勢,分表實現起來比較複雜,特別是分表規則的劃分,程序的編寫,以及後期的數據庫拆分移植維護。

 

一巴掌拍板直接選分庫或分表都是不可取的,主要是看須要達到什麼樣的擴展方式,才能決定先分庫仍是先分表,根據具體的場景決定。分庫分表的最終目的仍是爲了擴展,並且要看拆分的規劃設計是針對哪一層。

 

上述問題都解決了,該考慮如何實現了,究竟是在應用程序中實現,仍是使用中間件?我的建議若是是小規模的拆分,直接在程序邏輯中實現便可,大規模的拆分再考慮使用各類中間件。

 

目前業內已經開源了不少的MySQL中間件產品,例如Atlas、DBProxy、MyCAT、OneProxy、DRDS、Vitess等等,每一箇中間件都有本身的特色,個別不太成熟的可能會存在一些Bug,選用以前要作好相關的調研與測試工做,上線使用必定要保證本身能hold住。若是要徹底貼合自身業務,而且掌控得較好的仍是要自行開發。

 

下面說說咱們的拆分經驗。

 

首先咱們先在壓力比較大的數據庫上作垂直拆分,剝離出活動、後臺統計等業務。這一步也是最容易實現的。

 

接下來,若是是消息類的數據,就基於時間維度進行拆分,單表控制在5-10G,行數控制到500-1000w這個樣子。這個時候咱們發現數據庫的性能是比較好的,並且比較好維護。若是是用戶類的數據,就按照Hash或Range進行拆分。這種狀況下用這種方法拆分會拆的比較均勻一些。

 

併發仍然比較高怎麼辦?能夠在時間維度拆分的基礎上再按Range或Hash進行拆分。

 

最後要注意的就是不要過分的拆分,會形成複雜度的上升。Schema設計合理的狀況下,10億的數據量也能跑的好好的。個別不關鍵的應用,例如日誌、監控數據等,使用分區表、TokuDB也能抗。拆分對應用層老是有損的。

 

要作個「懶」DBA。

 

 

4、利用NoSQL爲MySQL減壓

 

最後一個議題,咱們聊一聊NoSQL。NoSQL如今遍地開花,應用也很普遍了,業內用的比較多的主要集中在Redis、MongoDB、Cassandra等NoSQL數據庫上。今天咱們主要來講說和MySQL關聯最爲密切的Redis。

 

爲何要使用Redis?

 

  • 數據存儲在內存中,訪問速度快

  • 能支持大批量操做及爆發性負載

  • 數據結構豐富,有效緩解MySQL壓力

  • 協議簡單,支持各類語言的API

  • 存儲大量數據無需擔憂性能

 

Redis主要做用仍是抗讀的壓力。讀操做先到Redis,Redis中取不到再從MySQL數據庫訪問,從MySQL讀取到數據後,還要回寫到Redis。

 

使用Redis要注意的幾點:

 

性能方面,因爲Redis徹底是基於內存的訪問,性能無需擔憂。

 

在使用Redis時,要注意Cache 和Storage不要混合使用。不要依賴Redis的持久化,持久化這一塊Redis要努力的還不少。另外若是你把Redis拿來作Storage的話,一旦Redis的內存跑滿,那就慘了,全部的Redis鏈接都會卡着不響應。若是隻是把Redis來作cache的話,那問題就不大。

 

還有諸如緩存穿透、緩存雪崩、熱點key重建時緩存失效這些問題也是重點關注的對象。

 

如何利用Redis給MySQL加速:

 

1)利用K/V結構,緩存結果,例如存儲用戶信息、全局排行、統計信息等。

2)利用其豐富的數據結構爲MySQL減壓,例如計數器、排序、Hash(把表映射到Redis中)、消息隊列等。

 

總結

 

 

 

系統架構設計是一個長期總結與進化的過程,講究均衡與取捨。在進行大規模MySQL架構設計的過程當中,除了要汲取別人的經驗以外,還要關注各類架構背後的業務場景與架構思想,與本身的實際業務場景相結合,才能設計出一個好的系統架構來。

相關文章
相關標籤/搜索