Elasticsearch 常見的 8 種錯誤及最佳實踐


題記

Elasticsearch 社區有大量關於 Elasticsearch 錯誤和異常的問題。

深挖這些錯誤背后的原因,把常見的錯誤積累為自己的實戰經驗甚至是工具,不僅可以節省我們的開發和運維時間,而且可以幫助確保 Elasticsearch 集群的長期健康運行。

常見的異常、原因和常規最佳實踐拆解如下,這些最佳實踐可以幫助我們更有效地識別、最小化定位和處理異常問題。

1、 Mapper_parsing_exception

Elasticsearch 依靠映射(Mapping)定義的數據類型處理數據。

映射定義了文檔中的字段並指定了它們對應的數據類型,例如日期類型 Date、長整數類型 long 和  字符串類型 text。

如果索引文檔包含沒有定義數據類型的新字段,Elasticsearch將使用動態映射來估計字段的類型,並在必要時將其從一種類型轉換為另一種類型。

如果Elasticsearch無法執行此轉換,它將引發“ mapper_parsing_exception無法解析” 異常。

如果此類異常太多會降低索引吞吐量。

實戰舉例如下:

DELETE mytest_0001
PUT mytest_0001/_doc/1
{
  "name":"John"
}

PUT mytest_0001/_doc/2
{
  "name": {
    "firstname": "John",
    "lastname": "doe"
  }
}

為避免此問題,可以在創建索引時顯示定義Mapping,明確敲定字段類型。或者可以使用 _mapping 動態添加新字段映射。

動態更新索引實戰:

PUT mytest_0001/_mapping
{
  "properties": {
    "title": {
      "type": "text"
    }
  }
}

請注意:雖然可以通過如上命令動態添加字段,但是不能更改現有字段映射。

若想做字段類型的修改,需要重新定義Mapping 結合 reindex 和 alias 別名 實現。

2、BulkIndexError

批量索引大型數據集通常更有效。

例如,您可以執行一個批量操作來索引 1,000 個文檔,而不是使用 1,000 個索引操作。

批量操作可以通過 bulk API 完成。

批量操作實戰:

PUT my_index_0003/_bulk
{"index":{"_id":1}}
{"myid":"c12345"}
{"index":{"_id":2}}
{"myid":"C12456"}
{"index":{"_id":3}}
{"myid":"C31268"}

但是,此過程容易出錯。執行批量操作的過程中,你需要仔細檢查:數據類型不匹配和空值匹配等問題。

對於批量 API ,你需要格外警惕,因為即使有數百個肯定的響應,批量中的某些索引請求也可能失敗。

批量操作捕獲錯誤實戰:

 @Override
  public void afterBulk(long executionId, BulkRequest request, BulkResponse response) {
 if (response.hasFailures()) {
  for (int i = 0; i < response.getItems().length; i++) {
   BulkItemResponse item = response.getItems()[i];
   if (item.isFailed()) {
      IndexRequest ireq = (IndexRequest) request.requests().get(i);
      logger.error("Failed while indexing to " + item.getIndex() + " type " + item.getType() + " " +
          "request: [" + ireq + "]: [" + item.getFailureMessage() + "]");
   }
  }
 }
  }

除了提前設置具有所有適當條件的批量 API 之外,還要瀏覽響應列表並檢查每個響應,以確保所有數據均按預期索引。

3、搜索超時錯誤:ConnectionTimeout,ReadTimeoutError,RequestTimeout 等

如果在指定的搜索時間內未收到響應,則請求將失敗並返回錯誤消息。這稱為搜索超時。

搜索超時很常見,多種原因都可以導致搜索超時,例如:大型數據集或占用大量內存的查詢。

要消除搜索超時,可以通過如下實現解決:

3.1 增加 elasticsearch.requestTimeout

設置注意:應該在 HTTP 客戶端而不是 Elasticsearch 中指定 timeout 值,Elasticsearch 端沒有請求超時參數。

kibana 請求顯示超時,優化方案如下:

kibana 默認請求等待時間是 30 秒,可以在 kibana.yml 中調整該值。

elasticsearch.requestTimeout: 90000

3.2 減少每個請求返回的文檔數量

不要將請求的 size 值設置太大,結合:from、size 深度翻頁機制實現。

全量遍歷借助 scroll 實現。

3.3 縮小時間范圍

請求時間范圍越長(比如 時間跨度周期 1  年以上的數據),請求數據量越大,超時的可能性越高。

