iT邦幫忙

第 11 屆 iT 邦幫忙鐵人賽

DAY 10
2
Software Development

30天之從 0 至 1 盡可能的建立一個好的系統 (性能基礎篇)系列 第 10

30-10 之資料庫層架構與優化方向

黑色好看版 - 傳送門


https://ithelp.ithome.com.tw/upload/images/20190925/20089358OB0WUwZvhl.png

正文開始


前面幾篇文章中,咱們大致上學習完了應用層的一些性能優化的基本知識,接下來咱們要來學學資料庫層的高性能優化方向。

在這裡先說一下一個重點 :

資料庫絕對是一個系統的性能核心,請把優質的 DBA 們當寶來餵食

接下來幾篇資料庫層文章將會以『 MySQL 』來進行說明,雖然不同的資料庫可能實作上會有些不同,但是大致上原理不會差距太大。

開始第一篇文章,咱們將要先理解一些 MySQL 的基本架構,接下來才能理解那些地方可能可以進行性能優化,又是那一些地方可能是會拖後腿,但是又是必要存在的地方,這篇也算是資料庫篇的小目錄。

本篇文章分成以下幾個章節 :

  • MySQL 基本架構。
  • 資料庫層的優化方向。
  • 資料庫層會拖性能後腿,但是又必須處理的地方。

MySQL 基本架構與運行


https://ithelp.ithome.com.tw/upload/images/20190925/20089358HQjYEuz0NQ.png
圖 1 : mysql 的基本架構

基本上分為以下幾個部份 :

  • 應用層 ( 紅色 )
  • 服務層 ( 綠色 )
  • 存儲引擎層 ( 藍色 )

應用層

應用層主要處理兩個工作 :

  • 連接處理任務
  • 權限管理

其中連接處理任務就是每當一個 client 端發送一個請求到 mysql 時,它會在從 thread poll 中分配一個 thread 來處理此請求,然後之後從此 client 來的任務,都會由此 thread 來處理。

mysql 並沒有使用之前說的非阻塞 I/O 模型 ( reactor ) 來處理請求的,原因可能在於,mysql 的任務是屬於 cpu 運算密集與磁碟 I/O 密集任務,因此比較不適合使用 reactor 這種使用 epoll 的模型。

另一種可能原因為當時 mysql 出來時間很早,那個時空背景的確沒有很好的 i/o 處理模式,所以到了現在真的支援非常的困難。

服務層

服務層最重要的有以下幾個部份,這幾個部份與我們操作 sql 性能習習相關。

  • SQL Parser
  • Optimizer
  • SQL Cache

首先來說說『 SQL Parser 』,它會將你所下達的 sql 指令,依據規則,將它轉化成抽象語法樹( Abstract Syntax Tree,AST )。

SQL -> PARSER -> AST

ast 基本上是用來描述語法的資料結構,像一些 ids 所提供的工具,都需要將你寫的語法產生 AST 才能幫你進行程式碼的 style 修改或啥的。

接下來『 Optimizer 』部份。這裡會將你的 AST 進行優化,比較白話文的說法就是 mysql 會自動將你的 sql,以它覺得最有效率的方法來處理。

最後是 『 SQL Cache 』。每當進行搜尋時,都會先至此處理看看有沒有緩存命中,有的話就直接取得,無的話,則將進行 Parser、Optimizer、執行。

有 : 回傳 Cache
無 : SQL -> Parser -> Optimizer -> 執行

存儲引擎層

這裡就是實際上要決定,如何處理與儲放你的資料,而用什麼儲存手法就由各種不同的存儲引擎來決定。

Mysql 基本的預設存儲引擎為 :

  • 5.5 以下 : MyISAM
  • 5.6 以上 : InnoDB

題外話 : MySQL Cache 的問題

Mysql 事實上內部有一個 cache,它叫『 query search 』,但看了不少篇文章都是建議,如果是 99% 以上的任務都是讀取相關的,才建議開啟,否則不要開啟。

會有這樣的結論有兩個原因 :

  • 緩存很難觸發,原因之一在於需完全相同的 sql 才會中,像如果你多用了 NOW() 的內建方法就掰了。
  • 開啟緩存成本高。因為需要更新緩存,以及它會鎖住緩存區,這些都會耗費不少資源。

