MySQL數據存儲

MySQL體系架構

  1. 客戶端連接器

提供與MySQL服務器建立的支持。目前幾乎支持所有主流的服務端編程技術,例如常見的 Java、C、Python、.NET等,它們通過各自API技術與MySQL建立連接

  1. 連接池

負責存儲和管理客戶端與數據庫的連接,一個線程負責管理一個連接。

  1. 系統管理和控制工具

例如備份恢復、安全管理、集羣管理等

  1. SQL接口

用於接受客戶端發送的各種SQL命令,並返回用戶需要查詢的結果。比如DML、DDL、存儲過程、視圖、觸發器等。

  1. 解析器

負責將請求的SQL解析生成一個“解析樹”。然後根據一些MySQL規則進一步檢查解析樹是否合法。

  1. 查詢優化器

當“解析樹”通過解析器語法檢查後,將交由優化器將其轉爲執行計劃,然後與存儲引擎交互

  1. 緩存

緩存機制是由一系列小緩存組成的。比如表緩存,記錄緩存,權限緩存,引擎緩存等。如果查詢緩存有命中的查詢結果,查詢語句就可以直接去查詢緩存中取數據

  1. 存儲引擎

存儲引擎負責MySQL中數據的存儲和提取,與底層系統文件進行交互。MySQL存儲引擎是插件式的,服務器中的查詢執行引擎通過接口與存儲引擎進行通信,接口屏蔽了不同存儲引擎之間的差異。現在有很多存儲引擎,各有各的特點,最常見的是MyISAM和InnoDB。

  1. 系統文件

該層負責將數據庫的數據和日誌存儲在文件系統之上,並完成與存儲引擎的交互,是文件的物理存儲層。主要包含日誌文件、數據文件、配置文件、pid文件、socket文件等。

MySQL運行機制

  1. 建立連接,MySQL客戶端與服務端的通信方式是半雙工。

全雙工:能夠同時發送和接收數據。例如平時打電話

半雙工:指的某一時刻,要麼發送數據,要麼接收數據,不能同時。例如早期對講機

單工:只能發送數據或只能接收數據。例如單行道

  1. 查詢緩存,如果開啓了查詢緩存並且在查詢緩存過程中查詢到完全相同的SQL語句,則將查詢結果直接返回客戶端

  2. 解析器,解析器將客戶端發送的SQL進行語法解析,生成“解析樹”。預處理器根據一些MySQL規則進一步檢查“解析樹”是否合法,例如這裏將檢查數據表和數據列是否存在,還會解析名字和別名,看看它們是否有歧義,最後生成新的“解析樹”。

  3. 查詢優化器,根據“解析樹”生成最優的執行計劃。MySQL試用很多優化策略生成最優的執行計劃,可以分爲兩類:靜態優化(編譯時優化)、動態優化(運行時優化)

  • 等級變換策略
    • a < b and a = 5 改爲 b>5 and a=5
    • 基於聯合索引,調整條件位置等
  • 優化count、max、min等函數
    • innoDB引擎min函數只需要找索引最左邊,max找索引最右邊。
    • MyISAM引擎count(*)不需要計算,直接返回
  • 提前終止查詢,使用了limit查詢,獲取到所需的數據就返回
  • in的優化,MySQL對in的查詢,會先進行排序,再採用二分法查找數據
  1. 查詢引擎,查詢引擎負責執行SQL語句,此時查詢執行引擎會根據 SQL 語句中表的存儲引擎類型,以及對應的API接口與底層存儲引擎緩存或者物理文件的交互,得到查詢結果並返回給客戶端。若開啓用查詢緩存,這時會將SQL語句和結果完整地保存到查詢緩存(Cache&Buffer)中,以後若有相同的 SQL語句執行則直接返回結果。
  • 如果開啓了查詢緩存,先將查詢結果做緩存操作
  • 返回結果過多,採用增量模式返回

MySQL存儲引擎

存儲引擎負責MySQL中的數據的存儲和提取,是與文件打交道的子系統,它是根據MySQL提供的文件訪問層抽象接口定製的一種文件訪問機制,這種機制叫做存儲引擎。

通過SHOW ENGINES命令,可以查看當前數據庫支持的引擎信息。

