簡體   English   中英

可搜索索引在手動更新時被鎖定(LockObtainFailedException)

[英]Searchable index gets locked on manual update (LockObtainFailedException)

我們有一個Grails項目,它在負載均衡器后面運行。 在服務器上運行了三個Grails應用程序實例(使用單獨的Tomcat實例)。 每個實例都有自己的可搜索索引。 由於索引是分開的,因此自動更新不足以使應用程序實例之間的索引保持一致。 因此,我們禁用了可搜索的索引鏡像,並且在預定的石英作業中手動完成對索引的更新。 根據我們的理解,應用程序的其他任何部分都不應修改索引。

石英作業每分鍾運行一次,它從數據庫中檢查應用程序已更新哪些行,並重新索引這些對象。 該作業還會檢查相同的作業是否已在運行,因此它不會執行任何並發索引。 應用程序在啟動后運行幾個小時,然后在作業啟動時突然運行,拋出LockObtainFailedException:

22.10.2012 11:20:40 [xxxx.ReindexJob]錯誤無法更新可搜索索引,類org.compass.core.engine.SearchEngineException:無法打開子索引[product]的編寫器; 嵌套異常是org.apache.lucene.store.LockObtainFailedException:Lock獲取超時:SimpleFSLock@/home/xxx/tomcat/searchable-index/index/product/lucene-a7bbc72a49512284f5ac54f5d7d32849-write.lock

根據上次執行作業的日志,重新編制索引沒有任何錯誤,並且作業成功完成。 但是,這次重新索引操作會拋出鎖定異常,就像前一個操作未完成並且鎖定尚未釋放一樣。 在重新啟動應用程序之前,不會釋放鎖定。

我們嘗試通過手動打開鎖定索引來解決問題,這會導致以下錯誤打印到日志:

22.10.2012 11:21:30 [manager.IndexWritersManager]錯誤非法狀態,標記索引編寫器打開,而另一個標記為打開子索引[產品]

在此之后,作業似乎正常工作,並且不會再次陷入鎖定狀態。 但是,這會導致應用程序不斷使用100%的CPU資源。 以下是石英作業代碼的縮短版本。

任何幫助將不勝感激,以提前解決問題。

class ReindexJob {

def compass
...

static Calendar lastIndexed

static triggers = {
    // Every day every minute (at xx:xx:30), start delay 2 min
    // cronExpression:                           "s  m h D M W [Y]"
    cron name: "ReindexTrigger", cronExpression: "30 * * * * ?", startDelay: 120000
}

def execute() {
    if (ConcurrencyHelper.isLocked(ConcurrencyHelper.Locks.LUCENE_INDEX)) {
        log.error("Search index has been locked, not doing anything.")
        return
    }

    try {
        boolean acquiredLock = ConcurrencyHelper.lock(ConcurrencyHelper.Locks.LUCENE_INDEX, "ReindexJob")
        if (!acquiredLock) {
            log.warn("Could not lock search index, not doing anything.")
            return
        }

        Calendar reindexDate = lastIndexed
        Calendar newReindexDate = Calendar.instance
        if (!reindexDate) {
            reindexDate = Calendar.instance
            reindexDate.add(Calendar.MINUTE, -3)
            lastIndexed = reindexDate
        }

        log.debug("+++ Starting ReindexJob, last indexed ${TextHelper.formatDate("yyyy-MM-dd HH:mm:ss", reindexDate.time)} +++")
        Long start = System.currentTimeMillis()

        String reindexMessage = ""

        // Retrieve the ids of products that have been modified since the job last ran
        String productQuery = "select p.id from Product ..."
        List<Long> productIds = Product.executeQuery(productQuery, ["lastIndexedDate": reindexDate.time, "lastIndexedCalendar": reindexDate])

        if (productIds) {
            reindexMessage += "Found ${productIds.size()} product(s) to reindex. "

            final int BATCH_SIZE = 10
            Long time = TimeHelper.timer {
                for (int inserted = 0; inserted < productIds.size(); inserted += BATCH_SIZE) {
                    log.debug("Indexing from ${inserted + 1} to ${Math.min(inserted + BATCH_SIZE, productIds.size())}: ${productIds.subList(inserted, Math.min(inserted + BATCH_SIZE, productIds.size()))}")
                    Product.reindex(productIds.subList(inserted, Math.min(inserted + BATCH_SIZE, productIds.size())))
                    Thread.sleep(250)
                }
            }

            reindexMessage += " (${time / 1000} s). "
        } else {
            reindexMessage += "No products to reindex. "
        }

        log.debug(reindexMessage)

        // Re-index brands
        Brand.reindex()

        lastIndexed = newReindexDate

        log.debug("+++ Finished ReindexJob (${(System.currentTimeMillis() - start) / 1000} s) +++")
    } catch (Exception e) {
        log.error("Could not update searchable index, ${e.class}: ${e.message}")
        if (e instanceof org.apache.lucene.store.LockObtainFailedException || e instanceof org.compass.core.engine.SearchEngineException) {
            log.info("This is a Lucene index locking exception.")
            for (String subIndex in compass.searchEngineIndexManager.getSubIndexes()) {
                if (compass.searchEngineIndexManager.isLocked(subIndex)) {
                    log.info("Releasing Lucene index lock for sub index ${subIndex}")
                    compass.searchEngineIndexManager.releaseLock(subIndex)
                }
            }
        }
    } finally {
        ConcurrencyHelper.unlock(ConcurrencyHelper.Locks.LUCENE_INDEX, "ReindexJob")
    }
}
}

