ES出現異常:
failed to notify ClusterStateListener
java.lang.IllegalStateException: environment is not locked
定位代碼:
下載ES 5.5源碼,在main/java/org/elasticsearch/env/NodeEnvironment.java 里可以看到:
private void assertEnvIsLocked() { if (!closed.get() && locks != null) { for (Lock lock : locks) { try { lock.ensureValid(); } catch (IOException e) { logger.warn("lock assertion failed", e); throw new IllegalStateException("environment is not locked", e); } } } }
assertEnvIsLocked調用地方,可以看到在檢測ES node數據路徑、index路徑使用:
/** * Returns an array of all of the nodes data locations. * @throws IllegalStateException if the node is not configured to store local locations */ public Path[] nodeDataPaths() { assertEnvIsLocked(); Path[] paths = new Path[nodePaths.length]; for(int i=0;i<paths.length;i++) { paths[i] = nodePaths[i].path; } return paths; } /** * Returns an array of all of the {@link NodePath}s. */ public NodePath[] nodePaths() { assertEnvIsLocked(); if (nodePaths == null || locks == null) { throw new IllegalStateException("node is not configured to store local location"); } return nodePaths; } public int getNodeLockId() { assertEnvIsLocked(); if (nodePaths == null || locks == null) { throw new IllegalStateException("node is not configured to store local location"); } return nodeLockId; } /** * Returns all index paths. */ public Path[] indexPaths(Index index) { assertEnvIsLocked(); Path[] indexPaths = new Path[nodePaths.length]; for (int i = 0; i < nodePaths.length; i++) { indexPaths[i] = nodePaths[i].resolve(index); } return indexPaths; }
而locks變量的賦值在:
public NodeEnvironment(Settings settings, Environment environment) throws IOException { if (!DiscoveryNode.nodeRequiresLocalStorage(settings)) { nodePaths = null; sharedDataPath = null; locks = null; nodeLockId = -1; nodeMetaData = new NodeMetaData(generateNodeId(settings)); logger = Loggers.getLogger(getClass(), Node.addNodeNameIfNeeded(settings, this.nodeMetaData.nodeId())); return; } final NodePath[] nodePaths = new NodePath[environment.dataWithClusterFiles().length]; final Lock[] locks = new Lock[nodePaths.length]; boolean success = false;
。。。
查了下Lock這個類:
import org.apache.lucene.store.Lock
作用:
- org.apache.lucene.store.Lock
-
An interprocess mutex lock.
Typical use might look like:
new Lock.With(directory.makeLock("my.lock")) { public Object doBody() { ... code to execute while locked ... } }.run();
一些加鎖、解鎖例子 https://www.programcreek.com/java-api-examples/index.php?api=org.apache.lucene.store.Lock
lucene鎖的作用,寫保護:在Lucene中,打開一個IndexWrite之后,就會自動在索引目錄中生成write.lock文件,這個文件中並不會有內容,不管是在索引打開期間還是在索引關閉之后,其大小都為0KB,並且在IndexWriter關閉之后,並不會刪除該文件。如果同時打開多個IndexWriter的話,后打開的IndexWriter就會拋出LockObtainFailedException
異常。這是個很重要的保護機制,因為若針對同一索引打開兩個writer的話,會導致索引損壞。所以Lucene中的鎖主要針對並發寫的情況,在寫的過程中並不會影響到並發讀操作。1. lucene並發規則
a,任意數量的只讀屬性IndexReader類都可以同時打開一個索引。
b,對於一個索引來說,一次只能打開一個IndexWriter對象。lucene采用鎖來提供保障。
c,IndexReader可以在indexwriter正在修改索引時打開。該對象只有在IndexWriter提交修改或自己重新打開后才能獲知索引的修改情況。
d,任意多個線程可以共享同一個indexreader或indexwriter。
2. lucene鎖機制
為了實現單一的writer,lucene采用了基於文件的鎖,如果鎖文件(默認writer.lock)存在於你的索引所在目錄內,說明此時正在打開一個writer。此時若企圖對同一個索引文件創建其他的writer的話,將產生一個LockObtainFailedException異常。
而由assertEnvIsLocked看,拋出的異常應該是鎖出現了問題,文件損壞或者目錄損壞、或者文件系統損壞導致。