1. 程式人生 > 實用技巧 >Elasticsearch 常見的 8 種錯誤及最佳實踐

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

題記

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

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

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

1、 Mapper_parsing_exception

Elasticsearch 依靠對映(Mapping)定義的資料型別處理資料。

對映定義了文件中的欄位並指定了它們對應的資料型別,例如日期型別 Date、長整數型別 long 和 字串型別 text。

如果索引文件包含沒有定義資料型別的新欄位,Elasticsearch將使用動態對映來估計欄位的型別,並在必要時將其從一種型別轉換為另一種型別。

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

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

實戰舉例如下:

DELETEmytest_0001
PUTmytest_0001/_doc/1
{
"name":"John"
}

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

為避免此問題,可以在建立索引時顯示定義Mapping,明確敲定欄位型別。或者可以使用 _mapping動態新增新欄位對映。

動態更新索引實戰:

PUTmytest_0001/_mapping
{
"properties":{
"title":{
"type":"text"
}
}
}

請注意:雖然可以通過如上命令動態新增欄位,但是不能更改現有欄位對映。

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

2、BulkIndexError

批量索引大型資料集通常更有效。

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

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

批量操作實戰:

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

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

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

批量操作捕獲錯誤實戰:

@Override
publicvoidafterBulk(longexecutionId,BulkRequestrequest,BulkResponseresponse){
if(response.hasFailures()){
for(inti=0;i<response.getItems().length;i++){
BulkItemResponseitem=response.getItems()[i];
if(item.isFailed()){
IndexRequestireq=(IndexRequest)request.requests().get(i);
logger.error("Failedwhileindexingto"+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]boundorpublishingtoanon-loopbackaddress,enforcingbootstrapchecks
[,565][ERROR][o.e.b.Bootstrap][node-1]nodevalidationexception
[1]bootstrapchecksfailed
[1]:memorylockingrequestedforelasticsearchprocessbutmemoryisnotlocked
[,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 即可。

elasticsearchsoftmemlockunlimited
elasticsearchhardmemlockunlimited

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

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'blockedby:[FORBIDDEN/12/indexread-only/allowdelete(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 版本時,您可能報錯如下:

“Elasticsearchjavaclientinitializationfails”

“\Commonwasunexpectedatthistime.”

最佳實踐:

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

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

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

  • 安裝和配置問題
  • 索引新資料問題
  • 叢集執行變慢問題

深究拆解如下:

9.1 安裝和配置問題

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

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

9.2 索引新資料問題

在 Elasticsearch 中,你必須非常仔細的對欄位命名、正確使用模板 template、資料建模規範化。

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

9.3 叢集速度變慢問題

隨著資料規模的擴大,以及操作頻繁度的擴充套件,Elasticsearch 有時會發生意外導致檢索響應速度慢,並可能彈出超時報錯。

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

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

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

10、結論

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

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

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

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

第二:索引新資料時要小心;

第三:確保叢集各項指標可被監視與視覺化檢視。

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