分佈式架構 Mysql優化及高可用

分佈式架構 Mysql優化及高可用


特點介紹

  • Mysql是一個關係型數據庫管理系統,分爲社區版和商業版,由於其體積小、速度快、總體擁有成本低
  • 源碼開放,不需要支付額外的費用
  • 適用於中小型網站數據庫
  • 爲多種編程語言提供了 API,支持多個操作系統使用
  • 支持多線程,充分利用 CPU 資源
  • 提供用於管理、檢查、優化數據庫操作的管理工具
  • 支持多種存儲引擎(MyISAM、查詢/插入快,不支持事物,InnoDB 插入慢 支持ACID事務,支持行級鎖定)

Mysql 優化思路

  • 表設計合理化
  • 索引優化(添加適當索引[四種: 普通索引、主鍵索引、唯一索引unique、全文索引])
  • Mysql配置優化 (配置最大併發數my.ini)
  • SQL查詢優化
  • Mysql服務器硬件升級
  • 定時的去清除不需要的數據,定時進行碎片整理

Mysql 優化步驟

表設計合理化

  • 1.字符集的選擇 如果確認全部是中文,不會使用多語言以及中文無法表示的字符,那麼選GBK,只需要2個字節 UTF-8編碼會佔用3個字節

  • 2.表的存儲引擎(查詢/插入快,不需要事物支持,可用MyISAM、需要事物可用 InnoDB,不支持全文索引),MyISAM適合SELECT密集型的表,而InnoDB適合INSERT和UPDATE密集型的表

  • 3.如果一個表有許多的列,但平時參與查詢和彙總的列卻並不是很多,此時可以考慮將表格拆分成2個表,一個是常用的字段,另一個是很少用到的字段

  • 4.BLOB和CLOB 此類字段一般數據量很大,建議設計上數據庫可以只保存其外部連接,而數據以其它方式保存,比如系統文件

  • 5.就是用空間換取時間。如果大表查詢裏經常要join某個基礎表,且這個數據基本不變,比如人的姓名,城市的名字等。一旦基礎表發生變動,
    則需要更新所有涉及到的冗餘表

  • 6 合理構建分區表,分區策略(Range/List/Hash/Key)

  • 7 如果預期長度範圍varchar就滿足,就避免使用TEXT,表數據量越大,讀取越慢,(Mysql 是行存儲模式,所以會把整行讀取出來,text 儲存了大量的數據。讀取時,佔了大量的io開銷)

  • 8.儘量使用TIMESTAMP而非DATETIME

