2012-01-24 54 views
10

我有一個HBase架構設計相關的問題。問題很簡單 - 我在hbase中存儲「通知」,每個都有一個狀態(「新」,「看到」和「讀取」)。這裏有API的,我需要提供:設計HBase架構以最好地支持特定的查詢

  • 獲取所有通知用戶
  • 獲取所有用戶
  • 「新」通知獲取所有「新」通知的計數爲用戶
  • 對於通知
  • 更新狀態
  • 所有用戶的通知更新狀態
  • 得到所有「新」的通知進行的跨數據庫
  • 通知笑可以按照逆時間順序掃描並允許分頁。

我有一些想法,我想看看他們中的一個是否最好,或者我完全錯過了一個好策略。所有這三個共同點,我認爲每個通知有一行,並在rowkey中有用戶ID是要走的路。爲了獲得分頁的時間順序,我需要在那裏有一個相反的時間戳。我想將所有notif保存在一個表中(所以我不必爲「爲用戶獲取所有通知」而不必合併排序),也不想爲輔助索引表編寫批處理作業(因爲更新了計數和狀態應該是實時的)。

最簡單的方法是(1)行鍵爲「userId_reverseTimestamp」並在客戶端進行狀態過濾。這似乎很天真,因爲我們將通過網絡發送大量不必要的數據。

下一種可能性是(2)將狀態編碼到rowkey中,以便對「userId_reverseTimestamp_status」進行編碼,然後對掃描執行rowkey正則表達式過濾。我看到的第一個問題是需要刪除一行,並在狀態更改時將通知數據複製到新行(推測每次通知應該只發生兩次)。此外,由於狀態是rowkey的最後一部分,對於每個用戶,我們將掃描大量額外的行。這是一個很大的表現?最後,爲了改變狀態,我需要知道以前的狀態是什麼(構建行鍵),否則我需要做另一次掃描。 (3)有兩個列族,一個用於靜態notif數據,另一個作爲狀態標誌,即「s:read」或「s:new」與s '作爲cf和作爲限定詞的地位。每行只有一個,我可以對該cf做一個MultipleColumnPrefixFilter或SkipFilter w/ColumnPrefixFilter。在這裏,我將不得不刪除和創建狀態更改列,但它應該比複製整行更輕量級。我唯一擔心的是HBase書中的警告:HBase與「2個或3個以上的專欄系列」不太一致 - 可能如果系統需要擴展更多的查詢功能,multi-cf策略將不會擴展。

所以(1)似乎會有太多的網絡開銷。 (2)似乎會浪費複製數據的花費,(3)可能會導致太多家庭出現問題。在(2)和(3)之間,哪種類型的濾波器應該提供更好的性能?在這兩種情況下,掃描都會查看用戶的每一行,這可能主要是讀取通知 - 這會有更好的性能。我認爲我傾向於(3) - 是否還有其他選項(或調整),我錯過了?

+0

只有在從新到可能的單個轉換過程中,通知纔會顯示'新'和'讀'嗎?這些通知的量是多少? – Gevorg

回答

2

你已經投入了很多思考,我認爲所有三個都是合理的!

由於大多數查詢都是「按用戶」,因此您希望將主鍵用作與時間戳連接的用戶名。這將有助於輕鬆掃描分頁,並且可以很快獲取用戶信息。

我認爲你的問題的癥結在於這種不斷變化的狀態部分。一般來說,像「讀取」 - >「刪除」 - >「重寫」之類的東西引入了各種併發問題。如果你的任務失敗了會發生什麼?你的數據處於無效狀態嗎?你會刪除一個記錄嗎?

我建議你將表格視爲「僅附加」。基本上,按照你對#3的建議,但是不要去掉旗子,把它留在那裏。如果讀過某些東西,它可以有三個「s:看過」,「s:讀過」(如果它是新的,我們可以認爲它是空的)。你也可以看中並在三者中的每一箇中加入時間戳,以顯示該事件何時得到滿足。由於所有操作都是隻寫和原子的,因此您不應該看到執行此操作時性能受到很大影響,因此您不必擔心併發性。

我希望這是有幫助的。由於你的問題如此廣泛,我不確定我是否回答了所有問題。請跟進另外的問題,我很樂意詳細說明或討論別的。

+0

Gppd關於使其成爲只寫的一點。不必破解原子更新使得它不那麼複雜 - 我的過濾器只會是「只要沒有未讀狀態」。 有人建議的另一種選擇是每行有多個列,其中一行是用戶的所有notif。據推測,這些列的排序方式與行相似。我的問題是,這是否給我們什麼?他們還建議在notif上做一個ValueFilter(因此,狀態存在於數據本身中,需要更新,而不是單獨的CF)。我的猜測是這會有更糟糕的表現。思考? – dyross

1

我的解決辦法是:

不要在HBase的保存通知狀態(可見,新的)每個通知。通知使用簡單的模式。鍵:userid_timestamp - 列:notification_message。

一旦客戶端詢問API「獲取所有新通知」,保存時間戳(推送所有新通知)。關鍵:用戶ID - colimn:All_new_notifications_pushed_time

與時間戳每個通知是不是「所有新的通知推送」假設「看到」下,如果更大的承擔「新」

要獲得所有新通知: 首先獲得價值(timestamp),然後按用戶ID 執行All_new_notifications_pushed_time的範圍掃描,然後按鍵執行範圍掃描notification_message列:從current_timestamp到All_new_notifications_pushed_time。

這將顯着限制受影響的列,其中大多數應該在memstore中。

計算客戶端上的新通知。