高性能MySQL梳理總結(jié)

cover.png

一、基礎(chǔ)

  1. 邏輯架構(gòu)圖


    邏輯架構(gòu).png
    1. 連接層:不是Mysql獨(dú)有,連接處理、授權(quán)認(rèn)證、安全等
    2. 服務(wù)層:核心服務(wù),包括查詢緩存、解析、分析、優(yōu)化、執(zhí)行,還包括所有跨存儲(chǔ)引擎的功能:存儲(chǔ)過(guò)程、觸發(fā)器、視圖等
    3. 引擎層:負(fù)責(zé)數(shù)據(jù)的存儲(chǔ)與提取,不同的存儲(chǔ)引擎都有各自的優(yōu)劣勢(shì)
    4. 所有子系統(tǒng)間共享的通用函數(shù);基于線程資源的管理的體系結(jié)構(gòu);提高查詢速度減少IO次數(shù)的緩存;維護(hù)全部會(huì)話與通訊的網(wǎng)絡(luò)管理;管理所有數(shù)據(jù)、操作、慢查詢、訪問(wèn)等日志的系統(tǒng);數(shù)據(jù)文件與存儲(chǔ)方式、格式、位置的管理系統(tǒng);
  2. 事務(wù)
    事務(wù)是一組原子性的SQL查詢,或者是一個(gè)獨(dú)立的工作單元,事務(wù)內(nèi)的語(yǔ)句,要么全部執(zhí)行成功,要么全部失敗

    1. 原子性(atomicity)
      不可分割的最小單元,要么全部提交、要么全部回滾
    2. 一致性(consisitency)
      總是從一個(gè)一致性的狀態(tài)轉(zhuǎn)換到另一個(gè)狀態(tài),
    3. 隔離性(isolation)
      在提交前,對(duì)其他事務(wù)不可見(jiàn)(不一定,受隔離級(jí)別影響)
    4. 持久性(durability)
      一旦提交,會(huì)永久保存到數(shù)據(jù)庫(kù)中

    Mysql 事務(wù)默認(rèn)是AutoCommit
    查看是否開(kāi)啟自動(dòng)提交:SHOW VARIABLES LIKE 'AUTOCOMMIT'
    設(shè)置自動(dòng)提交:SET AUTOCOMMMIT = 1/0

  3. 隔離級(jí)別
    對(duì)于多個(gè)并發(fā)執(zhí)行的事務(wù),在操作相同的數(shù)據(jù)時(shí),可能發(fā)生數(shù)據(jù)不一致等問(wèn)題,隔離級(jí)別可以避免這一問(wèn)題

隔離級(jí)別(Isolation Level) 臟讀(Dirty Read) 不可重復(fù)讀(Non Repeatable Read) 幻讀(Phantom Read)
未提交讀(Read UnCommmitted) ? ? ?
提交讀(Read Committed) ? ? ?
可重復(fù)讀(Repeatable Read) ? ? ?
串行化(Seriallzable) ? ? ?
  1. Read UnCommitted
    可以讀取其他事務(wù)未提交的數(shù)據(jù)
  2. Read Committed
    只能讀取已經(jīng)提交事務(wù)的修改,一個(gè)事務(wù)中,可能倆次讀取的數(shù)據(jù)是不同的;大多數(shù)(不包括Mysql)數(shù)據(jù)庫(kù)的默認(rèn)隔離級(jí)別,
  3. Repeatable Read
    在一個(gè)事務(wù)中,多次讀取相同數(shù)據(jù)是一致的,但是會(huì)出現(xiàn)幻讀(在范圍查詢時(shí),可能有新數(shù)據(jù)插入,導(dǎo)致讀取的行數(shù)不一致),InnoDB & XtraDB存儲(chǔ)引擎通過(guò)多版本控制來(lái)解決
  4. Serializable
    會(huì)在每行數(shù)據(jù)上都加鎖,強(qiáng)制事務(wù)串行化,導(dǎo)致的問(wèn)題:大量的超時(shí)、鎖競(jìng)爭(zhēng)、并發(fā)能力低,實(shí)際中很少用

設(shè)置隔離級(jí)別
全局:SET TRANSACTION ISOLATION LEVEL READ COMMITTED;
當(dāng)次會(huì)話有效:SET SESSION TRANSACTION ISOLATION LEVEL READ COMMITTED;

  1. 日志
    • binLog (二進(jìn)制日志)
      1. 通過(guò)追加的方式記錄寫(xiě)入性操作日志,以而精致的方式保存在磁盤(pán)中,是mysql的邏輯日志,由Server層進(jìn)行記錄,使用任何引擎都會(huì)記錄binlog日志
      2. 作用:主從復(fù)制、數(shù)據(jù)恢復(fù)
      3. 寫(xiě)入時(shí)機(jī):事務(wù)提交時(shí)記錄binlog,通過(guò)sync_binlog控制,0(不強(qiáng)制要求,由系統(tǒng)判斷何時(shí)寫(xiě)入)、1(每次commit都寫(xiě)入binlog)、N(每N個(gè)事務(wù),寫(xiě)入一次binlog)
      4. 日志格式:
        1. Statment(5.7.7前默認(rèn)):基于SQL語(yǔ)句的復(fù)制,每一條修改都會(huì)記錄到binlog
          優(yōu)點(diǎn):不需要記錄每一行的變化,減少binlog,節(jié)約IO,提高性能
          缺點(diǎn):有些情況會(huì)導(dǎo)致數(shù)據(jù)不一致,sysdate(),sleep()等、串行化執(zhí)行
        2. Row(5.7.7默認(rèn)):基于行的復(fù)制,記錄那條數(shù)據(jù)被修改了
          優(yōu)點(diǎn):不會(huì)出現(xiàn)某些特定情況下的存儲(chǔ)過(guò)程、function、的調(diào)用和觸發(fā)無(wú)法被正確復(fù)制ide問(wèn)題、不需要穿行執(zhí)行,減少鎖的使用
          缺點(diǎn):會(huì)產(chǎn)生大量的日志,尤其是alter table;
        3. Mixed:Statment & Row的混合,一般使用Statment,不能的使用Row
    • redoLog(事務(wù)日志):
      1. 記錄數(shù)據(jù)頁(yè)的變更,保證事務(wù)一致性,提交事務(wù)時(shí),將該事務(wù)涉及到的數(shù)據(jù)修改全部刷新到磁盤(pán)中
      2. 構(gòu)成:主要包括倆部分:1. 日志緩存;2. 日志問(wèn)價(jià);每執(zhí)行一條DML,先寫(xiě)入緩存,后續(xù)某個(gè)時(shí)間點(diǎn),一次性將多個(gè)操作寫(xiě)到文件,這種先寫(xiě)緩存,后寫(xiě)文件的方式就是WAL技術(shù);

對(duì)比:

redo log binlog
文件大小 固定 通過(guò)max_binlog_size 設(shè)置每個(gè)文件的大小
實(shí)現(xiàn)方式 InnoDB獨(dú)有 Server層實(shí)現(xiàn)
記錄方式 循環(huán)寫(xiě)的方式記錄,寫(xiě)到結(jié)尾時(shí),回到開(kāi)頭循環(huán)寫(xiě) 追加的方式
適用場(chǎng)景 適用于奔潰恢復(fù)(crash-safe) 使用于主從復(fù)制和數(shù)據(jù)恢復(fù)

