假設您有一個使用Node.js(或其他平台)開發的應用程式,該應用程式連接到MongoDB資料庫(NoSQL)以儲存書籍評分(給予的星數和評論)。同時,您還有另一個使用Java(或Python、C#、TypeScript…等)開發的應用程式,該應用程式連接到MariaDB資料庫(SQL,關聯式)以管理書籍目錄(標題、出版年份、頁數)。
您被要求創建一個報告,顯示每本書的標題和評分信息。請注意,MongoDB資料庫不包含書籍標題,而關聯式資料庫不包含評分。我們需要將NoSQL應用程式創建的數據與SQL應用程式創建的數據混合。
A common approach to this is to query both databases independently (using different data sources) and process the data to match by, for example, ISBN (the id of a book) and put the combined information in a new object. This needs to be done in a programming language like Java, TypeScript, C#, Python, or any other imperative programming language that is able to connect to both databases.
A polyglot application
這種方法可行。然而,合併數據是資料庫的工作。它們專為這類數據操作而設計。此外,採用此方法,SQL應用程式不再僅是SQL應用程式;它變成了資料庫多語言,這增加了複雜性,使其更難維護。
透過資料庫代理如MaxScale,您可以在資料庫層級使用最適合數據的語言——SQL來合併這些數據。您的SQL應用程式無需變成多語言。
儘管這需要在基礎設施中增加一個額外元素,但同時你也能獲得資料庫代理所提供的所有功能,例如自動故障轉移、透明資料遮罩、拓撲隔離、快取、安全過濾器等等。
MaxScale 是一款強大且智慧的資料庫代理,它理解 SQL 和 NoSQL。同時,它也理解Kafka(用於 CDC 或資料攝取),但這屬於另一個話題。簡而言之,透過 MaxScale,你可以將你的 NoSQL 應用程式連接到一個完全符合 ACID 規範的關聯式資料庫,並將資料直接儲存在其他 SQL 應用程式使用的表格旁邊。
MaxScale 允許 SQL 應用程式消費 NoSQL 資料。
讓我們嘗試使用 MaxScale 進行一個快速且易於跟隨的實驗。你需要在你的電腦上安裝以下內容:
設置MariaDB資料庫
使用純文本編輯器,創建一個新文件並將其命名為docker-compose.yml。該文件應包含以下內容:
version: "3.9"
services:
mariadb:
image: alejandrodu/mariadb
environment:
- MARIADB_CREATE_DATABASE=demo
- MARIADB_CREATE_USER=user:Password123!
- MARIADB_CREATE_MAXSCALE_USER=maxscale_user:MaxScalePassword123!
maxscale:
image: alejandrodu/mariadb-maxscale
command: --admin_host 0.0.0.0 --admin_secure_gui false
ports:
- "3306:4000"
- "27017:27017"
- "8989:8989"
environment:
- MAXSCALE_USER=maxscale_user:MaxScalePassword123!
- MARIADB_HOST_1=mariadb 3306
- MAXSCALE_CREATE_NOSQL_LISTENER=user:Password123!
這是一個Docker Compose文件。它描述了由Docker創建的一組服務。我們正在創建兩個服務(或容器)——一個MariaDB數據庫服務器和一個MaxScale數據庫代理。它們將在您的本地機器上運行,但在生產環境中,通常將它們部署在單獨的物理機器上。請記住,這些Docker映像不適合生產使用!它們旨在適合快速演示和測試。您可以在GitHub上找到這些映像的源代碼。對於來自MariaDB的官方Docker映像,請前往Docker Hub上的MariaDB頁面。
先前的Docker Compose檔案設定了名為demo
的MariaDB資料庫伺服器(資料庫與schema在MariaDB中為同義詞)。同時,創建了一個用戶名user
,其密碼為Password123!
。此用戶對demo
資料庫擁有適當的權限。另外還有一個用戶名maxscale_user
,密碼為MaxScalePassword123!
,這是MaxScale資料庫代理將用來連接到MariaDB資料庫的用戶。
Docker Compose檔案還配置了資料庫代理,禁用HTTPS(生產環境中切勿如此操作!),開放一組埠(稍後詳述),並配置了資料庫用戶及MariaDB資料庫代理的位置(通常是IP地址,但在此我們可以使用Docker檔案中先前定義的容器名稱)。最後一行創建了一個NoSQL listener,我們將用它以MongoDB客戶端身份連接到預設埠(27017)。
要使用命令行啟動服務(容器),請轉到保存Docker Compose檔案的目錄並運行以下命令:
docker compose up -d
下載所有軟件並啟動容器後,您將獲得一個已預先配置好的MariaDB資料庫和MaxScale代理,以供本次實驗使用。
在MariaDB中創建SQL表
讓我們連接到關聯式資料庫。在命令行中執行以下指令:
mariadb-shell --dsn mariadb://user:'Password123!'@127.0.0.1
確認您能看到 demo
資料庫:
show databases;
切換到 demo
資料庫:
use demo;
使用MariaDB Shell連接資料庫。
創建 books
表格:
CREATE TABLE books(
isbn VARCHAR(20) PRIMARY KEY,
title VARCHAR(256),
year INT
);
插入一些數據。我將使用插入自己的 書籍 這一老梗:
INSERT INTO books(title, isbn, year)
VALUES
("Vaadin 7 UI Design By Example", "978-1-78216-226-1", 2013),
("Data-Centric Applications with Vaadin 8", "978-1-78328-884-7", 2018),
("Practical Vaadin", "978-1-4842-7178-0", 2021);
通過運行以下命令來檢查書籍是否已存儲在資料庫中:
SELECT * FROM books;
使用MariaDB Shell插入數據。
在MariaDB中創建JSON集合
我們尚未安裝MongoDB,但我們可以使用MongoDB客戶端(或應用程序)連接以創建集合和文檔,就像我們正在使用MongoDB一樣,只不過數據存儲在一個強大、完全ACID-合規且可擴展的關係型資料庫中。讓我們試試看!
在命令行中,使用MongoDB shell工具連接到MongoDB…等等…實際上是MariaDB資料庫!運行以下命令:
mongosh
默認情況下,此工具嘗試連接到本地機器(127.0.0.1)上使用默認端口(20017)運行的MongoDB服務器(這次實際上是MariaDB)。如果一切順利,當您運行以下命令時,應該能看到列出的 demo
資料庫:
show databases
切換到 demo
資料庫:
use demo
使用Mongo Shell連接MariaDB。
我們從非關聯式客戶端連接到關聯式資料庫!讓我們建立ratings
集合並將一些數據插入其中:
db.ratings.insertMany([
{
"isbn": "978-1-78216-226-1",
"starts": 5,
"comment": "A good resource for beginners who want to learn Vaadin"
},
{
"isbn": "978-1-78328-884-7",
"starts": 4,
"comment": "Explains Vaadin in the context of other Java technologies"
},
{
"isbn": "978-1-4842-7178-0",
"starts": 5,
"comment": "The best resource to learn web development with Java and Vaadin"
}
])
檢查評分是否在資料庫中持久化:
db.ratings.find()
使用Mongo Shell查詢MariaDB資料庫。
在MariaDB中使用JSON函數
至此,我們擁有一個資料庫,從外部看,它既像是NoSQL(MongoDB)資料庫,又像是關聯式(MariaDB)資料庫。我們能夠連接到同一個資料庫,並從MongoDB客戶端和SQL客戶端進行數據的寫入和讀取。所有數據都存儲在MariaDB中,因此我們可以使用SQL將來自MongoDB客戶端或應用程序的數據與來自MariaDB客戶端或應用程序的數據進行聯接。讓我們探索MaxScale是如何使用MariaDB來存儲MongoDB數據(集合和文檔)的。
使用SQL客戶端如mariadb-shell
連接到資料庫,並顯示演示模式中的表:
show tables in demo;
您應該看到books
和ratings
表都被列出。ratings
作為MongoDB集合創建。MaxScale將來自MongoDB客戶端的命令進行了翻譯,並創建了一個表來存儲數據。讓我們看看這個表的結構:
describe demo.ratings;
A NoSQL collection is stored as a MariaDB relational table.
ratings
表包含兩個欄位:
id
:對象ID。doc
:以JSON格式表示的文檔。
若檢視表格內容,我們會發現所有關於評分的資料都儲存在doc
欄位中,採用JSON格式:
SELECT doc FROM demo.ratings \G
NoSQL文件儲存於MariaDB資料庫中。
讓我們回歸初衷——展示帶有評分資訊的書籍標題。以下情況並非現實,但假設片刻ratings
表為一個具有stars
和comment
欄位的常規表。若真如此,將此表與books
表連接將十分簡單,任務即告完成:
/* this doesn’t work */
SELECT b.title, r.stars, r.comment
FROM ratings r
JOIN books b USING(isbn)
回到現實。我們需將實際ratings
表中的doc
欄位轉換為可作為查詢中新表使用的關聯式表達。如下所示:
/* this still doesn’t work */
SELECT b.title, r.stars, r.comment
FROM ratings rt
JOIN ...something to convert rt.doc to a table... AS r
JOIN books b USING(isbn)
那個something即為JSON_TABLE
函數。MariaDB包含一系列JSON函數,用於操作JSON字串。我們將使用JSON_TABLE
函數將doc
欄位轉換為可用於執行SQL連接的關聯形式。JSON_TABLE
函數的一般語法如下:
JSON_TABLE(json_document, context_path COLUMNS (
column_definition_1,
column_definition_2,
...
)
) [AS] the_new_relational_table
其中:
json_document
:用於提取的JSON文件,可以是字串或返回JSON文件的表達式。context_path
: 一個JSON Path表達式,定義用作行來源的節點。
而列定義(column_definition_1
、column_definition_2
等…)具有以下語法:
new_column_name sql_type PATH path_in_the_json_doc [on_empty] [on_error]
結合這些知識,我們的SQL查詢將如下所示:
SELECT b.title, r.stars, r.comment
FROM ratings rt
JOIN JSON_TABLE(rt.doc, '$' COLUMNS(
isbn VARCHAR(20) PATH '$.isbn',
stars INT PATH '$.starts',
comment TEXT PATH '$.comment'
)
) AS r
JOIN books b USING(isbn);
在一個SQL查詢中結合NoSQL和SQL數據。
我們本可以使用ISBN值作為MongoDB ObjectID,並因此作為ratings
表中的id
列,但我將這留給你作為一個練習(提示:使用_id
而不是isbn
當使用MongoDB客戶端或應用程序插入數據時)。
A Word on Scalability
有一種誤解認為關係數據庫不能水平擴展(添加更多節點),而NoSQL數據庫可以。但關係數據庫在不犧牲ACID屬性的情況下擴展。MariaDB擁有多個針對不同工作負載定制的存儲引擎。例如,你可以通過實現Spider幫助下的數據分片來擴展MariaDB數據庫。你還可以使用各種存儲引擎以每表為基礎處理不同工作負載。在一個SQL查詢中實現跨引擎聯接是可能的。
在一個邏輯MariaDB數據庫中結合多個存儲引擎。
另一種更現代的替代方案是分散式SQL搭配MariaDB Xpand。分散式SQL資料庫透過透明分片,對應用程式呈現為單一邏輯關聯式資料庫。它採用無共享架構,能同時擴展讀取和寫入操作。
A distributed SQL database deployment.
結論
我們的任務已圓滿完成!現在,您的系統能夠擁有一個符合ACID原則、可擴展的360度數據視圖,無論數據是由SQL或NoSQL應用程式產生。從NoSQL遷移至SQL或使SQL應用程式成為多資料庫通用型的需求減少。如欲了解更多MaxScale的其他功能,請觀看此影片或訪問文件。
Source:
https://dzone.com/articles/mixing-sql-and-nosql-with-mariadb-and-mongodb