索引優化( (mysql單表最大索引數量爲16,建議4-8之間)

  • 1.儘可能使用長度短的主鍵,在主鍵上無需建單獨的索引,因爲系統內部爲主鍵建立了聚簇索引,允許在其它索引上包含主鍵列
  • 2.外鍵會影響插入和更新性能,對於批量可靠數據的插入,儘可能用選用對應主表的主鍵作作爲外鍵,外鍵是默認加上索引的
  • 3.優先創建複合索引,效果大於單索引
  • 4.經常需要檢索查詢、排序建議建立索引
  • 5.mysql強制使用指定索引查詢 (select * from table_name force index (index_name) where conditions;)
  • 6.創建索引時,需要指定合適長度,其長度直接影響索引文件的大小,因此會影響增刪改查的速度
    如 zachary_goods 商品表,title字段長度255,通過本地執行計劃
    explain select id,title from zachary_goods where title=“測試商品”;

±—±------------±----------±-----±--------------±------------±--------±------±-----±-------------------------+

| id | select_type | table | type | possible_keys | key |
key_len | ref | rows | Extra |

±—±------------±----------±-----±--------------±------------±--------±------±-----±-------------------------+

| 1 | SIMPLE | zachary_goods | ref | index_title |
index_title | 150 | const | 1 | Using where; Using index |

±—±------------±----------±-----±--------------±------------±--------±------±-----±-------------------------+

其中key_len 爲150過長這樣當更新時是比較佔內存的
設置區分度高的並且長度適合的索引
select count(distinct left(title,total))/count(*) from zachary_goods;
total是指截取的長度,實際上也可以發現設置該長度的查詢度,比例越大說明越良好
通過測試發現索引長度30最佳
alter table zachary_goods add index index_title(title(30));

執行計劃介紹

1.select_type: SIMPLE – 查詢類型(簡單查詢、聯合查詢、子查詢)
2.table: user – 顯示這一行的數據是關於哪張表的
3.type: range – 區間索引(在小於1990/2/2區間的數據),這是重要的列,顯示連接使用了何種類型。從最好到最差的連接類型爲system > const > eq_ref > ref > fulltext > ref_or_null > index_merge > unique_subquery > index_subquery > range > index > ALL,const代表一次就命中,ALL代表掃描了全表才確定結果。一般來說,得保證查詢至少達到range級別,最好能達到ref
4.possible_keys: birthday – 指出MySQL能使用哪個索引在該表中找到行。如果是空的,沒有相關的索引。這時要提高性能,可通過檢驗WHERE子句,看是否引用某些字段,或者檢查字段不是適合索引
5.key: birthday – 實際使用到的索引。如果爲NULL,則沒有使用索引。如果爲primary的話,表示使用了主鍵
6.key_len: 4 – 最長的索引寬度。如果鍵是NULL,長度就是NULL。在不損失精確性的情況下,長度越短越好
7.ref: const – 顯示哪個字段或常數與key一起被使用
8.rows: 1 – 這個數表示mysql要遍歷多少數據才能找到
9.Extra: Using where; Using index – 執行狀態說明,這裏可以看到的壞的例子是Using temporary和Using

SQL查詢優化

  • 1.可通過開啓慢查詢日誌來找出較慢的SQL
  • 2.sql語句儘可能簡單:一條sql只能在一個cpu運算;大語句拆小語句,減少鎖時間;一條大sql可以堵死整個庫
  • 3.不用SELECT *,羅列相關字段,減少資源開銷
  • 4.OR改寫成IN:OR的效率是n級別,IN的效率是log(n)級別,in的個數建議控制在200以內
  • 5.避免like %xxx式查詢,全表掃描
  • 6.儘量避免在WHERE子句中使用!=或<>操作符,否則將引擎放棄使用索引而進行全表掃描
  • 7.對於連續數值,使用BETWEEN不用IN
  • 8.列表數據不要拿全表,要使用LIMIT來分頁,每頁數量也不要太大

Mysql配置優化

  • 1.修改MySQL客戶端的數據庫連接閒置最大時間值 wait_timeout參數值,由默認的8小時,修改爲30分鐘,wait_timeout=1800(單位秒)
    通過命令show variables like 'wait_timeout’查看結果值
  • 2.修改back_log參數值:由默認的50修改爲500(每個連接256kb),back_log值指出在MySQL暫時停止回答新請求之前的短時間內多少個請求可以被存在堆棧中
  • 3.修改max_connections參數值,修改爲3000;max_connections=3000,
    max_connections是指MySql的最大連接數,如果服務器的併發連接請求量比較大,建議調高此值,以增加並行連接數量
  • 4.修改thread_concurrency值,thread_concurrency應設爲CPU核數的2倍

Mysql常見問題分析及處理

  1. Mysql死鎖(非主鍵索引更新引起的死鎖)
    死鎖一般會拋出MySQLTransactionRollbackException: Deadlock found when trying to get lock; try restarting transaction
    主鍵更新,Mysql會鎖住主鍵索引,非主鍵索引更新時;Mysql會先鎖住非主鍵索引,再鎖定主鍵索引
    如:update zachary_goods set status=‘CHECKED’ where title=“測試商品”,Mysql會執行以下過程
    1.由於用到了非主鍵索引,首先需要獲取index_title上的行級鎖
    2.獲取鎖成功後根據主鍵進行更新,所以需要獲取主鍵上的行級鎖
    3.更新完畢後,提交,並釋放所有鎖
    那麼死鎖如何產生呢?,如上SQL再執行1.2之間時,突然外界執行了 update zachary_goods set status=‘CHECKED’ where id=1 AND
    同樣會先鎖住主鍵索引,然後鎖住非主鍵索引,此時此刻 上敘SQL等待主鍵鎖,下敘SQL等待非主鍵索引,就產生了死鎖
    處理方案
    1.默認更新時,先獲取需要更新的記錄的主鍵
    2.通過主鍵更新記錄避免死鎖

  2. Mysql 缺少索引的數據表更新引起的死鎖
    相關異常Error: ER_LOCK_WAIT_TIMEOUT: Lock wait timeout exceeded; try restarting transaction
    分析思考:
    原因是鎖等待超時,當前事務在等待其它事務釋放鎖資源造成的
    MySQL 默認的級別是 REPEATABLE READ(可重複讀),這表示在 MySQL 的默認情況下,“髒讀”、“不可重複讀” 是不會發生的。這就需要在更新的時候進行必要的鎖定(InnoDB 是採用行級鎖的方式),從而保證一致性
    InnoDB 的行鎖是通過給索引上的索引項加鎖來實現的,意味着只有通過索引條件檢索數據,其才使用行級鎖,否則,其 將使用表鎖
    執行SQL時候沒有給相關字段加索引導致鎖住了整個表,由於數據量大導致其它查詢本表處於等待鎖資源,而這個等待時間太久,導致超時了
    處理方案
    1.相關字段加索引
    2.text 字段做索引,所以必須選擇字段前多少位做索引,或者使用全文索引,InnoDB不支持全文索引

  3. Mysql多線程update發生死鎖
    相關異常Error updating database.
    Cause: com.mysql.jdbc.exceptions.jdbc4.MySQLTransactionRollbackException: Deadlock found when trying to get lock; try restarting transaction
    分析思考: 因爲行鎖是對索引加鎖,那麼當where語句中包含多個條件時候,mysql在生成執行計劃的時候實際上也只用到一個字段的索引(區分度最大的字段),所以即使where語句中包含多個字段,實際上也只使用了一個字段的索引,那麼根據這個字段進行過濾出來的記錄數可能就不止一條,這個可以通過explain查看到。
    當高併發的情況下,當兩個事務同時需要對同一個檢索的記錄進行更新操作時,由於其中一個事務把同一個檢索的所有記錄都鎖住了,
    那麼必然會導致另外一個事務無法獲取到鎖
    處理方案
    1.建立複合索引,對where條件中所用到的所有的字段共同構建一個複合索引
    2.再次執行explain,發現這個時候確實只鎖住了一條記錄,問題解決

Mysql優化過程(千萬級別數據)

讀寫分離:

04
主從複製過程:
02

一主多從:
1

級聯複製:

2

  • 1.當傳統單節點數據庫由於負載過高,數據量大,查詢緩慢,此時優化思路 可以做主從、讀寫分離
  • 2.所謂讀寫分離,1個主節點用於寫數據,把讀數據分流到1個從節點。從而提高節點利用率、緩解數據庫壓力
  • 3.以上方案可以撐一段時間,當數據量持續加大後,以上方案已經到達瓶頸後,這個時候分析寫數據/讀數據哪個有瓶頸?
  • 4.如果讀數據有瓶頸後,可以優化成,1主多從,從節點做負載均衡。mysql的binlong同步5個節點以上會存在性能問題,建議3-5個節點
    如果由於業務系統需要,必須要大於5個節點以上,建議使用 從節點掛載同步到從節點,減少主節點同步到從節點的性能耗損
  • 5.如果寫數據存在瓶頸,此時考慮表構造、索引優化
  • 6.當表構造、索引優化後併發已到瓶頸後,此時考慮分庫,由於mysql單庫存在最大併發限制(3000),提高併發、提高磁盤存儲率
  • 7.分庫後由於數據庫持續增大,索引優化到瓶頸後效果不好。此時考慮分區。分區相當於單庫的分表,
    Mysql支持多種分區算法,無嵌入程序。Mysql支持單庫最大分區1024,意味着可以分1024個區塊
  • 8.由於應用程序裏面各種統計算法、業務模式加大,此時單臺主節點數據庫已經到達瓶頸(分區不支持數據庫橫向擴展),此時考慮分表,
    由於分表會有很多潛在問題,維護成本高額、統計數據繁瑣、數據移植難度大等。筆者建議不到萬不得已不要走此步驟
  • 9.分表有效將大表橫向切分成小表,可分佈在多臺數據庫上。性能非常高。常用分表如(shared-jdbc,my-cat,mysql-proxy官網插件)

註明:如是對公司業務發展非常瞭解、業務清晰明瞭、數據量預估到位、風險評估到位可提前設計一步到位、否則就是過度爲了設計而設計
筆者建議,按照系統規模、業務場景逐漸優化改造,不要想着一步到位。

Mysql 高可用部署架構

  1. 由於Mysql的寫入單臺存在瓶頸,不管是主從複製、讀寫分離都不能完全有效利用服務器資源,並存在數據延遲的風險,數據不一致風險
    筆者推薦一款開源好用的插件 Galera Cluster
    04

    簡單說明就是Mysql集羣,和主從結構稍有不同,集羣中都是主節點,都可以讀寫操作,當客戶端寫入到某臺數據庫後,
    實時自動同步新數據同步到其它節點上面,這種架構不共享任何數據,是一種高冗餘架構。 它能解決Mysql如下問題
    1.多主架構:真正的多點讀寫的集羣,在任何時候讀寫數據,都是最新的,充分利用服務器資源
    2.同步複製:集羣不同節點之間數據同步,沒有延遲,在數據庫掛掉之後,數據不會丟失
    3.併發複製:從節點在APPLY數據時,支持並行執行,有更好的性能表現
    4.故障切換:在出現數據庫故障時,因爲支持多點寫入,切的非常容易

總結

Mysql優化根據業務場景逐漸優化,不要盲目過度設計優化,根據系統業務情況採用適合數據庫進行業務處理,傳統數據庫可以和Nosql數據庫共存,分別使用它的優化,讓系統業務更加穩健運行

作者簡介:張程 技術研究

更多文章請關注微信公衆號:zachary分解獅 (frankly0423)

在這裏插入圖片描述

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章