binlog適用于歸檔,只依靠binlog是沒(méi)有crash-safe能力的,同時(shí)只有redolog也是不行,是InnoDB獨(dú)有,日志記錄落盤(pán)后會(huì)被覆蓋掉,同時(shí)保證服務(wù)宕機(jī)重啟可以快速恢復(fù),同時(shí)也是實(shí)現(xiàn)MVCC的實(shí)現(xiàn)關(guān)鍵;

  • undoLog(事務(wù)日志):
    提供回滾 & MVCC : insert -> delete
  • 慢查詢?nèi)罩荆?br> slow_query_log:默認(rèn)是OFF,可以捕獲執(zhí)行時(shí)間超過(guò)閾值的SQL語(yǔ)句
    long_query_time: 執(zhí)行時(shí)間的閾值,默認(rèn)是10s,
    slow_query_log_file:日志文件名
    log_queries_not_using_indexes:捕獲所有未使用索引的查詢
  1. 多版本控制(MVCC---Multi-Version Concurrency control)

    1. 簡(jiǎn)介:基于鎖的并發(fā)控制,通過(guò)版本號(hào),避免同一數(shù)據(jù)在不同事務(wù)間的競(jìng)爭(zhēng)(基于版本的樂(lè)觀鎖),在InnoDB存在,為了實(shí)現(xiàn)事務(wù)的隔離性,在Read Committed和Pereatable Read隔離級(jí)別生效,讀不加鎖,讀寫(xiě)不沖突,提高并發(fā)性能
    2. 實(shí)現(xiàn)方式:樂(lè)觀并發(fā)控制,悲觀并發(fā)控制
    3. 實(shí)現(xiàn)原理:InnoDB在每行都有三個(gè)隱藏字段
      DB_ROW_ID(行號(hào)):六個(gè)字節(jié),遞增行ID,
      DB_TRX_ID(創(chuàng)建版本號(hào)):六個(gè)字節(jié),最后一次修改本行記錄的事務(wù)ID,
      DB_ROLL_PTR(回滾版本號(hào)):七個(gè)字節(jié),回滾撤銷日志的記錄ID
      通過(guò)undoog & readview實(shí)現(xiàn),倆種隔離級(jí)別的區(qū)別是生成的ReadView的時(shí)機(jī)不同,RC中,每次查詢都會(huì)生成一個(gè)實(shí)時(shí)的ReadView,保證每次提交后的數(shù)據(jù)是處于當(dāng)前的可見(jiàn)狀態(tài);RR中,當(dāng)前事務(wù)第一次查詢時(shí)生成當(dāng)親的ReadView,并且當(dāng)前的ReadView會(huì)一直沿用到當(dāng)前事務(wù)的提交,以此來(lái)保證可重復(fù)讀;

  2. 鎖保證數(shù)據(jù)并發(fā)訪問(wèn)的一致性、有效性的重要手段,MySQL服務(wù)器層,存儲(chǔ)引擎層做并發(fā)控制,

    1. 共享鎖:別的事務(wù)可讀,但是不能寫(xiě):select * from table_name where .... lock in share mode
    2. 排他鎖:別的事務(wù)不可讀、不可寫(xiě): .............for update
    3. 行鎖:開(kāi)銷大,加鎖慢,會(huì)出現(xiàn)死鎖,鎖定粒度最小,發(fā)生沖突的概率小,并發(fā)度高,
    4. 表鎖:開(kāi)銷小,加鎖快,不會(huì)出現(xiàn)死鎖,鎖定粒度大,發(fā)生沖突概率大,并發(fā)能力低,
    5. 頁(yè)面鎖:開(kāi)銷間于行鎖& 表鎖間,會(huì)出現(xiàn)死鎖,并發(fā)讀一般
    6. 間隙鎖:是InnoDB在RR級(jí)別下,為了解決幻讀引入的鎖機(jī)制,
    7. 樂(lè)觀鎖
    8. 悲觀鎖
  3. 磁盤(pán)存儲(chǔ)結(jié)構(gòu) & 文件管理
    InnoDB盡可能的使用異步IO,降低I/O操作和優(yōu)化磁盤(pán)文件,

    1. 預(yù)讀(Read-Ahead)
      當(dāng)InnoDB可以確定如果某些數(shù)據(jù)將可能被使用,則會(huì)執(zhí)行預(yù)讀操作,數(shù)據(jù)載入緩存池
    2. 雙寫(xiě)緩存區(qū)
      文件刷新技術(shù),提升當(dāng)數(shù)據(jù)庫(kù)奔潰或斷點(diǎn)后恢復(fù)的安全性,對(duì)于大多數(shù)unix系統(tǒng),通過(guò)減少fsync()調(diào)用來(lái)提升數(shù)據(jù)庫(kù)性能,默認(rèn)開(kāi)啟(innodb_doublewrite),在將頁(yè)面寫(xiě)入連續(xù)的表空間區(qū)域(雙寫(xiě)緩存區(qū)),只有在寫(xiě)并刷新雙寫(xiě)緩存區(qū)后,InnoDB才會(huì)將頁(yè)面寫(xiě)入數(shù)據(jù)文件中的正確位置,
    3. 頁(yè)面、擴(kuò)展區(qū)、段、表空間


      image.png
      • 段(Segment):包含數(shù)據(jù)段、索引段、回滾段等,,在InnoDB中,對(duì)段的管理是由引擎自身完成
      • 區(qū)(extent) :由連續(xù)的頁(yè)組成,無(wú)論頁(yè)的大小如何變,區(qū)的大小是固定的,默認(rèn)個(gè)1MB,為了保證區(qū)中頁(yè)的連續(xù)性,InnoDB一次從磁盤(pán)申請(qǐng)4 - 5個(gè)區(qū),頁(yè)的默認(rèn)為16kb,一個(gè)區(qū)一共64(1024/16) 16個(gè)連續(xù)的頁(yè);每個(gè)段開(kāi)始32頁(yè)大小的碎片頁(yè)來(lái)存儲(chǔ)數(shù)據(jù),使用完這些頁(yè)后,再申請(qǐng)64個(gè)連續(xù)的頁(yè),目的是,對(duì)于一些小表或undo類的段,可以開(kāi)始申請(qǐng)較小的空間,節(jié)省磁盤(pán)開(kāi)銷
      • 頁(yè)/塊(page):是InnoDB管理的最小單位,默認(rèn)16KB(innodb_page_size),常見(jiàn)的頁(yè)有數(shù)據(jù)頁(yè)、undo頁(yè)、系統(tǒng)頁(yè)、事務(wù)數(shù)據(jù)頁(yè)、插入緩存位圖頁(yè)、插入緩存空閑列表頁(yè)、未壓縮的二進(jìn)制大對(duì)象頁(yè)、壓縮的二進(jìn)制大對(duì)象頁(yè)
      • 行(row):數(shù)據(jù)都是按行存放的,每頁(yè)存放的行記錄都是有硬性定義的,最多允許存放16KB/2-200(7992行)
  4. Page 頁(yè)

    結(jié)構(gòu) & 大小 作用
    文件頭(38byte) 文件頭,描述頁(yè)的信息
    頁(yè)頭(56byte) 頁(yè)頭,頁(yè)的狀態(tài)信息
    最大最小記錄(26byte) 最小和最大記錄,虛擬的行記錄
    用戶記錄 用戶記錄,存儲(chǔ)行記錄內(nèi)容
    空閑空間 頁(yè)中沒(méi)有被使用的空間
    頁(yè)目錄 用戶記錄的相對(duì)位置
    文件尾(8byte) 校驗(yàn)頁(yè)是否完成
    1. 第一部分
      通用部分,主要指文件頭 & 文件尾,將頁(yè)的內(nèi)容進(jìn)行封裝,通過(guò)頭、尾校驗(yàn)CheckSum方式來(lái)確保頁(yè)的傳輸完整,來(lái)個(gè)字段FIL_PAGE_PREV & FIL_PAGE_NEXT指向上一頁(yè)、下一頁(yè),相當(dāng)于雙向列表,
    2. 第二部分
      記錄部分,存儲(chǔ)記錄,最大、最小記錄、用戶記錄占了頁(yè)的主要空間,新記錄插入時(shí),將從空閑列表中分配空間,一頁(yè)必須存儲(chǔ)兩行記錄,否則就不是B+tree,而是鏈表
    3. 第三部分
      索引部分,這里主要是指頁(yè)目錄,起到記錄索引的作用,在頁(yè)中,記錄是以單向鏈表的形式進(jìn)行存儲(chǔ),缺點(diǎn)就是檢索效率太低,在頁(yè)目錄中提供了二分查找的方式,將記錄分為若干組,包括最大、最小記錄,第一組:最小的一個(gè)記錄;最后一組:最大的記錄的分組,會(huì)有1-8條記錄,其余的組記錄數(shù)量在4-8條,頁(yè)目錄存儲(chǔ)每組最后一條記錄的地址偏移量,也被稱為槽(slot)
      如果是通過(guò)B+tree的索引記錄的,首先沖B+Tree樹(shù)的根開(kāi)始,逐層檢索,直到找到葉子節(jié)點(diǎn),也是找到數(shù)據(jù)頁(yè)為止,將數(shù)據(jù)頁(yè)加載到內(nèi)存中,頁(yè)目錄的槽采用二分查找的方式粗略的找到記錄分組,然后遍歷鏈表
  5. 執(zhí)行計(jì)劃(Explain)
    Explain會(huì)返回每一步信息,是查看查詢優(yōu)化器如何決定執(zhí)行查詢的主要方法,這個(gè)功能有局限性,并不是總會(huì)顯示真相,但是是最好的的信息,可以了解到底層是如何執(zhí)行的,

    1. 相關(guān)列說(shuō)明
      1. id:編號(hào)

      2. select_type:對(duì)應(yīng)行是簡(jiǎn)單或復(fù)雜查詢,
        SIMPLE:不包括子查詢和UNION;
        PRIMARY:有復(fù)雜的查詢,最外面標(biāo)記為PRIMARY;
        SUBQUERY:包含在Select列表中的子查詢中的Select(不在FORM子句中)
        DERIVED:用來(lái)表示包含在Form子句中的Select,mysql會(huì)遞歸執(zhí)行并將結(jié)果放到一個(gè)臨時(shí)表中(派生表),
        UNION:在Union中的第二個(gè)和稅后的Select標(biāo)記為Union,
        UNION RESULT:從Union的匿名臨時(shí)表檢索結(jié)果的Select

      3. table:訪問(wèn)的表名,或是別名

      4. type:訪問(wèn)類型
        all:全表掃描
        index:索引全表掃描,把索引從頭到尾掃一遍,與全表掃描一樣,只是按照索引次序掃描而不是行
        range:范圍掃描,有限制的索引掃描,
        ref:索引訪問(wèn),返回單值匹配的行,可能有多行,ref_or_null:二次查找,找出NULL條目
        index_merge:使用了倆個(gè)以上的索引,最后取交集或并集,常見(jiàn)and、or
        eq_ref:索引查找,最多返回一條記錄,
        index_subquery:in形式的子查詢,
        unique_subquery:where的in查詢
        fulltext:全文索引搜索
        const、system:能對(duì)查詢的某部分進(jìn)行優(yōu)化將其轉(zhuǎn)化為一個(gè)常量

        順序:system,const,eq_ref,ref,fulltext,ref_or_null,unique_subquery,index_subquery,range,index_merge,index,ALL,all不使用索引,index_merge多個(gè)索引

      5. possible_keys:查詢可以使用哪些索引,可以高效的查找

      6. key:采用那個(gè)索引優(yōu)化訪問(wèn),可以最小化查詢成本

      7. key_len:索引里使用的字節(jié)數(shù),單列索引就是長(zhǎng)度,多列是具體使用的和

      8. ref:在key列中查找值所用的列或常亮,如果使用的常數(shù)等值查詢,顯示const,

      9. rows:為了找到所需要行而要讀取的行數(shù)

      10. filtered:5.1新加進(jìn)去的,使用Explain Extended出現(xiàn),針對(duì)表里符合某個(gè)條件的記錄數(shù)的百分比所做的悲觀估算,

      11. extra: 不適合在其他列顯示的額外信息,
        Using index:使用覆蓋索引,
        Using where:在存儲(chǔ)引擎檢索后在在進(jìn)行過(guò)濾,
        Using temporary:在查詢結(jié)果排序時(shí),會(huì)使用一個(gè)臨時(shí)表
        Using filesort:對(duì)結(jié)果使用外部索引排序,而不是按索引次序從表里讀取行
        Range checked for each record : 沒(méi)有好用的索引,新的索引將在鏈接的每一行上重新估算