在5.5版本之前默認採用MyISAM存儲引擎,從5.5開始採用InnoDB存儲引擎。

  • InnoDB:支持事務,具有提交,回滾和崩潰恢復能力,事務安全
  • MyISAM:不支持事務和外鍵,訪問速度快
  • Memory:利用內存創建表,訪問速度非常快,因爲數據在內存,而且默認使用Hash索引,但是一旦關閉,數據就會丟失
  • Archive:歸檔類型引擎,僅能支持insert和select語句
  • Csv:以CSV文件進行數據存儲,由於文件限制,所有列必須強制指定not null,另外CSV引擎也不支持索引和分區,適合做數據交換的中間表
  • BlackHole: 黑洞,只進不出,進來消失,所有插入數據都不會保存
  • Federated:可以訪問遠端MySQL數據庫中的表。一個本地表,不保存數據,訪問遠程表內容。
  • MRG_MyISAM:一組MyISAM表的組合,這些MyISAM表必須結構相同,Merge表本身沒有數據,對Merge操作可以對一組MyISAM表進行操作。

InnoDB和MyISAM對比

  • 事務和外鍵

InnoDB支持事務和外鍵,具有安全性和完整性,適合大量insert或update操作

MyISAM不支持事務和外鍵,它提供高速存儲和檢索,適合大量的select查詢操作

  • 鎖機制

InnoDB支持行級鎖,鎖定指定記錄。基於索引來加鎖實現

MyISAM支持表級鎖,鎖定整張表

  • 索引結構

InnoDB主鍵使用了聚集索引,索引和記錄在一起存儲,既緩存索引,也緩存記錄。

MyISAM使用非聚集索引,索引和記錄分開,有單獨的數據文件

  • 併發處理能力

MyISAM使用表鎖,寫操作併發低

InnoDB讀寫阻塞可以與隔離級別有關,可以採用MVCC(多版本併發控制)來支持高併發

  • 存儲文件

InnoDB表對應兩個文件,一個.frm表結構文件,一個.ibd數據文件。InnoDB最大支持64TB;

MyISAM表對應三個文件,一個.frm表結構文件,一個MYD表數據文件,一個.MYI索引文件。從MySQL5.0開始默認限制是256TB

InnoDB存儲結構

下面是InnoDB引擎架構圖,主要分爲++內存結構++和++磁盤結構++兩大部分。

內存結構

內存結構主要包括Buffer Pool、Change Buffer、Adaptive Hash Index和Log Buffer四大組件。

  1. Buffer Pool:緩衝池,簡稱BP。BP以Page頁爲單位,默認大小16K,BP的底層採用鏈表數據結構管理Page。在InnoDB訪問表記錄和索引時會在Page頁中緩存,以後使用可以減少磁盤IO操作,提升效率。
  • Page管理機制,Page根據狀態可以分爲三種類型:

    free page :空閒page,未被使用
    clean page:被使用page,數據沒有被修改過
    dirty page:髒頁,被使用page,數據被修改過,頁中數據和磁盤的數據產生了不一致

針對上述三種page類型,InnoDB通過三種鏈表結構來維護和管理

free list :表示空閒緩衝區,管理free page
flush list:表示需要刷新到磁盤的緩衝區,管理dirty page,內部page按修改時間排序。髒頁既存在於flush鏈表,也在LRU鏈表中,但是兩種互不影響,LRU鏈表負責管理page的可用性和釋放,而flush鏈表負責管理髒頁的刷盤操作。
lru list:表示正在使用的緩衝區,管理clean page和dirty page,緩衝區以midpoint爲基點,前面鏈表稱爲new列表區,存放經常訪問的數據,佔63%;後面的鏈表稱爲old列表區,存放使用較少數據,佔37%。
  • 改進型LRU算法維護

    普通LRU:末尾淘汰法,新數據從鏈表頭部加入,釋放空間時從末尾淘汰
    改性LRU:鏈表分爲new和old兩個部分,加入元素時並不是從表頭插入,而是從中間midpoint位置插入,如果數據很快被訪問,那麼page就會向new列表頭部移動,如果數據沒有被訪問,會逐步向old尾部移動,等待淘汰。每當有新的page數據讀取到buffer pool時,InnoDb引擎會判斷是否有空閒頁,是否足夠,如果有就將free page從free list列表刪除,放入到LRU列表中。沒有空閒頁,就會根據LRU算法淘汰LRU鏈表默認的頁,將內存空間釋放分配給新的頁。

  • Buffer Pool配置參數

    show variables like '%innodb_page_size%'; //查看page頁大小
    show variables like '%innodb_old%'; //查看lru list中old列表參數
    show variables like '%innodb_buffer%'; //查看buffer pool參數
    建議:將innodb_buffer_pool_size設置爲總內存大小的60%-80%,
    innodb_buffer_pool_instances可以設置爲多個,這樣可以避免緩存爭奪。

  1. Change Buffer:寫緩衝區,簡稱CB。在進行DML操作時,如果BP沒有其相應的Page數據,並不會立刻將磁盤頁加載到緩衝池,而是在CB記錄緩衝變更,等未來數據被讀取時,再將數據合併恢復到BP中。

