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的高可用架構,這種架構一般都須要自行開發,無通用的方案,比較適合大規模集羣的高可用,這裏咱們不過多贅述。
下面簡單回顧一下上述幾種高可用架構:
雙Master架構:很是成熟,使用很廣泛,要注意延遲和數據的一致性。
PXC: 分佈式協議,數據強一致性,併發效率略低,可用性好
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架構設計的過程當中,除了要汲取別人的經驗以外,還要關注各類架構背後的業務場景與架構思想,與本身的實際業務場景相結合,才能設計出一個好的系統架構來。