- Elastic Stack應用寶典
- 田雪松編著
- 3667字
- 2020-07-22 17:21:24
2.4 分片與復制
全文檢索面對的文檔數量往往十分驚人,因為這些文檔一般都來自訪問流量巨大的互聯網應用。比如,搜索引擎要處理的網頁數據,在線交易系統每天產生的訂單等。即便是在業務數據并不多的普通應用中,它們產生的日志文檔容量往往也十分龐大。如果這些文檔都存儲在Elasticsearch中,Elasticsearch就必須要解決海量文檔存儲的問題。這不僅是要解決文檔能夠存得下的問題,還要保證它們不會因為故障而丟失,同時還要保證文檔的檢索速度盡可能不受文檔數量增加的影響。
2.4.1 分片與集群
解決大數據存儲的通用方案稱為分片(Shard),它的核心思想是將數據分解成大小合適的片段,然后再將它們存儲到集群中不同的節點上。這樣一來,數據存儲的容量從理論上來說就沒有上限了。因為在數據量增加時,只需要向集群中添加新的節點就可以增加整體容量了。數據分片帶來的收益不僅體現在數據存儲上,對于數據處理來說也可以大幅提升性能和吞吐量。這是因為在現有硬件技術條件下,硬盤讀寫速度與CPU處理能力不在一個數量級上,所以硬盤往往是數據處理的最大瓶頸。所以,即使多個CPU或多個線程并發處理數據,只要處理的數據在同一個硬盤上,數據處理的速度也不會得到顯著提升。在使用數據分片技術后,數據會被散列到不同機器的硬盤上,數據的讀寫也就被分散到不同的硬盤上,這會顯著提升數據處理的速度。大數據處理開源框架Hadoop中的HDFS和MapReduce正是基于這種思想,實現了在短時間內處理大量數據的功能。Elasticsearch作為一種全文檢索引擎,顯然也有必要考慮大數據的問題,所以Elasticsearch在設計之初就支持文檔分片。因為Elasticsearch支持分片,所以它存儲文檔的容量在理論上沒有上限。也正是從這個意義上,它才被很多文獻歸類為一種數據庫,一種基于文檔的NoSQL數據庫。
分片的基礎是要創建集群,Elasticsearch創建集群非常簡單,只要集群中的節點在相互連接的網絡中,并且具有相同的集群名稱即可。Elasticsearch集群名稱在配置文件中指定,在安裝路徑的config目錄下找到elasticsearch.yml文件,其中的cluster.name就是配置集群名稱的參數,默認名稱為elasticsearch。所以在一個局域網內部創建Elasticsearch集群非常簡單,只要在不同的機器上直接運行elasticsearch命令即可,甚至不需要修改配置文件。但在學習Elasticsearch時,如果想要在單臺機器上創建一個集群,則需要在elasticsearch.yml文件中添加配置:“node.max_local_storage_nodes:2”。這將允許在單臺機器啟動多個Elasticsearch實例,否則在單機啟動多個Elasticsearch實例時會報錯。當啟動好多個實例后,可通過_nodes接口查看節點情況。在Kibana控制臺中執行“GET _nodes”命令,可在返回結果中看到如下信息:


示例2-14 查看節點信息
創建了Elasticsearch集群后,就需要確定索引分片的數量。分片一般會均勻地分散到集群的不同節點上,這就將存儲和檢索負載分散到集群的不同節點上。索引分片數量是在創建索引時通過number_of_shards參數設置的,例如在示例2-15中創建的test索引,分片數量為10:

示例2-15 索引分片數量
在索引定義好分片數量后,當有新的節點加入集群時,Elasticsearch會將分片均衡地散列到新的節點。例如,索引分片數量為2,當集群中只有一個節點A時,這些分片將全部位于節點A上;而當有節點B加入到集群中時,Elasticsearch會動態地將其中一個分片復制到節點B上。這也意味著如果索引的分片數量為1,那么這個索引未來將無法擴容。
2.4.2 路由
分片解決了海量文檔存儲的問題,但也引入了一個新的問題,那就是如何確定文檔應該存儲到哪個分片。在Elasticsearch中,確定文檔存儲在哪一個分片中的機制被稱為路由(Routing)。計算文檔路由的具體運算公式如下:

