Cassandra數據建模

来源:https://www.cnblogs.com/cjsblog/archive/2020/05/13/12878330.html
-Advertisement-
Play Games

1. 概述 Apache Cassandra將數據存儲在表中,每個表都由行和列組成。CQL(Cassandra查詢語言)用於查詢存儲在表中的數據。Apache Cassandra數據模型基於查詢並針對查詢進行了優化。Cassandra不支持用於關係資料庫的關係數據建模。Cassandra數據建模專註 ...


1.  概述

Apache Cassandra將數據存儲在表中,每個表都由行和列組成。CQL(Cassandra查詢語言)用於查詢存儲在表中的數據。Apache Cassandra數據模型基於查詢並針對查詢進行了優化。Cassandra不支持用於關係資料庫的關係數據建模。Cassandra數據建模專註於查詢。

Cassandra中的數據建模使用查詢驅動(query-driven)的方法,其中特定查詢是組織數據的關鍵。查詢(Query)是從表中選擇數據的結果,模式(Schema)是對錶中數據的排列方式的定義。Cassandra的資料庫設計基於對快速讀寫的需求,因此架構設計越好,數據寫入和檢索的速度就越快。

相反,關係型資料庫根據設計的表和關係對數據進行規範化,然後編寫將要進行的查詢。關係資料庫中的數據建模是表驅動(table-driven)的,表之間的任何關係都表示為查詢中的表連接。

1.1.  什麼是數據建模

數據建模是識別實體及其關係的過程。在關係資料庫中,數據放在具有外鍵的規範化表中,外鍵用於引用其他表中的相關數據。應用程式將進行的查詢由表的結構驅動,相關數據作為表連接進行查詢。

在Cassandra中,數據建模是查詢驅動(query-driven)的。 數據訪問模式和應用程式查詢確定數據的結構和組織,然後將其用於設計資料庫表。

數據圍繞特定查詢建模。查詢的最佳設計是訪問單個表,這意味著查詢中涉及的所有實體必須位於同一表中,以使數據訪問(讀取)變得非常快。 數據被建模為最適合一個查詢或一組查詢。一個表可能具有一個或多個最適合查詢的實體。由於實體之間通常確實具有關係,並且查詢可能涉及實體之間具有關係的實體,因此單個實體可以包含在多個表中。

1.2.  查詢驅動的建模

在關係資料庫模型中,查詢使用表連接從多個表獲取數據,而在Cassandra中不支持連接,因此所有必需欄位(列)必須組合在一個表中。由於每個查詢都由一個表支持,因此在稱為非規範化的過程中,數據會在多個表之間冗餘。 數據冗餘和高寫入吞吐量用於實現高讀取性能。 

1.3.  目標

主鍵(primary key)和分區鍵(partition key)的選擇對於在整個集群中均勻分佈數據很重要。使查詢讀取的分區數量保持最少也很重要,因為不同的分區可能位於不同的節點上,並且協調器將需要向每個節點發送請求,從而增加了請求的開銷和延遲。即使查詢中涉及的不同分區位於同一節點上,較少的分區也可以提高查詢效率。 

1.4.  分區

分區鍵(partition key)是從主鍵(primary key)的第一個欄位生成的。使用分區鍵分區到哈希表的數據可以提供更快的查詢。用於查詢的分區越少,查詢的響應時間就越快。

下麵是一個分區的例子,假設表t有一個主機id

CREATE TABLE t (
   id int,
   k int,
   v text,
   PRIMARY KEY (id)
);

分區鍵是從主鍵id生成的,用於在群集中的各個節點之間進行數據分配。

下麵這個例子,是一個複合主鍵

CREATE TABLE t (
   id int,
   c text,
   k int,
   v text,
   PRIMARY KEY (id,c)
);

對於具有複合主鍵的表t,第一個欄位id用於生成分區鍵,第二個欄位c是用於在分區內排序的聚類鍵。使用聚類鍵對數據進行排序可以提高檢索相鄰數據的效率。

