這期內(nèi)容當(dāng)中小編將會給大家?guī)碛嘘P(guān)如何進(jìn)行Elasticsearch性能優(yōu)化,文章內(nèi)容豐富且以專業(yè)的角度為大家分析和敘述,閱讀完這篇文章希望大家可以有所收獲。
創(chuàng)新互聯(lián)公司專業(yè)為企業(yè)提供康馬網(wǎng)站建設(shè)、康馬做網(wǎng)站、康馬網(wǎng)站設(shè)計、康馬網(wǎng)站制作等企業(yè)網(wǎng)站建設(shè)、網(wǎng)頁設(shè)計與制作、康馬企業(yè)網(wǎng)站模板建站服務(wù),10多年康馬做網(wǎng)站經(jīng)驗,不只是建網(wǎng)站,更提供有價值的思路和整體網(wǎng)絡(luò)服務(wù)。
Elasticsearch是目前大數(shù)據(jù)領(lǐng)域最熱門的技術(shù)棧之一,經(jīng)過近8年的發(fā)展,已從0.0.X版升級至6.X版本,雖然增加了很多的特性和功能,但是在主體架構(gòu)上,還是沒有太多的變化。下面就把我對于ES使用實(shí)踐的一些經(jīng)驗總結(jié)一下,供大家參考;也請大家拍磚。
一、 硬件環(huán)境選擇:
如果有條件,盡可能使用SSD硬盤, 不錯的CPU。ES的厲害之處在于ES本身的分布式架構(gòu)以及l(fā)ucene的特性。IO的提升,會極大改進(jìn)ES的速度和性能。
二、系統(tǒng)拓樸設(shè)計:
ES集群在架構(gòu)拓樸時,一般都會采用Hot-Warm的架構(gòu)模式,即設(shè)置3種不同類型的節(jié)點(diǎn):Master節(jié)點(diǎn)、Hot 節(jié)點(diǎn)和 Warm節(jié)點(diǎn)。
Master節(jié)點(diǎn)設(shè)置:一般會設(shè)置3個專用的maste節(jié)點(diǎn),以提供最好的彈性擴(kuò)展能力。當(dāng)然,必須注意discovery.zen.minimum_master_nodes 屬性的設(shè)置,以防split-brain問題,使用公式設(shè)置:N/2+1(N為候選master節(jié)點(diǎn)數(shù))。 該節(jié)點(diǎn)保持: node.data: false ; 因為master節(jié)點(diǎn)不參與查詢、索引操作,僅負(fù)責(zé)對于集群管理,所以在CPU、內(nèi)存、磁盤配置上,都可以比數(shù)據(jù)節(jié)點(diǎn)低很多。
Hot節(jié)點(diǎn)設(shè)置: 索引節(jié)點(diǎn)(寫節(jié)點(diǎn)),同時保持近期頻繁使用的索引。 屬于IO和CPU密集型操作,建議使用SSD的磁盤類型,保持良好的寫性能;節(jié)點(diǎn)的數(shù)量設(shè)置一般是大于等于3個。將節(jié)點(diǎn)設(shè)置為hot類型:
node.attr.box_type: hot
針對index, 通過設(shè)置index.routing.allocation.require.box_type: hot 可以設(shè)置將索引寫入hot節(jié)點(diǎn)。
Warm節(jié)點(diǎn)設(shè)置: 用于不經(jīng)常訪問的read-only索引。由于不經(jīng)常訪問,一般使用普通的磁盤即可。內(nèi)存、CPU的配置跟Hot節(jié)點(diǎn)保持一致即可;節(jié)點(diǎn)數(shù)量一般也是大于等于3個。
當(dāng)索引不再被頻繁查詢時,可通過index.routing.allocation.require.box_type: warm, 將索引標(biāo)記為warm, 從而保證索引不寫入hot節(jié)點(diǎn),以便將SSD磁盤資源用在刀刃上。一旦設(shè)置這個屬性,ES會自動將索引合并到warm節(jié)點(diǎn)。同時,也可以在elasticsearch.yml中設(shè)置 index.codec: best_compression 保證warm 節(jié)點(diǎn)的壓縮配置
Coordinating節(jié)點(diǎn):協(xié)調(diào)節(jié)點(diǎn)用于做分布式里的協(xié)調(diào),將各分片或節(jié)點(diǎn)返回的數(shù)據(jù)整合后返回。在ES集群中,所有的節(jié)點(diǎn)都有可能是協(xié)調(diào)節(jié)點(diǎn),但是,可以通過設(shè)置node.master、node.data 、 node.ingest 都為 false 來設(shè)置專門的協(xié)調(diào)節(jié)點(diǎn)。需要較好的CPU和較高的內(nèi)存。
三、ES的內(nèi)存設(shè)置:
由于ES構(gòu)建基于lucene, 而lucene設(shè)計強(qiáng)大之處在于lucene能夠很好的利用操作系統(tǒng)內(nèi)存來緩存索引數(shù)據(jù),以提供快速的查詢性能。lucene的索引文件segements是存儲在單文件中的,并且不可變,對于OS來說,能夠很友好地將索引文件保持在cache中,以便快速訪問;因此,我們很有必要將一半的物理內(nèi)存留給lucene ; 另一半的物理內(nèi)存留給ES(JVM heap )。所以, 在ES內(nèi)存設(shè)置方面,可以遵循以下原則:
1. 當(dāng)機(jī)器內(nèi)存小于64G時,遵循通用的原則,50%給ES,50%留給lucene。
2. 當(dāng)機(jī)器內(nèi)存大于64G時,遵循以下原則:
a. 如果主要的使用場景是全文檢索, 那么建議給ES Heap分配 4~32G的內(nèi)存即可;其它內(nèi)存留給操作系統(tǒng), 供lucene使用(segments cache), 以提供更快的查詢性能。
b. 如果主要的使用場景是聚合或排序, 并且大多數(shù)是numerics, dates, geo_points 以及not_analyzed的字符類型, 建議分配給ES Heap分配 4~32G的內(nèi)存即可,其它內(nèi)存留給操作系統(tǒng),供lucene使用(doc values cache),提供快速的基于文檔的聚類、排序性能。
c. 如果使用場景是聚合或排序,并且都是基于analyzed 字符數(shù)據(jù),這時需要更多的 heap size, 建議機(jī)器上運(yùn)行多ES實(shí)例,每個實(shí)例保持不超過50%的ES heap設(shè)置(但不超過32G,堆內(nèi)存設(shè)置32G以下時,JVM使用對象指標(biāo)壓縮技巧節(jié)省空間),50%以上留給lucene。
3. 禁止swap,一旦允許內(nèi)存與磁盤的交換,會引起致命的性能問題。 通過: 在elasticsearch.yml 中 bootstrap.memory_lock: true, 以保持JVM鎖定內(nèi)存,保證ES的性能。
4. GC設(shè)置原則:
a. 保持GC的現(xiàn)有設(shè)置,默認(rèn)設(shè)置為:Concurrent-Mark and Sweep (CMS),別換成G1GC,因為目前G1還有很多BUG。
b. 保持線程池的現(xiàn)有設(shè)置,目前ES的線程池較1.X有了較多優(yōu)化設(shè)置,保持現(xiàn)狀即可;默認(rèn)線程池大小等于CPU核心數(shù)。如果一定要改,按公式((CPU核心數(shù)* 3)/ 2)+ 1 設(shè)置;不能超過CPU核心數(shù)的2倍;但是不建議修改默認(rèn)配置,否則會對CPU造成硬傷。
四、 集群分片設(shè)置:
ES一旦創(chuàng)建好索引后,就無法調(diào)整分片的設(shè)置,而在ES中,一個分片實(shí)際上對應(yīng)一個lucene 索引,而lucene索引的讀寫會占用很多的系統(tǒng)資源,因此,分片數(shù)不能設(shè)置過大;所以,在創(chuàng)建索引時,合理配置分片數(shù)是非常重要的。一般來說,我們遵循一些原則:
1. 控制每個分片占用的硬盤容量不超過ES的最大JVM的堆空間設(shè)置(一般設(shè)置不超過32G,參加上文的JVM設(shè)置原則),因此,如果索引的總?cè)萘吭?00G左右,那分片大小在16個左右即可;當(dāng)然,最好同時考慮原則2。
2. 考慮一下node數(shù)量,一般一個節(jié)點(diǎn)有時候就是一臺物理機(jī),如果分片數(shù)過多,大大超過了節(jié)點(diǎn)數(shù),很可能會導(dǎo)致一個節(jié)點(diǎn)上存在多個分片,一旦該節(jié)點(diǎn)故障,即使保持了1個以上的副本,同樣有可能會導(dǎo)致數(shù)據(jù)丟失,集群無法恢復(fù)。所以, 一般都設(shè)置分片數(shù)不超過節(jié)點(diǎn)數(shù)的3倍。
五、 Mapping建模:
1. 盡量避免使用nested或 parent/child,能不用就不用;nested query慢, parent/child query 更慢,比nested query慢上百倍;因此能在mapping設(shè)計階段搞定的(大寬表設(shè)計或采用比較smart的數(shù)據(jù)結(jié)構(gòu)),就不要用父子關(guān)系的mapping。
2. 如果一定要使用nested fields,保證nested fields字段不能過多,目前ES默認(rèn)限制是50。參考:
index.mapping.nested_fields.limit :50
因為針對1個document, 每一個nested field, 都會生成一個獨(dú)立的document, 這將使Doc數(shù)量劇增,影響查詢效率,尤其是JOIN的效率。
3. 避免使用動態(tài)值作字段(key), 動態(tài)遞增的mapping,會導(dǎo)致集群崩潰;同樣,也需要控制字段的數(shù)量,業(yè)務(wù)中不使用的字段,就不要索引。控制索引的字段數(shù)量、mapping深度、索引字段的類型,對于ES的性能優(yōu)化是重中之重。以下是ES關(guān)于字段數(shù)、mapping深度的一些默認(rèn)設(shè)置:
index.mapping.nested_objects.limit :10000
index.mapping.total_fields.limit:1000
index.mapping.depth.limit: 20
六、 索引優(yōu)化設(shè)置:
1.設(shè)置refresh_interval 為-1,同時設(shè)置number_of_replicas 為0,通過關(guān)閉refresh間隔周期,同時不設(shè)置副本來提高寫性能。
2. 修改index_buffer_size 的設(shè)置,可以設(shè)置成百分?jǐn)?shù),也可設(shè)置成具體的大小,大小可根據(jù)集群的規(guī)模做不同的設(shè)置測試。
indices.memory.index_buffer_size:10%(默認(rèn))
indices.memory.min_index_buffer_size: 48mb(默認(rèn))
indices.memory.max_index_buffer_size
3. 修改translog相關(guān)的設(shè)置:
a. 控制數(shù)據(jù)從內(nèi)存到硬盤的操作頻率,以減少硬盤IO??蓪ync_interval的時間設(shè)置大一些。
index.translog.sync_interval:5s(默認(rèn))。
b. 控制tranlog數(shù)據(jù)塊的大小,達(dá)到threshold大小時,才會flush到lucene索引文件。
index.translog.flush_threshold_size:512mb(默認(rèn))
4. _id字段的使用,應(yīng)盡可能避免自定義_id, 以避免針對ID的版本管理;建議使用ES的默認(rèn)ID生成策略或使用數(shù)字類型ID做為主鍵。
5. _all字段及_source字段的使用,應(yīng)該注意場景和需要,_all字段包含了所有的索引字段,方便做全文檢索,如果無此需求,可以禁用;_source存儲了原始的document內(nèi)容,如果沒有獲取原始文檔數(shù)據(jù)的需求,可通過設(shè)置includes、excludes 屬性來定義放入_source的字段。
6. 合理的配置使用index屬性,analyzed 和not_analyzed,根據(jù)業(yè)務(wù)需求來控制字段是否分詞或不分詞。只有 groupby需求的字段,配置時就設(shè)置成not_analyzed, 以提高查詢或聚類的效率。
七、 查詢優(yōu)化:
1. query_string 或 multi_match的查詢字段越多, 查詢越慢??梢栽趍apping階段,利用copy_to屬性將多字段的值索引到一個新字段,multi_match時,用新的字段查詢。
2. 日期字段的查詢, 尤其是用now 的查詢實(shí)際上是不存在緩存的,因此, 可以從業(yè)務(wù)的角度來考慮是否一定要用now, 畢竟利用query cache 是能夠大大提高查詢效率的。
3. 查詢結(jié)果集的大小不能隨意設(shè)置成大得離譜的值, 如query.setSize不能設(shè)置成 Integer.MAX_VALUE, 因為ES內(nèi)部需要建立一個數(shù)據(jù)結(jié)構(gòu)來放指定大小的結(jié)果集數(shù)據(jù)。
4. 盡量避免使用script,萬不得已需要使用的話,選擇painless & experssions 引擎。一旦使用script查詢,一定要注意控制返回,千萬不要有死循環(huán)(如下錯誤的例子),因為ES沒有腳本運(yùn)行的超時控制,只要當(dāng)前的腳本沒執(zhí)行完,該查詢會一直阻塞。
如: {
“script_fields”:{
“test1”:{
“l(fā)ang”:“groovy”,
“script”:“while(true){print 'don’t use script'}”
}
}
}
5. 避免層級過深的聚合查詢, 層級過深的group by , 會導(dǎo)致內(nèi)存、CPU消耗,建議在服務(wù)層通過程序來組裝業(yè)務(wù),也可以通過pipeline的方式來優(yōu)化。
6. 復(fù)用預(yù)索引數(shù)據(jù)方式來提高AGG性能:
如通過 terms aggregations 替代 range aggregations, 如要根據(jù)年齡來分組,分組目標(biāo)是: 少年(14歲以下) 青年(14-28) 中年(29-50) 老年(51以上), 可以在索引的時候設(shè)置一個age_group字段,預(yù)先將數(shù)據(jù)進(jìn)行分類。從而不用按age來做range aggregations, 通過age_group字段就可以了。
7. Cache的設(shè)置及使用:
a) QueryCache: ES查詢的時候,使用filter查詢會使用query cache, 如果業(yè)務(wù)場景中的過濾查詢比較多,建議將querycache設(shè)置大一些,以提高查詢速度。
indices.queries.cache.size: 10%(默認(rèn)),可設(shè)置成百分比,也可設(shè)置成具體值,如256mb。
當(dāng)然也可以禁用查詢緩存(默認(rèn)是開啟), 通過index.queries.cache.enabled:false設(shè)置。
b) FieldDataCache: 在聚類或排序時,field data cache會使用頻繁,因此,設(shè)置字段數(shù)據(jù)緩存的大小,在聚類或排序場景較多的情形下很有必要,可通過indices.fielddata.cache.size:30% 或具體值10GB來設(shè)置。但是如果場景或數(shù)據(jù)變更比較頻繁,設(shè)置cache并不是好的做法,因為緩存加載的開銷也是特別大的。
c) ShardRequestCache: 查詢請求發(fā)起后,每個分片會將結(jié)果返回給協(xié)調(diào)節(jié)點(diǎn)(Coordinating Node), 由協(xié)調(diào)節(jié)點(diǎn)將結(jié)果整合。
如果有需求,可以設(shè)置開啟; 通過設(shè)置index.requests.cache.enable: true來開啟。
不過,shard request cache只緩存hits.total, aggregations, suggestions類型的數(shù)據(jù),并不會緩存hits的內(nèi)容。也可以通過設(shè)置indices.requests.cache.size: 1%(默認(rèn))來控制緩存空間大小。
上述就是小編為大家分享的如何進(jìn)行Elasticsearch性能優(yōu)化了,如果剛好有類似的疑惑,不妨參照上述分析進(jìn)行理解。如果想知道更多相關(guān)知識,歡迎關(guān)注創(chuàng)新互聯(lián)行業(yè)資訊頻道。