1. 程式人生 > 其它 >Spring Cloud+Spring Boot+Mybatis分散式微服務企業快速架構

Spring Cloud+Spring Boot+Mybatis分散式微服務企業快速架構

一、概述

深入學習MySQL,從概覽MySQL邏輯架構開始。

首先來看一下MySQL的邏輯架構圖:

MySQL最重要、最與眾不同的特性就是它的儲存引擎架構,這種架構將:查詢處理、其他系統任務、資料的儲存與提取 三部分分離。所以,帶來的好處就是可以在使用時根據效能、特性,以及其他需求來選擇資料儲存方式

儲存引擎架構分為三層,自上而下,分為第一層:連線層;第二層:服務層;第三層:引擎層

第一層:連線層

MySQL的最上層是連線服務,引入了執行緒池的概念,允許多臺客戶端連線。主要工作是:連線處理、授權認證、安全防護等

連線層為通過安全認證的接入使用者提供執行緒,同樣,在該層上可以實現基於SSL 的安全連線。

第二層:服務層

服務層用於處理核心服務,如標準的SQL介面、查詢解析、SQL優化和統計、全域性的和引擎依賴的快取與緩衝器等等。所有的與儲存引擎無關的工作,如過程、函式等,都會在這一層來處理。在該層上,伺服器會解析查詢並建立相應的內部解析樹,並對其完成優化,如確定查詢表的順序,是否利用索引等,最後生成相關的執行操作。如果是SELECT 語句,伺服器還會查詢內部的快取。如果快取空間足夠大,這樣在解決大量讀操作的環境中能夠很好的提升系統的效能。

第三層:**引擎層**:

儲存引擎層,儲存引擎負責實際的MySQL資料的儲存與提取,伺服器通過API 與 儲存引擎進行通訊。不同的儲存引擎功能和特性有所不同,這樣可以根據實際需要有針對性的使用不同的儲存引擎。

二、聯結器

當客戶端(應用)連線到MySQL伺服器時,伺服器需要對其進行認證。認證基於使用者名稱、原始主機資訊和密碼。

除了基本認證之外,聯結器還會進行一些執行緒的處理。

每個客戶端連線都會在伺服器程序中擁有一個執行緒,這個連線的查詢只會在這個單獨的執行緒中執行,該執行緒只能輪流在某個CPU核心或者CPU中執行。伺服器會負責快取執行緒,因此不需要為每一個新建的連線建立或者銷燬執行緒。

聯結器:負責跟客戶端建立連線 | 獲取許可權 | 維持和管理連線。連線命令一般如下形式:

mysql -h$ip -P$port -u$user -p

通過如下語句可以檢視當前連線的資訊:

mysql> show processlist;
+----+------+--------------------+-------+---------+------+----------+------------------+
| Id | User | Host | db | Command | Time | State | Info |
+----+------+--------------------+-------+---------+------+----------+------------------+
| 5 | root | 192.168.33.1:57721 | mysql | Sleep | 29 | | NULL |
| 6 | root | localhost | NULL | Query | 0 | starting | show processlist |
+----+------+--------------------+-------+---------+------+----------+------------------+
2 rows in set (0.00 sec)

其中"Sleep"代表現在系統裡面有一個空閒連線.

客戶端如果太長時間不活動, 聯結器就會自動斷開. 這個是由等待超時時間wait_timeout控制的,預設值是8小時.

資料庫長連線: 指連線成功後, 如果客戶端持續有請求, 則一直使用同一個連線.

資料庫短連線: 指每次執行完很少的幾次查詢後就斷開連線, 下次查詢重新再建立一個.

兩種連線實踐方案:

  1. 定期斷開長連線. 使用一段時間, 或者程式裡面判斷執行過一個佔用記憶體的大查詢後, 斷開連線, 之後要查詢再重連.

  2. 如果使用的MySQL版本是5.7或更新版本, 可以在執行一個比較大的操作後, 通過執行mysql_reset_connection來重新初始化連線資源. 這個過程不需要重連和重新做許可權驗證, 但是會將連線恢復到剛剛建立完時的狀態。

三、查詢快取

對於SELECT語句,在解析查詢之前,伺服器會先檢查查詢快取(Query Cache),如果能夠在其中找到對應的查詢,伺服器就不必再執行查詢解析、優化和執行的整個過程,而是直接返回查詢快取中的結果集。

但不推薦使用查詢快取**,即大多數情況下不建議使用查詢快取。為什麼呢?**

原因:查詢快取的失效非常頻繁,只要有對一個表的更新,這個表上所有的查詢快取都會被清空。對於更新壓力大的資料庫來說,查詢快取的命中率會非常低。除非你的業務就是有一張靜態表,很長時間才會更新一次。比如,一個系統配置表,那這張表上的查詢才適合使用查詢快取。

好在MySQL也提供了這種“按需使用”的方式。可以將引數query_cache_type設定成DEMAND,這樣對於預設的SQL語句都不使用查詢快取。而對於確定要使用查詢快取的語句,可以用SQL_CACHE顯式指定,如下:

mysql> select SQL_CACHE * from T where ID=10;

四、解析器

  • 詞法分析

  • 語法分析

如果快取沒有命中的話,MySQL會對查詢語句進行解析。簡單說解析的作用將我們人能看懂的SQL解析成MySQ能識別的語言。

解析器先會做“詞法解析”。輸入的是由多個字串和空格組成的一條SQL語句,MySQL需要識別出裡面的字串分別是什麼,代表什麼。

MySQL從輸入的"select"這個關鍵字識別出來,這是一個查詢語句。它也要把字串“T”識別成“表名T”,把字串“ID”識別成“列ID”。

