MySql架構設計:如何合理利用第三方 Cache 解決方案?

無敵天驕發表於2021-03-19

使用較為成熟的第三方解決方案最大的優勢就在於在節省自身研發成本的同時,還能夠在網際網路上面找到較多的文件資訊,幫助我們解決一些日常遇到的問題還是非常有幫助的。

目前比較流行的第三方  Cache 解決方案主要有基於物件的分散式記憶體  Cache 軟體  Memcached 和 嵌入式資料庫程式設計庫 Berkeley DB 這兩種。下面我將分別針對這兩種解決方案做一個分析和架構探討。

一、分散式記憶體 Cache 軟體 Memcached

相信對於很多讀者朋友來說, Memcached 並不會太陌生了吧,他現在的流行程度已經比  MySQL 並不會差太多了。 Memcached 之所以如此的流行,主要是因為以下幾個原因:

  • 通訊協議簡單,API 介面清晰;
  • 高效的 Cache 演算法,基於 libevent 的事件處理機制,效能卓越;
  • 物件導向的特性,對應用開發人員來說非常友好;
  • 所有資料都存放於記憶體中,資料訪問高效;
  • 軟體開源,基於 BSD 開源協議;

對於  Memcached 本身細節,這裡我就不涉及太多了,畢竟這不是本文的重點。下面我們重點看看如何透過  Memcached 來幫助我們你提升資料服務(這裡如果再使用資料庫本身可能會不太合適了)的擴充套件性。

要將  Memcached 較好的整合到系統架構中,首先要在應用系統中讓  Memcached 有一個準確的定位。是僅僅作為提升資料服務效能的一個 Cache 工具,還是讓他與 MySQL 資料庫較好的融合在一起成為一個更為更為高效理想的資料服務層。

①作為提升系統效能的 Cache 工具

如果我們僅僅只是系統透過  Memcached 來提升系統效能,作為一個 Cache 軟體,那麼更多的是需要透過應用程式來維護  Memcached 中的資料與資料庫中資料的同步更新。這時候的  Memcached 基本可以理解為比 MySQL 資料庫更為前端的一個 Cache 層。

如果我們將  Memcached 作為應用系統的一個資料 Cache 服務,那麼對於 MySQL 資料庫來說基本上不用做任何改造,僅僅透過應用程式自己來對這個 Cache 進行維護更新。這樣作最大的好處就在於可以做到完全不用動資料庫相關的架構,但是同時也會有一個弊端,那就是如果需要 Cache 的資料物件較多的時候,應用程式所需要增加的程式碼量就會增加很多,同時系統複雜度以及維護成本也會直線上升。

下面是將  Memcached 用為簡單的 Cache 服務層的時候的架構簡圖。


MySql架構設計:如何合理利用第三方 Cache 解決方案?

從圖中我們可以看到,所有資料都會寫入  MySQL Master 中,包括資料第一次寫入時候 的  INSERT,同時也包括對已有資料的  UPDATE 和  DELETE。不過,如果是對已經存在的資料 ,則需要在  UPDATE 或者  DELETE MySQL 中資料的同時,刪除  Memcached 中的資料,以此保證整體資料的一致性。而所有的讀請求首先會發往  Memcached 中,如果讀取到資料則直接返回,如果沒有讀取到資料,則再到  MySQL Slaves 中讀取資料,並將讀取得到的資料寫入到  Memcached 中進行  Cache

這種使用方式一般來說比較適用於需要快取物件型別少,而需要快取的資料量又比較大的環境,是一個快速有效的完全針對效能問題的解決方案。由於這種架構方式和 MySQL 資料庫本身並沒有太大關係,所以這裡就不涉及太多的技術細節了。

②和 MySQL 整合為資料服務層

除了將  Memcached 用作快速提升效率的工具之外,我們其實還可以將之利用到提高資料服務層的擴充套件性方面,和我們的資料庫整合成一個整體,或者作為資料庫的一個緩衝。

我們首先看看如何將  Memcached 和  MySQL 資料庫整合成一個整體來對外提供服務吧。一般來說,我們有兩種方式將  Memcached 和  MySQL 資料庫整合成一個整體來對外提供資料服務。 一種是直接利用  Memcached  的記憶體容量作為  MySQL  資料庫的二級快取,提升  MySQL Server  的快取大小,另一種是 透過  MySQL    UDF  來和  Memcached  進行資料通訊,維護和更新  Memcached  中的資料,而應用端則直接透過  Memcached  來讀取資料。

對於第一種方式,主要用於業務要求非常特殊,實在難以進行資料切分,而且有很難透過對應用程式進行改造利用上資料庫之外的 Cache 的場景。

當然,在正常情況下是肯定無法做到這一點的,之少目前必須藉助外界的力量,開源專案 Waffle Grid 就是我們需要藉助的外部力量。