基於JMX CPU示例,似乎Compass正在幕后進行一些調度。 從1分鍾的CPU樣本看,當正常和100%CPU實例進行比較時,幾乎沒有什么不同:

  • org.apache.lucene.index.IndexWriter.doWait()正在使用大部分CPU時間。
  • Compass Scheduled Executor Thread顯示在線程列表中,這在正常情況下是看不到的。
  • 一個Compass Executor Thread正在執行commitMerge,在正常情況下,這些線程都沒有執行commitMerge。

您可以嘗試增加'compass.transaction.lockTimeout'設置。 默認值為10(秒)。

另一種選擇是在Compass中禁用並發並使其同步。 這是通過'compass.transaction.processor.read_committed.concurrentOperations':'false'設置來控制的。 您可能還必須將'compass.transaction.processor'設置為'read_committed'

這些是我們目前使用的指南針設置:

compassSettings = [
'compass.engine.optimizer.schedule.period': '300',
'compass.engine.mergeFactor':'1000',
'compass.engine.maxBufferedDocs':'1000',
'compass.engine.ramBufferSize': '128',
'compass.engine.useCompoundFile': 'false',
'compass.transaction.processor': 'read_committed',
'compass.transaction.processor.read_committed.concurrentOperations': 'false',
'compass.transaction.lockTimeout': '30',
'compass.transaction.lockPollInterval': '500',
'compass.transaction.readCommitted.translog.connection': 'ram://'
]

這已經關閉了並發性。 您可以通過將'compass.transaction.processor.read_committed.concurrentOperations'設置更改為'true'來使其異步。 (或刪除條目)。

Compass配置參考: http//static.compassframework.org/docs/latest/core-configuration.html

read_committed處理器並發性的文檔: http//www.compass-project.org/docs/latest/reference/html/core-searchengine.html#core-searchengine-transaction-read_committed

如果要保持異步操作,還可以控制它使用的線程數。 使用compass.transaction.processor.read_committed.concurrencyLevel = 1設置將允許異步操作,但只使用一個線程(默認為5個線程)。 還有compass.transaction.processor.read_committed.backlog和compass.transaction.processor.read_committed.addTimeout設置。

我希望這有幫助。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM