1. 程式人生 > >Cassandra資料模型設計最佳實踐(上部)

Cassandra資料模型設計最佳實踐(上部)

本文是Cassandra資料模型設計第一篇(全兩篇),該系列文章包含了eBay使用Cassandra資料模型設計的一些實踐。其中一些最佳實踐我們是通過社群學到的,有些對我們來說也是新知識,還有一些仍然具有爭議性,可能在要通過進一步的實踐才能從中獲益。

本文中,我將會講解一些基本的實踐以及一個詳細的例子。即使你不瞭解Cassandra,也應該能理解下面大多數內容。


我們嘗試使用Cassandra已經超過1年時間了。Cassandra現在正在服務一些用例,涉及到的業務從大量寫操作的日誌記錄和跟蹤,到一些混合工作。其中一項服務是我們的“Social Signal”專案,支撐著ebay的pruduct pages裡like/own/want特性。我們開發的一些用例已經上線執行,但更多的還是處於開發階段。
說說Cassandra在ebay的使用情況

我們的Cassandra叢集規模並不龐大,但正在穩步的增長中。在過去幾個月裡,我們共部署了幾十個節點,它們分佈在幾個跨機房的小型叢集中。你可能會問,為什麼要多個叢集?我們通過的職能部門和業務來劃分叢集。相同職能部門的相同業務的用例共享一個叢集,但它們存在於不同的keyspaces中。

RedLaser, Hunch和其它ebay的合作伙伴也在嘗試cassandra解決現實中各種問題。除了Cassandra,我們也在使用MongoDB和Hbase,本文中我不會討論它們,但我相信它們都有各自的優點。

我相信此時你一定有很多問題,在這篇文章裡暫時不會一一說明。在即將到來的Cassandra Summit大會,我將更詳細的講解我們每個用例場景,資料模型和多資料中心部署,以及經驗教訓和其它知識。

本文重點講述我們在ebay應用的Cassandra資料模型設計最佳實踐。下面讓我們先看看這系列文章會用到的一些術語。

術語和約定

  • 術語“Column Name” 和 “Column Key”被認為是一樣的。同樣的,“Super Column Name” 和 “Super Column Key”也認為是相同的。
  • 下圖表示一個 Column Family (簡稱CF)中的一個row

  • 下圖表示一個 Super Column Family (簡稱SCF)中的一個row

  • 下圖表示一個Column Family中一個row,它包含Composite Columns。Composite Columns的屬性通過分隔符’|’連線。請注意,這裡看到的只是資料的表現形式,Cassandra內建了Composite Column,它是一個物件,並不是使用’|’作為屬性分隔符的字串。(順便說下,本文不要求你掌握Super Column和Composite Column方面知識。)

基於上面的內容,讓我們開始第一個實踐吧!

不要把Cassandra model想象成關係型資料庫table

取而代之,應該把它想象成事一個有序的map結構。

對於一個新手來說,下面關係型資料庫術語常常被對應到Cassandra模型

這種對比可以幫助我們從關係型資料庫轉換到非關係型資料庫。但是當設計Cassandra column famiy的時候請不要這樣去類比。取而代之,考慮它是一個map中嵌入另一個map:外部map的key為row key,內部map的key為column key,兩個map的key都是有序的。如下:

SortedMap<RowKey, SortedMap<ColumnKey, ColumnValue>>

why?

將column family想象成巢狀的並排序的map比關係型資料庫table描述的更為準確,它將幫助你正確的進行Cassandra模型設計。

How?

  • Map可以進行高效查詢,同時排序的特性可以進行高效column掃描。在Cassandra中,我們可以使用row key和column key做高效查詢和範圍掃描
  • Column key的數量是很龐大的(譯者注:目前譯者所使用的Cassandra1.2.5版本,每個row支援最多20億個columns)。換句話說你,你可以擁有一個wide rows。
  • Column key自身可以儲存值,即你可以擁有一個沒有值的column。

如果叢集使用Order Preserving Partitioner (OOP)策略進行資料儲存,就可以對row key進行範圍查詢。但是OOP大多數情況都不推薦使用(譯者注:將rowkey按照順序儲存到節點上,如果分割槽不均勻,將導致資料讀寫不均衡),所以你可以認為外部的map是不排序的,如下:

Map<RowKey, SortedMap<ColumnKey, ColumnValue>>

上面提到的”Super Column”,認為它們是一組column,這樣的話,兩級巢狀map就會像下面展示的一樣變為三級巢狀map:

