Apache ActiveMQ Classic 5.12.1 lease-database-locker工作异常排查
ActiveMQ Classic共享数据库高可用配置问题排查
你的配置确实存在两处关键问题,导致主节点在server1正常运行时被server2抢占:
1. 错误混用锁类型的自定义SQL语句
你使用的是lease-database-locker(租约式数据库锁),但同时配置了lockCreateStatement——这个参数是给PessimisticDatabaseLocker(悲观锁)用的自定义语句,与租约锁的逻辑完全不兼容。
租约锁的核心逻辑是:持有锁的节点定期更新锁记录的LAST_UPDATED时间,其他节点通过检查该时间是否超过租期来判断锁是否失效。而你自定义的SELECT * FROM ACTIVEMQ_LOCK WHERE ID = 1 FOR UPDATE WAIT 0是悲观锁的强制抢占语句,会直接跳过租约检查逻辑,导致server2启动时直接抢走server1的锁。
解决方法:删除<amq:statements>节点及其中的自定义SQL配置,让租约锁使用默认的SQL语句。
2. 租约锁参数配置不完整
你只设置了lockAcquireSleepInterval(获取锁失败后的重试间隔),但缺少lockExpiration(锁的租期时长)配置。默认情况下lockExpiration为30秒,结合你的lockKeepAlivePeriod=5000(每5秒续约一次),如果server2启动时刚好遇到server1的续约间隙,可能误判锁已过期。
解决方法:显式配置lockExpiration,值建议设为lockKeepAlivePeriod的2-3倍(比如20000毫秒),确保节点正常续约时,其他节点不会误判锁失效:
<amq:lease-database-locker lockAcquireSleepInterval="10000" lockExpiration="20000"></amq:lease-database-locker>
修正后的核心配置片段
<amq:broker useJmx="false" persistent="true" startAsync="true" brokerName="${server.instance.name}" useShutdownHook="false"> <amq:persistenceAdapter> <amq:jdbcPersistenceAdapter dataSource="#dataSource" lockKeepAlivePeriod="5000"> <amq:databaseLocker> <amq:lease-database-locker lockAcquireSleepInterval="10000" lockExpiration="20000"></amq:lease-database-locker> </amq:databaseLocker> </amq:jdbcPersistenceAdapter> </amq:persistenceAdapter> <!-- 其他配置保持不变 --> </amq:broker>
额外验证点
- 确保两台服务器的系统时间同步,否则租约锁的时间判断会出错,导致异常切换。
- 检查数据库的
ACTIVEMQ_LOCK表结构是否包含LAST_UPDATED字段(租约锁依赖该字段跟踪续约时间),如果是手动创建的表,需确保结构符合ActiveMQ的默认定义。
内容的提问来源于stack exchange,提问作者D_J
相关产品推荐
相关产品推荐