ChangeBuffer佔用BufferPool空間,默認佔25%,最大允許佔50%,可以根據讀寫業務量來進行調整。參數innodb_change_buffer_max_size;
3. Adaptive Hash Index:自適應哈希索引,用於優化對BP數據的查詢。InnoDB存儲引擎會監控對錶索引的查找,如果觀察到建立哈希索引可以帶來速度的提升,則建立哈希索引,所以稱之爲自適應。InnoDB存儲引擎會自動根據訪問的頻率和模式來爲某些頁建立哈希索引。
4. Log Buffer:日誌緩衝區,用來保存要寫入磁盤上log文件(Redo/Undo)的數據,日誌緩衝區的內容定期刷新到磁盤log文件中。日誌緩衝區滿時會自動將其刷新到磁盤,當遇到BLOB或多行更新的大事務操作時,增加日誌緩衝區可以節省磁盤I/O。

LogBuffer主要是用於記錄InnoDB引擎日誌,在DML操作時會產生Redo和Undo日誌。

磁盤結構

InnoDB磁盤主要包含Tablespaces,InnoDB Data Dictionary,Doublewrite Buffer、Redo Log和Undo Logs

  • 表空間(Tablespaces):用於存儲表結構和數據。表空間又分爲系統表空間、獨立表空間、通用表空間、臨時表空間、Undo表空間等多種類型;

  • 數據字典(InnoDB Data Dictionary)

InnoDB數據字典由內部系統表組成,這些表包含用於查找表、索引和表字段等對象的元數據。元數據物理上位於InnoDB系統表空間中。由於歷史原因,數據字典元數據在一定程度上與InnoDB表元數據文件(.frm文件)中存儲的信息重疊

  • 雙寫緩衝區(Doublewrite Buffer)

位於系統表空間,是一個存儲區域。在BufferPage的page頁刷新到磁盤真正的位置前,會先將數據存在Doublewrite緩衝區。如果在page頁寫入過程中出現操作系統、存儲子系統或mysqld進程崩潰,InnoDB可以在崩潰恢復期間從Doublewrite 緩衝區中找到頁面的一個好備份。在大多數情況下,默認情況下啓用雙寫緩衝區,要禁用Doublewrite緩衝區,可以將innodb_doublewrite設置爲0。使用Doublewrite緩衝區時建議將innodb_flush_method設置爲O_DIRECT

MySQL的innodb_flush_method這個參數控制着innodb數據文件及redo log的打開、刷寫模式。有三個值:fdatasync(默認),O_DSYNC,O_DIRECT。設置O_DIRECT表示數據文件寫入操作會通知操作系統不要緩存數據,也不要用預讀,直接從Innodb Buffer寫到磁盤文件。

  • 重做日誌(Redo Log)

重做日誌是一種基於磁盤的數據結構,用於在崩潰恢復期間更正不完整事務寫入的數據。
MySQL以循環方式寫入重做日誌文件,記錄InnoDB中所有對Buffer Pool修改的日誌。當出現實例故障(像斷電),導致數據未能更新到數據文件,則數據庫重啓時根據Redo Log重新把數據更新到數據文件。讀寫事務在執行的過程中,都會不斷的產生redo log。默認情況下,重做日誌在磁盤上由兩個名爲ib_logfile0和ib_logfile1的文件物理表示

  • 撤銷日誌(Undo Log)

撤消日誌是在事務開始之前保存的被修改數據的備份,用於例外情況時回滾事務。撤消日誌屬於邏輯日誌,根據每行記錄進行記錄。撤消日誌存在於系統表空間、撤消表空間和臨時表空間中。

