我与我合作的项目有一个非常奇怪的问题。如果有人能指出我正确的方向,我将不胜感激。
//设置
有多个Web服务器,并且前面有一个负载均衡器。服务器正在处理可能来自多个部分的请求,并且部分可以由不同的服务器处理。一旦收到所有部件,这些多部分请求应合并为一个单一的事务。 执行最终处理的服务器并不重要,但只有一台服务器可以执行此操作。接收前面部分的其他服务器应该只标记收到的部分,存储数据并立即回复。
现在我使用数据库表来处理节点之间的同步。 基本思想是,当服务器获得一个部分时,它会尝试获取带有rquest的事务ID的锁。这是通过尝试使用txid作为主键将行插入Lock表来完成的。如果插入成功,则该服务器获取锁并处理它收到的部分,通过将其存储到数据库检查是否已收到其他部分,如果没有则立即返回响应。
//问题
我遇到的问题是线程似乎随机锁定在数据库中,从而冻结了整个处理过程。我调试了它,以至于在多个请求同时进行处理的情况下,它们只是在尝试获取锁定时陷入困境并在30秒后最终超时。很少有第一个请求可能得到处理或者似乎是随机的,但即使是7个并发请求也会阻塞数据库。
对我来说,不应该有任何方式可能会遇到困难,而且我的想法很新鲜。
//信息
我正在使用带有InnoDB引擎的MySQL。服务器正在运行Java代码,Hibernate用作ORM层来访问数据库。
锁定表:
CREATE TABLE `lock` (
`id` varchar(255) NOT NULL,
`expiryDate` datetime DEFAULT NULL,
`issueDate` datetime DEFAULT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
id是用于组合各部分的事务ID。
我有一个管理锁访问的基本界面。
public interface LockProviderDao {
public boolean lock(String id);
public boolean unlock(String id);
}
使用Hibernate访问数据库的该类的实现。
@Override
public boolean lock(String id) {
Session session = this.sessionFactory.openSession();
Lock lock = new Lock(id);
Transaction tx = null;
boolean locked = false;
try {
// Try to lock
tx = session.beginTransaction();
session.save(lock);
tx.commit();
locked = true;
} catch(Exception e) {
if(tx != null) {
tx.rollback();
}
} finally {
session.close();
}
return locked;
}
@Override
public boolean unlock(String id) {
Session session = this.sessionFactory.openSession();
boolean status = true;
Transaction tx = null;
try {
Lock lock = (Lock) session.load(Lock.class, id);
tx = session.beginTransaction();
session.delete(lock);
tx.commit();
} catch(Exception e) {
if(tx != null) {
tx.rollback();
}
status = false;
} finally {
session.close();
}
return status;
}
看起来很简单。这是执行处理的代码。这个线程已经打开了一个Hibernate会话,所以Session内部的lock和unlock方法是一个嵌套的Session,如果这有什么不同的话。
int counter = 0;
boolean lockAcquired = false;
do {
// Try to acquire the lock
lockAcquired = this.lockProviderDao.lock(txId);
if (!lockAcquired) {
// Didn't get it try a bit later
try {
Thread.sleep(defaultSleepPeriod);
} catch (Exception e) {
}
if (counter >= defaultSleepCycles) {
return;
}
counter++;
}
} while (!lockAcquired);
// DO THE PROCESSING HERE ONCE LOCK ACQUIRED
// Release the lock
this.lockProviderDao.unlock(txId);
答案 0 :(得分:0)
我会在插入数据后锁定。这意味着,您必须将算法更改为以下内容:
如果您需要提高可靠性,您有三种选择: 1.将JMS与JTA一起使用来控制程序流程 2.让客户端轮询服务器以获取状态并开始处理,如果已收到所有部件,但处理尚未开始或已停止 3.如果适用相同的条件,则创建一个开始处理的调度程序