二、優(yōu)化

  1. 服務(wù)器
    相應(yīng)時(shí)間是定義性能最有效的方法,=對(duì)系統(tǒng)進(jìn)行新能剖析前,必須先進(jìn)行測(cè)量,5.5提供了Performance Schema,基于時(shí)間的一些測(cè)量,

    1. 性能剖析
      排名、總結(jié)、平均值,性能剖析、定期檢測(cè)都開(kāi)會(huì)帶來(lái)額外的開(kāi)銷,需要考慮開(kāi)銷與收益的比重
      • 哪些查詢值得優(yōu)化:占總相應(yīng)時(shí)間比重小的查詢不值得優(yōu)化,無(wú)論怎么優(yōu)化,效果都不明顯;優(yōu)化成本是否大于收益,如果是,應(yīng)該立即停止優(yōu)化
      • 異常情:有些異常情況會(huì)嚴(yán)重影響用戶體驗(yàn),但是總的響應(yīng)時(shí)間占比并不突出
      • 未知的時(shí)間丟失:丟失的時(shí)間是總的任務(wù)時(shí)間與實(shí)際測(cè)量時(shí)間的差,這里需要引起抵消,可能存在性能問(wèn)題
      • 被隱藏的細(xì)節(jié),性能剖析無(wú)法顯示所有的響應(yīng)時(shí)間的分布,只相信平均值非常危險(xiǎn),會(huì)隱藏很多細(xì)節(jié)而無(wú)法表達(dá)全部情況,
    2. 哪些因素會(huì)導(dǎo)致性能瓶頸
      • 外部資源調(diào)用
      • 應(yīng)用處理大量的數(shù)據(jù)
      • 循環(huán)中處理大量耗時(shí)操作,正則
      • 低效的算法
    3. 查詢剖析
      1. 慢查詢?nèi)罩臼情_(kāi)銷最低、精度最高的測(cè)量查詢時(shí)間的工具,在IO密集的場(chǎng)景,慢查詢的開(kāi)銷日志鹿晗可以忽略不計(jì),注意長(zhǎng)期開(kāi)啟慢查詢?nèi)罩?,要部署日志輪轉(zhuǎn)日志(log rotation),第一種:通過(guò)--processlist選項(xiàng),不斷通過(guò)show full processlist輸出,第二種:通過(guò)TCP抓包;
      2. 剖析語(yǔ)句:針對(duì)定位到的查詢,獲取更多的信息,
        • show status
          返回一些計(jì)數(shù)器,服務(wù)器級(jí)別的全局計(jì)數(shù)器、某個(gè)連接的會(huì)話級(jí)別的計(jì)數(shù)器,show global status,
        • show profile
          5.1后引入,默認(rèn)是禁用的,set profiling = 1; 測(cè)量其消耗的時(shí)間和其他一些查詢狀態(tài)變更的相關(guān)數(shù)據(jù),可能會(huì)被Performance Schema取代,
        • Performance Schema
        • show processlist:收集是否有線程處于不正常的狀態(tài),
  2. Schema & 數(shù)據(jù)類型

    1. 數(shù)據(jù)類型選擇

      • 最小的數(shù)據(jù)類型:一般使用正確的最小的數(shù)據(jù)類型,因?yàn)楦〉氖钦加么疟P(pán)更小、內(nèi)存、CPU緩存,更快;同時(shí)需要考慮增加數(shù)據(jù)類型的范圍是一個(gè)非常耗時(shí)和痛苦的操作
      • 簡(jiǎn)單的數(shù)據(jù)類型:簡(jiǎn)單的數(shù)據(jù)類型需要更少的CPU周期,例如:應(yīng)該用內(nèi)建的類型(日期而不是字符串)存儲(chǔ)日期,整型而不是字符串存儲(chǔ)IP
      • 盡量避免NULL:通常最好指定為NOT NULL,對(duì)于NULL列的優(yōu)化更難,Null的索引、索引統(tǒng)計(jì)、值比較都更加復(fù)雜,null的會(huì)使用更多的空間,特殊處理

      首先確定合適的類型,然后是選擇具體的類型(DateTime和Timestamp都是時(shí)間的,但是前者是后者存儲(chǔ)空間的二倍,后者會(huì)根據(jù)時(shí)區(qū)變化

    2. 數(shù)據(jù)類型

      • 整數(shù):TinyInt(8位)、SmallInt(16位)、MediumInt(24位)、Int(32位)、BigInt(64位),可選Unsigned有無(wú)符號(hào),對(duì)于int(5)對(duì)于存儲(chǔ)是沒(méi)有意義的,只是規(guī)定一些交互工具顯示的字符個(gè)數(shù);
      • 實(shí)數(shù): 有小數(shù)部分的數(shù)字,Decimal用于存儲(chǔ)精確的小數(shù),5.0后支持Decimal直接的計(jì)算,會(huì)將數(shù)字打包成二進(jìn)制字符串中(每4個(gè)字節(jié)存9個(gè)數(shù)字)Decimal(18,9),9個(gè)字節(jié),小數(shù)點(diǎn)占一個(gè),允許的最多65個(gè)數(shù)字;早起的版本中只是一種存儲(chǔ)格式,計(jì)算時(shí)會(huì)轉(zhuǎn)為Double;因?yàn)樾枰狣ecimal要使用額外的空間和計(jì)算開(kāi)銷,所以在
      • 字符串:Varchar可變的,比定長(zhǎng)節(jié)省空間(ROW_FORMAT=FIXED例外),需要使用1或2個(gè)字節(jié)記錄字符串長(zhǎng)度(長(zhǎng)度是否255),節(jié)省空間對(duì)性能有幫助,但是在update時(shí),如果比原來(lái)更長(zhǎng),會(huì)導(dǎo)致需要額外的工作,如果行占用的空間增長(zhǎng),并且在頁(yè)內(nèi)沒(méi)有跟多的空間,不同的引擎處理方式不同,MyISAM會(huì)將行拆成不同的片段存儲(chǔ),InnoDB需要分裂頁(yè)來(lái)使行可以放進(jìn)頁(yè)內(nèi);Varchar適用于最大長(zhǎng)度比平均長(zhǎng)度大很多,列的更新很少,所以碎片不是問(wèn)題;Char是定長(zhǎng)的,采用空格進(jìn)行填充,適合存儲(chǔ)很短的字符串,或者長(zhǎng)度相近的,比如MD5,經(jīng)常變動(dòng)的字符串也比Varchar更好,char不容易產(chǎn)生碎片,
      • Text/Blob:存儲(chǔ)更大的數(shù)據(jù),分別采用字符、二進(jìn)制方式存儲(chǔ),有TinyText、SmallText、Text、MediumText、LongText對(duì)應(yīng)的二進(jìn)制TinyBlob、SmallBlob、Blob、MediumBlob、LongBlob,Blob -> SmallBlob,Text -> SmallText,這些對(duì)象都有特殊的處理,在InnoDB中使用專門的*"外部"存儲(chǔ)區(qū)域進(jìn)行存儲(chǔ),需要1-4個(gè)字節(jié)存儲(chǔ)一個(gè)指針,然后在外部存儲(chǔ)實(shí)際的值,Blob(二進(jìn)制、沒(méi)有排序、沒(méi)有字符集),Text(字符、有排序、有字符集),排序?qū)ax_sort_length個(gè)字節(jié)排序,或者使用Order by Sustring(column,length);
      • Enum:有時(shí)候可以使用枚舉替代字符串,枚舉非常緊湊,會(huì)根據(jù)列表的值數(shù)量壓縮到一個(gè)或倆個(gè)字節(jié),
      • 日期 & 時(shí)間:mysql能存儲(chǔ)的最小的單位是秒,也可以使用微妙粒度進(jìn)行臨時(shí)運(yùn)算,提供兩種相似的Timestamp & DateTime,各有優(yōu)勢(shì),DateTime:范圍是1001 - 9999年,精度為秒,格式為:YYYYMMDDHHMMSS,與時(shí)區(qū)無(wú)關(guān),8個(gè)字節(jié)存儲(chǔ),TimeStamp:從1970- 2038年,精度為毫秒,使用四個(gè)字節(jié)存儲(chǔ),與時(shí)區(qū)有關(guān);后者比前者空間效率更高,
      • 位數(shù)據(jù):Bit:最長(zhǎng)64位,MyIsam打包所有的Bit列,當(dāng)做字符串類型,而不是數(shù)字類型,Set:保存多個(gè)true/false,可以合并到一個(gè)Set數(shù)據(jù)類型中,缺點(diǎn)是改變列的代價(jià)較高
      • 標(biāo)識(shí)符:MyIsam默認(rèn)對(duì)字符串使用壓縮索引,導(dǎo)致查詢慢的多,會(huì)有6倍的性能下降,對(duì)于隨機(jī)的字符串,新值會(huì)任意分布在很大的空間,會(huì)導(dǎo)致Insert以及一些Select會(huì)變慢,因?yàn)椴迦霑?huì)隨機(jī)寫(xiě)到索引的不同的位置,會(huì)導(dǎo)致列分裂、磁盤(pán)隨機(jī)訪問(wèn),以及對(duì)于聚簇存儲(chǔ)產(chǎn)生碎片,select會(huì)慢,因?yàn)檫壿嬒噜彽男袝?huì)分布在磁盤(pán)和內(nèi)存的不同的地方
    3. Schema設(shè)計(jì)

      • 太多的列:存儲(chǔ)引擎在服務(wù)器層、存儲(chǔ)引擎層之間通過(guò)行緩存格式數(shù)據(jù)拷貝,然后服務(wù)器層將緩存內(nèi)容解碼,這個(gè)這個(gè)過(guò)程代價(jià)是非常高的
      • 太多的關(guān)聯(lián):實(shí)體 -> 屬性 (EAV)設(shè)計(jì)模式是常見(jiàn)的非常糟糕的模式, Myslq限制最多關(guān)聯(lián)61張表,
      • 枚舉:注意防止過(guò)多使用枚舉,
      • Null:注意Null的合理使用
    4. 范式 & 反范式:通過(guò)遵守范式,可以設(shè)計(jì)關(guān)系型數(shù)據(jù)庫(kù),各種范式呈遞次規(guī)范,越高的范式數(shù)據(jù)庫(kù)冗余越小,些時(shí)候一昧的追求范式減少冗余,反而會(huì)降低數(shù)據(jù)讀寫(xiě)的效率,這個(gè)時(shí)候就要反范式,利用空間來(lái)?yè)Q時(shí)間。

      • 第一范式:即表的列的具有原子性,不可再分解,即列的信息,不能分解;
      • 第二范式:在第一范式的基礎(chǔ)上建立起來(lái)的,滿足第二范式必須先滿足第一范式。第二范式要求數(shù)據(jù)庫(kù)表中的每個(gè)實(shí)例或行必須可以被惟一地區(qū)分。為實(shí)現(xiàn)區(qū)分通常需要我們?cè)O(shè)計(jì)一個(gè)主鍵來(lái)實(shí)現(xiàn)(這里的主鍵不包含業(yè)務(wù)邏輯)
      • 第三范式:滿足第三范式必須先滿足第二范式。簡(jiǎn)而言之,第三范式要求一個(gè)數(shù)據(jù)庫(kù)表中不包含已在其它表中已包含的非主鍵字段。就是說(shuō),表的信息,如果能夠被推導(dǎo)出來(lái),就不應(yīng)該單獨(dú)的設(shè)計(jì)一個(gè)字段來(lái)存放(能盡量外鍵join就用外鍵join)。很多時(shí)候,我們?yōu)榱藵M足第三范式往往會(huì)把一張表分成多張表
      • 反范式:沒(méi)有冗余的數(shù)據(jù)庫(kù)未必是最好的數(shù)據(jù)庫(kù),有時(shí)為了提高運(yùn)行效率,就必須降低范式標(biāo)準(zhǔn),適當(dāng)保留冗余數(shù)據(jù)。具體做法是: 在概念數(shù)據(jù)模型設(shè)計(jì)時(shí)遵守第三范式,降低范式標(biāo)準(zhǔn)的工作放到物理數(shù)據(jù)模型設(shè)計(jì)時(shí)考慮。降低范式就是增加字段,減少了查詢時(shí)的關(guān)聯(lián),提高查詢效率,因?yàn)樵跀?shù)據(jù)庫(kù)的操作中查詢的比例要遠(yuǎn)遠(yuǎn)大于DML的比例。但是反范式化一定要適度,并且在原本已滿足三范式的基礎(chǔ)上再做調(diào)整的。
  3. 索引
    是存儲(chǔ)引擎用于快速找到記錄的一種數(shù)據(jù)結(jié)構(gòu)

    1. 優(yōu)點(diǎn)
      索引大大減小了服務(wù)器需要掃描的數(shù)據(jù)量
      索引可以幫助服務(wù)器避免排序和臨時(shí)表
      索引可以將隨機(jī)IO變成順序IO
      索引對(duì)于InnoDB(對(duì)索引支持行級(jí)鎖)非常重要,因?yàn)樗梢宰尣樵冩i更少的元組。在MySQL5.1和更新的版本中,InnoDB可以在服務(wù)器端過(guò)濾掉行后就釋放鎖,但在早期的MySQL版本中,InnoDB直到事務(wù)提交時(shí)才會(huì)解鎖。對(duì)不需要的元組的加鎖,會(huì)增加鎖的開(kāi)銷,降低并發(fā)性。 InnoDB僅對(duì)需要訪問(wèn)的元組加鎖,而索引能夠減少InnoDB訪問(wèn)的元組數(shù)。但是只有在存儲(chǔ)引擎層過(guò)濾掉那些不需要的數(shù)據(jù)才能達(dá)到這種目的。一旦索引不允許InnoDB那樣做(即索引達(dá)不到過(guò)濾的目的),MySQL服務(wù)器只能對(duì)InnoDB返回的數(shù)據(jù)進(jìn)行WHERE操作,此時(shí),已經(jīng)無(wú)法避免對(duì)那些元組加鎖了。如果查詢不能使用索引,MySQL會(huì)進(jìn)行全表掃描,并鎖住每一個(gè)元組,不管是否真正需要。
      關(guān)于InnoDB、索引和鎖:InnoDB在二級(jí)索引上使用共享鎖(讀鎖),但訪問(wèn)主鍵索引需要排他鎖(寫(xiě)鎖)

    2. 缺點(diǎn)
      雖然索引大大提高了查詢速度,同時(shí)卻會(huì)降低更新表的速度,如對(duì)表進(jìn)行INSERT、UPDATE和DELETE。因?yàn)楦卤頃r(shí),MySQL不僅要保存數(shù)據(jù),還要保存索引文件。
      建立索引會(huì)占用磁盤(pán)空間的索引文件。一般情況這個(gè)問(wèn)題不太嚴(yán)重,但如果你在一個(gè)大表上創(chuàng)建了多種組合索引,索引文件的會(huì)膨脹很快。
      如果某個(gè)數(shù)據(jù)列包含許多重復(fù)的內(nèi)容,為它建立索引就沒(méi)有太大的實(shí)際效果。
      對(duì)于非常小的表,大部分情況下簡(jiǎn)單的全表掃描更高效;
      索引只是提高效率的一個(gè)因素,如果你的MySQL有大數(shù)據(jù)量的表,就需要花時(shí)間研究建立最優(yōu)秀的索引,或優(yōu)化查詢語(yǔ)句。
      因此應(yīng)該只為最經(jīng)常查詢和最經(jīng)常排序的數(shù)據(jù)列建立索引。
      MySQL里同一個(gè)數(shù)據(jù)表里的索引總數(shù)限制為16個(gè)。

    3. 索引類型:

      • B-Tree索引:InnoDB使用的是B+Tree。
      • B+Tree:每一個(gè)葉子節(jié)點(diǎn)都包含指向下一個(gè)葉子節(jié)點(diǎn)的指針,從而方便葉子節(jié)點(diǎn)的范圍遍歷。

      B-Tree通常意味著所有的值都是按順序存儲(chǔ)的,并且每一個(gè)葉子頁(yè)到根的距離相同,很適合查找范圍數(shù)據(jù)。
      B-Tree可以對(duì)<,<=,=,>,>=,BETWEEN,IN,以及不以通配符開(kāi)始的LIKE使用索引。

    4. 匹配規(guī)則:全指匹配、最左前綴、匹配列前綴、匹配范圍值、精確匹配一列范圍匹配另一列

    5. 哈希索引:基于哈希表實(shí)現(xiàn),自由精確匹配索引所有的列查詢才有效,哈希索引只包含哈希值和行指針,而不存儲(chǔ)字段值,所以避免不了讀取行;不是按照順序存儲(chǔ),無(wú)法排序;不支持部分索引匹配查找,支持支等值比較;訪問(wèn)速度快,除非哈希沖突多,

    6. 自適應(yīng)哈希索引:InnoDB中某些索引值被頻繁使用時(shí),會(huì)在內(nèi)存中基于B-Tree索引上再創(chuàng)建一個(gè)哈希索引,

    7. 全文索引:查找全文中的關(guān)鍵詞

    8. 聚簇索引:是一種數(shù)據(jù)存儲(chǔ)方式,一個(gè)表只能有一個(gè)聚簇索引。將數(shù)據(jù)存儲(chǔ)與索引放到了一塊,找到索引也就找到了數(shù)據(jù),數(shù)據(jù)的物理存放順序與索引順序是一致的

    9. 非聚簇索引:將數(shù)據(jù)存儲(chǔ)于索引分開(kāi)結(jié)構(gòu),索引結(jié)構(gòu)的葉子節(jié)點(diǎn)指向了數(shù)據(jù)的對(duì)應(yīng)行,MyIsam通過(guò)key_buffer把索引先緩存到內(nèi)存中,當(dāng)需要訪問(wèn)數(shù)據(jù)時(shí)(通過(guò)索引訪問(wèn)數(shù)據(jù)),在內(nèi)存中直接搜索索引,然后通過(guò)索引找到磁盤(pán)相應(yīng)數(shù)據(jù),這也就是為什么索引不在key buffer命中時(shí),速度慢的原因

  4. 查詢

    1. Mysql優(yōu)化和執(zhí)行查詢過(guò)程
      061033331994784.png
    • 客戶端發(fā)送查詢到服務(wù)端
    • 服務(wù)器先檢查查詢緩存,如果命中,返回
    • 服務(wù)器進(jìn)行Sql解析、預(yù)處理、再由優(yōu)化器生成對(duì)應(yīng)的執(zhí)行計(jì)劃
    • 根據(jù)執(zhí)行計(jì)劃,調(diào)用存儲(chǔ)引擎的API來(lái)執(zhí)行查詢
    • 將結(jié)果返回給客戶端
    1. 查詢慢的原因
      1. 檢索大量超過(guò)需要的數(shù)據(jù),比如不需要的數(shù)據(jù)、全部列
      2. 確認(rèn)服務(wù)器層,是否分析大量超過(guò)需要的數(shù)據(jù)行,掃描的行數(shù)、返回的行數(shù)
    2. 重構(gòu)查詢方式
      1. 將一個(gè)復(fù)雜查詢拆成多個(gè)簡(jiǎn)單的查詢
      2. 切分查詢
      3. 分解關(guān)聯(lián)查詢
  1. 操作系統(tǒng) & 硬件
    在性能與成本之間找到一個(gè)平衡點(diǎn),
    1. CPU:如果在更快 & 更多做選擇,一般會(huì)選擇更快
    2. IO:順序IO與隨機(jī)IO、閃存
    3. 硬盤(pán):固態(tài) & 機(jī)械
    4. 網(wǎng)絡(luò):網(wǎng)絡(luò)一般不會(huì)作為很嚴(yán)重你的瓶頸
  2. 應(yīng)用層優(yōu)化
    不要局限于Mysql本身性能而花費(fèi)太多時(shí)間,或許MySql已經(jīng)足夠優(yōu)化,應(yīng)該關(guān)注下其他部分,
    1. 常見(jiàn)問(wèn)題
      • 消耗系統(tǒng)資源的根本原因
      • 是否獲取了冗余數(shù)據(jù)
      • 應(yīng)用層 & DB層是否是各司其職,是否使用合理
      • 執(zhí)行了太多的查詢,ORM導(dǎo)致的查詢,可以考慮在DB層做關(guān)聯(lián)
      • 創(chuàng)建了沒(méi)必要的連接,使用連接池
    2. Web服務(wù)器問(wèn)題
      • 使用緩存代理服務(wù)器
      • 對(duì)動(dòng)態(tài) & 靜態(tài)資源設(shè)置過(guò)期策略
      • 尋找最優(yōu)的并發(fā)度
    3. 緩存
      緩存多高負(fù)載應(yīng)用來(lái)說(shuō)至關(guān)重要,要找到正確的粒度和緩存過(guò)期策略
      • 本地緩存:很小,在進(jìn)程處理期間在內(nèi)存中
      • 本地共享內(nèi)存緩存:中等大小,快速、難以在多臺(tái)機(jī)器間同步
      • 分布式內(nèi)存緩存:例如Memcached,需要考慮一致性問(wèn)題
      • 磁盤(pán)緩存:很慢,最好是持久化對(duì)象
        失效策略有TTL(設(shè)置過(guò)期時(shí)間)、顯式失效(數(shù)據(jù)更新時(shí)失效)、讀時(shí)失效(根據(jù)一些信息,作為是失效標(biāo)記),緩存對(duì)象得分層、緩存預(yù)熱

