Elasticsearch 常見的 8 種錯(cuò)誤及最佳實(shí)踐
題記
Elasticsearch 社區(qū)有大量關(guān)于 Elasticsearch 錯(cuò)誤和異常的問題。
深挖這些錯(cuò)誤背后的原因,把常見的錯(cuò)誤積累為自己的實(shí)戰(zhàn)經(jīng)驗(yàn)甚至是工具,不僅可以節(jié)省我們的開發(fā)和運(yùn)維時(shí)間,而且可以幫助確保 Elasticsearch 集群的長(zhǎng)期健康運(yùn)行。
常見的異常、原因和常規(guī)最佳實(shí)踐拆解如下,這些最佳實(shí)踐可以幫助我們更有效地識(shí)別、最小化定位和處理異常問題。
1、 Mapper_parsing_exception
Elasticsearch 依靠映射(Mapping)定義的數(shù)據(jù)類型處理數(shù)據(jù)。
映射定義了文檔中的字段并指定了它們對(duì)應(yīng)的數(shù)據(jù)類型,例如日期類型 Date、長(zhǎng)整數(shù)類型 long 和 ?字符串類型 text。
如果索引文檔包含沒有定義數(shù)據(jù)類型的新字段,Elasticsearch將使用動(dòng)態(tài)映射來(lái)估計(jì)字段的類型,并在必要時(shí)將其從一種類型轉(zhuǎn)換為另一種類型。
如果Elasticsearch無(wú)法執(zhí)行此轉(zhuǎn)換,它將引發(fā)“ mapper_parsing_exception無(wú)法解析” 異常。
如果此類異常太多會(huì)降低索引吞吐量。
實(shí)戰(zhàn)舉例如下:
DELETE?mytest_0001
PUT?mytest_0001/_doc/1
{
??"name":"John"
}
PUT?mytest_0001/_doc/2
{
??"name":?{
????"firstname":?"John",
????"lastname":?"doe"
??}
}
為避免此問題,可以在創(chuàng)建索引時(shí)顯示定義Mapping,明確敲定字段類型。或者可以使用 _mapping 動(dòng)態(tài)添加新字段映射。
動(dòng)態(tài)更新索引實(shí)戰(zhàn):
PUT?mytest_0001/_mapping
{
??"properties":?{
????"title":?{
??????"type":?"text"
????}
??}
}
請(qǐng)注意:雖然可以通過(guò)如上命令動(dòng)態(tài)添加字段,但是不能更改現(xiàn)有字段映射。
若想做字段類型的修改,需要重新定義Mapping 結(jié)合 reindex 和 alias 別名 實(shí)現(xiàn)。
2、BulkIndexError
批量索引大型數(shù)據(jù)集通常更有效。
例如,您可以執(zhí)行一個(gè)批量操作來(lái)索引 1,000 個(gè)文檔,而不是使用 1,000 個(gè)索引操作。
批量操作可以通過(guò) bulk API 完成。
批量操作實(shí)戰(zhàn):
PUT?my_index_0003/_bulk
{"index":{"_id":1}}
{"myid":"c12345"}
{"index":{"_id":2}}
{"myid":"C12456"}
{"index":{"_id":3}}
{"myid":"C31268"}
但是,此過(guò)程容易出錯(cuò)。執(zhí)行批量操作的過(guò)程中,你需要仔細(xì)檢查:數(shù)據(jù)類型不匹配和空值匹配等問題。
對(duì)于批量 API ,你需要格外警惕,因?yàn)榧词褂袛?shù)百個(gè)肯定的響應(yīng),批量中的某些索引請(qǐng)求也可能失敗。
批量操作捕獲錯(cuò)誤實(shí)戰(zhàn):
?@Override
??public?void?afterBulk(long?executionId,?BulkRequest?request,?BulkResponse?response)?{
?if?(response.hasFailures())?{
??for?(int?i?=?0;?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()?+?"]");
???}
??}
?}
??}
除了提前設(shè)置具有所有適當(dāng)條件的批量 API 之外,還要瀏覽響應(yīng)列表并檢查每個(gè)響應(yīng),以確保所有數(shù)據(jù)均按預(yù)期索引。
3、搜索超時(shí)錯(cuò)誤:ConnectionTimeout,ReadTimeoutError,RequestTimeout 等
如果在指定的搜索時(shí)間內(nèi)未收到響應(yīng),則請(qǐng)求將失敗并返回錯(cuò)誤消息。這稱為搜索超時(shí)。
搜索超時(shí)很常見,多種原因都可以導(dǎo)致搜索超時(shí),例如:大型數(shù)據(jù)集或占用大量?jī)?nèi)存的查詢。
要消除搜索超時(shí),可以通過(guò)如下實(shí)現(xiàn)解決:
3.1 增加 elasticsearch.requestTimeout
設(shè)置注意:應(yīng)該在 HTTP 客戶端而不是 Elasticsearch 中指定 timeout 值,Elasticsearch 端沒有請(qǐng)求超時(shí)參數(shù)。
kibana 請(qǐng)求顯示超時(shí),優(yōu)化方案如下:
kibana 默認(rèn)請(qǐng)求等待時(shí)間是 30 秒,可以在 kibana.yml 中調(diào)整該值。
elasticsearch.requestTimeout:?90000
3.2 減少每個(gè)請(qǐng)求返回的文檔數(shù)量
不要將請(qǐng)求的 size 值設(shè)置太大,結(jié)合:from、size 深度翻頁(yè)機(jī)制實(shí)現(xiàn)。
全量遍歷借助 scroll 實(shí)現(xiàn)。
3.3 縮小時(shí)間范圍
請(qǐng)求時(shí)間范圍越長(zhǎng)(比如 時(shí)間跨度周期 1 ?年以上的數(shù)據(jù)),請(qǐng)求數(shù)據(jù)量越大,超時(shí)的可能性越高。
3.4 調(diào)整內(nèi)存設(shè)置
通過(guò)配置單個(gè)查詢的內(nèi)存斷路器來(lái)限制單個(gè)查詢的內(nèi)存使用量。
如:將 index.breaker.request.limit 限制為 40%,默認(rèn)是 60%。
集群層面設(shè)置請(qǐng)求熔斷內(nèi)存實(shí)戰(zhàn):
PUT?/_cluster/settings
{
??"persistent":?{
????"indices.breaker.request.limit":?"40%"
??}
}
通過(guò)將search.max_buckets設(shè)置為 5000 (默認(rèn)值:10000)來(lái)限制用于聚合的存儲(chǔ)桶數(shù)。
PUT?_cluster/settings
{
??"transient":?{
????"search.max_buckets":?5000
??}
}
3.5 優(yōu)化查詢、索引和分片。
3.6 啟用慢速搜索日志
監(jiān)視搜索運(yùn)行時(shí)間,掃描繁重的搜索等等。
慢日志開啟實(shí)戰(zhàn):
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 搜索時(shí),可能會(huì)遇到 “All Shards Failed” 的錯(cuò)誤消息。