3.4 調整內存設置

通過配置單個查詢的內存斷路器來限制單個查詢的內存使用量。

如:將 index.breaker.request.limit 限制為 40%,默認是 60%。

集群層面設置請求熔斷內存實戰:

PUT /_cluster/settings
{
  "persistent": {
    "indices.breaker.request.limit": "40%"
  }
}

通過將search.max_buckets設置為 5000 (默認值:10000)來限制用於聚合的存儲桶數。

PUT _cluster/settings
{
  "transient": {
    "search.max_buckets": 5000
  }
}

3.5 優化查詢、索引和分片。

3.6 啟用慢速搜索日志

監視搜索運行時間,掃描繁重的搜索等等。

慢日志開啟實戰:

PUT /_settings
{
  "index.search.slowlog.threshold.query.debug": "30s",
  "index.search.slowlog.threshold.fetch.debug": "30s",
  "index.indexing.slowlog.threshold.index.debug": "30s"
}

4、 All Shards Failed

在 Elasticsearch 搜索時,可能會遇到 “All Shards Failed” 的錯誤消息。

發生 All Shards Failed 的幾種情況:

  • 當讀取請求無法從分片獲得響應時
  • 當由於集群或節點仍處於初始啟動過程而無法搜索數據
  • 當分片丟失或處於恢復模式並且集群為紅色時

造成 All Shards Failed 可能的原因:

  • 節點可能已斷開連接或重新連接
  • 正在查詢的分片可能正在恢復中,因此不可用
  • 磁盤可能已損壞
  • 搜索query 語句可能寫的有問題。例如,引用字段類型錯誤的字段。
  • 配置錯誤可能導致操作失敗。

問題排查實戰舉例:

GET /_cat/health
GET /_cat/indices?v
GET _cluster/health/?level=shards
GET _cluster/allocation/explain

5、進程內存鎖定失敗:“memory locking requested for elasticsearch process but memory is not locked”

為了使節點保持健康,必須確保沒有將 JVM 內存換出到磁盤。

發生系統 swapping (交換)的時候 Elasticsearch 節點的性能會非常差,也會影響節點的穩定性。

所以要不惜一切代價來避免 swapping 。swapping會導致Java GC的周期延遲從毫秒級惡化到分鍾,更嚴重的是會引起節點響應延遲甚至脫離集群。

限制 elasticsearch占用的內存情況,可選擇少用swap。而:啟用 bootstrap.memory_lock 就是限制交換的三種方案之一。

在 elasticsearch.yml 中 啟動 memory_lock 實踐:

bootstrap.memory_lock: true

報錯復現如下:

[,260][INFO ][o.e.n.Node               ] [node-1] starting ...
[,529][INFO ][o.e.t.TransportService   ] [node-1] publish_address {172.17.0.5:9300}, bound_addresses {172.17.0.5:9300}
[,537][INFO ][o.e.b.BootstrapChecks    ] [node-1] bound or publishing to a non-loopback address, enforcing bootstrap checks
[,565][ERROR][o.e.b.Bootstrap          ] [node-1] node validation exception
[1] bootstrap checks failed
[1]: memory locking requested for elasticsearch process but memory is not locked
[,575][INFO ][o.e.n.Node               ] [node-1] stopping ...
[,596][INFO ][o.e.n.Node               ] [node-1] stopped
[,597][INFO ][o.e.n.Node               ] [node-1] closing ...
[,615][INFO ][o.e.n.Node               ] [node-1] closed

centos 7.x 解決方案:在 /etc/security/limits.conf 文件中添加如下內容,並保持,然后重啟 elasticsearch 即可。

elasticsearch soft memlock unlimited
elasticsearch hard memlock unlimited

最佳實踐之驗證啟動是否成功:

GET _nodes?filter_path=**.mlockall

正確返回結果如下:

{
  "nodes" : {
    "gJUT-E48u_nUw" : {
      "process" : {
        "mlockall" : true
      }
    }
  }
}

6、引導檢查失敗 Bootstrap Checks Failed

Bootstrap 檢查會在 Elasticsearch 開始之前檢查各種設置和配置,以確保其可以安全運行。

如果引導檢查失敗,則它們可以阻止 Elasticsearch 啟動(如果處於生產模式)或在開發模式下發出警告日志。

建議你熟悉引導檢查所強制執行的設置,並注意它們在開發和生產模式上是不同的。通過將系統屬性