Map<RowKey, SortedMap<SuperColumnKey,
           SortedMap<ColumnKey, ColumnValue>>>

注意:

  • 你需要傳遞timestamp給每個column value,因為Cassandra使用它做內部的衝突處理機制。但在建模過程中你可以忽略它(譯者注:在操作column的時候timestamp資訊會自動新增到column)。同時,不要考慮在你的程式中使用column的timestamp,因為它不是為你設計的,與Hbase不同,它們不會生成新的version資料(譯者注:在Hbase中相同rowkey和column key的資料會儲存多個version,而Cassandra會將相同資料覆蓋,timestamp只儲存最後一次更新的時間)。
  • 因為Super Column的效能問題和缺乏二級索引支援問題,Cassandra社群對它的使用曾有過強烈爭議。所以,推薦使用Composite Columns代替Super Column實現功能。(譯者注:使用Super Column,如果你要獲取其中一個columnvalue,則要掃描整個Super Column,這會導致查詢效能很糟糕)

圍繞著查詢模式進行Column Family建模

建模儘量從實體和它們的關係開始

  • 與關係型資料庫不同,在Cassandra中通過建立二級索引或者編寫複雜SQL(使用joins, order by, group by)來新建或修改查詢不是件容易的事情。因為Cassandra具有很高的分散式特性,所以要先考慮查詢模式,然後再設計column family。
  • 牢記前面提到的嵌入排序map資料結構,在考慮如何組織你的資料到map,以滿足快速查詢/排序/分組/過濾/聚合的要求。

在大部分情況下,實體和它們的關係是很重要的(特殊用例除外,如日誌儲存或者其它時間序列資料)。如果我給你一個查詢模式,用於為一個電子商務網站建立Cassandra模型,但不告訴你任何實體和它們的關係。你會有意或者無意的從查詢模式或者從你之前領域物件的理解找出實體和它們之間的關係(因為我們是通過實體和關係來描述真實世界)。在設計資料模型時最好從實體和關係開始,然後使用反正規化化和冗餘的方式繼續圍繞查詢模式建模。如果這聽起來有些讓人困惑,通過後面的詳細例子就可以理解。

注意:在建模的時候考慮以下幾點會很有幫助。區分頻次大的查詢和頻次小的查詢,有些查詢可能只被查詢幾千次,其它可能被查詢數十億次;還要考慮哪些查詢對資料延遲是敏感的。確保你的模型優先滿足查詢頻次大的查詢和重要查詢。

為提升讀效能進行反正規化化(De-normalize)和冗餘

根據實際情況,如果不需要就不要反正規化化。

在關係型資料庫的世界裡,正規化化的優點是顯而易見的:較少的資料冗餘,較少的資料修改異常,概念更清晰,更容易維護等等;同樣,它的缺點也十分明顯:多表join查詢會很慢等等。這兩方面也會體現在Cassandra中,但是缺點會更明顯,因為Cassandra資料是分散式儲存,當然它也並不支援join操作。所以,對於一個完全正規化化的schema,Cassandra讀操作效能可能比RDBMS更糟糕,所以我們通常通過反正規化化來提升查詢效能。(譯者注:Cassandra一次查詢可能會請求多個節點並將結果彙總到客戶端,而RDBMS查詢只需從本地查詢即可)。

這個實踐和上一個查詢建模實踐是非常重要的,我會在餘下的文章中通過一個詳細的例子做進一步說明。

注意:下面我們要討論的例子只是個演示,它不代表eBayCassandra專案的資料模型。

實戰:User和Item中間的’Like’關係

這個示例是關於電子商務系統的一個功能,一個user可以喜歡多個item,同時一個item可以被多個user所喜愛,在關係型資料庫中這個關係是通過many-to-many實現的,如下圖所示:

通過上面的模型,我們可以進行如下查詢:

  • 通過user id獲取user
  • 通過item id獲取item
  • 獲取指定user喜歡的所有item
  • 檢視指定item被那些user所喜愛

下面將介紹幾個通過Cassandra建模解決上面問題的現方案,反正規化的順序從低到高。你會發現最佳方案依賴於查詢模式。

方案1:完全按照關係資料庫模型設計

這個模型支援通過user id查詢user和通過item id查詢item。但無法簡單查詢某個user喜愛的所有item或者某個item被那些user所喜愛。

對於這個用例來說,這是最糟糕的設計,主要是因為User_Item_Like沒有設計好。

注意:為了簡單起見,關係型資料模型中的timestamp欄位沒有體現到Cassandra模型中(這個欄位用於儲存user何時喜愛某個item),我會在後面介紹它。

方案2:使用自定義索引正規化化實體

這個模型中User和Item是正規化化實體,user id 和item id被對映儲存兩次,第一次是通過item id儲存user id(User_By_Item),第二次通過item id儲存user id(Item_By_User)。

這樣,我們很容易可以通過Item_By_User查詢某個user喜歡的全部item,還可以通過User_By_Item查詢某個item被哪些user所喜愛。這裡我們使用了,Item_By_User和User_By_Item這兩個column family作為自定義二級索引。(譯者注:Cassandra column family也有二級索引功能,它的作用是通過建立column key索引快速查詢到column value)。

有這樣一個場景,我們總是希望通過指定user查詢其喜愛的item,同時要獲取item title資訊。在當前模型下,我們首先要通過Item_By_User獲取指定user關聯的item id,然後根據這些item id依次查詢Item模型獲取title資訊,反之亦然。一個item有可能被幾百個user所喜愛,或者一個活躍user可能喜愛許多item,基於當前的模型設計,將會導致很多額外的查詢。所以,最好通過反正規化‘Item_by_User’ 中的itemtitle和’ User_by_Item’中的username資訊來優化查詢,方案3將會向大家展示。

注意:即使你可以批量讀取(譯者注:在Cassandra Java客戶端hector中可以MultigetSliceQuery類實現一次查詢傳入多個rowkey),但它們將仍然很慢,因為Cassandra底層仍然會單獨查詢每個rowkey,然後通過Coordinator 節點(譯者注:Coordinator 節點為Cassandra客戶端直接請求的節點,可以理解為它是一個代理)彙總到客戶端。批量讀取可以避免請求的往返耗時,它是個不錯的選擇,你可以去嘗試它。

方案3:正規化化實體,並將它們反正規化化到自定義索引

在這個模型中,title和username被分別反正規化到User_By_Item和Item_By_User。這樣將允許我們高效查詢指定user喜愛的所有item,以及喜愛指定item所有的user。這樣我們就為整個用例做了很大的反正規化化工作。

問題又來了,如何獲取指定user喜愛item的具體資訊(title,desc,price等等)?首先我們要問問自己我們是否真的需要這個查詢。還是上面的例子,當用戶希望獲取item額外資訊的時候,我們可以在頁面上展示所有的item title,當點選item title時,在開啟的新頁面顯示這個item的具體資訊。所以,在這個用例中我們最好不要極端反正規化化。(item title列表中通常還會顯示title和price資訊,這也很容易實現,這個就留給大家做練習)

讓我們考慮下面兩個查詢:

  • 通過所給item id,獲取具體item資訊(title, desc等等),並一同查詢喜歡這個item的user name
  • 通過所給的user id,獲取具體user資訊,並一同查詢user喜歡的所有item titile

上面兩個查詢出現在查詢item和user的詳情頁面是很正常的,這些在當前模型中可以很好的實現。兩者都需要兩次查詢,一次查詢item(或者user)資訊,另一次查詢user name(或者item title)。User變得更加活躍的(喜歡上千個items)或者item變得很熱門(被幾百萬user喜愛),查詢的次數不會隨之增加,仍然為兩次。這很好,當我們從方案2到方案3,反正規化化並沒有讓我們變糟糕。讓我們看看方案4如何做更進一步的優化。

方案4:正規化化部分實體

很明顯,方案4看起來有些凌亂。在資料儲存結構上,它與方案3也不同。

如果User和Item之間是高度關聯的實體(類似ebay),相比當前方案我將更傾向於方案3。

因為我們不打算反正規化化所有item屬性到User實體或者反正規化化所有user屬性到Item實體,所以這裡我們使用了部分正規化化。我不會打算進行極限反正規化化(讓所有time屬性到User實體和所有user屬性到Item實體),因為在這個用例中那樣做是沒有意義的。

注意:這裡我使用Super Column只是為了給展示。大多情況,應該傾向於使用composite columns,而不是Super Column。

最佳模型

在本文的用例中方案3是優勝者。上面的方案中我們忽略了timestamp資訊,下面我們將把它以timeuuid(type-1 uuid)形式新增到最終模型上。注意,在User_By_Item實體中timeuuid和userid合併為一個composite column key,在Item_By_user實體中timeuuid和item id合併為一個composite column key。

回想一下,column key是有序儲存的。這裡我們的User_By_Item 和 Item_By_User兩個實體的column keys通過timeuid排序後被儲存到磁碟,這使得基於時間的範圍查詢非常高效。在這個模型中,我們不需要讀取一個row中所有column,就可以高效的查詢某個item最近被哪些user所喜愛,以及某個使用者最近喜歡了哪些item。

最終模型如下:

總結

我們通過一些基本的實踐和詳細例子幫你開啟Cassandra資料建模之旅。下面是一些關鍵點:

  • 當設計Cassandra列族時,不要把它想成是關係表,要把它想成是巢狀的、排序的map資料結構。
  • 要圍繞著查詢來設計列族,從設計實體及其關係開始。
  • 在需要的時候,通過反正規化化和冗餘來提升讀效能。
  • 記住有多種方式建立模型,最佳的方式依賴於你的用例和查詢模式。

這裡我沒有提到其它常用的用例,如日誌記錄、監控、實時分析(rollups, counters),或者時間序列。但是,我們討論的實踐也適用於它們。此外,有些眾所周知的技術和模式用於時間序列的模型設計。在eBay,我們也使用這些技術,也樂於在後續的文章中分享這些。關於時間序列資料建模,我推薦你閱讀 Advanced time series with Cassandra and Metric collection and storage,如果你是Cassandra新手,請先閱讀DataStax documentation

Part 2 about Cassandra is now published.

Jay Patel, [email protected]

相關推薦

Cassandra資料模型設計最佳實踐上部

本文是Cassandra資料模型設計第一篇(全兩篇),該系列文章包含了eBay使用Cassandra資料模型設計的一些實踐。其中一些最佳實踐我們是通過社群學到的,有些對我們來說也是新知識,還有一些仍然具有爭議性,可能在要通過進一步的實踐才能從中獲益。 本文中,我將會講解

Cassandra資料模型設計最佳實踐

本文是Cassandra資料模型設計第一篇(全兩篇),該系列文章包含了eBay使用Cassandra資料模型設計的一些實踐。其中一些最佳實踐我們是通過社群學到的,有些對我們來說也是新知識,還有一些仍然具有爭議性,可能在要通過進一步的實踐才能從中獲益。 本文中,我將會講解一些

Cassandra 資料模型設計總結

結合前段時間使用Cassandra使用過程,團隊簡單總結了Cassandra  資料模型設計,請大家斧正。 1、相關概念 Column:Cassandra中的最基本的儲存單元,用於儲存某一行的資訊;

自動化測試最佳實踐:從紡錘模型到金字塔模型

一、當前軟體開發的趨勢 開篇我們先簡要介紹一些近幾年在企業開發中出現的重要概念,以便引入持續測試的主旨。這些概念中最重要的兩個便是DevOps和微服務。兩者都是目前軟體開發中的最佳實踐和方法論,旨在為企業提供更高的靈活性,提升運營效率。 1.1 DevOps DevOps是一套實踐方法論和文化,提

三維渲染引擎設計實踐

方式 lora 扇面 多個 幀緩存 binding osg smo tco 五、繪制幾何對象和文字 幀緩存(Frame Buffer)為用戶與顯示設備交互的一個接口,將顯示的畫面抽象成一塊可以進行讀寫操作的內存區域。 幀緩存的每一個存儲單元都對應顯示屏上的一個像素。整個緩存

三維渲染引擎設計實踐

窗口 drag 支持機制 對象 window ani handle ima 視頻 8.2三維人機交互工具 osg實現了三維場景的漫遊以及場景中三維對象的操縱。 8.2.1漫遊器 osgGA::MatrixManipulator類 漫遊器也是事件處理器GUIEventHand

項目管理全過程最佳實踐

管理昨天參加了部門組織的項目管理培訓,培訓主題是「項目管理全過程最佳實踐」,培訓時間為1天,講師是現代卓越的鄭曉龍老師,整體感覺,教授氛圍和互動方式都很輕松,讓人印象深刻,有不少收獲,分享給大家。 會分2篇文章分享,整體分享點如下: 教授方式 概述 定目標 拜真佛 編計劃 要資源 抓落實 一頁紙項目管理

Java Exception最佳實踐

理解 異常 resource 開發 lock 結束線程 用戶名 文檔 each https://www.dubby.cn/detail.html?id=9033 1.異常介紹 2.Java中的異常介紹 3.自定義異常 4.幾個建議 1)不要生吞異常 2)申明具體的異常

Spring Boot 最佳實踐快速入門

