前言
elasticsearch是基于lucene封裝的一個分布式欲间、實時楚里、可擴展、支持海量數據存儲的分析猎贴、搜索引擎班缎。
- 相較于lucene蝴光,操作更簡單。
- 更好的索引吝梅、搜索性能。
- 分布式惹骂、擴展能力更強苏携。
一、索引全過程
Gateway代表ElasticSearch索引的持久化存儲方式对粪。
在Gateway中右冻,ElasticSearch默認先把索引存儲在內存中,然后當內存滿的時候著拭,再持久化到Gateway里纱扭。當ES集群關閉或重啟的時候,它就會從Gateway里去讀取索引數據儡遮。比如LocalFileSystem和HDFS乳蛾、AS3等。DistributedLucene Directory鄙币,它是Lucene里的一些列索引文件組成的目錄肃叶。它負責管理這些索引文件。包括數據的讀取十嘿、寫入因惭,以及索引的添加和合并等。
Mapping绩衷,映射的意思蹦魔,非常類似于靜態(tài)語言中的數據類型。比如我們聲明一個int類型的變量咳燕,那以后這個變量只能存儲int類型的數據勿决。比如我們聲明一個double類型的mapping字段,則只能存儲double類型的數據招盲。Mapping不僅是告訴ElasticSearch剥险,哪個字段是哪種類型。還能告訴ElasticSearch如何來索引數據宪肖,以及數據是否被索引到等表制。
Search Moudle,這個很簡單
Index Moudle控乾,這個很簡單
Disvcovery么介,主要是負責集群的master節(jié)點發(fā)現。比如某個節(jié)點突然離開或進來的情況蜕衡,進行一個分片重新分片等壤短。這里有個發(fā)現機制。發(fā)現機制默認的實現方式是單播和多播的形式,即Zen久脯,同時也支持點對點的實現纳胧。另外一種是以插件的形式,即EC2帘撰。
Scripting跑慕,即腳本語言甲捏。包括很多褐桌,這里不多贅述澎嚣。如mvel窥淆、js座云、python等碎连。
Transport训桶,代表ElasticSearch內部節(jié)點不脯,代表跟集群的客戶端交互综苔。包括 Thrift惩系、Memcached、Http等協(xié)議
RESTful Style API如筛,通過RESTful方式來實現API編程蛆挫。3rd plugins,代表第三方插件妙黍。
Java(Netty)悴侵,是開發(fā)框架。
-
JMX拭嫁,是監(jiān)控可免。
image.png
1、客戶端發(fā)送索引請求 客戶端向ES節(jié)點發(fā)送索引請求
2做粤、參數檢查對請求中的參數進行檢查浇借,檢查參數是否合法,不合法的參數直接返回失敗給客戶端怕品。
3妇垢、數據預處理如果請求指定了pipeline參數,則對數據進行預處理肉康,數據預處理的節(jié)點為Ingest Node闯估,如果接受請求的節(jié)點不具有數據處理能力,則轉發(fā)給其他能處理的節(jié)點吼和。在Ingest Node上有定義好的處理數據的Pipeline涨薪,Pipeline中有一組定義好的Processor,每個Processor分別具有不同的處理功能炫乓,ES提供了一些內置的Processor刚夺,如:split献丑、join、set 侠姑、script等创橄,同時也支持通過插件的方式,實現自定義的Processor莽红。數據經過Pipeline處理完畢后繼續(xù)進行下一步操作妥畏。
4.判斷索引是否存在判斷索引是否存在。如果索引不存在船老,則判斷是否能夠自動創(chuàng)建咖熟,可以通過action.auto_create_index設置能否自動創(chuàng)建索引圃酵;如果節(jié)點支持Dynamic Mapping柳畔,寫入文檔時,如果字段尚未在mapping中定義郭赐,則會根據索引文檔信息推算字段的類型薪韩,但并不能完全推算正確。配置Dynamic:true時捌锭,文檔有新增字段的時候俘陷,索引的mapping也會同步更新。Dynamic:false時观谦,索引的mapping不會被更新拉盾,新增字段無法被索引到。Dynamic:strict時豁状,索引有新增字段時捉偏,將會報錯。
5.創(chuàng)建索引創(chuàng)建索引請求被發(fā)送到Master節(jié)點泻红,由Master節(jié)點負責進行索引的創(chuàng)建夭禽,索引創(chuàng)建成功后,Master節(jié)點會更新集群狀態(tài)clusterstate【同步到其他節(jié)點谊路,只有主節(jié)點可更新讹躯,其他節(jié)點只讀】,更新完畢后將索引創(chuàng)建的情況返回給Coordinate節(jié)點缠劝,收到Master節(jié)點返回后潮梯,進入下一流程。
6.請求預處理獲取集群狀態(tài)信息惨恭,判斷集群是否正常酷麦;從集群狀態(tài)中獲取對應索引的元信息,從元信息中獲取索引的mapping喉恋、version等信息沃饶,從請求中解析routing母廷、id信息,如果請求沒有指定文檔的id糊肤,則會生成一個UUID作為文檔的id琴昆。
7、路由算法及構建shard請求路由算法
路由算法即根據請求的routing和文檔id信息計算文檔應該被索引到那個分片ID的過程馆揉。
計算公式如下:shard_num = hash(_routing) % num_primary_shards
默認情況下业舍,_routing就是文檔id,num_primary_shards是主分片個數升酣,所以從算法中即可以看出索引的主分片個數一旦指定便無法修改舷暮,因為文檔利用主分片的個數來進行定位。當使用自定義_routing或者id時噩茄,按照上面的公式計算下面,數據可能會大量聚集于某些分片,造成數據分布不均衡绩聘,所以ES提供了routing_partition_size參數沥割,routing_partition_size越大,數據的分布越均勻凿菩。分片的計算公式變?yōu)椋簊hard_num = (hash(_routing) + hash(_id) % routing_partition_size) % num_primary_shards也就是說机杜,_routing字段用于計算索引中的一組分片,然后使用_id來選擇該組內的分片衅谷。index.routing_partition_size取值應具有大于1且小于index.number_of_shards的值椒拗。構建shard請求
將用戶的 bulkRequest 重新組織為基于 shard 的請求列表。例如获黔,原始用戶請求可能有10個寫操作蚀苛,如果這些文檔的主分片都屬于同一個,則寫請求被合并為1個肢执。根據路由算法計算某文檔屬于哪個分片枉阵。遍歷所有的用戶請求,重新封裝后添加到上述map結構预茄。Map<ShardId, List<BulkItemRequest>> requestsByShard = new HashMap<>()兴溜;
8、轉發(fā)請求并等待響應根據集群狀態(tài)中的內容路由表確定主分片所在節(jié)點耻陕,轉發(fā)請求并等待響應拙徽。遍歷所有需要寫的 shard,將位于某個 shard 的請求封裝為 BulkShardRequest類诗宣,調用TransportShardBulkAction#execute執(zhí)行發(fā)送膘怕,在listener中等待響應,每個響應也是以shard為單位的【如果某個shard的響應中部分doc寫失敗了召庞,則將異常信息填充到Response中岛心,整體請求做成功處理】来破。待收到所有響應后(無論成功還是失敗的),回復給客戶端忘古。
9徘禁、主分片節(jié)點流程主分片索引文檔,詳見第三節(jié)髓堪。
9送朱、副本分片索引文檔
- 當主分片完成索引操作后,會循環(huán)處理要寫的所有副本分片干旁,向副本分片所在的節(jié)點發(fā)送請求驶沼。副本分片執(zhí)行和主分片一樣的文檔寫入流程,然后返回寫入結果給主分片節(jié)點争群。
10回怜、請求返回 - 主分片收到副本分片的響應后,會執(zhí)行finish()操作祭阀,將收到的響應信息返回給Coordinate節(jié)點鹉戚,告知Coordinate節(jié)點文檔寫入分片成功鲜戒、失敗的情況专控;coordinate節(jié)點收到響應后,將索引執(zhí)行情況返回給客戶端遏餐。當文檔寫入失敗時伦腐,主分片節(jié)點會向Master節(jié)點返送shardFieled請求,因為主副本分片未同步失都,Master會更新集群的狀態(tài)柏蘑,將寫失敗的副本分片從in-sync-allocation中去除;同時在路由表中將該分片的狀態(tài)改為unassigned粹庞,即未分配狀態(tài)咳焚。
二、集群管理
2.1庞溜、節(jié)點類型
根據職能的不同革半,es的服務可分為,協(xié)調節(jié)點流码、主節(jié)點又官、數據節(jié)點、處理節(jié)點漫试×矗【一個節(jié)點可以同時兼具多個角色】
- 主節(jié)點Master:管理集群的機器(分片安排到哪個節(jié)點),盡量不處理用戶的數據請求(master節(jié)點也可以做協(xié)調節(jié)點驾荣,盡量不要做)外构。
- 協(xié)調節(jié)點coordinate:路由數據寫到哪個分片普泡。(數據存儲路由所有節(jié)點都具備這個能力,如果是創(chuàng)建分片只能主節(jié)點能操作审编。)
- 數據節(jié)點Data:存放分片數據劫哼。
- 處理節(jié)點Ingest:對數據做預處理。(是數據具備數據預處理能力的數據節(jié)點)
數據可以分為主分片割笙、副本分片权烧。 - 主分片:所有主分片加起來代表這個索引的總和。
- 副本分片:主分片的備份伤溉。
2.2般码、節(jié)點狀態(tài)
- 紅:部分主分片不可用
- 黃:部分副本不可用
- 綠:全部分片和副本都可用
2.3、節(jié)點職責
- master node職責處理索引創(chuàng)建乱顾、刪除板祝;分片分配到哪個節(jié)點;集群狀態(tài)維護和更新走净。
- 在每個節(jié)點上都保存了集群的狀態(tài)信息券时,但是只有master節(jié)點才能修改集群的狀態(tài)信息,并負責同步到其他的節(jié)點伏伯。
2.4橘洞、選舉
- 不依賴第三方組件,沒有節(jié)點數奇數的限制说搅,滿足一定規(guī)則即可炸枣。
- ES 集群由一個或多個 Elasticsearch 節(jié)點組成,每個節(jié)點配置相同的 cluster.name 即可加入集群【不同節(jié)點上弄唧,還需要單播主機列表】适肠,默認值為 “elasticsearch”。
- 每個節(jié)點都有一個名字node.name候引,啟動后會分配一個UID侯养,一份節(jié)點列表,并保存了集群狀態(tài)澄干。
選舉時逛揩,通過單播發(fā)現,互相ping對方傻寂,比較Node Id 記錄自己認為的主節(jié)點【Node Id 低的會成為被選舉的節(jié)點】息尺,最后多數者成為主節(jié)點;其他節(jié)點再加入集群時疾掰,不會承擔主節(jié)點角色搂誉;主節(jié)點丟失,就會重新通過互相ping對方選出主節(jié)點静檬。
2.5炭懊、腦裂問題
分布式系統(tǒng)的經典網路問題并级,當出現網路問題時,一個節(jié)點與其他節(jié)點無法連接侮腹。
- Node2和Node3會重新選舉Master
- Node1自己還是作為Master嘲碧,組成一個集群,同時更新Cluster State
- 導致2個Master父阻,維護不同的Cluster State愈涩,當網絡恢復時,無法選擇正確恢復
避免腦裂問題【7.0之后不需要配置】
限定選舉條件加矛,設置quorun【quorun = master節(jié)點總數/2+1】履婉,只有在master eligible節(jié)點大于quorun時,才能進行選舉斟览』偻龋【當有一半的候選主節(jié)點宕機后,集群將不會自動恢復】
2.6苛茂、集群伸縮
- 集群伸縮可以表現為節(jié)點配置提高或降低已烤,也可以表現為節(jié)點數增加或減少。
- 明確最后都是保證主節(jié)點正常妓羊,分片胯究,副本與設置一致,集群才能正常提供服務支持侍瑟。
- 主節(jié)點負責索引管理唐片、分片分配丙猬;數據節(jié)點負責數據存儲涨颜,提供查詢,主分片【所有主分片對待】接收請求茧球,同步數據到副本庭瑰。
2.7、故障轉移
- Node1主節(jié)點掛掉抢埋,集群變紅弹灭,重新選舉。
- Node2選為主節(jié)點揪垄,將副本R0升級為分片P0穷吮,此時集群變黃。
- 接著主節(jié)點下發(fā)生成R0,R1副本的命令到指定節(jié)點饥努,生成后捡鱼,集群恢復正常,變綠酷愧。
2.8驾诈、elasticsearch.yml
cluster.name
當前節(jié)點所屬集群名稱缠诅,多個節(jié)點如果要組成同一個集群,那么集群名稱一定要配置成相同乍迄。默認值elasticsearch管引,生產環(huán)境建議根據ES集群的使用目的修改成合適的名字。node.name
當前節(jié)點名稱闯两,默認值當前節(jié)點部署所在機器的主機名褥伴,所以如果一臺機器上要起多個ES節(jié)點的話,需要通過配置該屬性明確指定不同的節(jié)點名稱漾狼。path.data
配置數據存儲目錄噩翠,比如索引數據等,默認值 $ES_HOME/data邦投,生產環(huán)境下強烈建議部署到另外的安全目錄伤锚,防止ES升級導致數據被誤刪除。path.logs
配置日志存儲目錄志衣,比如運行日志和集群健康信息等屯援,默認值 $ES_HOME/logs,生產環(huán)境下強烈建議部署到另外的安全目錄念脯,防止ES升級導致數據被誤刪除狞洋。node.master
是否作為主節(jié)點,每個節(jié)點都可以被配置成為主節(jié)點绿店,默認值為true吉懊。node.data
是否存儲數據,即存儲索引片段假勿,默認值為true借嗽。bootstrap.memory_lock
配置ES啟動時是否進行內存鎖定檢查,默認值true转培。
ES對于內存的需求比較大恶导,一般生產環(huán)境建議配置大內存,如果內存不足浸须,容易導致內存交換到磁盤惨寿,嚴重影響ES的性能。所以默認啟動時進行相應大小內存的鎖定删窒,如果無法鎖定則會啟動失敗裂垦。非生產環(huán)境可能機器內存本身就很小,能夠供給ES使用的就更小肌索,如果該參數配置為true的話很可能導致無法鎖定內存以致ES無法成功啟動蕉拢,此時可以修改為false。network.host
配置能夠訪問當前節(jié)點的地址,
1企量、默認值為當前節(jié)點所在機器的本機回環(huán)地址127.0.0.1 和[::1]测萎,這就導致默認情況下只能通過當前節(jié)點所在主機訪問當前節(jié)點。
2届巩、配置成某一ip硅瞧,例如192.168.1.0時,其他服務只能通過此ip訪問es恕汇。
3腕唧、可以配置為 0.0.0.0 ,表示所有主機均可訪問瘾英。network.public_host
publish_host設置其他節(jié)點連接此集群的地址枣接,公共集群網絡(集群間通信)。network.bind_host
network.bind_host: ["192.168.1.100","10.210.32.xx"]外部網絡可訪問的地址缺谴。http.port
配置當前ES節(jié)點對外提供服務的http端口但惶,默認值 9200transport
配置當前ES節(jié)點對內提供服務的服務發(fā)現端口,默認值 9300http.max_content_length
設置內容的最大長度100Mdiscovery.seed_hosts
配置參與集群節(jié)點發(fā)現過程的主機列表湿蛔,說白一點就是集群中所有符合主節(jié)點要求的主機列表膀曾,可以是具體的IP地址,也可以是可解析的域名阳啥。cluster.initial_master_nodes【建議刪除此配置】
配置ES集群初始化時參與master選舉的節(jié)點名稱列表添谊,集群自舉節(jié)點列表〔斐伲【為了設置特定節(jié)點作為master時設置】啟動Master候選節(jié)點時斩狱,可以在命令行上或elasticsearch.yml文件中提供此設置. 群集形成后,不再需要此設置扎瓶,并且會忽略它所踊,也就是說,這個屬性就只是在集群首次啟動時有用栗弟。并且可以不需要在非Master候選節(jié)點上設置污筷。discovery.zen.ping.unicast.hosts【過時配置】
設置新節(jié)點被啟動時能夠發(fā)現的主節(jié)點列表(主要用于不同網段機器連接)【transport端口】discovery.zen.minimum_master_nodes
設置一個集群中參與選舉的主節(jié)點的數量,當多于三個節(jié)點時乍赫,該值可在2-4之間。discovery.zen.ping.timeout
設置ping其他節(jié)點時的超時時間陆蟆,網絡比較慢時可將該值設大雷厂。discovery.zen.ping.multicast.enabled
禁止當前節(jié)點發(fā)現多個集群節(jié)點,默認值為true叠殷。node.rack
每個節(jié)點都可以定義一些與之關聯(lián)的通用屬性改鲫,用于后期集群進行碎片分配時的過濾。node.max_local_storage_nodes
默認情況下,多個節(jié)點可以在同一個安裝路徑啟動像棘,如果你想讓你的es只啟動一個節(jié)點稽亏,可以設置為1。
三缕题、索引詳細過程
3.1截歉、路由
客戶端發(fā)起數據寫入請求,對你寫的這條數據根據_routing規(guī)則選擇發(fā)給哪個Shard烟零”袼桑【確認Index Request中是否設置了使用哪個Filed的值作為路由參數,如果沒有設置锨阿,則使用Mapping中的配置宵睦,如果mapping中也沒有配置,則使用_id作為路由參數墅诡,然后通過_routing的Hash值選擇出Shard壳嚎,最后從集群的Meta中找出出該Shard的Primary節(jié)點∧┰纾】
3.2诬辈、buffer
寫入請求到達Shard后,先把數據寫入到內存(buffer)中荐吉,同時會寫入一條日志到translog日志文件中去焙糟。【還未構建倒排索引】
3.3样屠、refresh
執(zhí)行refresh操作:從內存buffer中將數據寫入os cache(操作系統(tǒng)的內存)穿撮,產生一個新的segment file文件(不需要落盤,寫入os cache后痪欲,文件句柄也就可以被訪問了)悦穿,buffer清空。默認是每隔1秒refresh一次的业踢,所以es是準實時的栗柒,因為寫入的數據1秒之后才能被看到。buffer內存占滿的時候也會執(zhí)行refresh操作知举,buffer默認值是JVM內存的10%瞬沦,若要優(yōu)化索引速度, 而不注重實時性, 可以降低刷新頻率。通過es的restful api或者java api雇锡,手動執(zhí)行一次refresh操作逛钻,就是手動將buffer中的數據刷入os cache中,讓數據立馬就可以被搜索到锰提。
3.4曙痘、translog
translog會每隔5秒或者在一個變更請求完成之后芳悲,將translog從緩存刷入磁盤”呃ぃ【也就是translog也有緩存】translog是存儲在os cache【然后定期fsync】中名扛,每個分片有一個,如果節(jié)點宕機會有5秒數據丟失茧痒,但是性能比較好肮韧,最多丟5秒的數據。文黎∪敲纾可以將translog設置成每次寫操作必須是直接fsync到磁盤,但是性能會差很多耸峭∽兀【translog的fsync頻率決定了數據的安全性,recovery就是在commit point沒有劳闹,translog有的數據】可以通過配置增加transLog刷磁盤的頻率來增加數據可靠性院究,最小可配置100ms,但不建議這么做本涕,因為這會對性能有非常大的影響业汰。
3.5、fsync
將os cache中的數據刷到磁盤菩颖,他是一個linux的系統(tǒng)命令样漆。
flush參數設置:
index.translog.flush_threshold_period
index.translog.flush_threshold_size
控制每收到多少條數據后flush一次
index.translog.flush_threshold_ops
3.6、flush
每30分鐘或者當tanslog的大小達到512M時候晦闰,就會執(zhí)行commit操作(flush操作)放祟,將os cache中所有的數據全以segment file的形式,持久到磁盤上去呻右。第一步跪妥,就是將buffer中現有數據refresh到os cache中去。清空buffer 然后強行將os cache中所有的數據全都一個一個的通過segmentfile的形式声滥,持久到磁盤上去眉撵。將commit point這個文件更新到磁盤中,每個Shard都有一個提交點(commit point), 其中保存了當前Shard成功寫入磁盤的所有segment落塑。把translog文件刪掉清空纽疟,再開一個空的translog文件。
3.7芜赌、Segment merge
- Segment的merge操作:
每次refresh的時候都會生成一個新的segment仰挣,太多的Segment會占用過多的資源,而且每個搜索請求都會遍歷所有的Segment缠沈,Segment過多會導致搜索變慢,所以ES會定期合并Segment,減少Segment的個數洲愤,并將Segment和并為一個大的Segment颓芭;每次在啟動segment合并工作時,那些被標記為刪除的文檔才會被真正刪除柬赐。在操作Segment時亡问,會維護一個Commit Point文件,其中記錄了所有成功寫入磁盤的Segment的信息肛宋;同時維護.del文件用于記錄所有刪除的Segment信息州藕。單個倒排索引文件被稱為Segment。多個Segment匯總在一起酝陈,就是Lucene的索引床玻,對應的就是ES中的shard。 - 我們可以手動進行merge:POST index/_forcemerge沉帮。一般不需要锈死,這是一個比較消耗資源的操作。
- segment總和=os cache+disk穆壕。
- 每個shard有一個commit point待牵,記錄成功寫入磁盤的所有segment。
四喇勋、Lucene結構
4.1缨该、正排數據
4.2、倒排數據
4.3川背、DocValues
4.4贰拿、segment文件
注意
細化索引
一個ES的index包含多個shard,一個shard就是lucene的一個索引渗常,一個lucene的索引包含多個segment壮不,一個segment包含多個doc,一個doc包含多個filed皱碘,一個field包含term询一。
索引不可變
一個ES索引創(chuàng)建后,各個字段的數據類型都確定癌椿,那么數據插入的時候健蕊,就會按照字段類型,為每個字段構建倒排索引踢俄,所以說索引一旦創(chuàng)建就不能修改缩功,這個不能改指的是字段類型,添加字段是可以的都办。
分片不可改
索引一旦創(chuàng)建嫡锌,不能修改分片數虑稼,因為數據寫入索引是根據分片數路由,改了分片數势木,就需要將之前的數據重新路由蛛倦,不然找不到之前寫入的數據。
索引近實時
ES是近實時啦桌,是因為數據寫入索引瀑凝,先寫入緩存输莺,此時不可查薪寓,1s后刷新到os cache才能查女蜈,因為有了文件句柄就可以查,不用落盤板驳。
副本增加吞吐量
添加副本數又跛,可以提高搜索的效率,因為查詢的時候笋庄,不管是主分片效扫,還是副本只要一個位置搜索到,就可以返回直砂。