Apache Cassandra和Apache Ignite:關係並置和分佈式SQL 頂 原 薦

在上一篇文章中,回顧和總結了Cassandra中使用的查詢驅動數據模型(或者說非常規數據模型)方法論的缺陷。事實證明,如果不對查詢有深入的瞭解,通過該方法論將無法開發高效的應用。實際上,這種場景的應用架構上會變得更加的複雜,難於維護,並且會造成很大的數據冗餘。

此外,這個問題通常會被這樣的觀點掩蓋:“如果想要擴展性、速度以及高可用性,那麼就得準備存儲多份數據,並且犧牲SQL和強一致性。”,這個論調十年前可能是正確的,但是現在完全錯誤!

沒那麼誇張,我們選擇了另一個ASF成員,Apache Ignite。在本文中,會講解基於Ignite的應用架構,然後衡量它的維護成本。

我們選擇的應用仍然是跟蹤所有廠商生產的車輛,然後瞭解每個單一廠商的產能,如果看過第一篇文章,那麼應該知道關係模型如下:

下一步,可以使用Ignite的CREATE TABLE命令創建這三個表,然後運行由SQL驅動的應用了麼?不一定,如果不需要對存儲於不同表中的數據進行關聯操作,那麼是可以的。但是根據前文,前提是應用需要支持兩種關聯的查詢:

  1. Q1:獲取一個廠商在特定的時間段內生產的車型。
  2. Q2:獲取一個廠商特定車型的產量。

在Cassandra的案例中,我們爲每個查詢創建了一張表規避了關聯的問題,那麼用Ignite,是不是還要經歷同樣的過程?完全不用。事實上,Ignite的非並置的關聯已經完全可用,如果三個表已經建好了,那麼不需要什麼額外的工作。但是,這沒有比並置的高效和快速。因此,首先要多學習一下關係並置,然後瞭解這個概念在Ignite中是如何使用的。

基於並置關聯的數據模型

關係並置在Ignite(還有其他的分佈式數據庫,比如Google Spanner以及MemSQL)中是一個強大的概念,它可以在以一個集羣節點上存儲相關的數據。那麼哪些數據是相關的呢?尤其是在關係數據庫的背景下,這非常簡單,只需要在業務對象之間標示一個父子關係,在CREATE TABLE語句中指定一個關係鍵就可以了,剩下的就交給Ignite了!

還是拿車輛和廠商的應用舉例,使用廠商作爲父實體,車輛作爲子實體是合理的。比如,按照這樣配置好之後,某個廠商生產的所有車輛數據都會存儲於同一個節點上,如下圖所示:

如圖所示,豐田生產的車輛都存儲於節點1,而福特生產的車輛都存儲於節點2,這就是關係並置,車輛都會存儲於對應的廠商所在的節點上。

要做到這樣的數據分佈,Vendor表的SQL定義如下:

CREATE TABLE Vendor (
    id INT PRIMARY KEY,
    name VARCHAR,
    address VARCHAR
);

廠商數據會在整個集羣中隨機地分佈,Ignite會使用主鍵列計算廠商數據所在的節點。 下一個是Car表:

CREATE TABLE Car (
    id INT,
    vendor_id INT,
    model VARCHAR,
    year INT,
    price float,
    PRIMARY KEY(id, vendor_id)
) WITH "affinityKey=vendor_id";

車輛表有一個affinityKey參數,配置爲vendor_id列,它告訴Ignite,車輛存儲於vendor_id對應的集羣節點。

Production表上重複同樣的過程,它的數據也是存儲於vendor_id對應的集羣節點上,如下:

CREATE TABLE Production (
    id INT,
    car_id INT,
    vendor_id INT,
    country VARCHAR,
    total INT,
    year INT,
    PRIMARY KEY(id, car_id, vendor_id)
) WITH "affinityKey=vendor_id";

這樣數據模型就建完了,下一步就進入應用的代碼,然後開發必要的查詢。

帶關聯的SQL查詢

Ignite集羣可以使用我們熟悉的SQL進行查詢,它支持分佈式的SQL關聯以及二級索引。 Ignite支持兩種類型的關聯:並置非並置。假定要關聯的表已經並置,並且本地數據全部可用,那麼並置的關聯會避免數據(關聯所需的)的移動,這是在分佈式數據庫中效率最高、性能最好的。如果部分表無法實現關係並置,但是還需要進行關聯,那麼非並置的關聯就是一個備份計劃。這種類型的關聯速度較慢,因爲在關聯時它需要在集羣節點間進行數據的移動。

之前,已經配置好了VendorCarProduction表,下一步就是利用並置關聯的優勢,爲Q1寫一個SQL:

SELECT c.model, p.country, p.total, p.year FROM Vendor as v
JOIN Production as p ON v.id = p.vendor_id
JOIN Car as c ON c.id = p.car_id
WHERE v.name = 'Ford Motor' and p.year >= 2017
ORDER BY p.year;

還能更快麼?當然能。下面爲Vendor.nameProduction.year列定義二級索引:

CREATE INDEX vendor_name_id ON Vendor (name);
CREATE INDEX prod_year_id ON Production (year);

針對Q2的查詢也不需要額外的工作:

SELECT p.country, p.total, p.year FROM Vendor as v
JOIN Production as p ON v.id = p.vendor_id
JOIN Car as c ON c.id = p.car_id
WHERE v.name = 'Ford Motor' and c.model = 'Explorer';

現在,如果老闆要求增加一個新特性時,很快就能構造出一套新的SQL滿足他。 完成!作爲比較,如果要支持Q2,可以看看基於Cassandra的架構是怎麼搞的。

架構簡化:任務完成!

Ignite的基於關係並置的數據模型,針對Cassandra的基於查詢驅動的模型有如下的優點:

  • 應用的數據層基於熟悉的關係模型進行建模,易於維護;
  • 數據使用標準的SQL語法進行訪問;
  • 關係並置提供了現代分佈式數據庫的更多好處:

使用Ignite替代Cassandra,簡化的軟件架構並不是唯一的好處,過段時間,還會有關於強一致性和內存極性能方面的想法。

本文譯自Denis Magda的博客

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章