Waffle Grid 是國外的幾位 DBA 在工作之餘突發奇想出來的一個點子:既然  PC Server 的低廉成本如此的吸引我們,而其  Scale Up 的能力又很難有一個較大的突破,何不利用上現在非常流行的  Memcached 作為突破單臺  PC Server 的記憶體上限呢?就在這個想法的推動下,幾位小夥子啟動了  Waffle Grid 這個開源專案,利用  MySQL 和  Memcached 雙雙開源的特性,結合  Memcached 通訊協議簡單的特點,將  Memcached 成功實現成為  MySQL 主機的外部“二級快取”,目前僅支援用於  Innodb 的  Buffer Pool

Waffle Grid 的實現原理其實並不複雜,他所做的事情就是當  Innodb 在本地的  Buffer Pool(我們姑且稱其為  Local Buffer Pool 吧)的時候,在從磁碟資料檔案讀取資料之前,先透過  Memcached 的通訊 API 介面嘗試從  Memcached 中讀取相應的快取資料(我們稱之為  Remote Buffer 吧),只有在  Remote Buffer 中也不存在需要的資料的時候,  Innodb 才會訪問磁碟檔案來讀取資料。而且,只有處於  Innodb Buffer pool 中的  LRU List 中的資料會被髮送到  Remote Buffer Pool 中,而這些資料一旦被修改,就會  Innodb 就會將之移入  FLUSH List , Waffle Grid 同時會將進入  FLUSH List 的資料從  Remote Buffer Pool 中清除掉。所以可以說, Remote Buffer Pool 中永遠不會存在  Dirty Pages,這也保證了當  Remote Buffer Pool 出現故障的時候不會產生資料丟失的問題。下圖是使用  Waffle Grid 專案時候的架構簡圖:

MySql架構設計:如何合理利用第三方 Cache 解決方案?

如架構圖上所示,我們首先在  MySQL 資料庫端應用  Waffle Grid Patch,透過他連與其他的  Memcached 伺服器通訊。為了保證網路通訊的效能, MySQL 與  Memcached 之間儘可能用高頻寬私有網路。

另外,這裡的架構圖中並沒有再將資料庫區分  Master 和  Slave 了,並不是說一定不能區分,只是一個示意圖。在實際應用過程中,大部分時候只需要在  Slave 上面應用  Waffle Grid 即可, Master 本身並不需要如此大的記憶體。

看了  Waffle Grid 的實現原理,可能有些讀者朋友會有些疑問了。這樣做不是所有需要產生物理讀的  Query 的效能就會受到直接影響了嗎?所有讀取  Remote Buffer 的操作都需要透過網路來獲取,其效能是否足夠高呢?對此,我同樣使用作者對  Waffle 的實測資料來接觸大家的疑慮:

MySql架構設計:如何合理利用第三方 Cache 解決方案?








透過 DBT2 所得到的這組測試對比資料,在效能我想並不需要太多的擔憂了吧。至於  Waffle Grid 是否適合您的應用場景,那就只能依靠各位讀者朋友自己進行評估了。

下面我們再來介紹一下  Memcached 和  MySQL 的另外一種整合方式,也就是透過  MySQL 所提供的 UDF 功能,自行編寫相應的程式來實現  MySQL 與  Memcached 的資料通訊更新操作。

這種方式和  Waffle Grid 不一樣的是  Memcached 中的資料並不完全由  MySQL 來控制維護,而是由應用程式和  MySQL 一起來維護資料。每次應用程式從  Memcached 讀取資料的時候,如果發現找不到自己需要的資料,則再轉為從資料庫中讀取資料,然後將讀取到的資料寫入  Memcached 中。而  MySQL 則控制  Memcached 中資料的失效清理工作,每次資料庫中有資料被更新或者被刪除的時候, MySQL 則透過使用者自行編寫的 UDF 來呼叫  Memcached 的  API 來通知  Memcached 某些資料已經失效並刪除該資料。

基於上面的實現原理,我們可以設計出如下這樣的一個資料服務層架構:

MySql架構設計:如何合理利用第三方 Cache 解決方案?














如圖中所示,此架構和上面將  Memcached 完全和  MySQL 讀離開作為常規的 Cache 伺服器來比較,最大的區別在於  Memcached 的資料變為由  MySQL 資料庫來維護更新,而不是應用程式來更新。首先資料被應用程式寫入  MySQL 資料庫,這時候將會觸發  MySQL 上面使用者自行編寫的相關 UDF,然後透過該 UDF 呼叫  Memcached 的相關通訊介面,將資料寫入  Memcached。而當  MySQL 中的資料被更新或者刪除的時候, MySQL 中的相關 UDF 同樣會更新或者刪除  Memcached 中的資料。當然,我們也可以讓  MySQL 做更少一些的事情,僅僅只是遇到資料被更新或者刪除的時候,透過 UDF 來刪除  Memcached 中的資料,寫入工作則像前面的架構一樣由應用程式來作。

由於  Memcached 基於物件的資料存取,以及透過  Hash 進行資料檢索的特性,所以所有儲存在  Memcached 中的資料都需要我們設定一個用於標識該資料的 Key,所有資料的存取操作都透過該 Key 來進行。也就是說,如果您並不能像  MySQL 的  Query 語句一樣透過某一個(或者多個)關鍵字條件來讀取包含多條資料的結果集,僅適用於透過某個唯一鍵來獲取單條資料的資料讀取方式。

