2011-02-28 100 views
1

我們有一個應用程序,當前有線程(約50個線程)來處理事務。Redis和Java在多線程應用程序中的幫助!

我們建立了一個redis數據庫,並使用DECRBY從用戶帳戶中扣除信用額度。

這裏是這個過程的一個例子:

1. Get amount of credits for this transaction 
2. Get current credit amount from from Redis: GET <key> 
3. If amount of credits exceeds amount cost of transaction continue 
4. DECRBY the transaction amount from Redis. 

我這裏的問題是顯而易見的,當用戶積分達到0時,它失敗的交易(好),但是它允許約10-20通過線程進行交易。

我曾想過用Redis設置WATCH, MULTI, EXEC,然後重試,但這不會造成瓶頸(我認爲它叫做競爭條件),因爲線程會不斷爭取完成交易。

有什麼建議嗎?

+1

你希望我們確認添加事務/同步到您的代碼(這是絕對需要的正確性,你似乎就知道了),很可能會引進競爭和因此可能會損害性能?是的,它會。問題的關鍵是什麼? – chetan 2011-02-28 05:26:22

+0

我想知道的是,如果我使用WATCH,MULTI,EXEC和retries,這是做事的最佳方式?此外,由於使用這種方法,確認性能受到傷害。 – James 2011-02-28 05:39:34

回答

0

這不是最常規的做法IMO(最常見的方式可能是在RDBMS中使用鎖),但使用WATCH, MULTI, EXEC看起來類似於CAS,它對我來說似乎不太奇怪。

我假設Redis的作者打算用WATCH這樣使用。表現的含義顯然取決於如何實現這個東西(我不知道),但我敢打賭,它會表現的很好。

這是因爲在您的情況下,對於相同密鑰的幾乎沒有爭用的可能性會很小(用戶爲他/她自己發出交易的機會有多大?),成功率第一次交換操作將會非常好。所以重試只會發生在非常罕見的情況下。由於Redis似乎是一個可信的框架,他們也可能知道他們在做什麼(即較少的爭用=對Redis來說很容易,因此它可以處理它!)。

2

鎖定是你需要的。由於數據庫鎖定開銷很大,因此可以使用SETNX在Redis中實現簡單的鎖定方案,並避免競爭條件。這裏很好解釋 - http://redis.io/commands/setnx。但是您仍然需要在應用程序級別執行重試。

0

您可以嘗試使用由Redisson框架提供的基於Redis的Lock對象實現,而不是使用WATCH-MULTI命令重試。使用WATCH-MULTI會在每次嘗試時向Redis提出不必要的請求,這些請求比已獲取的鎖更慢。

下面是代碼示例:

Lock lock = redisson.getLock("transationLock"); 
lock.lock(); 
try { 
    ... // instructions 
} finally { 
    lock.unlock(); 
}