Cassandra中的数据建模
在關(guān)系數(shù)據(jù)模型中,我們?yōu)橛蛑械拿總€對象建模關(guān)系/表。 對于Cassandra,情況并非如此。本文將詳細(xì)介紹在Cassandra中進(jìn)行數(shù)據(jù)建模時需要考慮的所有方面。 以下是Cassandra數(shù)據(jù)建模的粗略概述。
從上圖可以看出, 概念數(shù)據(jù)建模和應(yīng)用程序查詢是構(gòu)建模型時要考慮的輸入。 對于任何建模(無論是關(guān)系數(shù)據(jù)庫還是Cassandra),概念數(shù)據(jù)建模都是相同的,因?yàn)樗嗟厥顷P(guān)于從實(shí)體,關(guān)系及其屬性方面獲取所需系統(tǒng)功能的知識(因此而得名-ER模型)。
考慮以下有關(guān)病理實(shí)驗(yàn)室門戶的示例。 通過此病理實(shí)驗(yàn)室門戶,實(shí)驗(yàn)室可以向同意進(jìn)行建議的所有測試的門戶進(jìn)行注冊。 此外,它還允許患者(用戶)在門戶網(wǎng)站上注冊,以通過他/她選擇的實(shí)驗(yàn)室預(yù)訂測試約會。 這是概念模型的相關(guān)部分,將在Cassandra中進(jìn)行數(shù)據(jù)建模:
Cassandra中的數(shù)據(jù)建模是查詢驅(qū)動的。 因此,下一步是確定需要支持的應(yīng)用程序級查詢。 對于所舉的示例,以下是我們感興趣的查詢列表:
- 問題1:通過指定的注冊號獲取實(shí)驗(yàn)室詳細(xì)信息?
- 問題2:按預(yù)訂順序獲取給定實(shí)驗(yàn)室要處理的所有待處理訂單?
- 問題3:通過用戶的電子郵件ID /電話號碼查看用戶的詳細(xì)信息?
- 問題4:獲取指定時間段內(nèi)用戶的所有掛單?
映射規(guī)則:列出應(yīng)用程序查詢后,將應(yīng)用以下規(guī)則將概念模型轉(zhuǎn)換為邏輯模型。
- 規(guī)則1:列出我們將在其上執(zhí)行基于相等性的查詢的屬性。 例如:按注冊編號查找實(shí)驗(yàn)室。
- 規(guī)則2:列出在上一步中列出的查詢中必須使用的基于范圍的屬性。
- 規(guī)則3:應(yīng)用程序感興趣的結(jié)果是否有排序? 例如:返回用戶按其姓名升序/降序排序?
從概念模型和查詢中,我們可以看到僅在第一季度使用了實(shí)體“實(shí)驗(yàn)室”。 由于Q1基于等式,因此只能從映射規(guī)則中應(yīng)用規(guī)則1。 因此,“實(shí)驗(yàn)室”表可以設(shè)計(jì)如下:
create table lab_detail(registration_number text, name text, address text, primary key(registration_number));
實(shí)體“用戶”已在第三季度使用。 該查詢指定通過電子郵件ID或電話號碼獲取用戶詳細(xì)信息。 在關(guān)系數(shù)據(jù)庫中,我們可以使用電子郵件ID /電話號碼之一作為標(biāo)識符創(chuàng)建單個用戶表。 如果表中的數(shù)據(jù)很大,則可以在非標(biāo)識符列上創(chuàng)建索引以加快數(shù)據(jù)檢索速度。 但是在Cassandra中,這是以不同的方式建模的。 我們可以使用2個表來解決這個問題:
create table users_by_email(email text primary key, phone_number text, first_name text, last_name text, address text);
create table users_by_phone(phone_number text primary key, email text, first_name text, last_name text, address text);
當(dāng)我們要基于不屬于主鍵的列查詢表時,可以使用二級索引 。 但是在表上創(chuàng)建二級索引時必須小心。 不建議在許多情況下使用它們:
如我們所見,二級索引不適合我們的用戶表,最好創(chuàng)建一個滿足應(yīng)用程序目的的其他表。 請注意, 數(shù)據(jù)復(fù)制在Cassandra數(shù)據(jù)建模中非常普遍。 但是出于性能原因,我們應(yīng)該限制我們愿意復(fù)制多少數(shù)據(jù)。 現(xiàn)在,創(chuàng)建不同表的問題在于,需要注意可能的數(shù)據(jù)一致性異常。
- 如果更新在一個表中成功而在另一個表中失敗,該怎么辦?
- 如何使兩個表中的數(shù)據(jù)保持一致,以便在兩個表中為用戶查詢數(shù)據(jù)都能獲得相同的結(jié)果?
盡管Cassandra不支持參照完整性,但是有一些方法可以解決這些問題- 批次和輕量交易 (LWT) 。 請注意,與關(guān)系數(shù)據(jù)庫一樣,Cassandra中的批處理未用于提高性能。 此處的批處理用于實(shí)現(xiàn)操作的原子性,而異步查詢用于提高性能。 批處理操作的不正確使用可能由于協(xié)調(diào)器節(jié)點(diǎn)上的更大壓力而導(dǎo)致性能下降。 更多關(guān)于此這里 。 當(dāng)需要在寫入之前執(zhí)行讀取時,LWT可用于實(shí)現(xiàn)數(shù)據(jù)完整性(要寫入的數(shù)據(jù)取決于已讀取的數(shù)據(jù))。 但是,據(jù)說LWT查詢比常規(guī)查詢慢很多倍。 使用LWT時,需要特別小心,因?yàn)樗鼈兊纳炜s性不好。
實(shí)現(xiàn)此目的的另一種方法是使用實(shí)例化視圖 。 它們解決了應(yīng)用程序維護(hù)多個引用相同數(shù)據(jù)的表同步的問題。 為了保持?jǐn)?shù)據(jù)與基本表一致,Cassandra代替了應(yīng)用程序維護(hù)這些表,而是負(fù)責(zé)更新視圖。 結(jié)果,為了保持這種一致性,寫操作將受到很小的性能損失。 但是,一旦創(chuàng)建了物化視圖,我們就可以像對待其他任何表一樣對待它。 既然我們已經(jīng)了解了視圖,那么我們可以重新考慮先前的users_by_phone設(shè)計(jì):
create table users_by_email(email text primary key, phone_number text, first_name text, last_name text, address text);
create materialized view users_by_phone as
select * from users_by_email where phone_number is not null and email is not
null and primary key(phone_number, email);
注意,“不為空”約束必須應(yīng)用于主鍵中的每一列。 因此,到目前為止,我們已經(jīng)在應(yīng)用程序工作流程中解決了Q1和Q3。 現(xiàn)在剩下第二和第四季度了:
- 問題2:按預(yù)訂順序獲取給定實(shí)驗(yàn)室要處理的所有待處理訂單?
- 問題4:獲取指定期間內(nèi)用戶的所有掛單?
在一種情況下,必須由用戶獲取訂單詳細(xì)信息,而在另一種情況下,必須由實(shí)驗(yàn)室獲取訂單詳細(xì)信息。 在關(guān)系數(shù)據(jù)庫中,我們將訂單,用戶和實(shí)驗(yàn)室建模為不同的關(guān)系。 使用讀取數(shù)據(jù)的JOIN查詢可以在這些關(guān)系上實(shí)現(xiàn)Q2和Q4。 由于無法進(jìn)行讀取級別連接,因此必須在Cassandra中以不同的方式進(jìn)行建模。 必須完成數(shù)據(jù)非規(guī)范化才能實(shí)現(xiàn)此用例。 作為非規(guī)范化的一部分,數(shù)據(jù)將被復(fù)制。 但是,如前所述,Cassandra的經(jīng)驗(yàn)法則之一就是不要將數(shù)據(jù)復(fù)制視為一件壞事。 與時間相比,我們基本上會在空間上進(jìn)行權(quán)衡。 由于以下原因, Cassandra寧愿在寫入時聯(lián)接而不是在讀取時聯(lián)接。
- 可以通過向群集添加更多節(jié)點(diǎn)來擴(kuò)大數(shù)據(jù)復(fù)制的規(guī)模,而聯(lián)接則無法處理大量數(shù)據(jù)。
- 同樣,數(shù)據(jù)復(fù)制允許具有恒定的查詢時間,而分布式聯(lián)接對協(xié)調(diào)器節(jié)點(diǎn)施加了巨大壓力。 因此,它建議寫時連接而不是讀時連接。 由于實(shí)驗(yàn)室和用戶完全是兩個不同的實(shí)體,因此可以使用兩個不同的表對這些查詢進(jìn)行建模。
Cassandra的一般建議是盡可能避免客戶端加入。 因此,我們使用邏輯模型中的表(orders_for_user)和視圖(orders_for_lab)從概念模型中對“訂單”實(shí)體進(jìn)行建模,就像之前所做的那樣。 創(chuàng)建支持Q4的表時,必須考慮映射規(guī)則#1(基于平等的屬性:user_id)和#2(基于范圍的屬性:booking_time)。 將列order_id和test_id作為主鍵的一部分添加,以支持該行的唯一性。
create table orders_for_user(user_id text, order_id text, lab_id text, test_id text, booking_time timestamp, amount_paid double, primary key(user_id, booking_time, order_id, test_id));
同樣,可以根據(jù)映射規(guī)則#1(基于平等的屬性:lab_id)和#3(屬性的聚類順序:booking_time)對視圖進(jìn)行建模
create materialized view orders_for_lab as
select * from orders_for_user where lab_id is not null and order_id is not
null and test_id is not null and user_id is not null primary key(lab_id,
booking_time, test_id, order_id, user_id) with clustering order by(booking_time asc, order_id asc, test_id asc, user_id asc);
最后要考慮的一點(diǎn)是,建模數(shù)據(jù)時不要讓分區(qū)大小變得太大。 可以將新字段添加到分區(qū)鍵以解決此不平衡問題。 例如:如果某些實(shí)驗(yàn)室與其他實(shí)驗(yàn)室相比訂單過多,則會通過將更多的負(fù)載分配給集群中的幾個節(jié)點(diǎn)來在其中創(chuàng)建不平衡的分區(qū)。 為了解決這個問題,我們可以添加一個bucket-id列,將每個實(shí)驗(yàn)室1000個訂單分組到一個分區(qū)中。 通過這種方式,負(fù)載在群集的所有節(jié)點(diǎn)之間平均分配。
翻譯自: https://www.javacodegeeks.com/2019/05/data-modeling-cassandra.html
總結(jié)
以上是生活随笔為你收集整理的Cassandra中的数据建模的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 晋江文学城又双叒叕崩了晋江又崩了?
- 下一篇: midlet_如何在J2ME中创建MID