公式(2-1)中,shard_num為分片序號,hash為散列函數,_routing為路由參數,而num_primary_shards則是一個索引的主分片數量。這里之所以要使用主分片主要是為了區別副本分片,即在運算時并不包含副本分片數量。決定一份文檔最終存儲在哪一個分片上,最關鍵的參數就是_routing。在默認情況下,文檔的_routing參數是文檔ID,也就是前面介紹的元字段_id。如果想要修改路由參數,可以通過在添加或檢索文檔時設置routing參數。從負載均衡的角度來看,routing參數的值越分散,文檔分散的越均勻。所以選擇合適的routing無論對文檔添加還是對文檔檢索,都會有非常顯著的性能提升。示例2-16中使用routing參數設置了自定義規則:

示例2-16 自定義路由規則
為了提升檢索效率,Elasticsearch在檢索文檔時,并不會將所有分片整合到一起做檢索,而是先根據路由規則路由到具體分片,然后再在分片上根據檢索條件查找文檔。所以如果文檔添加時的路由規則與文檔檢索時的路由規則不相同,在檢索文檔時就有可能被路由到錯誤的分片上,從而導致檢索失敗。一種比較常見的錯誤情況就是在文檔添加時使用了自定義的路由規則,而在文檔檢索時忘記使用路由規則。為了避免這種情況的發生,可以在創建索引時將文檔路由參數設置為強制要求,例如示例2-17中test索引的路由參數設置為強制:

示例2-17 路由參數
在路由參數設置為強制之后,對文檔CRUD操作都必須要指定routing參數,否則在執行請求時將報錯誤。
由于路由選擇對于索引性能的影響很大,往往選擇的routing參數看似分散但卻會路由到相同的分片。為了解決這個問題,Elasticsearch又引入了另一個分區參數來平衡路由運算,這就是routing_partition_size。引入這個參數后,路由運算公式變為

