這個問題我也是無意間碰到的,之前一直是使用單機的ActiveMQ,所以也沒這個問題,但是做集群時碰到這個問題,問題是這樣子出現的:
首先,我准備了三台虛擬機,然后使用 Replicated LevelDB 的方式配置集群,配置如下:
<persistenceAdapter> <!--<kahaDB directory="${activemq.data}/kahadb"/>--> <replicatedLevelDB directory="${activemq.data}/leveldb" replicas="3" bind="tcp://0.0.0.0:61619" zkAddress="192.168.209.133:2181,192.168.209.134:2181,192.168.209.135:2181" zkPath="/activemq" hostname="test3" /> </persistenceAdapter>
之后使用 ./activemq console 命令將三個虛擬機中的ActiveMQ成功啟動。
接着我斷開master節點,發現剩下兩台slave節點會自動選舉一個成為master節點,再把原來的master節點啟動,就相當於一個新的slave節點加入了集群。
這樣子,我以為集群就是好的了,然后寫代碼,發布消費,都是很正常的。然后問題就出現了。
我在把master節點關閉,本來期望着剩下的節點能自動選一個成為master節點,可結果發現本該成為master節點的服務拋出了異常,重啟都無效,而且此時代碼也訪問不了,ActiveMQ的管理后台也訪問不了,就相當於整個集群掛了!!!
報錯大概是這樣子的:
java.io.IOException: com/google/common/util/concurrent/internal/InternalFutureFailureAccess at org.apache.activemq.util.IOExceptionSupport.create(IOExceptionSupport.java:40) at org.apache.activemq.leveldb.LevelDBClient.might_fail(LevelDBClient.scala:552) at org.apache.activemq.leveldb.LevelDBClient.replay_init(LevelDBClient.scala:667) at org.apache.activemq.leveldb.LevelDBClient.start(LevelDBClient.scala:558) at org.apache.activemq.leveldb.DBManager.start(DBManager.scala:648) at org.apache.activemq.leveldb.LevelDBStore.doStart(LevelDBStore.scala:312) at org.apache.activemq.leveldb.replicated.MasterLevelDBStore.doStart(MasterLevelDBStore.scala:110) at org.apache.activemq.util.ServiceSupport.start(ServiceSupport.java:55) at org.apache.activemq.leveldb.replicated.ElectingLevelDBStore$$anonfun$start_master$1.apply$mcV$sp(ElectingLevelDBStore.scala:230) at org.fusesource.hawtdispatch.package$$anon$4.run(hawtdispatch.scala:330) at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149) at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624) at java.lang.Thread.run(Thread.java:748) Caused by: java.lang.NoClassDefFoundError: com/google/common/util/concurrent/internal/InternalFutureFailureAccess at java.lang.ClassLoader.defineClass1(Native Method) at java.lang.ClassLoader.defineClass(ClassLoader.java:763) at java.security.SecureClassLoader.defineClass(SecureClassLoader.java:142) at java.net.URLClassLoader.defineClass(URLClassLoader.java:468) at java.net.URLClassLoader.access$100(URLClassLoader.java:74) at java.net.URLClassLoader$1.run(URLClassLoader.java:369) at java.net.URLClassLoader$1.run(URLClassLoader.java:363) at java.security.AccessController.doPrivileged(Native Method) at java.net.URLClassLoader.findClass(URLClassLoader.java:362) at java.lang.ClassLoader.loadClass(ClassLoader.java:424) at java.lang.ClassLoader.loadClass(ClassLoader.java:357) at java.lang.ClassLoader.defineClass1(Native Method) at java.lang.ClassLoader.defineClass(ClassLoader.java:763) at java.security.SecureClassLoader.defineClass(SecureClassLoader.java:142) at java.net.URLClassLoader.defineClass(URLClassLoader.java:468) at java.net.URLClassLoader.access$100(URLClassLoader.java:74) at java.net.URLClassLoader$1.run(URLClassLoader.java:369) at java.net.URLClassLoader$1.run(URLClassLoader.java:363) at java.security.AccessController.doPrivileged(Native Method) at java.net.URLClassLoader.findClass(URLClassLoader.java:362) at java.lang.ClassLoader.loadClass(ClassLoader.java:424) at java.lang.ClassLoader.loadClass(ClassLoader.java:357) at java.lang.ClassLoader.defineClass1(Native Method) at java.lang.ClassLoader.defineClass(ClassLoader.java:763) at java.security.SecureClassLoader.defineClass(SecureClassLoader.java:142) at java.net.URLClassLoader.defineClass(URLClassLoader.java:468) at java.net.URLClassLoader.access$100(URLClassLoader.java:74) at java.net.URLClassLoader$1.run(URLClassLoader.java:369) at java.net.URLClassLoader$1.run(URLClassLoader.java:363) at java.security.AccessController.doPrivileged(Native Method) at java.net.URLClassLoader.findClass(URLClassLoader.java:362) at java.lang.ClassLoader.loadClass(ClassLoader.java:424) at java.lang.ClassLoader.loadClass(ClassLoader.java:357) at com.google.common.cache.LocalCache$LoadingValueReference.<init>(LocalCache.java:3472) at com.google.common.cache.LocalCache$LoadingValueReference.<init>(LocalCache.java:3476) at com.google.common.cache.LocalCache$Segment.lockedGetOrLoad(LocalCache.java:2134) at com.google.common.cache.LocalCache$Segment.get(LocalCache.java:2045) at com.google.common.cache.LocalCache.get(LocalCache.java:3951) at com.google.common.cache.LocalCache.getOrLoad(LocalCache.java:3974) at com.google.common.cache.LocalCache$LocalLoadingCache.get(LocalCache.java:4958) at org.iq80.leveldb.impl.TableCache.getTable(TableCache.java:90) at org.iq80.leveldb.impl.TableCache.newIterator(TableCache.java:78) at org.iq80.leveldb.impl.TableCache.newIterator(TableCache.java:73) at org.iq80.leveldb.impl.DbImpl.buildTable(DbImpl.java:1011) at org.iq80.leveldb.impl.DbImpl.writeLevel0Table(DbImpl.java:952) at org.iq80.leveldb.impl.DbImpl.recoverLogFile(DbImpl.java:564) at org.iq80.leveldb.impl.DbImpl.<init>(DbImpl.java:209) at org.iq80.leveldb.impl.Iq80DBFactory.open(Iq80DBFactory.java:82) at org.apache.activemq.leveldb.LevelDBClient$$anonfun$replay_init$2.apply$mcV$sp(LevelDBClient.scala:687) at org.apache.activemq.leveldb.LevelDBClient$$anonfun$replay_init$2.apply(LevelDBClient.scala:667) at org.apache.activemq.leveldb.LevelDBClient$$anonfun$replay_init$2.apply(LevelDBClient.scala:667) at org.apache.activemq.leveldb.LevelDBClient.might_fail(LevelDBClient.scala:549) ... 11 more Caused by: java.lang.ClassNotFoundException: com.google.common.util.concurrent.internal.InternalFutureFailureAccess at java.net.URLClassLoader.findClass(URLClassLoader.java:382) at java.lang.ClassLoader.loadClass(ClassLoader.java:424) at java.lang.ClassLoader.loadClass(ClassLoader.java:357) ... 63 more
然后花了半個小時的時間百度(Google進不去,可惜了),得到的解決方法主要有四種:
1、移除lib目錄中的pax-url-aether-1.5.2.jar包(對我情況無效,lib目錄下沒有這個包,園友們可以試試)
2、注釋或者刪除conf/activemq.xml中id="logQuery"的bean,它的class="io.fabric8.insight.log.log4j.Log4jLogQuery"(對我情況無效,園友們可以試試)
3、清除所有的數據,也就是刪除每個節點的上面配置的 replicatedLevelDB 節點中 directory 屬性指向的目錄 ,比如我這里就是刪除每個節點下的 data/leveldb 目錄(證實有效)
4、換低版本的activemq試試(這個沒試)
唯一能解決這個問題的辦法是清除所有數據,這讓我難以接受,如果哪天線上環境不小心把master節點停了,然道要清除所有數據才能重啟?這種情況誰都無法接受。
只能自己想辦法了,看異常信息,開頭是:
java.io.IOException: com/google/common/util/concurrent/internal/InternalFutureFailureAccess at org.apache.activemq.util.IOExceptionSupport.create(IOExceptionSupport.java:40) at org.apache.activemq.leveldb.LevelDBClient.might_fail(LevelDBClient.scala:552) at org.apache.activemq.leveldb.LevelDBClient.replay_init(LevelDBClient.scala:667) at org.apache.activemq.leveldb.LevelDBClient.start(LevelDBClient.scala:558) at org.apache.activemq.leveldb.DBManager.start(DBManager.scala:648) at org.apache.activemq.leveldb.LevelDBStore.doStart(LevelDBStore.scala:312) at org.apache.activemq.leveldb.replicated.MasterLevelDBStore.doStart(MasterLevelDBStore.scala:110) at org.apache.activemq.util.ServiceSupport.start(ServiceSupport.java:55) at org.apache.activemq.leveldb.replicated.ElectingLevelDBStore$$anonfun$start_master$1.apply$mcV$sp(ElectingLevelDBStore.scala:230) at org.fusesource.hawtdispatch.package$$anon$4.run(hawtdispatch.scala:330) at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149) at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624) at java.lang.Thread.run(Thread.java:748)
....
這個大致信息可以理解為,本節點在作為master節點啟動時出錯了,在 IOExceptionSupport.create()方法想創建一個對象時拋出異常,異常信息是下面的:
Caused by: java.lang.NoClassDefFoundError: com/google/common/util/concurrent/internal/InternalFutureFailureAccess at java.lang.ClassLoader.defineClass1(Native Method) at java.lang.ClassLoader.defineClass(ClassLoader.java:763) at java.security.SecureClassLoader.defineClass(SecureClassLoader.java:142) ... Caused by: java.lang.ClassNotFoundException: com.google.common.util.concurrent.internal.InternalFutureFailureAccess at java.net.URLClassLoader.findClass(URLClassLoader.java:382) at java.lang.ClassLoader.loadClass(ClassLoader.java:424) at java.lang.ClassLoader.loadClass(ClassLoader.java:357) ... 63 more
這個明顯是說找不到類:com.google.common.util.concurrent.internal.InternalFutureFailureAccess,那好吧,我給你去找這個類。
於是接着百度,果然度娘最喜歡辜負了苦心人,沒有!
這時腦子突然機靈了一下,為什么不去Maven上面找找呢?maven直通車:https://mvnrepository.com/
然后我搜索 com.google.common.util.concurrent.internal.InternalFutureFailureAccess 這個類,果然在上面找到一個包存在這個類:
進去看詳情,好家伙,這個包就兩個版本,還兩三年沒更新了,然后我選擇1.0.1版本進去,下載jar包:
為避免不熟悉maven的朋友找不到,我將兩個版本的jar包都下載再來了,因為擔心每個版本依賴不一樣,大家可以從百度網盤獲取:https://pan.baidu.com/s/1T7sxBYuqqrPnyGWU4VJz9g (提取碼: mtaj )
jar下載下來后,我將包放到每個節點ActiveMQ的lib目錄下,然后重啟每個節點,問題完美解決!!!!
這個問題寫這么多,是因為確實度娘上的資料太少了,相信以后還有很多園友會碰到這個問題了,特此記一下!
- - - - - - - - - - - - - - - - - - - 分割線- - - - - - - - - - - - - - - - - - -
另外,還有一個小問題,在使用過程中,發現ActiveMQ啟動后,拋出下面的異常:An IOException was thrown (should never happen in this method).
java.lang.RuntimeException: An IOException was thrown (should never happen in this method). at org.apache.activemq.leveldb.record.CollectionKey$Buffer.bean(CollectionKey.java:264) at org.apache.activemq.leveldb.record.CollectionKey$Buffer.getKey(CollectionKey.java:284) at org.apache.activemq.leveldb.LevelDBClient$$anonfun$replay_from$1$$anonfun$apply$mcV$sp$4.apply(LevelDBClient.scala:757) at org.apache.activemq.leveldb.LevelDBClient$$anonfun$replay_from$1$$anonfun$apply$mcV$sp$4.apply(LevelDBClient.scala:740) at scala.Option.map(Option.scala:146) at org.apache.activemq.leveldb.LevelDBClient$$anonfun$replay_from$1.apply$mcV$sp(LevelDBClient.scala:740) at org.apache.activemq.leveldb.LevelDBClient$$anonfun$replay_from$1.apply(LevelDBClient.scala:707) at org.apache.activemq.leveldb.LevelDBClient$$anonfun$replay_from$1.apply(LevelDBClient.scala:707) at org.apache.activemq.leveldb.LevelDBClient.might_fail(LevelDBClient.scala:549) at org.apache.activemq.leveldb.LevelDBClient.replay_from(LevelDBClient.scala:706) at org.apache.activemq.leveldb.replicated.SlaveLevelDBStore$$anonfun$send_wal_ack$1.apply$mcV$sp(SlaveLevelDBStore.scala:185) at org.fusesource.hawtdispatch.package$$anon$4.run(hawtdispatch.scala:330) at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149) at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624) at java.lang.Thread.run(Thread.java:748) Caused by: java.io.EOFException at org.fusesource.hawtbuf.proto.CodedInputStream.readRawByte(CodedInputStream.java:346) at org.fusesource.hawtbuf.proto.CodedInputStream.readRawVarint32(CodedInputStream.java:240) at org.fusesource.hawtbuf.proto.CodedInputStream.skipField(CodedInputStream.java:117) at org.apache.activemq.leveldb.record.CollectionKey$Bean.mergeUnframed(CollectionKey.java:172) at org.apache.activemq.leveldb.record.CollectionKey$Buffer.bean(CollectionKey.java:259) ... 14 more
雖然有這個異常,但是ActiveMQ還是能正常啟動正常使用,不過我還是有些擔心,所以就查了一下,結果發現后台跑了兩個ActiveMQ進程,殺掉再啟動還是會再啟動兩個進程,沒辦法,只好試試重啟一下機器,結果問題解決