邏輯模組組成
總的來說,MySQL可以看成是二層架構,第一層我們通常叫做SQLLayer,在MySQL資料庫系統處理底層資料之前的所有工作都是在這一層完成的,包括許可權判斷,sql解析,執行計畫最佳化,querycache的處理等等;第二層就是儲存引擎層,我們通常叫做StorageEngineLayer,也就是底層資料存取操作實現部分,由多種儲存引擎共同組成。所以,可以用如下一張最簡單的架構來表示MySQL的基本架構,:
雖然從看起來MySQL架構非常的簡單,就是簡單的兩部分而已,但實際上每一層中都含有各自的很多小模組,尤其是第一層SQLLayer,結構相當複雜的。下面我們就分別針對SQLLayer和StorageEngineLayer做一個簡單的分析。
SQL Layer 中包含了多個子模組,下面我將逐個做一下簡單的介紹:
1、初始化模組
顧名思議,初始化模組就是在MySQLServer啟動的時候,對整個系統做各種各樣的初始化操作,比如各種buffer,cache結構的初始化和記憶體空間的申請,各種系統變數的初始化設定,各種儲存引擎的初始化設定,等等。
2、核心API
核心API模組主要是為了提供一些需要非常高效的底層操作功能的最佳化實現,包括各種底層資料結構的實現,特殊演算法的實現,字串處理,數文書處理等,小檔案I/O,格式化輸出,以及最重要的記憶體管理部分。核心API模組的所有原始碼都集中在mysys和strings檔案夾下面,有興趣的讀者可以研究研究。
3、網路互動模組
底層網路互動模組抽象出底層網路互動所使用的介面api,實現底層網路資料的接收與發送,以方便其他各個模組調用,以及對這一部分的維護。所有源碼都在vio檔案夾下面。
4、Client&Server互動協議模組
任何C/S結構的軟體系統,都肯定會有自己專屬的資訊互動協議,MySQL也不例外。MySQL的Client&Server互動協議模組部分,實現了用戶端與MySQL互動過程中的所有協議。當然這些協議都是建立在現有的OS和網路通訊協定之上的,如TCP/IP以及UnixSocket。
5、使用者模組
使用者模組所實現的功能,主要包括使用者的登入串連許可權控制和使用者的授權管理。他就像MySQL的大門守衛一樣,決定是否給來訪者“開門”。
6、存取控制模組
造訪客人進門了就可以想幹嘛就幹嘛嗎?為了安全考慮,肯定不能如此隨意。這時候就需要存取控制模組即時監控客人的每一個動作,給不同的客人以不同的許可權。存取控制模組實現的功能就是根據使用者模組中各使用者的授權資訊,以及資料庫自身特有的各種約束,來控制使用者對資料的訪問。使用者模組和存取控制模組兩者結合起來,組成了MySQL整個資料庫系統的許可權安全管理的功能。
7、串連管理、連接線程和線程管理
串連管理模組負責監聽對MySQLServer的各種請求,接收串連請求,轉寄所有串連請求到線程管理模組。每一個串連上MySQLServer的用戶端請求都會被分配(或建立)一個連接線程為其單獨服務。而連接線程的主要工作就是負責MySQLServer與用戶端的通訊,接受用戶端的命令請求,傳遞Server端的結果資訊等。線程管理模組則負責管理維護這些連接線程。包括線程的建立,線程的cache等。
8、Query解析和轉寄模組
在MySQL中我們習慣將所有Client端發送給Server端的命令都稱為query,在MySQLServer裡面,連接線程接收到用戶端的一個Query後,會直接將該query傳遞給專門負責將各種Query進行分類然後轉寄給各個對應的處理模組,這個模組就是query解析和轉寄模組。其主要工作就是將query語句進行語義和文法的分析,然後按照不同的操作類型進行分類,然後做出針對性的轉寄。
9、Query Cache 模組
QueryCache模組在MySQL中是一個非常重要的模組,他的主要功能是將用戶端提交給MySQL的Select類query請求的返回結果集cache到記憶體中,與該query的一個hash值做一個對應。該Query所取資料的基表發生任何資料的變化之後,MySQL會自動使該query的Cache失效。在讀寫比例非常高的應用系統中,QueryCache對效能的提高是非常顯著的。當然它對記憶體的消耗也是非常大的。
10、Query最佳化器模組
Query最佳化器,顧名思義,就是最佳化用戶端請求的query,根據用戶端請求的query語句,和資料庫中的一些統計資訊,在一系列演算法的基礎上進行分析,得出一個最優的策略,告訴後面的程式如何取得這個query語句的結果。
11、表變更管理模組
表變更管理模組主要是負責完成一些DML和DDL的query,如:update,delte,insert,createtable,altertable等語句的處理。
12、表維護模組
表的狀態檢查,錯誤修複,以及最佳化和分析等工作都是表維護模組需要做的事情。
13、系統狀態管理模組
系統狀態管理模組負責在用戶端請求系統狀態的時候,將各種狀態資料返回給使用者,像DBA常用的各種showstatus命令,showvariables命令等,所得到的結果都是由這個模組返回的。
14、表管理器
這個模組從名字上看來很容易和上面的表變更和表維護模組相混淆,但是其功能與變更及維護模組卻完全不同。大家知道,每一個MySQL的表都有一個表的定義檔案,也就是*.frm檔案。表管理器的工作主要就是維護這些檔案,以及一個cache,該cache中的主要內容是各個表的結構資訊。此外它還維護table層級的鎖管理。
15、日誌記錄模組
日誌記錄模組主要負責整個系統層級的邏輯層的日誌的記錄,包括errorlog,binarylog,slowquerylog等。
16、複製模組
複製模組又可分為Master模組和Slave模組兩部分,Master模組主要負責在Replication環境中讀取Master端的binary日誌,以及與Slave端的I/O線程互動等工作。Slave模組比Master模組所要做的事情稍多一些,在系統中主要體現在兩個線程上面。一個是負責從Master請求和接受binary日誌,並寫入本地relaylog中的I/O線程。另外一個是負責從relaylog中讀取相關日誌事件,然後解析成可以在Slave端正確執行並得到和Master端完全相同的結果的命令並再交給Slave執行的SQL線程。
17、儲存引擎介面模組
儲存引擎介面模組可以說是MySQL資料庫中最有特色的一點了。目前各種資料庫產品中,基本上只有MySQL可以實現其底層資料存放區引擎的外掛程式式管理。這個模組實際上只是一個抽象類別,但正是因為它成功地將各種資料處理高度抽象化,才成就了今天MySQL可插拔儲存引擎的特色。
各模組工作配合
在瞭解了MySQL的各個模組之後,我們再看看MySQL各個模組間是如何相互協同工作的。接下來,我們通過啟動MySQL,用戶端串連,請求query,得到返回結果,最後退出,這樣一整個過程來進行分析。
當我們執行啟動MySQL命令之後,MySQL的初始化模組就從系統設定檔中讀取系統參數和命令列參數,並按照參數來初始化整個系統,如申請並分配buffer,初始化全域變數,以及各種結構等。同時各個儲存引擎也被啟動,並進行各自的初始化工作。當整個系統初始化結束後,由串連管理模組接手。串連管理模組會啟動處理用戶端串連請求的監聽程式,包括tcp/ip的網路監聽,還有unix的socket。這時候,MySQLServer就基本啟動完成,準備好接受用戶端請求了。
當串連管理模組監聽到用戶端的串連請求(藉助網路互動模組的相關功能),雙方通過Client&Server互動協議模組所定義的協議“寒暄”幾句之後,串連管理模組就會將串連請求轉寄給線程管理模組,去請求一個連接線程。
線程管理模組馬上又會將控制交給連接線程模組,告訴連接線程模組:現在我這邊有串連請求過來了,需要建立串連,你趕快處理一下。連接線程模組在接到串連請求後,首先會檢查當前連接線程池中是否有被cache的空閑連接線程,如果有,就取出一個和用戶端請求串連上,如果沒有閒置連接線程,則建立一個新的連接線程與用戶端請求串連。當然,連接線程模組並不是在收到串連請求後馬上就會取出一個連接線程連和用戶端串連,而是首先通過調用使用者模組進行授權檢查,只有用戶端請求通過了授權檢查後,他才會將用戶端請求和負責請求的連接線程連上。
在MySQL中,將用戶端請求分為了兩種類型:一種是query,需要調用Parser也就是Query解析和轉寄模組的解析才能夠執行的請求;一種是command,不需要調用Parser就可以直接執行的請求。如果我們的初始化配置中開啟了FullQueryLogging的功能,那麼Query解析與轉寄模組會調用日誌記錄模組將請求計入日誌,不管是一個Query類型的請求還是一個command類型的請求,都會被記錄進入日誌,所以出於效能考慮,一般很少開啟FullQueryLogging的功能。
當用戶端請求和連接線程“互換暗號(互連協議)”接上頭之後,連接線程就開始處理用戶端請求發送過來的各種命令(或者query),接受相關請求。它將收到的query語句轉給Query解析和轉寄模組,Query解析器先對Query進行基本的語義和文法解析,然後根據命令類型的不同,有些會直接處理,有些會分發給其他模組來處理。
如果是一個Query類型的請求,會將控制權交給Query解析器。Query解析器首先分析看是不是一個select類型的query,如果是,則調用查詢快取模組,讓它檢查該query在querycache中是否已經存在。如果有,則直接將cache中的資料返回給連接線程模組,然後通過與用戶端的串連的線程將資料轉送給用戶端。如果不是一個可以被cache的query類型,或者cache中沒有該query的資料,那麼query將被繼續傳回query解析器,讓query解析器進行相應處理,再通過query分發器分發給相關處理模組。
如果解析器解析結果是一條未被cache的select語句,則將控制權交給Optimizer,也就是Query最佳化器模組,如果是DML或者是DDL語句,則會交給表變更管理模組,如果是一些更新統計資料、檢測、修複和整理類的query則會交給表維護模組去處理,複製相關的query則轉交給複製模組去進行相應的處理,請求狀態的query則轉交給了狀態收集報告模組。實際上表變更管理模組根據所對應的處理請求的不同,是分別由insert處理器、delete處理器、update處理器、create處理器,以及alter處理器這些小模組來負責不同的DML和DDL的。
在各個模組收到Query解析與分發模組分發過來的請求後,首先會通過存取控制模組檢查串連使用者是否有訪問目標表以及目標欄位的許可權,如果有,就會調用表管理模組請求相應的表,並擷取對應的鎖。表管理模組首先會查看該表是否已經存在於tablecache中,如果已經開啟則直接進行鎖相關的處理,如果沒有在cache中,則需要再開啟表檔案擷取鎖,然後將開啟的表交給表變更管理模組。
當表變更管理模組“擷取”開啟的表之後,就會根據該表的相關meta資訊,判斷表的儲存引擎類型和其他相關資訊。根據表的儲存引擎類型,提交請求給儲存引擎介面模組,調用對應的儲存引擎實現模組,進行相應處理。
不過,對於表變更管理模組來說,可見的僅是儲存引擎介面模組所提供的一系列“標準”介面,底層儲存引擎實現模組的具體實現,對於表變更管理模組來說是透明的。他只需要調用對應的介面,並指明表類型,介面模組會根據表類型調用正確的儲存引擎來進行相應的處理。
當一條query或者一個command處理完成(成功或者失敗)之後,控制權都會交還給連接線程模組。如果處理成功,則將處理結果(可能是一個Resultset,也可能是成功或者失敗的標識)通過連接線程反饋給用戶端。如果處理過程中發生錯誤,也會將相應的錯誤資訊發送給用戶端,然後連接線程模組會進行相應的清理工作,並繼續等待後面的請求,重複上面提到的過程,或者完成用戶端中斷連線的請求。
如果在上面的過程中,相關模組使資料庫中的資料發生了變化,而且MySQL開啟了bin-log功能,則對應的處理模組還會調用Tlog模組將相應的變更語句以更新事件的形式記錄到相關參數指定的二進位記錄檔中。
在上面各個模組的處理過程中,各自的核心運算處理功能部分都會高度依賴整個MySQL的核心API模組,比如記憶體管理,檔案I/O,數字和字串處理等等。
瞭解到整個處理過程之後,我們可以將以上各個模組畫成2-2的關係圖:
轉自 《MySQL效能調優與架構》