發(fā)生 All Shards Failed 的幾種情況:
當(dāng)讀取請(qǐng)求無(wú)法從分片獲得響應(yīng)時(shí) 當(dāng)由于集群或節(jié)點(diǎn)仍處于初始啟動(dòng)過(guò)程而無(wú)法搜索數(shù)據(jù) 當(dāng)分片丟失或處于恢復(fù)模式并且集群為紅色時(shí)
造成 All Shards Failed 可能的原因:
節(jié)點(diǎn)可能已斷開連接或重新連接 正在查詢的分片可能正在恢復(fù)中,因此不可用 磁盤可能已損壞 搜索query 語(yǔ)句可能寫的有問題。例如,引用字段類型錯(cuò)誤的字段。 配置錯(cuò)誤可能導(dǎo)致操作失敗。
問題排查實(shí)戰(zhàn)舉例:
GET?/_cat/health
GET?/_cat/indices?v
GET?_cluster/health/?level=shards
GET?_cluster/allocation/explain
5、進(jìn)程內(nèi)存鎖定失敗:“memory locking requested for elasticsearch process but memory is not locked”
為了使節(jié)點(diǎn)保持健康,必須確保沒有將 JVM 內(nèi)存換出到磁盤。
發(fā)生系統(tǒng) swapping (交換)的時(shí)候 Elasticsearch 節(jié)點(diǎn)的性能會(huì)非常差,也會(huì)影響節(jié)點(diǎn)的穩(wěn)定性。
所以要不惜一切代價(jià)來(lái)避免 swapping 。swapping會(huì)導(dǎo)致Java GC的周期延遲從毫秒級(jí)惡化到分鐘,更嚴(yán)重的是會(huì)引起節(jié)點(diǎn)響應(yīng)延遲甚至脫離集群。
限制 elasticsearch占用的內(nèi)存情況,可選擇少用swap。而:?jiǎn)⒂?bootstrap.memory_lock 就是限制交換的三種方案之一。
在 elasticsearch.yml 中 啟動(dòng) memory_lock 實(shí)踐:
bootstrap.memory_lock:?true
報(bào)錯(cuò)復(fù)現(xiàn)如下:
[,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 文件中添加如下內(nèi)容,并保持,然后重啟 elasticsearch 即可。
elasticsearch?soft?memlock?unlimited
elasticsearch?hard?memlock?unlimited
最佳實(shí)踐之驗(yàn)證啟動(dòng)是否成功:
GET?_nodes?filter_path=**.mlockall
正確返回結(jié)果如下:
{
??"nodes"?:?{
????"gJUT-E48u_nUw"?:?{
??????"process"?:?{
????????"mlockall"?:?true
??????}
????}
??}
}
6、引導(dǎo)檢查失敗 Bootstrap Checks Failed
Bootstrap 檢查會(huì)在 Elasticsearch 開始之前檢查各種設(shè)置和配置,以確保其可以安全運(yùn)行。
如果引導(dǎo)檢查失敗,則它們可以阻止 Elasticsearch 啟動(dòng)(如果處于生產(chǎn)模式)或在開發(fā)模式下發(fā)出警告日志。
建議你熟悉引導(dǎo)檢查所強(qiáng)制執(zhí)行的設(shè)置,并注意它們?cè)陂_發(fā)和生產(chǎn)模式上是不同的。通過(guò)將系統(tǒng)屬性
es.enforce.bootstrap.checks設(shè)置為true,可以強(qiáng)制執(zhí)行引導(dǎo)檢查。
主要檢查內(nèi)容包含但不限于:
堆的大小檢查 文件描述符 最大線程數(shù) 文件大小限制 最大虛擬內(nèi)存 最大映射數(shù) 客戶端jvm檢查 垃圾收集檢查 OnError和OnOutOfMemoryError檢查 ......
最佳實(shí)踐:在 jvm.option 中添加如下配置后重啟 Elasticsearch。
-Des.enforce.bootstrap.checks=true
7、TransportError
在Elasticsearch中,傳輸模塊核心功能是:集群中節(jié)點(diǎn)之間的通信。
傳輸錯(cuò)誤Transport errors 經(jīng)常出現(xiàn),失敗可能是如下的原因引起的:
分片丟失
設(shè)置沖突
數(shù)據(jù)建模不合理
網(wǎng)絡(luò)故障
.....
TransportError(403,?u'cluster_block_exception',?u'blocked?by:?[FORBIDDEN/12/index?read-only?/?allow?delete?(api)];')
原因分析:
當(dāng)沒有足夠的可用磁盤空間供 Elasticsearch 在節(jié)點(diǎn)之間分配時(shí),可能會(huì)發(fā)生這種情況。
解決方案:
增加磁盤空間 刪除舊數(shù)據(jù)以釋放空間 更新索引只讀模式。
注意:當(dāng)磁盤使用率>=95%,index.blocks.read_only_allow_delete設(shè)置是防止節(jié)點(diǎn)用完磁盤空間的最后手段。不再允許寫入,只能刪除。
以下命令能重置索引上的只讀索引塊:
PUT?/_all/_settings
{
??"index.blocks.read_only_allow_delete":?null
}
在分配所有分片之前,嘗試使用剛剛創(chuàng)建的索引時(shí),可能會(huì)出現(xiàn)另一種傳輸錯(cuò)誤。
在這種情況下,報(bào)錯(cuò)如下:
TransportError(503,?u”).?
傳輸錯(cuò)誤也可能與 ?Mapping 問題相關(guān)。
例如,當(dāng)您嘗試索引具有與其映射不同的數(shù)據(jù)類型的字段時(shí),可能報(bào)錯(cuò)如下:
TransportError?(400,?u’mapper_pasing_exception’)?
8、初始化/啟動(dòng)失敗 Initialization/Startup Failures
有時(shí)候,分片的問題可能會(huì)阻止 Elasticsearch 啟動(dòng)。
例如,當(dāng)使用有沖突的 Elasticsearch 版本時(shí),您可能報(bào)錯(cuò)如下:
“?Elasticsearch?java?client?initialization?fails”?
或
?“\Common?was?unexpected?at?this?time.”
最佳實(shí)踐:
做好版本核驗(yàn),確保開發(fā)使用的 jar 包版本和部署版本一致。
9、如何最小化錯(cuò)誤和異常?探究錯(cuò)誤及解決方案的底層邏輯
如果你不想僅僅一次處理一條錯(cuò)誤消息,當(dāng)你處理的問題多了以后,你會(huì)發(fā)現(xiàn):很多錯(cuò)誤和異常與如下三個(gè)更深層次的問題相關(guān):
安裝和配置問題 索引新數(shù)據(jù)問題 集群運(yùn)行變慢問題
深究拆解如下:
9.1 ?安裝和配置問題
快速安裝 Elasticsearch 很容易,但是要確保其生產(chǎn)級(jí)別的運(yùn)行,需要仔細(xì)核對(duì)配置。
這可以幫助避免各種錯(cuò)誤和異常,例如:引導(dǎo)檢查失敗 ?bootstrap checks failure 問題。
9.2 索引新數(shù)據(jù)問題
在 Elasticsearch 中,你必須非常仔細(xì)的對(duì)字段命名、正確使用模板 template、數(shù)據(jù)建模規(guī)范化。
仔細(xì)核對(duì)這些參數(shù)配置,可以幫助你避免諸如:映射 mapping 異常和批量索引錯(cuò)誤( bulk index errors)之類的問題。
9.3 集群速度變慢問題
隨著數(shù)據(jù)規(guī)模的擴(kuò)大,以及操作頻繁度的擴(kuò)展,Elasticsearch 有時(shí)會(huì)發(fā)生意外導(dǎo)致檢索響應(yīng)速度慢,并可能彈出超時(shí)報(bào)錯(cuò)。
因此,你必須持續(xù)監(jiān)控集群的如下指標(biāo)內(nèi)容:
借助 kibana 或者 cerebro 等可視化工具觀察錯(cuò)誤率及走勢(shì) 監(jiān)控錯(cuò)誤日志 核對(duì)拒絕的指標(biāo)
以提前將可能錯(cuò)誤扼殺在搖籃階段,并確保集群一切正常。
10、結(jié)論
Elasticsearch 運(yùn)維或開發(fā)實(shí)戰(zhàn)必定會(huì)遇到錯(cuò)誤或異常。
盡管我們無(wú)法完全避免,但是可以采用一些最佳實(shí)踐來(lái)幫助減少錯(cuò)誤或異常的發(fā)生,并在出現(xiàn)問題時(shí)更有效地解決問題。
快速有效地解決集群緩慢等復(fù)雜問題離不開如下三點(diǎn):
第一:密切關(guān)注各項(xiàng)設(shè)置和配置;
第二:索引新數(shù)據(jù)時(shí)要小心;
第三:確保集群各項(xiàng)指標(biāo)可被監(jiān)視與可視化查看。
簡(jiǎn)而言之,你應(yīng)該將錯(cuò)誤和異常視為優(yōu)化?Elasticsearch 集群基礎(chǔ)架構(gòu)的機(jī)會(huì),而不必過(guò)分擔(dān)心它們的出現(xiàn)。
參考:
https://opster.com/blogs/common-elasticsearch-errors-and-exceptions/
Elasticsearch?官方文檔?
https://discuss.elastic.co/t/how-to-identify-message-causing-error-in-bulk-request/42885/5
更短時(shí)間更快習(xí)得更多干貨!
中國(guó)近 1/4 的 Elastic認(rèn)證工程師出自于此!