三、如何達(dá)到高性能

  1. 復(fù)制
    復(fù)制是構(gòu)建大規(guī)模、高性能應(yīng)用的基礎(chǔ),提供高可用、可擴(kuò)展、容災(zāi)恢復(fù)的能力
    1. 解決了哪些問(wèn)題:服務(wù)器間保持?jǐn)?shù)據(jù)同步,形成主備,主要解決數(shù)據(jù)分布、負(fù)載均衡、備份、個(gè)高可用、故障切換、升級(jí)測(cè)試

    2. 方式:基于行的復(fù)制、基于語(yǔ)句的復(fù)制,都是通過(guò)在主庫(kù)上記錄二進(jìn)制日志,在備庫(kù)重放日志的方式來(lái)實(shí)現(xiàn)異步數(shù)據(jù)的復(fù)制,這意味著,在一個(gè)時(shí)間點(diǎn),主備數(shù)據(jù)可能存在不一致,并無(wú)法保證延遲,復(fù)制主庫(kù)主要是啟用二進(jìn)制日志帶來(lái)的開(kāi)銷,每個(gè)備庫(kù)也會(huì)對(duì)主庫(kù)增加一些負(fù)載,隨著備庫(kù)的增加,主庫(kù)的負(fù)載會(huì)累加

    3. 復(fù)制的流程:


      image.png

      在提交事務(wù)完成數(shù)據(jù)更新前,主庫(kù)將變更記錄寫(xiě)入到二進(jìn)制日志,備庫(kù)復(fù)制日志到中繼日志并重放,主庫(kù)一個(gè)線程,備庫(kù)兩個(gè)線程

    4. 原理

      1. 基于語(yǔ)句復(fù)制(邏輯復(fù)制)
        5.0及以前只支持該復(fù)制方式,主庫(kù)會(huì)記錄所有的變更語(yǔ)句,在備庫(kù)將變更語(yǔ)句執(zhí)行一遍,好處就是簡(jiǎn)單,不會(huì)使用太多帶寬,但實(shí)際存在一些問(wèn)題,例如元數(shù)據(jù)信息,無(wú)法被真確復(fù)制的SQL、CURRENT_USER等,同時(shí)更新必須是穿行的,需要更多的鎖,
      2. 基于行的復(fù)制
        5.1開(kāi)始,將實(shí)際數(shù)據(jù)記錄在二進(jìn)制日志中,最大的好處就是可以正確的復(fù)制每一行,由于無(wú)需重放查詢,所以更高效,但是在一些表變更中,需要全表復(fù)制變更,所以開(kāi)銷會(huì)很大
      優(yōu)點(diǎn) 缺點(diǎn)
      基于語(yǔ)句 在主備不同模式時(shí),可以在多種情況下運(yùn)行,原理簡(jiǎn)單,定位問(wèn)題容易 很多情況下無(wú)法正確復(fù)制,如果使用觸發(fā)器、存儲(chǔ)過(guò)程,就不要使用該方式
      基于行 沒(méi)有行復(fù)制不能處理的問(wèn)題,能更快的解決數(shù)據(jù)不一致的情況。 沒(méi)有記錄語(yǔ)句,所以無(wú)法判斷執(zhí)行了哪些語(yǔ)句,在某些情況下,修改了Schema、沒(méi)有找到行等會(huì)導(dǎo)致異常
      1. 事件 & 過(guò)濾
        • 可以通過(guò)log_slave_updates讓備庫(kù)稱為其他服務(wù)器的主庫(kù)
        • 可以設(shè)置,只復(fù)制一部分?jǐn)?shù)據(jù),有倆種過(guò)濾方式,1. 在主庫(kù)過(guò)濾記錄到二進(jìn)制日志中的日志事件,2. 備庫(kù)過(guò)濾記錄到中繼日志事件,


          image.png
    5. 拓?fù)?br> 可以在任意多個(gè)主備間復(fù)制,唯一限制:一個(gè)備庫(kù)只能有一個(gè)主庫(kù),

      1. 一主多備
        簡(jiǎn)單靈活,能滿足多種需求
        • 不同的角色使用不同的備庫(kù)
        • 將一臺(tái)備庫(kù)當(dāng)做待用主庫(kù)、用作容災(zāi)恢復(fù)
        • 可以使用一個(gè)備庫(kù)做測(cè)試
      2. 雙主主動(dòng)復(fù)制
        每一個(gè)被配置成對(duì)方的主庫(kù)和備庫(kù),在不同的位置,都需要可寫(xiě),最大的問(wèn)題就是如何解決沖突,
      3. 雙主被動(dòng)復(fù)制
        雙主的衍生,區(qū)別是其中一臺(tái)是只讀的被動(dòng)服務(wù)器,可以有效的避免數(shù)據(jù)沖突問(wèn)題,在反復(fù)切換主動(dòng)、被動(dòng)服務(wù)器很方便,
      4. 雙主多備
        每個(gè)主庫(kù)有相應(yīng)的備庫(kù),消除單點(diǎn)
      5. 環(huán)形復(fù)制
        非常脆弱、盡量避免
      6. 主、分發(fā)主、備
        在備庫(kù)越來(lái)越多的情況下會(huì)對(duì)主庫(kù)造成很大的負(fù)載,每個(gè)備庫(kù)會(huì)在主庫(kù)創(chuàng)建一個(gè)binlog dump命令,如果不在緩存,會(huì)導(dǎo)致大量的磁盤(pán)IO,這種情況下,可以使用分發(fā)主庫(kù)減輕主庫(kù)的負(fù)擔(dān),分發(fā)主庫(kù)其實(shí)就是一個(gè)備庫(kù),負(fù)責(zé)提取和提供主庫(kù)的二進(jìn)制日志
      7. 數(shù)形結(jié)構(gòu)


        image.png

        不管是分發(fā),還是提供更高的讀性能,都是更好的管理,缺點(diǎn)是中間層出現(xiàn)問(wèn)題會(huì)影響后面的服務(wù)器,
        過(guò)大的復(fù)制延遲是一個(gè)很普遍的問(wèn)題,最好在設(shè)計(jì)應(yīng)用程序時(shí)能夠讓其容忍備庫(kù)出現(xiàn)延遲,如果無(wú)法容忍,那就不要使用復(fù)制,單線程的設(shè)計(jì),導(dǎo)致了備庫(kù)的效率低下,備庫(kù)的鎖同樣是問(wèn)題,會(huì)阻塞復(fù)制線程

    6. 復(fù)制總結(jié)

