Spring集成JDBCLockRepository选主时重复插入DB致键冲突的原因咨询
关于Spring Integration JDBC锁机制重复键冲突的设计疑问
几年前,我们在MariaDB集群上将自研主节点选举机制切换为Spring Integration主节点选举机制,二者均依赖唯一键冲突实现。切换的原因是原机制在MariaDB集群同步时偶尔会出现死锁问题。
切换时我们的理解是:仅主节点会向INT_LOCK表写入带时间戳的锁记录,其他节点仅通过读取该表判断是否需要重新选主(当主节点宕机时,锁的时间戳会过期)。
但最近版本更新后,日志中频繁出现重复键冲突告警。分析代码后发现,所有节点一直在尝试插入同一行数据。相关核心逻辑如下(来自DefaultLockRepository的acquire方法):
if (this.template.update(this.updateQuery, new Object[]{this.id, epochMillis(), this.region, lock, this.id, this.ttlEpochMillis()}) > 0) { return true; } else { try { return this.template.update(this.insertQuery, new Object[]{this.region, lock, this.id, epochMillis()}) > 0; } catch (DataIntegrityViolationException var4) { return false; } }
逻辑分析:
- 第一个
updateQuery的WHERE条件只有当前持有锁的主节点能满足,因此非主节点执行update后返回0,会进入else分支 - 非主节点执行
insertQuery时,由于主键(region+lock)已存在,会触发DataIntegrityViolationException,进入catch块返回false - 这个流程会被非主节点反复执行,导致重复键冲突告警持续出现
想咨询该设计的底层原因:是不是插入失败的处理效率比单纯读取判断锁是否存在更高?虽然可以通过屏蔽告警解决问题,但希望理解这个实现逻辑,确认是否为最优方案。另外我们了解到可以通过设置自定义insertStatement来消除告警。
内容的提问来源于stack exchange,提问作者mangiari
相关产品推荐
相关产品推荐