InnoDB線程模型

  • Master Thread

Master Thread是InnoDB的主線程,負責調度其他線程,優先級最高。作用是將緩衝池中的數據異步刷新到磁盤,保證數據的一致性。包含:髒頁的刷新(page cleaner thread)、undo頁回收(purge thread)、redo日誌刷新(log thread)、合併寫緩衝等。

  • IO Thread

在InnoDB中使用了大量的AIO來做讀寫處理,這樣可以極大提高數據庫的性能。一共10個線程。

- read thread : 負責讀取操作,將數據從磁盤加載到緩存page頁。4個
- write thread:負責寫操作,將緩存髒頁刷新到磁盤。4個
- log thread:負責將日誌緩衝區內容刷新到磁盤。1個
- insert buffer thread :負責將寫緩衝內容刷新到磁盤。1個
  • Purge Thread

事務提交之後,其使用的undo日誌將不再需要,因此需要Purge Thread回收已經分配的undo頁。

  • Page Cleaner Thread

作用是將髒數據刷新到磁盤,髒數據刷盤後相應的redo log也就可以覆蓋,即可以同步數據,又能達到redo log循環使用的目的。會調用write thread線程處理。

InnoDB數據文件

InnoDB數據文件存儲結構分爲一個ibd數據文件-->Segment(段)-->Extent(區)-->Page(頁)-->Row(行)

  • Tablesapce

表空間,用於存儲多個ibd數據文件,用於存儲表的記錄和索引。一個文件包含多個段。

  • Segment

段,用於管理多個Extent,分爲數據段、索引段、回滾段。一個表至少有兩個segment,一個管理索引,一個管理數據。

  • Extent

區,一個區固定包含64個連續的頁,大小爲1M。當表空間不足,需要分配新的頁資源,不會一頁頁的分,直接分配一個區

  • Page

頁,用於存儲多個Row行記錄,大小爲16K。包含很多種頁類型,比如數據頁、undo頁、系統頁、事務數據頁、大的BLOB對象頁。

  • Row

行,包含了記錄的字段值、事務ID、回滾指針、字段指針等信息。

Undo Log、Redo Log和Binlog

  1. Undo Log(撤銷日誌)

數據庫事務開始前,會將要修改的記錄放到Undo日誌裏,當事務要回滾或數據庫崩潰時,撤銷對未提交的事務對數據庫產生的影響。

Undo Log產生和銷燬:Undo Log在事務開始前產生;事務在提交時,並不會立刻刪除Undo log,innodb會將該事務對應的Undo log放入到刪除列表中,後面會通過後臺線程purge thread進行回收處理。Undo Log屬於邏輯日誌,記錄一個變化過程。例如執行一個delete,undolog會記錄一個insert;執行一個update,undolog會記錄一個相反的update。

show variables like '%innodb_undo%';

Undo Log的作用:

  • 實現事務的原子性。事務處理中,如果出現了錯誤或用戶執行了Roll Back語句,MySQL可以利用Undo Log中的備份將數據恢復到事務開始前的狀態
  • 實現多版本併發控制(MVCC)
  1. Redo Log(重做日誌)

事務中修改的任何數據,將最新的數據備份存儲到Redo Log裏。Redo Log 是爲了實現事務的持久性而出現的產物。防止在發生故障的時間點,尚有髒頁未寫入表的IBD文件中,在重啓MySQL服務的時候,根據 Redo Log進行重做,將未入磁盤數據進行持久化。

Redo Log 的生成和釋放:隨着事務操作的執行,就會生成Redo Log,在事務提交時會將產生Redo Log寫入Log Buffer,並不是隨着事務的提交就立刻寫入磁盤文件。等事務操作的髒頁寫入到磁盤之後,Redo Log 的使命也就完成了,Redo Log佔用的空間就可以重用(被覆蓋寫入)

Redo Buffer 持久化到 Redo Log 的策略,可通過Innodb_flush_log_at_trx_commit 設置:

  • 0:每秒提交 Redo buffer ->OS cache -> flush cache to disk,可能丟失一秒內的事務數據。由後臺Master線程每隔1秒執行一次操作。
  • 1(默認值):每次事務提交執行 Redo Buffer -> OS cache -> flush cache to disk,最安全,性能最差的方式。
  • 2:每次事務提交執行 Redo Buffer -> OS cache,然後由後臺Master線程再每隔1秒執行OS cache -> flush cache to disk的操作。