二、嵌入式資料庫程式設計庫 Berkeley DB

說實話,資料庫程式設計庫這個叫法實在有些彆扭,但我也實在找不到其他合適的名詞來稱呼  Berkeley DB 了,那就姑且使用網上較為通用的叫法吧。

Memcached 所實現的是記憶體式 Cache,如果我們對效能的要求並沒有如此之高,在預算方面也不是太充裕的話,我們還可以選擇  Berkeley DB 這樣的資料庫型 Cache 軟體。可能很多讀者朋友又會產生疑惑了,我們使用的  MySQL 資料庫,為什麼還要再使用一個  Berkeley DB 這樣的“資料庫”呢?實際上  Berkeley DB 在之前也是  MySQL 的儲存引擎之一,只不過後期不知道是何原因(獲取與商業競爭有關吧),被  MySQL 從支援的儲存引擎中移除了。之所以在使用資料庫的同時還使用  Berkeley DB 這樣的資料庫型 Cache,是因為我們可以充分發揮出二者各自的優勢,在使用傳統通用型資料庫的同時,同時可以利用  Berkeley DB  高效的鍵值對儲存方式作為高效資料檢索的效能補充,以得到更好的資料服務層擴充套件性和更高的整體效能

Berkeley DB 自身架構可以分為五個功能模組,五個模組的在整個系統中相對比較獨立,而且可以設定使用或者禁用某一個(或者幾個)模組,所以可能稱之為五個子系統會更為恰當一些。這五個子系統及基本介紹分別如下:

  • 資料存取
    資料存取子系統主要負責最主要也是最基本的資料存與取的工作。而且  Berkeley DB 同時支援了以下四種資料的儲存結果方式: HashB-TreeFixed Length 以及  Dynamic Length。實際上,這四種方式對應了四種資料檔案儲存的實際格式。資料儲存子系統可以完全單獨使用,也是必須開啟的一個子系統。
  • 事務管理
    事務管理子系統主要是針對有事務要求的資料處理服務,提供完整的  ACID 事務屬性。在開啟事務管理子系統的時候,出了需要開啟最基本的資料存取子系統外,還至少需要開啟鎖管理子系統和日誌系統來幫助實現事務的一致性和完整性。
  • 鎖管理
    鎖管理系統主要就是為了保證資料的一致性而提供的共享資料控制功能。支援行級別和頁級別的鎖定機制,同時為事務管理子系統提供服務。
  • 共享記憶體
    共享記憶體子系統我想大家看到名稱就應該基本知道是做什麼事情的了,就是用來管理維護共享  Cache 和  Buffer 的,為系統提升效能而提供資料快取服務。
  • 日誌系統
    日誌系統主要服務於事務管理系統,為保證事務的一致性, Berkeley DB 也採用先寫日誌再寫資料的策略,一般也都是與事務管理系統同時使用同時關閉。

基於  Berkeley DB 的特性,我們很難像使用  Memcached 那樣將他和  MySQL 資料庫結合的那麼緊密。資料的維護與更新操作主要還是需要透過應用程式來完成。一般來說,在使用  MySQL 的同時還要使用  Berkeley DB 的主要原因就是為了提升系統的效能及擴充套件性。所以,大多數時候都主要是使用  Hash 和  B-Tree 這兩種結構的資料儲存格式,尤其是  Hash 格式,是使用最為廣泛的,因為這種方式也是存取效率最高的。

在應用程式中,每次資料請求,都先透過預先設定的  Key 到  Berkeley DB 中取查詢一次,如果存在資料,則返回取得的資料,如果位檢索到資料,則再次到資料庫中讀取。然後將讀取到的資料按照預先設定的  Key,整條存入  Berkeley DB 中,再返回給客戶端。而當發生資料修改的時候,應用程式在修改  MySQL 中的資料之後必須還要將  Berkeley DB 中的資料刪除。當然,如果您願意,也可以直接修改  Berkeley DB 中的資料,但是這樣就可能引入更多的資料一致性風險並提高系統複雜度了。

從原理來看,使用  Berkeley DB 的方式和將  Memcached 作為純  Cache 來使用差別不大嘛,為什麼我們不用  Memcached 來做呢?其實主要有兩個原因,一個是  Memcached 是使用純記憶體來存放資料的,而  Berkeley DB 則可以使用物理磁碟,兩者在成本方面還是有較大差別的。另外一個原因就是  Berkeley DB 所能支援的資料儲存方式除了  Memcached 所使用的  Hash 儲存格式之外,同時還可以使用其他儲存格式,如  B-Tree 等。

由於和  Memcached 的基本使用原理區別不大,所以這裡就不再畫圖示意了。


來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/69964492/viewspace-2763901/,如需轉載,請註明出處,否則將追究法律責任。

相關文章