2011-02-28 57 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(); 
}