邏輯上 技術(shù)上
異步復(fù)制 默認(rèn)的復(fù)制方式,主庫(kù)在執(zhí)行完客戶端提交的事務(wù)后會(huì)立即將結(jié)果返給給客戶端,并不關(guān)心從庫(kù)是否已經(jīng)接收并處理,這樣就會(huì)有一個(gè)問(wèn)題,主如果crash掉了,此時(shí)主上已經(jīng)提交的事務(wù)可能并沒(méi)有傳到從庫(kù)上,如果此時(shí),強(qiáng)行將從提升為主,可能導(dǎo)致新主上的數(shù)據(jù)不完整。 主庫(kù)將事務(wù) Binlog 事件寫(xiě)入到 Binlog 文件中,此時(shí)主庫(kù)只會(huì)通知一下 Dump 線程發(fā)送這些新的 Binlog,然后主庫(kù)就會(huì)繼續(xù)處理提交操作,而此時(shí)不會(huì)保證這些 Binlog 傳到任何一個(gè)從庫(kù)節(jié)點(diǎn)上。
全同步 當(dāng)主庫(kù)執(zhí)行完一個(gè)事務(wù),所有的從庫(kù)都執(zhí)行了該事務(wù)才返回給客戶端。因?yàn)樾枰却袕膸?kù)執(zhí)行完該事務(wù)才能返回,所以全同步復(fù)制的性能必然會(huì)收到嚴(yán)重的影響。 當(dāng)主庫(kù)提交事務(wù)之后,所有的從庫(kù)節(jié)點(diǎn)必須收到、APPLY并且提交這些事務(wù),然后主庫(kù)線程才能繼續(xù)做后續(xù)操作。但缺點(diǎn)是,主庫(kù)完成一個(gè)事務(wù)的時(shí)間會(huì)被拉長(zhǎng),性能降低。
半同步 介于全同步復(fù)制與全異步復(fù)制之間的一種,主庫(kù)只需要等待至少一個(gè)從庫(kù)節(jié)點(diǎn)收到并且 Flush Binlog 到 Relay Log 文件即可,主庫(kù)不需要等待所有從庫(kù)給主庫(kù)反饋。同時(shí),這里只是一個(gè)收到的反饋,而不是已經(jīng)完全完成并且提交的反饋,如此,節(jié)省了很多時(shí)間。 介于異步復(fù)制和全同步復(fù)制之間,主庫(kù)在執(zhí)行完客戶端提交的事務(wù)后不是立刻返回給客戶端,而是等待至少一個(gè)從庫(kù)接收到并寫(xiě)到relay log中才返回給客戶端。相對(duì)于異步復(fù)制,半同步復(fù)制提高了數(shù)據(jù)的安全性,同時(shí)它也造成了一定程度的延遲,這個(gè)延遲最少是一個(gè)TCP/IP往返的時(shí)間。所以,半同步復(fù)制最好在低延時(shí)的網(wǎng)絡(luò)中使用。
  1. 可擴(kuò)展
    當(dāng)需要增加資源以處理更大的負(fù)載時(shí),系統(tǒng)能夠獲得劃算的等同提升的能力,以及投資產(chǎn)出率,缺乏擴(kuò)展能力的系統(tǒng),在達(dá)到一個(gè)點(diǎn)后,將無(wú)法增長(zhǎng);簡(jiǎn)單說(shuō),擴(kuò)展性就是能夠通過(guò)增加資源來(lái)提升處理負(fù)載的能力,負(fù)載要從數(shù)據(jù)量、用戶量、用戶活躍度、相關(guān)數(shù)據(jù)集的大小。
    大部分系統(tǒng)只能以線性擴(kuò)展略低的擴(kuò)展系數(shù)進(jìn)行擴(kuò)展,事實(shí)上,多數(shù)系統(tǒng)在達(dá)到一個(gè)最大吞吐量臨界點(diǎn),超過(guò)這個(gè)臨界點(diǎn),投入產(chǎn)出會(huì)帶來(lái)負(fù)回報(bào),

    1. 垂直擴(kuò)展
      對(duì)于垂直擴(kuò)展,意味著購(gòu)買更多性能強(qiáng)悍的硬件,對(duì)很多應(yīng)用來(lái)說(shuō)這是唯一需要做的事情。如果在此基礎(chǔ)上繼續(xù)提升硬件的配置,MySQL的性能雖然還能提升,但性價(jià)比就會(huì)降低。
    2. 水平擴(kuò)展
      一般策略劃分為三個(gè)部分:復(fù)制、拆分、以及數(shù)據(jù)分片(sharding)。
      最簡(jiǎn)單也最常見(jiàn)的水平擴(kuò)展(向外擴(kuò)展)的方法是通過(guò)復(fù)制將數(shù)據(jù)分發(fā)到多個(gè)服務(wù)器上,然后將備庫(kù)用于讀查詢。這種技術(shù)對(duì)于以讀為主的應(yīng)用很有效。他也有一些缺點(diǎn),例如重復(fù)緩存,但如果數(shù)據(jù)規(guī)模有限就不存在這個(gè)問(wèn)題。
      • 按功能拆分:將不同的功能或者是不同的業(yè)務(wù)盡可能地拆分開(kāi),然后把各個(gè)功能或業(yè)務(wù)需要的數(shù)據(jù)庫(kù)獨(dú)立運(yùn)行
      • 數(shù)據(jù)分片:在目前用于擴(kuò)展大型MySQL應(yīng)用的方案中,數(shù)據(jù)分片是最通用且最成功的方法。他把數(shù)據(jù)分割成一小片,或者說(shuō)一塊,然后存儲(chǔ)到不同的節(jié)點(diǎn)中。如果想擴(kuò)展寫(xiě)容量,就必須切分?jǐn)?shù)據(jù)。如果只有單臺(tái)主庫(kù),那么不管有多少備庫(kù),寫(xiě)容量都是無(wú)法擴(kuò)展的。最大的挑戰(zhàn)是查找和獲取數(shù)據(jù),選擇分區(qū)鍵非常重要,選擇分區(qū)鍵的時(shí)候,盡可能選擇那些能夠避免跨分片查詢的,但同時(shí)也要讓分片足夠小,以避免過(guò)大的數(shù)據(jù)片導(dǎo)致問(wèn)題。如果可能,應(yīng)該期望分片盡可能同樣小,這樣在為不同數(shù)量的分片進(jìn)行分組時(shí)能夠很容易平衡。
      • 分配方式有倆種:固定分配:固定分配使用的分區(qū)函數(shù)僅僅依賴于分區(qū)鍵的值,例如取模,優(yōu)點(diǎn)是:簡(jiǎn)單、開(kāi)銷低、可以直接使用硬編碼,缺點(diǎn)是如果分片很大并且數(shù)量不多,就很難平衡不同分片間的負(fù)載。修改分片策略比較困難,因?yàn)樾枰匦路峙湟延械臄?shù)據(jù)。動(dòng)態(tài)分配:將每個(gè)數(shù)據(jù)單元映射到一個(gè)分片,動(dòng)態(tài)分配增加了分區(qū)函數(shù)的開(kāi)銷,因?yàn)樾枰~外調(diào)用一次外部資源,例如目錄服務(wù)器(存儲(chǔ)映射關(guān)系的數(shù)據(jù)存儲(chǔ)節(jié)點(diǎn))。動(dòng)態(tài)分配的最大好處是可以對(duì)數(shù)據(jù)存儲(chǔ)位置做細(xì)粒度的控制
      • 負(fù)載均衡:達(dá)到可擴(kuò)展、高效、可用、透明、一致目的,讀寫(xiě)分離,DNS、轉(zhuǎn)移IP地址,引入中間件,負(fù)載均衡算法有隨機(jī)、輪詢、最少連接數(shù)、最快響應(yīng)、哈希、權(quán)重
  2. 高可用
    更少的宕機(jī)時(shí)間,可用性每提高一點(diǎn),所花費(fèi)的成本都會(huì)遠(yuǎn)超從前,效果與開(kāi)銷不成線性

    1. 導(dǎo)致不可用的原因
      • 運(yùn)營(yíng)環(huán)境中,最普遍的問(wèn)題是磁盤(pán)空間耗盡
      • 性能問(wèn)題中,最普遍的是SQL的性能問(wèn)題,
      • 糟糕的Schema和索引
      • 復(fù)制導(dǎo)致數(shù)據(jù)不一致問(wèn)題
      • 數(shù)據(jù)丟失一般是Drop table導(dǎo)致
    2. 實(shí)現(xiàn)高可用
      首先減少宕機(jī)時(shí)間,第二宕機(jī)后快熟恢復(fù),兩個(gè)維度來(lái)確定:平均失效時(shí)間、平均恢復(fù)時(shí)間,
      • 提升平均失效時(shí)間
        測(cè)試回復(fù)工具和流程
        最小權(quán)限
        用好的命名和組織約定避免混亂,比如測(cè)試開(kāi)發(fā)庫(kù)分離
        確認(rèn)服務(wù)器配置項(xiàng)
        通過(guò)skip_name_resolve禁止DNS
        除非證明有效,否則不使用查詢緩存。
        避免使用復(fù)雜的特性,如觸發(fā)器等
        監(jiān)控重要組件
        盡量記錄服務(wù)器狀態(tài)和性能做成曲線查看走向
        定期檢查復(fù)制完整性
        備庫(kù)設(shè)置為只讀,不要讓復(fù)制自動(dòng)啟動(dòng)
        對(duì)查詢語(yǔ)句做檢查
        歸檔并清理不需要的數(shù)據(jù)
        為文件系統(tǒng)保留空余空間,在linux中可以使用-m選項(xiàng)為系統(tǒng)本身保留空間。或者創(chuàng)建很大的空文件,在快滿是刪除
        養(yǎng)成習(xí)慣,評(píng)估和管理系統(tǒng)的改變,狀態(tài)以及性能信息。
      • 降低平均恢復(fù)時(shí)間
        通過(guò)建立冗余來(lái)避免系統(tǒng)完全失效,比如避免單點(diǎn)。
        能夠提供冗余和故障轉(zhuǎn)移能力的系統(tǒng)架構(gòu)
        熟悉業(yè)務(wù)的員工和詳細(xì)的文檔和流程
        宕機(jī)事后反思
    3. 避免單點(diǎn)
      單個(gè)磁盤(pán),單臺(tái)服務(wù)器,單臺(tái)交換機(jī)路由器,單電力網(wǎng)。 任何不冗余的部分都可能是一個(gè)失敗的單點(diǎn)。用池加負(fù)載均衡,可以動(dòng)態(tài)的切換及避免冗余,共享存儲(chǔ)或者復(fù)制,做到數(shù)據(jù)的冗余。共享存儲(chǔ)就是在華為的時(shí)候的存儲(chǔ)產(chǎn)品
    4. 同步復(fù)制
      mysql 普通的復(fù)制,主服務(wù)器掛掉之后會(huì)丟數(shù)據(jù),使用同步復(fù)制保證至少在一條備機(jī)持久化之后才能持久化本地,所以減少了丟失。
    5. 故障轉(zhuǎn)移和恢復(fù)
      冗余只是一個(gè)基礎(chǔ),真正影響可用性的是如何利用這些冗余做轉(zhuǎn)移和恢復(fù)。轉(zhuǎn)移是A出問(wèn)題了切到B上,等A好了再切回去,這要比僅僅恢復(fù)A要好。
      通常有如下的手段來(lái)做:
      提升備庫(kù)。
      使用虛擬IP,如果服務(wù)器出問(wèn)題,則讓虛擬ip指向備庫(kù)。但是這樣可能會(huì)因?yàn)榫W(wǎng)絡(luò)緩存,ip接管等引起錯(cuò)誤
      中間件 可以使用代理,端口轉(zhuǎn)發(fā),LVS等等方法來(lái)作為中間件,屏蔽應(yīng)用和數(shù)據(jù)庫(kù)。比如最簡(jiǎn)單的http代理