es.enforce.bootstrap.checks設置為true,可以強制執行引導檢查。

主要檢查內容包含但不限於:

  • 堆的大小檢查
  • 文件描述符
  • 最大線程數
  • 文件大小限制
  • 最大虛擬內存
  • 最大映射數
  • 客戶端jvm檢查
  • 垃圾收集檢查
  • OnError和OnOutOfMemoryError檢查 ......

最佳實踐:在 jvm.option 中添加如下配置后重啟 Elasticsearch。

-Des.enforce.bootstrap.checks=true

7、TransportError

在Elasticsearch中,傳輸模塊核心功能是:集群中節點之間的通信。

傳輸錯誤Transport errors 經常出現,失敗可能是如下的原因引起的:

  • 分片丟失

  • 設置沖突

  • 數據建模不合理

  • 網絡故障

  • .....

常見的 Transport errors 錯誤如下:

TransportError(403, u'cluster_block_exception', u'blocked by: [FORBIDDEN/12/index read-only / allow delete (api)];')

原因分析:

當沒有足夠的可用磁盤空間供 Elasticsearch 在節點之間分配時,可能會發生這種情況。

解決方案:

  • 增加磁盤空間
  • 刪除舊數據以釋放空間
  • 更新索引只讀模式。

注意:當磁盤使用率>=95%,index.blocks.read_only_allow_delete設置是防止節點用完磁盤空間的最后手段。不再允許寫入,只能刪除。

以下命令能重置索引上的只讀索引塊:

PUT /_all/_settings
{
  "index.blocks.read_only_allow_delete": null
}

在分配所有分片之前,嘗試使用剛剛創建的索引時,可能會出現另一種傳輸錯誤。

在這種情況下,報錯如下:

TransportError(503, u”). 

傳輸錯誤也可能與  Mapping 問題相關。

例如,當您嘗試索引具有與其映射不同的數據類型的字段時,可能報錯如下:

TransportError (400, u’mapper_pasing_exception’) 

8、初始化/啟動失敗 Initialization/Startup Failures

有時候,分片的問題可能會阻止 Elasticsearch 啟動。

例如,當使用有沖突的 Elasticsearch 版本時,您可能報錯如下:

“ Elasticsearch java client initialization fails” 

 “\Common was unexpected at this time.”

最佳實踐:

做好版本核驗,確保開發使用的 jar 包版本和部署版本一致。

9、如何最小化錯誤和異常?探究錯誤及解決方案的底層邏輯

如果你不想僅僅一次處理一條錯誤消息,當你處理的問題多了以后,你會發現:很多錯誤和異常與如下三個更深層次的問題相關:

  • 安裝和配置問題
  • 索引新數據問題
  • 集群運行變慢問題

深究拆解如下:

9.1  安裝和配置問題

快速安裝 Elasticsearch 很容易,但是要確保其生產級別的運行,需要仔細核對配置。

這可以幫助避免各種錯誤和異常,例如:引導檢查失敗  bootstrap checks failure 問題。

9.2 索引新數據問題

在 Elasticsearch 中,你必須非常仔細的對字段命名、正確使用模板 template、數據建模規范化。

仔細核對這些參數配置,可以幫助你避免諸如:映射 mapping 異常和批量索引錯誤( bulk index errors)之類的問題。

9.3 集群速度變慢問題

隨着數據規模的擴大,以及操作頻繁度的擴展,Elasticsearch 有時會發生意外導致檢索響應速度慢,並可能彈出超時報錯。

因此,你必須持續監控集群的如下指標內容:

  • 借助 kibana 或者 cerebro 等可視化工具觀察錯誤率及走勢
  • 監控錯誤日志
  • 核對拒絕的指標

以提前將可能錯誤扼殺在搖籃階段,並確保集群一切正常。

10、結論

Elasticsearch 運維或開發實戰必定會遇到錯誤或異常。

盡管我們無法完全避免,但是可以采用一些最佳實踐來幫助減少錯誤或異常的發生,並在出現問題時更有效地解決問題。

快速有效地解決集群緩慢等復雜問題離不開如下三點:

第一:密切關注各項設置和配置;

第二:索引新數據時要小心;

第三:確保集群各項指標可被監視與可視化查看。

簡而言之,你應該將錯誤和異常視為優化 Elasticsearch 集群基礎架構的機會,而不必過分擔心它們的出現。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM