2014-01-06 65 views
15

我有一個Cassandra問題。你知道Cassandra如何更新/增加計數器嗎?如何在Cassandra w/o過期中快速增加計數器

我想使用一個風暴螺栓(CassandraCounterBatchingBolt從github上的storm-contrib回購)寫入cassandra。不過,我不知道如何某些incrementCounterColumn()方法的工作..而且還有與卡桑德拉計數器(來源:http://wiki.apache.org/cassandra/Counters)限制的實施,這使得它們不能用於我的情況恕我直言:

  • 如果寫入意外失敗(超時或失去與協調節點的連接),客戶端將不知道操作是否已執行。重試可能導致CASSANDRA-2495超過計數。

  • 計數器的去除本質上是有限的。例如,如果您發出非常迅速的序列「增加,刪除,增加」有可能會丟失

去除不管怎麼說,這是我的情景:
我比更快的更新相同的計數器更新傳播到其他Cassandra節點。


說我有3個卡桑德拉節點。在每個這些節點中的計數器爲0。
節點1:0,節點2:0,節點3:0

的增量來了:5 - >節點1:0,節點2:0,節點3:0

增量開始於節點2 - 仍然需要傳播到節點1和節點3
節點1:0,節點2:5,節點3:0

在此期間,另一增量先前增量
被傳播之前到達:3 - >節點1: 0,node2:5,node3:0

假設3點開始在比5開始,我們在不同的節點有:
節點1:3,節點2:5,節點3:0

現在,如果3被傳播到其他節點作爲一個增量,而不是作爲新值 (和5相同),然後最終節點都將等於8,這就是我想要的。

如果3重寫5(因爲它有一個更晚的時間戳)這是有問題的 - 不是我想要的。

你知道Cassandra如何處理這些更新/增量嗎?

。注意,寫之前讀仍然容易受到因同樣的問題,從哪個副本節點讀取執行(如果傳播不遠處沿着法定人數依然會失效)

我也在想,也許把我的風暴螺栓放在緩存上,Cassandra可能會解決這個問題,但這是另一個故事。

回答

17

C *中的計數器具有複雜的內部表示形式,可避免無領導者分佈式系統中大部分(但不是全部)計數事物的問題。我喜歡把它們看作是分片計數器。計數器由多個由主機ID和版本號標識的子計數器組成。接收計數器操作的主機只增加其自己的子計數器,並且也增加版本。然後它將其整個計數器狀態複製到其他副本,並將其與狀態合併。當讀取計數器時,處理讀取操作的節點通過總計來自每個主機的計數來確定計數器值。

在每個節點上,計數器增量就像Cassandra中的其他所有內容一樣,只是一個寫操作。將增量寫入memtable,並且在讀取時通過合併memtable中的所有增量和所有SSTable來確定本地值。

我希望當我說你不必擔心增加計數器的速度比Cassandra能夠處理更快時,我的解釋可以幫助你相信我。由於每個節點都保留自己的計數器,並且從不復制增量操作,因此不會出現像讀取 - 修改 - 寫入場景那樣的競爭條件丟失計數的可能性。如果卡桑德拉接受寫作,你幾乎可以保證它會數。

但是,您不能保證的是,計數在任何時候都會顯示正確,除非。如果將一個增量寫入一個節點,但是剛剛從另一個節點讀取的計數器值不能保證增量已被複制,並且您還必須考慮在網絡分區過程中會發生什麼情況。這與Cassandra中的任何寫入或多或少都是一樣的,它最終具有一致性,並且取決於您用於操作的哪些一致性級別。

還有可能會遺失確認。如果你在獲得響應之前做了一個增量並釋放與Cassandra的連接,則無法知道你的寫作是否通過。當你連接回來時,你也不能告訴,因爲在增加之前你不知道計數是什麼。這是選擇可用性而不是一致性的系統的固有問題,以及您爲許多其他好處付出的代價。

最後,快速刪除,增加,刪除的問題是真實的,應該避免的。問題在於增量操作本質上會重新生成列,如果這些操作足夠接近彼此,它們可能會得到相同的時間戳。 Cassandra嚴格地說是最後一次寫贏,並根據操作的時間戳確定最後的結果。如果兩個操作具有相同的時間戳,則「較大」一個獲勝,這意味着以嚴格字節順序排序的那個。這是真實的,但我不會擔心太多,除非您正在進行非常快速的寫入並刪除相同的值(這可能是數據模型中的錯誤)。

這裏有一個很好的指導Cassandra的計數器的內部:http://www.datastax.com/wp-content/uploads/2011/07/cassandra_sf_counters.pdf

+0

感謝您的詳細解釋。優秀的鏈接和帖子!是的,爲什麼我問這個問題的原因是上次獲得時間戳的原因。現在,我明白有一個計數器的遞增指令(而不是讀取+寫入)。 '這是真的嗎?'如果我轉移到雲端,延遲將會增加,並且在寫入後避免讀取錯誤的數字,因此我需要在保存到數據庫之前增加累積的時間。我希望計數器增量指令存在。 – Adrian

+0

有一個增量指令,你不必在做一個增量前進行讀取。如果您使用QUORUM一致性級別進行遞增操作並使用QUORUM一致性級別進行讀取,則不應該在計數中看到不一致。 – Theo

+0

我應該補充說的是,在特殊情況下(例如分區和崩潰),當然有可能超過或低於計數。 – Theo

2

要理解更新/增量,例如寫操作,我會建議你通過Cassandra用於溝通的協議。在八卦中,每個參與者(節點)使用元組σ(K) = (V*N)維護其狀態,其中σ(K)K密鑰的狀態,V值和N作爲版本號。

保持數據包真實的單一版本八卦維護協調機制,即Precise & Scuttlebutt(當前)。根據Scuttlebutt Reconciliation,更新任何元組之前,他們之間互相通信,以檢查誰持有最高版本(最新值)的密鑰。無論誰持有最高版本都負責寫入操作。

欲瞭解更多信息,請閱讀article

3

計數器的當前版本只是不適合用於需要無過計數和即時一致性保證的使用情況。

有增量和減量操作,並且這些操作不會相互碰撞,並且,除非任何丟失的突變或重播的突變,將會給您一個正確的結果。

重寫Cassandra計數器(https://issues.apache.org/jira/browse/CASSANDRA-6504)可能對您很有意思,它應該解決當前所有關於獲取正確計數的問題。與此同時,如果我必須在當前版本的Cassandra上實現此功能,並且準確的計數是必不可少的,那麼我可能會將每個增量或減量存儲爲一列,然後進行讀取時間聚合結果,同時寫回檢查點,以便您不必讀回時間開始以計算後續結果。

雖然它在寫入路徑上非常高效,但它爲讀取方增加了很多負擔,因此它可能適用於您的用例,也可能不適用。

+0

讀取僅用於在遞增和寫入之前讀取新值;現在我可以增加,我不需要先閱讀,只是增加;我確實執行閱讀,但每30分鐘或20分鐘,所以不經常:) – Adrian