ElasticSearch使用問題及解決方案匯總
Elasticsearch是一個(gè)開源的分布式實(shí)時(shí)搜索與分析引擎,支持云服務(wù)。它是基于Apache Lucene搜索引擎的類庫創(chuàng)建的,提供了全文搜索能力、多語言支持、專門的查詢語言、支持地理位置服務(wù)、基于上下文的搜索建議、自動(dòng)完成以及搜索片段(snippet)的能力。Elasticsearch支持RESTful的API,可以使用JSON通過HTTP調(diào)用它的各種功能,包括搜索、分析與監(jiān)控。此外,它還為Java、PHP、Perl、Python以及Ruby等各種語言提供了原生的客戶端類庫。下面是總結(jié)了一下使用 elasticsearch所遇到的各類問題以及相關(guān)的解決方案。
1、out of memory錯(cuò)誤問題
因?yàn)槟J(rèn)情況下es對(duì)字段數(shù)據(jù)緩存(Field Data Cache)大小是無限制的,查詢時(shí)會(huì)把字段值放到內(nèi)存,特別是facet查詢,對(duì)內(nèi)存要求非常高,它會(huì)把結(jié)果都放在內(nèi)存,然后進(jìn)行排序等操作,一直使用內(nèi)存,直到內(nèi)存用完,當(dāng)內(nèi)存不夠用時(shí)就有可能出現(xiàn)out of memory錯(cuò)誤。
解決方法:
(1)設(shè)置es的緩存類型為Soft Reference,它的主要特點(diǎn)是據(jù)有較強(qiáng)的引用功能。只有當(dāng)內(nèi)存不夠的時(shí)候,才進(jìn)行回收這類內(nèi)存,因此在內(nèi)存足夠的時(shí)候,它們通常不被回收。另外,這些引 用對(duì)象還能保證在Java拋出OutOfMemory 異常之前,被設(shè)置為null。它可以用于實(shí)現(xiàn)一些常用圖片的緩存,實(shí)現(xiàn)Cache的功能,保證最大限度的使用內(nèi)存而不引起OutOfMemory。在es 的配置文件加上index.cache.field.type: soft即可。
(2)設(shè)置es最大緩存數(shù)據(jù)條數(shù)和緩存失效時(shí)間,通過設(shè)置index.cache.field.max_size: 50000來把緩存field的最大值設(shè)置為50000,設(shè)置index.cache.field.expire: 10m把過期時(shí)間設(shè)置成10分鐘。
2、拋出異常,錯(cuò)誤如下:
- 1org.elasticsearch.transport.RemoteTransportException: Failed to deserialize exception response from stream
原因:es節(jié)點(diǎn)之間的JDK版本不一樣
解決方式:統(tǒng)一JDK版本和環(huán)境
3、拋出異常,錯(cuò)誤如下:
- org.elasticsearch.client.transport.NoNodeAvailableException: No node available
(1)端口錯(cuò)誤
client = new TransportClient().addTransportAddress(new InetSocketTransportAddress(ipAddress, 9300));
端口9300寫成9200的報(bào)錯(cuò)No node available 或者查看連接的是不是本地計(jì)算機(jī),如果是遠(yuǎn)程的話查看一下IP地址是否正確。
(2)jar包報(bào)錯(cuò)誤的話可能是引用包不匹配,開啟的服務(wù)是什么版本最好對(duì)應(yīng)相應(yīng)的jar包。
(3)修改了集群名稱,設(shè)置了集群名字導(dǎo)致出現(xiàn)問題,設(shè)置操作如下:
- Settings settings = ImmutableSettings.settingsBuilder().put("cluster.name", "yoodb").build();
- client = new TransportClient(settings).addTransportAddress(new InetSocketTransportAddress(ipAddress, 9300));
(4)集群超過5s沒有響應(yīng),解決方式如下:
1)設(shè)置client.transport.ping_timeout超時(shí)時(shí)間,增大一些
2)代碼內(nèi)嵌入,如下:
- while (true) {
- try {
- bulk.execute().actionGet(getRetryTimeout());
- break;
- } catch (NoNodeAvailableException cont) {
- Thread.sleep(5000);
- continue;
- }
- }
4、由gc引起節(jié)點(diǎn)脫離集群
因?yàn)間c時(shí)會(huì)使jvm停止工作,如果某個(gè)節(jié)點(diǎn)gc時(shí)間過長(zhǎng),master ping3次(zen discovery默認(rèn)ping失敗重試3次)不通后就會(huì)把該節(jié)點(diǎn)剔除出集群,從而導(dǎo)致索引進(jìn)行重新分配。解決方法如下:
(1)優(yōu)化gc,減少gc時(shí)間。
(2)調(diào)大zen discovery的重試次數(shù)(es參數(shù):ping_retries)和超時(shí)時(shí)間(es參數(shù):ping_timeout)。后來發(fā)現(xiàn)根本原因是有個(gè)節(jié)點(diǎn)的系統(tǒng)所在硬盤滿了。導(dǎo)致系統(tǒng)性能下降。
#p#
5、無法創(chuàng)建本地線程問題
es恢復(fù)時(shí)報(bào)錯(cuò),如下:
- RecoverFilesRecoveryException[[index][3] Failed to transfer [215] files with total size of [9.4gb]]; nested: OutOfMemoryError[unable to create new native thread]; ]]
剛開始以為是文件句柄數(shù)限制,但想到之前報(bào)的是too many open file這個(gè)錯(cuò)誤,并且也把數(shù)據(jù)改大了。查資料得知一個(gè)進(jìn)程的jvm進(jìn)程的最大線程數(shù)為:虛擬內(nèi)存/(堆棧大小*1024*1024),也就是說虛擬內(nèi)存越大或堆棧越小,能創(chuàng)建的線程越多。重新設(shè)置后還是會(huì)報(bào)那這錯(cuò),按理說可創(chuàng)建線程數(shù)完全夠用了的,就想是不是系統(tǒng)的一些限制。后來在網(wǎng)上找到說是max user processes的問題,這個(gè)值默認(rèn)是1024,這個(gè)參數(shù)單看名字是用戶最大打開的進(jìn)程數(shù),但看官方說明,就是用戶最多可創(chuàng)建線程數(shù),因?yàn)橐粋€(gè)進(jìn)程最少有一個(gè)線程,所以間接影響到最大進(jìn)程數(shù)。調(diào)大這個(gè)參數(shù)后就沒有報(bào)這個(gè)錯(cuò)了。
解決方法:
(1)增大jvm的heap內(nèi)存或降低xss堆棧大小(默認(rèn)的是512K)。
(2)打開/etc/security/limits.d/90-nproc.conf,把soft nproc 1024這行的1024改大就行了。
6、集群狀態(tài)為黃色時(shí)并發(fā)插入數(shù)據(jù)報(bào)錯(cuò),錯(cuò)誤如下:
- [7]: index [index], type [index], id [1569133], message [UnavailableShardsException[[index][1] [4] shardIt, [2] active : Timeout waiting for [1m], request: org.elasticsearch.action.bulk.BulkShardRequest@5989fa07]]
這是錯(cuò)誤信息,當(dāng)時(shí)集群狀態(tài)為黃色,即副本沒有分配。當(dāng)時(shí)副本設(shè)置為2,只有一個(gè)節(jié)點(diǎn),當(dāng)你設(shè)置的副本大于可分配的機(jī)器時(shí),此時(shí)如果你插入數(shù)據(jù)就有可能報(bào)上面的錯(cuò),因?yàn)閑s的寫一致性默認(rèn)是使用quorum,即quorum值必須大于(副本數(shù)/2+1),我這里2/2+1=2也就是說要要至少插入到兩份索引中,由于只有一個(gè)節(jié)點(diǎn),quorum等于1,所以只插入到主索引,副本找不到從而報(bào)上面那個(gè)錯(cuò)。
解決方法:(1)去掉沒分配的副本。(2)把寫一致性改成one,即只寫入一份索引就行。
7、錯(cuò)誤使用api導(dǎo)致集群卡死
其實(shí)這個(gè)是很低級(jí)的錯(cuò)誤。功能就是更新一些數(shù)據(jù),可能會(huì)對(duì)一些數(shù)據(jù)進(jìn)行刪除,但刪除時(shí)同事使用了deleteByQuery這個(gè)接口,通過構(gòu)造 BoolQuery把要?jiǎng)h除數(shù)據(jù)的id傳進(jìn)去,查出這些數(shù)據(jù)刪除。但問題是BoolQuery最多只支持1024個(gè)條件,100個(gè)條件都已經(jīng)很多了,所以這樣的查詢一下子就把es集群卡死了。
解決方法:用bulkRequest進(jìn)行批量刪除操作。
8、設(shè)置jvm鎖住內(nèi)存時(shí)啟動(dòng)警告
當(dāng)設(shè)置bootstrap.mlockall: true時(shí),啟動(dòng)es報(bào)警告Unknown mlockall error 0,因?yàn)閘inux系統(tǒng)默認(rèn)能讓進(jìn)程鎖住的內(nèi)存為45k。
解決方法:設(shè)置為無限制,linux命令:ulimit -l unlimited