四、總結(jié)

首先通過(guò)對(duì)Mysql基礎(chǔ)知識(shí)的大致串聯(lián),讓我對(duì)Mysql具備的能力事務(wù)、日志、鎖等有了基本的認(rèn)識(shí),然后在設(shè)計(jì)過(guò)程中,從服務(wù)器、Schema、索引、查詢、應(yīng)用等層如何讓系統(tǒng)應(yīng)用達(dá)到最優(yōu),最后通過(guò)復(fù)制、可擴(kuò)展、高可用讓Mysql性能達(dá)到最優(yōu),通過(guò)上述介紹,讓我們?cè)趯?shí)際使用中,可以更能深入了解Mysql的運(yùn)行原理,從而寫(xiě)出高性能的Sql以及遇到問(wèn)題可以快速定位優(yōu)化

參考:
《高性能MySql》第三版
官網(wǎng):https://dev.mysql.com/doc/refman/5.7/en/innodb-parameters.html
日志:https://www.cnblogs.com/f-ck-need-u/archive/2018/05/08/9010872.html
MVCC:https://blog.csdn.net/qq_35190492/article/details/109044141
鎖:https://zhuanlan.zhihu.com/p/29150809
磁盤(pán)IO:https://t.hao0.me/mysql/2016/10/25/mysql-innodb-04-io-file-mgr.html
分區(qū):https://database.51cto.com/art/202003/612742.htm
頁(yè)結(jié)構(gòu):https://blog.haohtml.com/archives/19232

`

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容