做完了這些識別以後,就要做“語法解析”。根據詞法解析的結果,語法解析器會根據語法規則,判斷輸入的這個SQL語句是否滿足MySQL語法。

五、優化器

  • 選擇合適的索引

  • 決定各個表的連線順序

經過了解析器,MySQL知道我們要幹什麼。

接下來並不是直接執行,而是會在優化器這一層進行優化,優化器是個非常複雜的部件,它會幫我們去使用他自己認為的最好的方式去優化這條 SQL 語句,並生成一條條的執行計劃。

例如在表裡面有多個索引的時候,決定使用哪個索引;或者在一個語句有多表關聯(join)的時候,決定各個表的連線順序。比如你執行下面這樣的語句,這個語句是執行兩個表的join:

mysql> select * from t1 join t2 using(ID) where t1.c=10 and t2.d=20;
  • 既可以先從表t1裡面取出c=10的記錄的ID值,再根據ID值關聯到表t2,再判斷t2裡面d的值是否等於20。

  • 也可以先從表t2裡面取出d=20的記錄的ID值,再根據ID值關聯到t1,再判斷t1裡面c的值是否等於10。

這兩種執行方法的邏輯結果是一樣的,但是執行的效率會有不同,而優化器的作用就是決定選擇使用哪一個方案。

優化器階段完成後,這個語句的執行方案就確定下來了,然後進入執行器階段。如果你還有一些疑問,比如優化器是怎麼選擇索引的,有沒有可能選擇錯等等,沒關係,我會在後面的文章中單獨展開說明優化器的內容。

六、執行器

  1. 判斷對這個表有沒有查詢許可權

  2. 有許可權, 則繼續執行.

  3. 呼叫儲存引擎介面進行執行查詢或其他操作.

  4. 最終將查詢結果集返回給客戶端, 語句即執行完成.

MySQL通過解析器知道了你要做什麼,通過優化器知道了該怎麼做,於是就進入了執行器階段,執行器會根據一系列的執行計劃去呼叫儲存引擎的介面去完成SQL的執行。

開始執行的時候,要先判斷一下你對這個表T有沒有執行查詢的許可權,如果沒有,就會返回沒有許可權的錯誤,如下所示(在工程實現上,如果命中查詢快取,會在查詢快取放回結果的時候,做許可權驗證。查詢也會在優化器之前呼叫precheck驗證許可權)。

mysql> select * from T where ID=10;
ERROR 1142 (42000): SELECT command denied to user 'b'@'localhost' for table 'T'

如果有許可權,就開啟表繼續執行。開啟表的時候,執行器就會根據表的引擎定義,去使用這個引擎提供的介面。

比如我們這個例子中的表T中,ID欄位沒有索引,那麼執行器的執行流程是這樣的:

  1. 呼叫InnoDB引擎介面取這個表的第一行,判斷ID值是不是10,如果不是則跳過,如果是則將這行存在結果集中;

  2. 呼叫引擎介面取“下一行”,重複相同的判斷邏輯,直到取到這個表的最後一行。

  3. 執行器將上述遍歷過程中所有滿足條件的行組成的記錄集作為結果集返回給客戶端。

至此,這個語句就執行完成了。

對於有索引的表,執行的邏輯也差不多。第一次呼叫的是“取滿足條件的第一行”這個介面,之後迴圈取“滿足條件的下一行”這個介面,這些介面都是引擎中已經定義好的。

七、問題1:MySQL的工作流程

最上層:客戶端連線

1、連線處理:客戶端同資料庫服務層建立TCP連線,連線管理模組會建立連線,並請求一個連線執行緒。如果連線池中有空閒的連線執行緒,則分配給這個連線,如果沒有,在沒有超過最大連線數的情況下,建立新的連線執行緒負責這個客戶端。

2、授權認證:在真正的操作之前,還需要呼叫使用者模組進行授權檢查,來驗證使用者是否有許可權。通過後,方才提供服務,連線執行緒開始接收並處理來自客戶端的SQL語句。

第二層:核心服務

1、連線執行緒接收到SQL語句之後,將語句交給SQL語句解析模組進行語法分析和語義分析。

2、如果是一個查詢語句,則可以先看查詢快取中是否有結果,如果有結果可以直接返回給客戶端。

3、如果查詢快取中沒有結果,就需要真的查詢資料庫引擎層了,於是發給SQL優化器,進行查詢的優化。如果是表變更,則分別交給insert、update、delete、create、alter處理模組進行處理。

第三層:資料庫引擎層

1、開啟表,如果需要的話獲取相應的鎖。    2、先查詢快取頁中有沒有相應的資料,如果有則可以直接返回,如果沒有就要從磁碟上去讀取。

3、當在磁碟中找到相應的資料之後,則會載入到快取中來,從而使得後面的查詢更加高效,由於記憶體有限,多采用變通的LRU表來管理快取頁,保證快取的都是經常訪問的資料。

最後,獲取資料後返回給客戶端,關閉連線,釋放連線執行緒。

八、問題2

如果表 T 中沒有欄位 k,而你執行了這個語句 select * from T where k=1, 那肯定是會報“不存在這個列”的錯誤:“Unknown column ‘k’ in ‘where clause’”。你覺得這個錯誤是在哪個階段報出來的呢?

答案:分析器.

MySQL會解析查詢, 並建立內部資料結構(解析樹). 分析器會檢查: 資料表和資料列是否存在, 別名是否有歧義等. 所以此為分析器階段. ----- 參考自<MySQL實戰45講> 01節課後討論@圈圈圓圓的回答.


參考資料

[1] MYSQL提升筆記(1):MySQL邏輯架構

[2] MySQL 高階-MySQL邏輯架構圖簡介

[3] <MySQL實戰45講>


快來關注我的微信公眾號吧:正午Coder