在添加了分區參數以后,分片編號同時由路由參數_routing和索引_id字段共同決定,這也就加大分片均衡的可能性。routing_partition_size參數必須大于1并且小于主分片數量,它的默認值1代表不會使用式(2-2)計算分片編號。當使用式(2-2)計算分片編號時,需要按示例2-17的方式將索引路由參數設置為強制,同時也不能再使用join類型字段構建父子關系。
2.4.3 容量規劃
文檔所在分片除了由routing參數決定以外,索引分片數量也是其中一個重要的決定因素。按公式(2-1)所示,在索引分片數量發生變化時,即使routing參數不變,最終的分片位置也會發生變化。如果在運行時索引分片數量發生了變化,為了保證文檔存儲和檢索都能路由到正確的分片,已經存儲到分片中的文檔就必須按公式(2-1)做分片的重新路由。這個過程在Elasticsearch中叫重新索引(Reindex),顯然當分片中已經存儲了大量文檔時,這將是一個非常耗費資源的過程。
為了避免重新索引導致的性能開銷,Elasticsearch對索引分片數量做了一個嚴格的限制,這就是索引分片數量一旦在創建索引時確定后就不能再修改。這雖然解決了重新索引問題,但索引的存儲容量也被分片數量、節點存儲容量限制死了。節點存儲容量決定了分片容量的上限,而索引總容量則是單個分片容量與分片數量的乘積。從性能角度考慮,分片太大顯然會降低檢索速度,所以單個分片的容量也不能過大,需要根據用戶對檢索性能的要求估算單個分片的容量上限。盡管最好的辦法是將分片平均分配到不同的節點上,但如果節點存儲容量大于單分片容量上限時,也可以考慮在一個節點上存儲多個分片。盡管如此,這還是意味著索引存儲容量存在上限,所以在創建索引時有必要對索引容量預先做好規劃。如果用戶在容量規劃時低估了文檔容量,那么索引將無法通過擴容來支持更多的文檔。
索引容量規劃主要是根據一些已知條件規劃分片數量,這些已知條件主要包括文檔存儲整體容量和檢索性能要求兩個方面。通過檢索性能要求可以估算出每個分片的最大容量,再使用整體容量除以分片大小就可以估算出分片數量。文檔整體容量有時可能無法估算,比如說日志文件每天都在產生,數量只可能越來越多,不可能估算出上限來。這種情況下可以取一個固定的時間段,比如一天或是一個月,每隔這樣一段時間就創建一個新的索引出來。由于固定時間段內的文檔數量可估算,所以分片數量也就可以預先估算。本書第3章3.1.1節介紹的_rollover接口,以滾動別名的方式給出解決這種問題的一個備選方案。
事實上,無論容量規劃得多科學依然不能完全避免文檔實際存儲量與索引容量不相符的情況。在這種情況下,惟一可行的辦法就是創建新的索引,再將原索引中的文檔存儲到新的索引中。Elasticsearch針對這種情況提供了三個接口,即_split接口、_shrink接口和_reindex接口。這三個接口都沒有修改原索引容量的能力,而是通過創建新索引的方法間接改變索引容量,但它們在性能上比手工創建索引和復制文檔還是要好一些。有關這三個接口的詳細介紹,請參考本書第3章3.3節。
2.4.4 副本
分片在解決了Elasticsearch文檔存儲容量問題的同時,也提升了文檔處理的性能和吞吐量,但并不能解決容災容錯等高可用性問題。也就是說當集群中存儲分片的節點發生故障,分片技術并不能保證文檔存儲、檢索等服務依然可用,更不能保證分片中的數據不丟失。為了解決這個問題,Elasticsearch在存儲上又引入了另一項稱為副本(Replica)的技術。
副本是主分片的復制品,它與主分片的數據完全一致,能夠在主分片故障時迅速恢復數據。所以主分片與副本分片永遠不會在同一節點上,因為這樣對于數據恢復沒有任何意義。在默認情況下,Elasticsearch為每個索引都設置了1個副本分片,這意味著集群中應該至少有兩個節點。如果集群中只有一個節點,副本分片就永遠不會被創建,這時Elasticsearch就會將集群健康狀態設置為黃色。索引的副本分片數量可以通過number_of_replicas參數設置,例如:

示例2-18 副本分片
在創建了示例2-18中的索引后,可使用“GET _cat/shards”命令查看集群中的分片情況。test索引的主分片為10個,每個主分片有2個副本分片,所以總共是30個分片。除了使用number_of_replicas設置固定的副本分片以外,還可以根據節點數量使用auto_expend_replicas參數設置動態擴展副本分片。這個參數的格式為“<from>-<to>”,如“1-10”代表副本分片數量是1~10個,而“0-all”中all代表所有節點數量。與主分片不同的,副本分片的數量在索引創建之后可以隨時動態更改,具體請參考第3章3.1.2節。
- Dynamics 365 for Finance and Operations Development Cookbook(Fourth Edition)
- Arduino開發實戰指南:LabVIEW卷
- Django:Web Development with Python
- Learning Laravel 4 Application Development
- Julia Cookbook
- HTML5入門經典
- Rust Essentials(Second Edition)
- 西門子S7-200 SMART PLC編程從入門到實踐
- 深度學習入門:基于Python的理論與實現
- SAP Web Dynpro for ABAP開發技術詳解:基礎應用
- Java從入門到精通(視頻實戰版)
- 少兒編程輕松學(全2冊)
- Web開發新體驗
- 精益軟件開發管理之道
- 輕松學Scratch 3.0 少兒編程(全彩)