通常,對主鍵的第一個欄位進行哈希處理以生成分區鍵,而其餘欄位則是用於對分區內的數據進行排序的聚類關鍵字。對數據進行分區可以提高讀寫效率。不是主鍵欄位的其他欄位可以單獨建立索引,以進一步提高查詢性能。

接下來這個例子,id1和id2用戶生成分區鍵,c1和c2用於在分區內排序的聚類關鍵字。

CREATE TABLE t (
   id1 int,
   id2 int,
   c1 text,
   c2 text
   k int,
   v text,
   PRIMARY KEY ((id1,id2),c1,c2)
);

1.5.  與關係數據模型比較

關係資料庫使用外鍵將數據存儲在與其他表有關係的表中。關係資料庫的數據建模方法是以表為中心的。查詢必須使用表連接從多個表中獲取數據,這些表之間存在關係。Apache Cassandra沒有外鍵或關係完整性的概念。Cassandra的數據模型是基於設計高效的查詢,不涉及多個表的查詢。關係資料庫對數據進行規範化以避免重覆。相反,Cassandra通過在以查詢為中心的數據模型的多個表中冗餘數據來對數據進行非規範化。如果Cassandra數據模型不能完全整合用於特定查詢的不同實體之間關係的複雜性,則可以使用應用程式代碼中的客戶端連接(client-side joins)。

1.6.  數據建模示例

假設有一組雜誌數據,屬性有雜誌id、雜誌名稱、出版頻率、出版日期和出版商。

查詢一:列出所有雜誌名稱,包括其發佈頻率。 

由於不需要查詢所有屬性,因此數據模型將僅由ID(用於分區鍵),雜誌名稱和發佈頻率組成,如下圖所示:

 

查詢二:按出版商列出所有雜誌名稱

輸出列增加出版商,同時用出版商作分區鍵,如下圖所示:

1.7.  定義Schema

對於查詢一,定義如下:

CREATE TABLE magazine_name (
    id int PRIMARY KEY,
    name text,
    publication_requency text
)

對於查詢二,定義如下:

CREATE TABLE magazine_publisher (
    publisher text,
    id int,
    name text, 
    publication_requency text,
    PRIMARY KEY (publisher, id)
) WITH CLUSTERING ORDER BY (id DESC)

2.  概念數據建模

首先,創建一個簡單的域模型,它在關係型世界中很容易理解,然後看看如何在Cassandra中將它從關係型映射到分散式哈希表模型。

以酒店預訂為例,概念性領域包括酒店、入住酒店的客人、每個酒店的房間集合、這些房間的價格和空房情況以及為客人預訂的預訂記錄。酒店通常還會維護“景點”的集合,這些景點包括公園,博物館,購物畫廊,古跡或客人在住宿期間可能要參觀的酒店附近的其他地方。旅館和興趣點都需要維護地理位置數據,以便可以在地圖上找到它們進行混搭,並計算距離。ER圖如下:

   

一目瞭然,一個酒店有多個房間,一個房間裡面有多個休閑設施,房間的空閑情況也是分時段的,酒店附近有多個景點,一位顧客可以訂多個房間,每一個預訂記錄對應多個房間。

3.  關係型資料庫設計

當我們構建一個新的數據驅動應用程式時,將使用關係型資料庫。首先,將領域對象轉化為一組規範化的表,並使用外鍵引用其他表中的相關數據。

 

3.1.  RDBMS和Cassandra之間的設計差異

