Redis&多线程应用程序中的Java帮助!

时间:2011-02-28 03:51:29

标签: java multithreading transactions redis

我们有一个应用程序,当前正在处理(大约50个线程)以处理事务。

我们设置了一个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,然后重试,但这不会导致瓶颈(我认为它叫做竞争条件),因为线程会不断努力完成交易。 / p>

有什么建议吗?

3 个答案:

答案 0 :(得分:2)

锁定是您所需要的。由于DB锁很昂贵,您可以使用SETNX在Redis中实现一个简单的锁定方案,并避免竞争条件。这里有很好的解释 - http://redis.io/commands/setnx。但是您仍然需要在应用程序级别实现重试。

答案 1 :(得分:0)

这不是最常用的IMO方式(最常用的方式可能是在RDBMS中使用锁),但使用WATCH, MULTI, EXEC看起来类似于CAS而它不是对我来说似乎太奇怪了。

我认为Redis的作者打算WATCH像这样使用。性能暗示显然取决于这个东西是如何实现的(我不知道),但我敢打赌它会表现得相当不错。

这是因为在您的情况下,相同的密钥似乎很少或几乎没有争用(用户疯狂地为他/她自己发布交易的可能性是多少?),第一个成功率交换操作真的很好。所以重试只会在极少数情况下发生。由于Redis似乎是一个可信的框架,他们也可能知道他们在做什么(即争用较少= Redis的轻松工作,因此它可以处理它!)。

答案 2 :(得分:0)

您可以尝试使用基于Redis的Redisson框架提供的Java对象实现,而不是使用WATCH-MULTI命令重试。使用WATCH-MULTI会在每次尝试期间对Redis进行不必要的请求,这比对已获取的锁定要慢得多。

以下是代码示例:

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