我想 並不是 系統 exe 輸出 開發環境 模型 hot 根據 一、關於Spring Boot 在開始了解Spring Boot之前,我們需要先了解一下Spring,因為Spring Boot的誕生和Spring是息息相關的,Spring Boot是Spring發展到一定程

Spring Boot 最佳實踐集成Jsp與生產環境部署

內容 tro conf 相關 安裝 packaging exc 詳細介紹 更新 一、簡介 提起Java不得不說的一個開發場景就是Web開發,也是Java最熱門的開發場景之一,說到Web開發繞不開的一個技術就是JSP,因為目前市面上仍有很多的公司在使用JSP,所以本文就來介紹

Spring Boot 最佳實踐模板引擎Thymeleaf集成

data 圖層 int app 創建模板 原因 xmlns make 使用場景 一、Thymeleaf介紹 Thymeleaf是一種Java XML / XHTML / HTML5模板引擎,可以在Web和非Web環境中使用。它更適合在基於MVC的Web應用程序的視圖層提供X

車聯網上雲最佳實踐

ice http請求 ack lse .html 1.2 ive bms 的人 摘要: 我們對傳統IDC應用架構進行分析之後,我們發現之前的系統架構存在一些不合理的地方導致了很多的痛點,為了解決這些痛點我們最終考慮上雲。開始思考怎樣利用雲上產品來解決目前遇到的痛點。例如 雲

高效運維最佳實踐03:Redis叢集技術及Codis實踐 (轉)

專欄介紹 “高效運維最佳實踐”是InfoQ在2015年推出的精品專欄,由觸控科技運維總監蕭田國撰寫,InfoQ總編輯崔康策劃。 前言 誠如開篇文章所言,高效運維包括管理的專業化和技術的專業化。前兩篇我們主要在說些管理相關的內容,本篇說一下技術專業化。希望讀者朋友們能適應這個轉

OpenResty 最佳實踐 2

此文已由作者湯曉靜授權網易雲社群釋出。 歡迎訪問網易雲社群,瞭解更多網易技術產品運營經驗。 lua 協程與 nginx 事件機制結合 文章前部分用大量篇幅闡述了 lua 和 nginx 的相關知識,包括 nginx 的程序架構,nginx 的事件迴圈機制,lua 協程,lua 協程如何與 C

Unity2018照明流程最佳實踐

目前 Unity 提供了多種渲染管道,兩種全域性照明系統,四種照明模式,三種燈光模式,以及兩種 Shadowmask 模式,為開發者在建立面向高配PC、主機、移動和XR裝置專案的過程中提供了高度靈活性。但是,作為 Unity 新手,如果不熟悉渲染的話,面對這些選擇不免感到茫然,本文

Spring Boot 最佳實踐模板引擎FreeMarker整合

一、FreeMaker介紹 FreeMarker是一款免費的Java模板引擎,是一種基於模板和資料生成文字(HMLT、電子郵件、配置檔案、原始碼等)的工具,它不是面向終端使用者的,而是一款程式設計師使用的元件。 FreeMarker最初設計是用來在MVC模式的Web

Spring Boot 最佳實踐Spring Data JPA 操作 MySQL 8

一、Spring Data JPA 介紹 JPA(Java Persistence API)Java持久化API,是 Java 持久化的標準規範,Hibernate是持久化規範的技術實現,而Spring Data JPA是在 Hibernate 基礎上封裝的一款框架

SpringCloud入門最佳實踐Rest微服務構建案例工程模組

介紹 承接著我們的springmvc+mybatis+mysql初級高階課程,以Dept部門模組做一個微服務通用案例Consumer消費(Client)通過REST呼叫Provider提供者(Serv

百億資料入庫elasticsearch生產實踐

一、前言    前情回顧,hive中有三個具有關聯關係的表,依次是一對多的關係,當前歷史資料總量在500億左右,每日增量依次是百萬、千萬、億級的體量。其中,這500億資料只是一個領域,還有另一個塊更大領域的資料第三層日增量在10~25億之間,這塊還沒來得及去啃。這一塊資料,需

Greenplum在企業生產中的最佳實踐

原文地址 今天,我們將分享國內客戶在使用GP時遇到的問題及相關建議。同時,架構師就大家經常遇到的技術問題進行了細緻的說明,相信對您有所啟迪! 第一個案例——底層資料檔案報錯處理 在一個金融客戶的案例中發現RAID卡故障導致底層的資料檔案損壞了。這是什麼意思呢?假如通