一般建議選擇取值2,因爲 MySQL掛了數據沒有損失,整個服務器掛了纔會損失1秒的事務提交數據。
3. Binlog(Binary log(二進制日誌))

BinLog和上面的兩種日誌不同,他說屬於Mysql Server的日誌,不是InnoDb引擎特有的。Binlog是記錄所有數據庫表結構變更以及表數據修改的二進制日誌。不會記錄select這類操作。Binlog日誌是以事件形式記錄,還包含語句所執行的消耗時間。開啓Binlog日誌有以下兩個最重要的使用場景。

  • 主從複製:在主庫中開啓Binlog功能,這樣主庫就可以把Binlog傳遞給從庫,從庫拿到Binlog後實現數據恢復達到主從數據一致性。
  • 數據恢復:通過mysqlbinlog工具來恢復數據。

Binlog文件名默認爲“主機名_binlog-序列號”格式,例如oak_binlog-000001,也可以在配置文件中指定名稱。文件記錄模式有STATEMENT、ROW和MIXED三種,具體含義如下:

  • ROW(row-based replication,RBR):日誌中會記錄每一行數據被修改的情況,然後在slave端對相同的數據進行修改。
    • 優點:能清楚記錄每一個數據的修改細節,實現主從完全的同步和數據恢復
    • 批量的操作會產生大量日誌,如:alter table
  • STATMENT(statement-based replication,SBR):每一條被修改數據的SQL都會記錄到master的Binlog中,slave在複製的時候SQL進程會解析成和原來master端執行過的相同的SQL再次執行。簡稱SQL語句複製
    • 優點:日誌量少,減少磁盤IO
    • 缺點:在某些情況下會導致主從數據不一致,如last_insert_id()、now()等函數的執行。
  • MIXED(mixed-based replication,MBR):以上兩種模式的混合使用,一般會使用STATEMENT模式保存Binlog,對於STATEMENT模式無法複製的操作使用ROW模式保存Binlog,MySQL會根據執行的SQL語句選擇寫入模式。

Binlog文件操作命令

  • Binlog狀態查看
SHOW VARIABLES LIKE 'log_bin';
  • 開啓Binlog

需要修改my.cnf或my.ini配置文件,在[mysqld]下面增加log_bin=mysql_bin_log,重啓MySQL服務。

  • 使用show binlog events命令
show binary logs; //等價於show master logs;
show master status;
show binlog events;
show binlog events in 'mysqlbinlog.000001';
  • mysqlbinlog命令
mysqlbinlog "文件名"
mysqlbinlog "文件名" > "test.sql"
  • binlog數據恢復

mysqldump:定期全部備份數據庫數據。mysqlbinlog可以做增量備份和恢復操作。

//按指定時間恢復
mysqlbinlog --start-datetime="2020-04-25 18:00:00" --stop-
datetime="2020-04-26 00:00:00" mysqlbinlog.000002 | mysql -uroot -p1234
//按事件位置號恢復
mysqlbinlog --start-position=154 --stop-position=957 mysqlbinlog.000002
| mysql -uroot -p1234
  • 刪除binlog文件
purge binary logs to 'mysqlbinlog.000001'; //刪除指定文件
purge binary logs before '2020-04-28 00:00:00'; //刪除指定時間之前的文件
reset master; //清除所有文件

可以通過設置expire_logs_days參數來啓動自動清理功能。默認值爲0表示沒啓用。設置爲1表示超出1天binlog文件會自動刪除掉。

Redo Log和Binlog的區別

  • Redo Log是屬於InnoDB引擎的;Binlog屬於MySQL Server自帶的功能
  • Redo Log屬於物理日誌,記錄的是“在某個數據頁上做了什麼修改”;Binlog是記錄的這個語句的原始邏輯,比如“給某個行的某字段+1”
  • Redo Log是日誌循環寫,日誌空間大小是固定的;Binlog是追加寫入,不會覆蓋使用
  • Redo Log作爲服務器異常宕機後事務數據自動恢復使用;Binlog可以作爲主從複製和數據恢復使用。
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章