BTW 如果你們公司本來就已經打開緩存了,那可以使用以下的指令看看,你們 cache hit 到底是多少,來決定要不要繼續開這查詢緩存。

SHOW GLOBAL STATUS WHERE Variable_name='Qcache_hits' OR Variable_name='Com_select';

MySQL 的運行流程

接下來咱們簡單的看一下一個 sql 它在 mysql 中是會如何運行的。

如下圖 2 所示 :

  1. client 傳送一個 sql 請求。
  2. 應用層權限驗證與開啟一個 thread 後,丟給解析器。
  3. 接下解析器會先看看緩存區中有沒有相同的 sql,有則回傳。
  4. 無則根據這 sql 建立執行計畫提交給優化器。
  5. 優化器這時會根據一些統計資料,來優化一下執行計畫,最後在打儲存引擎的 api 來處理它。

https://ithelp.ithome.com.tw/upload/images/20190925/20089358KIHIdRZqzM.png
圖 2 : mysql 的運行流程。

MySQL 性能優化方向


咱們基本上理解完 MySQL 基本架構以後,接下來咱們要來看看性能優化的方向,與有沒有什麼地方是性能的減項,但是又一定是需要它的地方。

基本上在下圖的兩個地方 :

  • 存儲引擎
  • 優化器

存儲引擎

首先咱們最重要的地方在於存儲引擎,雖然咱們應用端不太會直接和他接觸,但是如果你不理解它,會完全的無法理解,為什麼要進行之後要說的優化,因此咱們這個部份會往以下幾個地方探討。

  • 索引原理

索引基本上就是資料庫的心臟,索引設計好,帶你上天堂,設計不好,帶你下地獄。而在 mysql 中,就是描述你的資料如何儲的方法,當然不是儲一般檔案那麼簡單,而是需要設計一套規則,來加速查詢,這才是索引真正要做的事情。

優化器

基本上咱們理解完資料如何儲以後,就可以來理解一些咱們實際上如何的優化 sql 性能的技巧,基本上分為以下幾個部份,然後這一些都是會在優化器裡面處理掉。

  • 索引設計
  • 表的設計
  • 優化器優化原理

資料庫層會拖性能後腿,但是又必須處理的地方


資料庫性能大敵就是 :

一致性難題

咱們先簡單的看兩個簡單例子,基本上以下兩個例子,就是咱們資料庫最常見的問題,但這只是冰山一角,之後的文章會更詳細的說明,然後你會發現,下面兩個真的只是個小角落。

在之後的文章中咱們詳細的說明 mysql 它到底是如何的處理『 一致性 』這難題的呢 ?

問題 1 : 銀行轉帳問題

這是一個老掉牙的範例,但是也是最真實的範例。

假設有一個情境要實作 :

帳戶 A 轉帳 1000 元至帳戶 B

而基本上你的操作步驟為:

  1. 帳戶 A 減 1000 元
  2. 帳戶 B 加 1000 元

但如果在進行完 1 後,資料庫掛了,你要如何處理呢 ? 這就是咱們的第一個問題。

問題 2 : 投票問題

假設有一個情境要實作 :

用戶 A 投了 Z 一票,用戶 B 也投了 Z 一票

而基本上你的操作驟為 :

  1. 取出原本 Z 的票數加一 ( 用戶 A )。
  2. 取出原本 Z 的票數加一 ( 用戶 B )。

但問題來了,如果 1、2 是幾乎同時間取出 Z 的票數,要如何處理呢 ?

結論與心得


本篇文章咱們簡單的理解一下 mysql 的架構與一些性能優化的方向,這方向也就是咱們接下來幾篇的重點,接下來資料庫篇要正式的開始囉。

最後咱們重複說一句話 :

資料庫絕對是一個系統的性能核心,請把優質的 DBA 們當寶來餵食

這點真的很重要。

參考資料



上一篇
30-09之應用層的兩個池 - 進 ( 線 ) 程池與連線池
下一篇
30-11 之資料庫層的核心 - 索引結構演化論 B+樹
系列文
30天之從 0 至 1 盡可能的建立一個好的系統 (性能基礎篇)30

尚未有邦友留言

立即登入留言