沒有連接(join

在Cassandra中,無法執行連接(join)操作。如果你已經設計了一個數據模型並且需要一個連接其它表的數據,那麼你不得不在客戶端做這種連接,或者創建一個非規範化的第二個表來表示連接結果,後一種方法是Cassandra數據建模的首選方法。

• 沒有外鍵引用

在關係資料庫中,可以在表中指定外鍵來引用另一個表的主鍵。但Cassandra並沒有強制要求必須定義外鍵來引用。在表中存儲與其他實體相關的ID仍然是常見的設計需求,但是級聯刪除等操作不可用。

• 非規範化

在關係資料庫設計中,經常會強調範式重要性,資料庫設計三範式。但是在Cassandra中,遵循範式不是一個好的選擇,因為通常在不遵循範式時執行得最好。

關係資料庫故意去規範化的第二個原因是需要保留的業務文檔結構。也就是說,有一個封閉的表,它引用了很多外部表,這些表的數據可能會隨著時間的變化而變化,但是你需要將封閉的文檔保存為歷史記錄中的一個快照。這裡最常見的例子是發票。假設已經有了customer和product表,可能你認為可以只製作一個針對這些表的發票,但在實踐中永遠不應該這樣做。顧客或價格信息可能會改變,然後你將失去失去發票單據上發票日期的完整性,這可能違反審計、報告、或法律,並導致其他問題。可以看到,在這種情況下,冗餘是必要的。

在Cassandra中,非規範化是完全正常的。

查詢優先

簡單的來說,關係建模意味著概念領域模型開始,用表來表示領域對象,用表欄位來表示領域對象的屬性,然後設置主鍵和外鍵來表示領域對象之前的關係。如果有多對多的關係,還要再建一張中間表。關係世界中的查詢是次要的。只要對錶進行適當的建模,就可以始終獲得所需的數據。即使必須使用幾個複雜的子查詢或連接語句,這通常也是正確的。

相比之下,在Cassandra中,不是從數據模型開始的,而是從查詢模型開始的。Cassandra不是先對數據建模,然後編寫查詢,而是先對查詢建模,讓數據圍繞查詢進行組織。考慮應用程式將使用的最常見的查詢路徑,然後創建支持它們所需的表。

• 最佳存儲設計

在關係資料庫中,對於用戶來說,表是如何存儲在磁碟上的通常是透明的,基本不用關心。然而,這是Cassandra中的重要考慮因素。由於Cassandra表都存儲在磁碟上的獨立文件中,因此將相關列一起定義在同一個表中非常重要。

在Cassandra中創建數據模型時,一個關鍵目標是最小化必須搜索的分區數量,以滿足給定的查詢。由於分區是不跨節點劃分的存儲單元,因此搜索單個分區的查詢通常會產生最佳性能。

• 排序是一個設計決策

在RDBMS中,可以通過在查詢中使用ORDER BY輕鬆地更改記錄返回的順序。預設的排序順序是不可配置的;預設情況下,記錄是按照寫入的順序返回的。如果要更改順序,只需修改查詢即可,並且可以根據任何列進行排序。

但是,在Cassandra中,排序的處理方式有所不同。這是一個設計決策。查詢中可用的排序順序是固定的,並且完全由在CREATE TABLE命令中提供的集群列的選擇確定。CQL SELECT語句確實支持ORDER BY語義,但僅按聚簇列指定的順序。

4.  定義應用程式的查詢

既然是查詢驅動的,那麼就先看看針對酒店預訂這個例子,業務都需要查詢,畢竟技術是為業務服務的,拋開業務彈設計是不可取的。

(畫外音:此刻,突然想到那句“技術支撐商業、技術拓展商業、技術創作商業”)

言歸正傳,在酒店預訂的例子中,可以大致梳理出以下業務查詢:

Q1: 查找某個景點附近的酒店
Q2: 查找某個酒店的信息
Q3: 查找某個酒店附近的景點
Q4: 在給定的日期範圍內找到一個可用的房間
Q5: 查找房間的價格和設施
Q6: 通過確認碼查找預訂
Q7: 根據酒店、日期和顧客姓名查找預訂
Q8: 按顧客姓名查找所有預訂
Q9: 查看顧客詳細信息

 

5.  邏輯數據建模

為了更生動形象地表示數據模型,這裡採用下麵這種圖表方式:

 

5.1.  Hotel邏輯數據模型

按照上面的圖表方式,酒店邏輯數據模型表示如下:

5.2.  Reservation邏輯數據模型

同樣的方式,預訂邏輯數據模型表示如下:

6.  物理數據建模

(畫外音:一切設計都是為了查詢,這話聽著很耳熟,哈哈,Elasticsearch說過,一切設計都是為了提高檢索的性能) 

為了方便理解,採用如下格式來表示。不用多說,看圖說話:

 

酒店數據模型:

預訂數據模型:

7.  評估和完善數據模型

7.1.  計算分區大小

首先要考慮的是,表的分區是否太大,或者換句話說,太寬。分區大小是通過存儲在分區中的單元格(值)的數量來度量的。Cassandra的硬限制是每個分區有20億個單元格(PS:類比Excel中的單元格),但是在達到這個限制之前,可能會遇到性能問題。

分區大小計算公式:N_v = N_r (N_c - N_{pk} - N_s) + N_s

其中:

N_r表示行數
N_c表示列數
N_pk表示主鍵列數
N_s表示靜態列數
N_v表示單元格數量

那麼,單元格數量 = 行數 × (總列數 - 主鍵列數 - 靜態列數) + 靜態列數

以available_rooms_by_hotel_date表為例,根據公式,該表的單元格總數 = 行數 × (4 - 3 -0) + 0

7.2.  計算磁碟大小

每種數據類型所占磁碟空間大小不一,粗略地可以用所有列所占磁碟大小乘以行數來計算

7.3.  拆分大分區

有一種稱為bucketing的技術常被用來將數據分割成中等大小的分區。例如,可以通過向分區鍵添加一個month列(可能表示為一個整數)來分解available_rooms_by_hotel_date表。與原設計的對比如下圖所示。雖然month列部分重覆了date,但它提供了一種很好的方法,可以在分區中對相關數據進行分組,而且分區不會變得太大。

 

8.  定義資料庫Schema

schema可以理解為資料庫,一個schema就是指一個資料庫

下麵是為hotel keyspace定義的schema:

CREATE KEYSPACE hotel WITH replication =
  {‘class’: ‘SimpleStrategy’, ‘replication_factor’ : 3};

CREATE TYPE hotel.address (
  street text,
  city text,
  state_or_province text,
  postal_code text,
  country text );

CREATE TABLE hotel.hotels_by_poi (
  poi_name text,
  hotel_id text,
  name text,
  phone text,
  address frozen<address>,
  PRIMARY KEY ((poi_name), hotel_id) )
  WITH comment = ‘Q1. Find hotels near given poi’
  AND CLUSTERING ORDER BY (hotel_id ASC) ;

CREATE TABLE hotel.hotels (
  id text PRIMARY KEY,
  name text,
  phone text,
  address frozen<address>,
  pois set )
  WITH comment = ‘Q2. Find information about a hotel’;

CREATE TABLE hotel.pois_by_hotel (
  poi_name text,
  hotel_id text,
  description text,
  PRIMARY KEY ((hotel_id), poi_name) )
  WITH comment = Q3. Find pois near a hotel’;

CREATE TABLE hotel.available_rooms_by_hotel_date (
  hotel_id text,
  date date,
  room_number smallint,
  is_available boolean,
  PRIMARY KEY ((hotel_id), date, room_number) )
  WITH comment = ‘Q4. Find available rooms by hotel date’;

CREATE TABLE hotel.amenities_by_room (
  hotel_id text,
  room_number smallint,
  amenity_name text,
  description text,
  PRIMARY KEY ((hotel_id, room_number), amenity_name) )
  WITH comment = ‘Q5. Find amenities for a room’;

reservation keyspace 的 schema 如下:

CREATE KEYSPACE reservation WITH replication = {‘class’:
  ‘SimpleStrategy’, ‘replication_factor’ : 3};

CREATE TYPE reservation.address (
  street text,
  city text,
  state_or_province text,
  postal_code text,
  country text );

CREATE TABLE reservation.reservations_by_confirmation (
  confirm_number text,
  hotel_id text,
  start_date date,
  end_date date,
  room_number smallint,
  guest_id uuid,
  PRIMARY KEY (confirm_number) )
  WITH comment = ‘Q6. Find reservations by confirmation number’;

CREATE TABLE reservation.reservations_by_hotel_date (
  hotel_id text,
  start_date date,
  end_date date,
  room_number smallint,
  confirm_number text,
  guest_id uuid,
  PRIMARY KEY ((hotel_id, start_date), room_number) )
  WITH comment = ‘Q7. Find reservations by hotel and date’;

CREATE TABLE reservation.reservations_by_guest (
  guest_last_name text,
  hotel_id text,
  start_date date,
  end_date date,
  room_number smallint,
  confirm_number text,
  guest_id uuid,
  PRIMARY KEY ((guest_last_name), hotel_id) )
  WITH comment = ‘Q8. Find reservations by guest name’;

CREATE TABLE reservation.guests (
  guest_id uuid PRIMARY KEY,
  first_name text,
  last_name text,
  title text,
  emails set,
  phone_numbers list,
  addresses map<text,
  frozen<address>,
  confirm_number text )
  WITH comment = ‘Q9. Find guest by ID’;

9.  文檔

https://cassandra.apache.org/doc/latest/data_modeling/index.html 

https://cassandra.apache.org/doc/latest/data_modeling/intro.html 

https://cassandra.apache.org/doc/latest/data_modeling/data_modeling_rdbms.html 

https://cassandra.apache.org/doc/latest/cql/index.html 


您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • fork函數 在諸多應用中,創建多個進程是任務分解時行之有效的方法。例如,某一網路伺服器進程可在偵聽客戶端請求的同時,為處理每 請求而創建一新的子進程,與此同時,伺服器進程會繼續偵聽更多的客戶端連接請求。以此類手法分解任務,通常會簡化應用程式的設計,同時提高了系統的併發性。(即,可同時處理更多的任務 ...
  • Centos網路IP地址配置文件在 /etc/sysconfig/network-scripts 文件夾下,ifcfg-ens33 //ens33是你當前的網卡名稱 這個就是要修改的配置文件 對配置文件預設的設置進行編輯 vim ifcfg-ens33 TYPE=Ethernet PROXY_MET ...
  • 第一部分 概括 ELK是集分散式數據存儲、可視化查詢和日誌解析於一體的日誌分析平臺。ELK=elasticsearch+Logstash+kibana,三者各司其職,相互配合,共同完成日誌的數據處理工作。ELK各組件的主要功能如下: elasticsearch,數據存儲以及全文檢索; logstas ...
  • 壓縮列表是列表鍵與哈希鍵的底層實現之一。當一個列表鍵只包含少量的列表項,並且每個列表項要麼就是小整數值,要麼就是長度較短的字元串,那麼Redis就會使用壓縮列表來做列表鍵的底層實現。 壓縮列表是為了節約記憶體而開發的,是由一系列特殊編碼的連續記憶體塊組成的順序型數據結構。一個壓縮列表可以包含任意多的節點 ...
  • 本次安裝Mysql的CentOS版本是7.7 1.下載Mysql 首先去Mysql官網下載安裝包,網址 推薦大家下載Linux通用版本的,便於管理安裝位置,也方便一臺伺服器安裝多個版本的mysql,下載後將Mysql安裝包上傳至伺服器/usr/local/目錄下 2.創建Mysql用戶和組 3.解壓 ...
  • 一、簡單介紹 SQLite 觸發器(Trigger)是資料庫的回調函數,它會在指定的資料庫事件發生時自動執行/調用。以下是關於 SQLite 的觸發器(Trigger)的要點: SQLite 觸發器(Trigger)可以指定在特定的資料庫表發生 DELETE、INSERT 或 UPDATE 時觸發, ...
  • 1. 2,點擊其他--新建目錄--輸入目錄路徑....dmp的目錄 3,新建一個表空間, 其他--表空間--新建表空間 點擊保存 4...點擊數據泵,,數據泵導入 5...點擊生成sql,運行, (運行裡面有ora報錯的話,自行百度) 6...創建一個用戶可能登陸的,用戶--用戶--新建用戶 7.. ...
  • 表結構 student(StuId,StuName,StuAge,StuSex) 學生表 teacher(TId,Tname) 教師表 course(CId,Cname,C_TId) 課程表 sc(SId,S_CId,Score) 成績表 問題十一:查詢至少有一門課與學號為“1001”的同學所學相同 ...
一周排行
    -Advertisement-
    Play Games
  • 前言 在我們開發過程中基本上不可或缺的用到一些敏感機密數據,比如SQL伺服器的連接串或者是OAuth2的Secret等,這些敏感數據在代碼中是不太安全的,我們不應該在源代碼中存儲密碼和其他的敏感數據,一種推薦的方式是通過Asp.Net Core的機密管理器。 機密管理器 在 ASP.NET Core ...
  • 新改進提供的Taurus Rpc 功能,可以簡化微服務間的調用,同時可以不用再手動輸出模塊名稱,或調用路徑,包括負載均衡,這一切,由框架實現並提供了。新的Taurus Rpc 功能,將使得服務間的調用,更加輕鬆、簡約、高效。 ...
  • 順序棧的介面程式 目錄順序棧的介面程式頭文件創建順序棧入棧出棧利用棧將10進位轉16進位數驗證 頭文件 #include <stdio.h> #include <stdbool.h> #include <stdlib.h> 創建順序棧 // 指的是順序棧中的元素的數據類型,用戶可以根據需要進行修改 ...
  • 前言 整理這個官方翻譯的系列,原因是網上大部分的 tomcat 版本比較舊,此版本為 v11 最新的版本。 開源項目 從零手寫實現 tomcat minicat 別稱【嗅虎】心有猛虎,輕嗅薔薇。 系列文章 web server apache tomcat11-01-官方文檔入門介紹 web serv ...
  • C總結與剖析:關鍵字篇 -- <<C語言深度解剖>> 目錄C總結與剖析:關鍵字篇 -- <<C語言深度解剖>>程式的本質:二進位文件變數1.變數:記憶體上的某個位置開闢的空間2.變數的初始化3.為什麼要有變數4.局部變數與全局變數5.變數的大小由類型決定6.任何一個變數,記憶體賦值都是從低地址開始往高地 ...
  • 如果讓你來做一個有狀態流式應用的故障恢復,你會如何來做呢? 單機和多機會遇到什麼不同的問題? Flink Checkpoint 是做什麼用的?原理是什麼? ...
  • C++ 多級繼承 多級繼承是一種面向對象編程(OOP)特性,允許一個類從多個基類繼承屬性和方法。它使代碼更易於組織和維護,並促進代碼重用。 多級繼承的語法 在 C++ 中,使用 : 符號來指定繼承關係。多級繼承的語法如下: class DerivedClass : public BaseClass1 ...
  • 前言 什麼是SpringCloud? Spring Cloud 是一系列框架的有序集合,它利用 Spring Boot 的開發便利性簡化了分散式系統的開發,比如服務註冊、服務發現、網關、路由、鏈路追蹤等。Spring Cloud 並不是重覆造輪子,而是將市面上開發得比較好的模塊集成進去,進行封裝,從 ...
  • class_template 類模板和函數模板的定義和使用類似,我們已經進行了介紹。有時,有兩個或多個類,其功能是相同的,僅僅是數據類型不同。類模板用於實現類所需數據的類型參數化 template<class NameType, class AgeType> class Person { publi ...
  • 目錄system v IPC簡介共用記憶體需要用到的函數介面shmget函數--獲取對象IDshmat函數--獲得映射空間shmctl函數--釋放資源共用記憶體實現思路註意 system v IPC簡介 消息隊列、共用記憶體和信號量統稱為system v IPC(進程間通信機制),V是羅馬數字5,是UNI ...