1、es的內存千萬不能低於8G
2、機器盡量內存不能大於64G,生產上面盡量elk設置內存大小為64G
4 cpu核心數目要求沒有那樣高,8核或者16核都可以
這里要介紹下磁盤陣列
Raid0
之前有部電影是300G,之前是將這300G直接寫入到一個600G的磁盤ssd上面
現在有3個200G的ssd磁盤構成了一個磁盤陣列,radio0,就是將300G的電影分成三部分同時寫入到三個磁盤上面,這樣速度是相對的快,但是如果一旦一個磁盤壞了整個數據就丟失了
磁盤
對於es的生產環境來說,磁盤是非常重要的,尤其是對那些大量寫入的es集群,比如互聯網公司將每天的實時日志數據以高並發的速度寫入es集群。在服務器上,磁盤是最慢的那個資源,所以對於大量寫入的es集群來說,會很容易因為磁盤的讀寫性能造成整個集群的性能瓶頸。
如果我們能夠使用SSD固態硬盤,而不是機械硬盤,那么當然是最好的,SSD的性能比機械硬盤可以高很多倍,可以讓es的讀寫性能都高很多倍。
所以,如果公司出的起錢大量使用固態硬盤,那么當然是最好的。
如果我們在用SSD硬盤的化,那么需要檢查我們的I/O scheduler,需要正確的配置IO scheduler。當我們將數據寫入磁盤時,IO scheduler會決定什么時候數據才會真正的寫入磁盤,而不是停留在os cache內存緩沖中。大多數機器上,默認的IO scheduler是cfq,也就是completely fair queuing。
這個scheduler會給每個進程都分配一些時間分片,time slice,然后會優化每個進程的數據如何寫入磁盤中,優化的思路主要 是根據磁盤的物理布局來決定如何將數據寫入磁盤,進而提升寫入磁盤的性能。這是針對機械硬盤做出的優化,因為機械硬盤是一種旋轉存儲介質,是通過機械旋轉磁盤+磁頭進行磁盤讀寫的機制。
但是scheduler的這種默認的執行機制,對於SSD來說是不太高效的,因為SSD跟機械硬盤是不一樣的,SSD不涉及到機械磁盤旋轉和磁頭讀取這種傳統的讀寫機制。對於SSD來說,應該用deadline/noop scheduler。deadline scheduler會基於寫操作被pending了多長時間來進行寫磁盤優化,而noop scheduler就是一個簡單的FIFO隊列先進先出的機制。
調整io scheduler可以帶來很大的性能提升,甚至可以達到數百倍。
如果我們沒有辦法使用SSD,只能使用機械硬盤,那么至少得盡量正確讀寫速度最快的磁盤,比如高性能的服務器磁盤。
此外,使用RAID 0也是一種提升磁盤讀寫速度的高效的方式,無論是對於機械硬盤,還是SSD,都一樣。
RAID 0也被稱之為條帶式存儲機制,striping,在RAID各種級別中性能是最高的。RAID 0的基本原理,是把連續的數據分散存儲到多個磁盤上進行讀寫,也就是對數據進行條帶式存儲。這樣系統的磁盤讀寫請求就可以被分散到多個磁盤上並行執行。但是沒有必要使用鏡像或者RAID的其他模式,因為我們不需要通過RAID來實現數據高可用存儲,es的replica副本機制本身已經實現了數據高可用存儲。
最后,我們要避免跟網絡相關的存儲模式,network-attached storage,NAS,比如基於網絡的分布式存儲模式。
雖然很多供應商都說他們的NAS解決方案性能非常高,而且比本地存儲的可靠性更高。但是實際上用起來會有很多性能和可靠性上的風險,一般因為網絡傳輸會造成較高的延時,同時還有單點故障的風險。
結論:使用ssd磁盤,磁盤陣列使用raid0,雖然raido沒有數據的備份,但是es本身分區的備份功能已經能夠保證數據的有效性了
網絡
對於es這種分布式系統來說,快速而且可靠的網絡是非常的重要的。
因為高速網絡通信可以讓es的節點間通信達到低延時的效果,高帶寬可以讓shard的移動和恢復,以及分配等操作更加的快速。
現代的數據中心的網絡對於大多數的集群來說,性能都足夠高了。比如千兆網卡,這都是可以的。
但是要避免一個集群橫跨多個數據中心,比如異地多機房部署一個集群,因為那樣的話跨機房,跨地域的傳輸會導致網絡通信和數據傳輸性能較差。es集群是一種p2p模式的分布式系統架構,不是master-slave主從分布式系統。在es集群中,所有的node都是相等的,任意兩個node間的互相通信都是很頻繁和正常的。因此如果部署在異地多機房,那么可能會導致node間頻繁跨地域進行通信,通信延時會非常高,甚至造成集群運行頻繁不正常。
就跟NAS存儲模式一樣,很多供應商都說跨地域的多數據中心是非常可靠的,而且低延時的。一般來說,可能的確是這樣,但是一旦發生了網絡故障,那么集群就完了。通常來說,跨地域多機房部署一個es集群帶來的效益,遠遠低於維護這樣的集群所帶來的額外成本。
結論:網絡帶寬至少在百M網絡以上,一定不能在異地多機房部署一個es集群,因為es集群之后的通信非常頻繁
自建集群 vs 雲部署
現在一般很容易就可以拿到高性能的機器來部署集群:很多高性能的機器可以有上百G的內存資源,還有幾十個cpu core。但是同時我們也可以再雲供應商上,比如阿里雲,租用大量的小資源的虛擬機。那么對於自己購買昂貴高性能服務器自建集群,以及租用雲機器來部署,該選擇哪種方案呢?
你是自己購買5台,比如說,8核64G的物理機,搭建es集群
或者是,比如說,上阿里雲,或者其他的雲服務,購買了2核4G,16台,虛擬機,搭建es集群
你上阿里雲,也可以買到大資源量的虛擬機,4/8/16核64G
一般來說,對於es集群而言,是建議擁有少數機器,但是每個機器的資源都非常多,盡量避免擁有大量的少資源的虛擬機。因為對於運維和管理來說,管理5個物理機組成的es集群,遠遠比管理100個虛擬機組成的es集群要簡單的多。
同時即使是自建集群,也要盡量避免那種超大資源量的超級服務器,因為那樣可能造成資源無法完全利用,然后在一個物理機上部署多個es節點,這會導致我們的集群管理更加的復雜。
結論:盡量申請大的資源充足的物理機器,不要選擇多個資源小的虛擬機,因為管理5個 8cpu 64G內存的物理機,比管理 20個8內存的虛擬機方便的多
第三個jvm規划:
JVM
對於最新的es版本,一般多建議用最新的jvm版本,除非es明確說明要用哪個jdk版本。es和lucene都是一種滿足特殊需求的軟件,lucene的單元測試和集成測試中,經常會發現jvm自身的一些bug。這些bug涵蓋的范圍很廣,因此盡量用最新的jvm版本,bug會少一些。
es 5.x版本以上,建議用jdk 8,而不是jdk 7,同時jdk 6已經不再被支持了。
如果我們用java編寫es應用程序,而且在使用transport client或者node client,要確保運行我們的應用程序的jvm版本跟es服務器運行的jvm版本是一樣的。
在es中,有些java的本地序列化機制都被使用了,比如ip地址,異常信息,等等。而jvm可能在不同的minor版本之間修改序列化格式,所以如果client和server的jvm版本不一致,可能有序列化的問題。
同時官方推薦,絕對不要隨便調整jvm的設置。雖然jvm有幾百個配置選項,而且我們可以手動調優jvm的幾乎方方面面。同時遇到一個性能場景的時候,每個人都會第一時間想到去調優jvm,但是es官方還是推薦我們不要隨便調節jvm參數。因為es是一個非常復雜的分布式軟件系統,而且es的默認jvm配置都是基於真實業務場景中長期的實踐得到的。隨便調節jvm配置反而有可能導致集群性能變得更加差,以及出現一些未知的問題。反而是很多情況下,將自定義的jvm配置全部刪除,性能是保持的最好的。
1、jdk盡量使用1.8版本
2、es服務器和es java客戶端使用的jdk的版本盡量一致,否則會存在jvm序列化的問題
3、es安裝包里面的jvm參數盡量不要做修改
容量規划:
容量規划
在規划你的es集群的時候,一般要規划你需要多少台服務器,每台服務器要有多少資源,能夠支撐你預計的多大的數據量。但是這個東西其實不是一概而論的,要視具體的讀寫場景,包括你執行多么復雜的操作,讀寫QPS來決定的。不過一般而言,實際經驗,對於很多的中小型公司,都是建議es集群承載的數據量在10億規模以內。用最合理的技術做最合理的事情。
這里可以給出幾個在國內es非常適合的幾個場景,es是做搜索的,當然可以做某個系統的搜索引擎。比如網站或者app的搜索引擎,或者是某些軟件系統的搜索引擎,此外es還可以用來做數據分析。那么針對這幾個不同的場景,都可以給出具體建議。比如做網站或者app的搜索引擎,一般數據量會相對來說大一些,但是通常而言,一個網站或者app的內容都是有限的,不會無限膨脹,通常數據量從百萬級到億級不等,因此用於搜索的數據都放在es中是合理的。
然后一些軟件系統或者特殊項目的搜索引擎,根據項目情況不同,數據量也是從百萬量級到幾十億,甚至幾百億,或者每日增量幾億,都有可能,那么此時就要根據具體的業務場景來決定了。如果數據量特別大,日增量都幾億規模,那么其實建議不要將每天全量的數據都寫入es中,es也不適合這種無限規模膨脹的場景。es是很耗費內存的,無限膨脹的數據量,會導致我們無法提供足夠的資源來支撐這么大的數據量。可以考慮是不是就將部分熱數據,比如最近幾天的數據,放到es中做高頻高性能搜索,然后將大量的很少訪問的冷數據放大數據系統做離線批量處理,比如hadoop系統里面。
比如說,你預計一下,你的數據量有多大,需要多少台機器,每台機器要多少資源,來支撐,可以達到多大的性能
數據量 -> 性能,10億 -> 要求1s內返回
es達到ms級的化,你必須要有足夠的os cache去緩存幾乎大部分的索引數據
10億,每條數據是多大,比如多少個字節,1k -> 假設數據大小為100G
如果有5台,64G,8核,那么總內存就是300G左右 -> 100G的總數據量,300G的內存,一般要分給es jvm heap,150G (每台32G)-> 那么100G的數據總量,100G落地到磁盤文件加入很多es自己的信息,假設100G -> 200G
200G落地磁盤的數據,物理內存剩余的只有150G,可能還有一些操作系統,還有其他的損耗100G
200G落地磁盤的數據,100G物理內存可以用來做os cache,50%的概率是基於os cache做磁盤索引文件的讀寫,幾秒,很正常啦。。。
根據我們的實踐經驗而言,一般來說,除非是你的機器的內存資源,完全可以容納所有的落地的磁盤文件的os cache,ms,否則的話,如果不是的話,會大量走磁盤,查詢秒級別很正常
同時如果數據量在10億以內的規模,那么一般而言,如果提供5台以上的機器,每台機器的配置到8核64G的配置,一般而言都能hold住。當然,這個也看具體的使用場景,如果你讀寫特別頻繁,或者查詢特別復雜,那么可能還需要更多的機器資源。如果你要承載更大的數據量,那么就相應的提供更多的機器和資源。
要提升你的es的性能,最重要的,還是說規划合理的數據量,物理內存資源大小,os cache
es優化的參數:
1. master 的設置還是選擇三個節點吧,每個節點設置的時候把 ingest 設置為 false;
2. 寫入的時候,索引的副本數可以設置為 0,刷新時間設置為 60s 或者更大時間;
3. 調整 translog 的設置:
index.translog.durability: async
index.translog.sync_interval: 600s
index.translog.flush_threshold:50000
index.translog.flush_threshold_size: 1024mb
4. 對不參與搜索的字段關閉分析器,對不參與聚合、排序的字段設置關閉 doc_values;
5. 調整 logstash 的 bulk 大小,以及消費 kafka 的線程數;
6. 設置索引相關的線程池:
threadpool.index.size: 100
threadpool.index.queue_size: 500
7. 增大索引實時時間設置:index.engine.robin.refresh_interval: 10s
8. 增大內存緩沖區: indices.memory.index_buffer_size: 20%
進階-第92_es生產集群部署之必須根據自己的集群設置的一些重要參數
1、es的默認參數
es的默認參數是非常好的,適合絕大多數的情況,尤其是一些性能相關的配置。因此剛開始部署一個生產環境下的es集群時,幾乎所有的配置參數都可以用默認的設置。
比如mysql或者oracle這種關系型數據庫,也許是需要非常重的調優,但是es是真的不用。如果我們現在面臨着一些es的性能問題,通常建議的解決方案是更好的進行數據結構的布局,或者增加更多的節點和機器資源。在es的性能調優中,真的很少有那種magic knobs,就是某個參數一調節,直接性能提升上百倍。即使有這種參數,es官方也早就將其設置為默認的最佳值了。
但是在生產環境中,還是極少數跟公司和業務相關的配置是需要我們修改的。這些設置都是具體的公司和業務相關聯的,是沒法預先給予最好的默認配置的。
2、集群名稱和節點名稱
默認情況下,es會啟動一個名稱為elasticsearch的集群。通常建議一定要將自己的集群名稱重新進行命名,主要是避免公司網絡環境中,也許某個開發人員的開發機會無意中加入你的集群。比如將你的集群名稱命名為elasticsearch_production。在elasticsearch.yml中,可以設置集群名稱:
cluster.name: cluster-elasticsearch-prod
此外,每個node啟動的時候,es也會分配一個隨機的名稱。這個也不適合在生產環境中,因為這會導致我們沒法記住每台機器。而且每次重啟節點都會隨機分配,就導致node名稱每次重啟都會變化。因此通常我們在生產環境中是需要給每個node都分配一個名稱的。在elasticsearch.yml中配置即可:
node.name: node-elasticsearch-01
3、文件路徑
(1)數據目錄、日志目錄以及插件目錄
默認情況下,es會將plugin,log,還有data ,config,file都放在es的安裝目錄中。這有一個問題,就是在進行es升級的時候,可能會導致這些目錄被覆蓋掉。導致我們丟失之前安裝好的plugin,已有的log,還有已有的數據,以及配置好的配置文件。
所以一般建議在生產環境中,必須將這些重要的文件路徑,都重新設置一下,放在es安裝目錄之外。path.data用於設置數據文件的目錄,path.logs用於設置日志文件的目錄,path.plugins用於設置插件存放的目錄。path.data可以指定多個目錄,用逗號分隔即可。如果多個目錄在不同的磁盤上,那么這就是一個最簡單的RAID 0的方式,將數據在本地進行條帶化存儲了,可以提升整體的磁盤讀寫性能。es會自動將數據在多個磁盤的多個目錄中條帶化存儲數據。
一般建議的目錄地址是:
mkdir -p /var/log/elasticsearch
mkdir -p /var/data/elasticsearch
mkdir -p /var/plugin/elasticsearch
mkdir -p /etc/elasticsearch
cp /usr/local/elasticsearch/config/elasticsearch.yml /etc/elasticsearch/
cp /usr/local/elasticsearch/config/jvm.options /etc/elasticsearch/
cp /usr/local/elasticsearch/config/log4j2.properties /etc/elasticsearch/
[root@localhost /]# cd /etc/elasticsearch/
[root@localhost elasticsearch]# vi elasticsearch.yml
添加如下參數:
path.logs: /var/log/elasticsearch
path.data: /var/data/elasticsearch
path.plugins: /var/plugin/elasticsearch
config:/etc/elasticsearch
在RAID 0的存儲級別下,每個磁盤上回存儲一部分數據,但是如果一個磁盤故障了,那么可能導致這台機器上的部分數據就丟失了。如果我們的es是有replica的,那么在其他機器上還是會有一份副本的。如果data file指定了多個目錄,為了盡量減少數據丟失的風險,es會將某個shard的數據都分配到一個磁盤上去。這就意味着每個shard都僅僅會放在一個磁盤上。es不會將一個shard的數據條帶化存儲到多個磁盤上去,因為如果一個磁盤丟失了,就會導致整個shard數據丟失。
但是這又引入了性能的問題,如果我們給一個機器添加更多的磁盤來提升單個索引的讀寫性能,是沒有效果的。因為這個索引在這個機器上的shard僅僅存在於一個磁盤上。因此data file指定多個目錄,僅僅對於你的一台機器上存儲了多個index的多個shard時,才會有效果的。因為不同index的shard可能就被存儲到不同的磁盤上去了,對多個index的shard讀寫可以走不同磁盤,提升了性能。
雖然multiple data path是一個很有用的功能,但是es畢竟不是一個專門的RAID軟件。如果我們要對RAID存儲策略進行更多的配置,提高存儲的健壯性以及靈活性,還是要用專門的RAID軟件來進行機器的磁盤數據存儲,而不是用multiple data path策略。
綜上所述,multiple data path功能在實際的生產環境中,其實是較少使用的。
(2)配置文件目錄
es有兩個配置文件,elasticsearch.yml,用於配置es,還有一個log4j.properties用來配置es日志打印。這些文件都被放在config目錄下,默認就是ES_HOME/config。可以通過下面的命令來重新設置:./bin/elasticsearch -Epath.conf=/path/to/my/config/。
配置文件的格式是yaml格式的,比如下面這種格式:
path:
data: /var/lib/elasticsearch
logs: /var/log/elasticsearch
path.data: /var/lib/elasticsearch
path.logs: /var/log/elasticsearch
4、日志配置
es使用log4j2來記錄日志,log4j2可以通過log4j2.properties文件來進行配置。比如下面的這份配置文件:
appender.rolling.type = RollingFile
appender.rolling.name = rolling
appender.rolling.fileName = ${sys:es.logs.base_path}${sys:file.separator}${sys:es.logs.cluster_name}.log
appender.rolling.layout.type = PatternLayout
appender.rolling.layout.pattern = [%d{ISO8601}][%-5p][%-25c] %.10000m%n
appender.rolling.filePattern = ${sys:es.logs.base_path}${sys:file.separator}${sys:es.logs.cluster_name}-%d{yyyy-MM-dd}.log
appender.rolling.policies.type = Policies
appender.rolling.policies.time.type = TimeBasedTriggeringPolicy
appender.rolling.policies.time.interval = 1
appender.rolling.policies.time.modulate = true
appender.rolling.type = RollingFile,就配置了appender類型是RollingFile
appender.rolling.fileName = ${sys:es.logs.base_path}${sys:file.separator}${sys:es.logs.cluster_name}.log,
就配置了日志路徑是/var/log/elasticsearch/production.log
appender.rolling.filePattern = ${sys:es.logs.base_path}${sys:file.separator}${sys:es.logs.cluster_name}-%d{yyyy-MM-dd}.log
就配置了將日志每天寫一份到/var/log/elasticsearch/production-2019-01-01.log文件中
appender.rolling.policies.time.type = TimeBasedTriggeringPolic
這里配置了用基於時間的roll策略
appender.rolling.policies.time.interval = 1
這個設置了每天一份日志文件
appender.rolling.policies.time.modulate = true
這個設置了根據自然天來划分文件,而不是24小時
還可以配置將日志文件保留一段時間內,同時刪除之前的日志文件
appender.rolling.strategy.type = DefaultRolloverStrategy
appender.rolling.strategy.action.type = Delete
appender.rolling.strategy.action.basepath = ${sys:es.logs.base_path}
appender.rolling.strategy.action.condition.type = IfLastModified
appender.rolling.strategy.action.condition.age = 7D
appender.rolling.strategy.action.PathConditions.type = IfFileName
appender.rolling.strategy.action.PathConditions.glob = ${sys:es.logs.cluster_name}-*
第一行是配置了默認的DefaultRolloverStrategy
第二行是配置了Delete action,在rollover之后,就會刪除文件
第三行是配置了es log的基礎路徑
第四行是配置了rollover發生的條件,是基於IfLastModified
第五行是配置了保留的天數,這里是7天
第六行是配置了刪除匹配7天前的文件
第七行是配置了一個刪除文件的格式,這樣就只是刪除過期日志文件,但是不要刪除慢查詢日志
進階-第93_es生產集群部署之針對生產集群的腦裂問題專門定制的重要參數
兩點一刻 2019-03-23 17:44:12 59 收藏
分類專欄: elasticsearch 文章標簽: elasticsearch
版權
最少master候選節點以及腦裂問題
discovery.zen.minimum_master_nodes參數對於集群的可靠性來說,是非常重要的。這個設置可以預防腦裂問題,也就是一個集群中存在兩個master。
如果因為網絡的故障,導致一個集群被划分成了兩片,每片都有多個node,以及一個master,那么集群中就出現了兩個master了。但是因為master是集群中非常重要的一個角色,主宰了集群狀態的維護,以及shard的分配,因此如果有兩個master的化,可能會導致破壞數據。
那么那個參數的作用,就是告訴es直到有足夠的master候選節點時,才可以選舉出一個master,否則就不要選舉出一個master。這個參數必須被設置為集群中master候選節點的quorum數量,也就是大多數。至於quorum的算法,就是:master候選節點數量 / 2 + 1。
比如我們有10個節點,都能維護數據,也可以是master候選節點,那么quorum就是10 / 2 + 1 = 6。
如果我們有三個master候選節點,還有100個數據節點,那么quorum就是3 / 2 + 1 = 2
如果我們有2個節點,都可以是master候選節點,那么quorum是2 / 2 + 1 = 2。此時就有問題了,因為如果一個node掛掉了,那么剩下一個master候選節點,是無法滿足quorum數量的,也就無法選舉出新的master,集群就徹底掛掉了。此時就只能將這個參數設置為1,但是這就無法阻止腦裂的發生了。
2個節點,discovery.zen.minimum_master_nodes分別設置成2和1會怎么樣
綜上所述,一個生產環境的es集群,至少要有3個節點,同時將這個參數設置為quorum,也就是2。discovery.zen.minimum_master_nodes設置為2,如何避免腦裂呢?
那么這個是參數是如何避免腦裂問題的產生的呢?比如我們有3個節點,quorum是2.現在網絡故障,1個節點在一個網絡區域,另外2個節點在另外一個網絡區域,不同的網絡區域內無法通信。這個時候有兩種情況情況:
(1)如果master是單獨的那個節點,另外2個節點是master候選節點,那么此時那個單獨的master節點因為沒有指定數量的候選master node在自己當前所在的集群內,因此就會取消當前master的角色,嘗試重新選舉,但是無法選舉成功。然后另外一個網絡區域內的node因為無法連接到master,就會發起重新選舉,因為有兩個master候選節點,滿足了quorum,因此可以成功選舉出一個master。此時集群中就會還是只有一個master。
(2)如果master和另外一個node在一個網絡區域內,然后一個node單獨在一個網絡區域內。那么此時那個單獨的node因為連接不上master,會嘗試發起選舉,但是因為master候選節點數量不到quorum,因此無法選舉出master。而另外一個網絡區域內,原先的那個master還會繼續工作。這也可以保證集群內只有一個master節點。
綜上所述,通過在elasticsearch.yml中配置discovery.zen.minimum_master_nodes: 2,就可以避免腦裂問題的產生。
但是因為es集群是可以動態增加和下線節點的,所以可能隨時會改變quorum。所以這個參數也是可以通過api隨時修改的,特別是在節點上線和下線的時候,都需要作出對應的修改。而且一旦修改過后,這個配置就會持久化保存下來。
PUT /_cluster/settings
{
"persistent" : {
"discovery.zen.minimum_master_nodes" : 2
}
}
進階-第94_es生產集群部署之針對集群重啟時的shard恢復耗時過長問題定制的重要參數
shard recovery配置以及集群重啟時的無意義shard重分配問題
在集群重啟的時候,有一些配置會影響shard恢復的過程。首先,我們需要理解默認配置下,shard恢復過程會發生什么事情。如果我們有10個node,每個node都有一個shard,可能是primary shard或者replica shard,你有一個index,有5個primary shard,每個primary shard有一個replica shard。如果我們將整個集群關閉了進行一些維護性的操作,比如給機器安裝新的磁盤之類的事情。當我們重啟集群的時候,肯定節點是一個接一個的啟動的,可能會出現5個節點先啟動了,然后剩下5個節點還沒啟動。
也許是因為剩下的5個節點沒來得及啟動,或者是因為一些原因耽擱了,總之不管是什么原因,就是現在只有5個節點是在線的。這5個節點會通過gossip協議互相通信,選舉出一個master,然后組成一個集群。他們會發現數據沒有被均勻的分布,因為有5個節點沒有啟動,那么那5個節點上的shard就是不可用的,集群中就少了一半的shard。此時在線的5個node就會將部分replica shard提升為primary shard,同時為每個primary shard復制足夠的replica shard。
最后,可能剩下的5個節點加入了集群。但是這些節點發現本來是他們持有的shard已經被重新復制並且放在之前的5個node速度回當了,此時他們就會刪除自己本地的數據。然后集群又會開始進行shard的rebalance操作,將最早啟動的5個node上的shard均勻分布到后來啟動的5個node上去。
在這個過程中,這些shard重新復制,移動,刪除,再次移動的過程,會大量的耗費網絡和磁盤資源。對於數據量龐大的集群來說,可能導致每次集群重啟時,都有TB級別的數據無端移動,可能導致集群啟動會耗費很長時間。但是如果所有的節點都可以等待整個集群中的所有節點都完全上線之后,所有的數據都有了以后,再決定是否要復制和移動shard,情況就會好很多。
所以現在問題我們已經知道了,那么我們就可以配置一些設置來解決這個問題。首先我們需要設置一個參數,gateway.recover_after_nodes: 8。這個參數可以讓es直到有足夠的node都上線之后,再開始shard recovery的過程。所以這個參數是跟具體的集群相關的,要根據我們的集群中節點的數量來決定。此外,還應該設置一個集群中至少要有多少個node,等待那些node的時間:gateway.expected_nodes: 10,gateway.recover_after_time: 5m。經過上面的配置之后,es集群的行為會變成下面這樣,等待至少8個節點在線,然后等待最多5分鍾,或者10個節點都在線,開始shard recovery的過程。這樣就可以避免少數node啟動時,就立即開始shard recovery,消耗大量的網絡和磁盤資源,甚至可以將shard recovery過程從數小時縮短為數分鍾。
進階-第95_es生產集群部署之絕對不能隨意調節jvm和thread pool的原因
es中有很多的配置都讓大家忍不住去調優,因為也許大家都太過於迷戀性能優化了,都認為優化一些配置可以大幅度提升性能,就感覺性能調優像個魔法一樣,是個萬能的東西。但是其實99.99%的情況下,對於es來說,大部分的參數都保留為默認的就可以了。因為這些參數經常被濫用和錯誤的調節,繼而導致嚴重的穩定性問題以及性能的急劇下降。
1、jvm gc
jvm使用垃圾回收器來釋放掉不用的內存,千萬不要去調節默認的垃圾回收行為。es默認用的垃圾回收器是CMS。CMS回收器是並發式的回收器,能夠跟應用程序工作線程並發工作,最大程度減少垃圾回收時的服務停頓時間。但是CMS還是會有兩個停頓階段,同時在回收特別大的heap時也會有一些問題。盡管有一些缺點,但是CMS對於要求低延時請求響應的軟件來說,還是最佳的垃圾回收器,因此官方的推薦就是使用CMS垃圾回收器。
有一種最新的垃圾回收器叫做G1。G1回收器可以比CMS提供更少的回收停頓時間,而且能夠這對大heap有更好的回收表現。它會將heap划分為多個region,然后自動預測哪個region會有最多可以回收的空間。通過回收那些region,就可以最小化停頓時長,而且可以針對大heap進行回收。
聽起來還挺不錯的,但是不幸的是,G1還是比較年輕的一種垃圾回收器,而且經常會發現一些新的bug,這些bug可能會導致jvm掛掉。lucene的測試套件就檢查出來了G1的一些bug。因此es官方不推薦現在使用G1垃圾回收器,也許在不久的未來,等G1更加穩定的時候,可以使用G1。
現在到了額2020年,其實推薦可以使用G1垃圾回收器了
2、threadpool
每個人都很喜歡去調優線程池,而且大部分人都特別喜歡增加線程池的線程數量,無論是大量的寫入,還是大量的搜索,或者是感覺服務器的cpu idle空閑率太高,都會增加更多的線程。在es中,默認的threadpool設置是非常合理的,對於所有的threadpool來說,除了搜索的線程池,都是線程數量設置的跟cpu core一樣多的。如果我們有8個cpu core,那么就可以並行運行8個線程。那么對於大部分的線程池來說,分配8個線程就是最合理的數量。
不過搜索會有一個更加大的threadpool,一般被配置為:cpu core * 3 / 2 + 1。
也許我們會覺得有些線程可能會因為磁盤IO等操作block住,所以我們需要更多的線程。但是在es中這並不是一個問題,大多數的磁盤IO操作都是由lucene的線程管理的,而不是由es管理的,因此es的線程不需要關心這個問題。此外,threadpool還會通過在彼此之間傳遞任務來協作執行,我們不需要擔心某一個網絡線程會因為等待一次磁盤寫操作,而導致自己被block住,無法處理網絡請求。網絡線程可以將那個磁盤寫操作交給其他線程池去執行,然后自己接着回來處理網絡請求。
其實我們的進程的計算能力是有限的,分配更多的線程只會強迫cpu在多個線程上下文之間頻繁來回切換。一個cpu core在同一時間只能運行一條線程,所以如果cpu要切換到另外一個線程去執行,需要將當前的state保存起來,然后加載其他的線程進來執行。如果線程上下文切換發生在一個cpu core內,那么還好一些,但是如果在多個cpu core之間發生線程上下文切換,那么還需要走一個cpu core內部的通信。這種線程上下文切換會消耗掉很多的cpu資源,對於現在的cpu來說,每次線程上下文切換,都會導致30微秒的時間開銷,所以寧願將這些時間花費在任務的處理上。
很多人會將threadpool大小設置為一些很愚蠢的數值,在一個8核的機器上,可能運行了超過60,100,甚至1000個線程。這么多的線程會導致cpu資源利用率很低。所以下次如果我們要調節線程池的話,記住,千萬別這么干。如果一定要調節線程數量,也得記住要根據你的cpu core數量來調節,比如設置為cpu core的兩倍,如果設置的再多,那么就是一種浪費了。
進階-第96_es生產集群部署之jvm和服務器內存分配的最佳實踐以及原理分析
除了之前講解的一些配置,根據你的集群環境特殊的配置,我們這一講來講解最重要的內存的分配,提出一些問題,生產環境部署es,不可避免要回答一個問題,比如我的機器上有64G的內存,或者32G的內存,那么一般來說我應該分配多少個G的內存給es的jvm heap
1、jvm heap分配
es默認會給jvm heap分配2個G的大小,對於幾乎所有的生產環境來說,這個內存都太小了。如果用這個默認的heap size,那么生產環境的集群肯定表現不會太好。
有兩個方式來調節es中的jvm heap size。最簡單的就是設置環境變量,ES_HEAP_SIZE。當es進程啟動的時候,會讀取這個環境變量的值,然后設置為jvm的heap size。舉例來說,可以這樣來設置:export ES_HEAP_SIZE=10g。此外,還可以在啟動es進程的時候,傳遞一個jvm的option,比如:ES_JAVA_OPTS="-Xms10g -Xmx10g" ./bin/elasticsearch,但是要注意-Xms和-Xmx最小和最大堆內存一定設置的一樣,避免運行過程中的jvm heap resize,那會是一個非常耗時的過程。
在老版本的es中,比如es 2.x里面,一般推薦用ES_HEAP_SIZE環境變量的方式來設置jvm heap size。
在新版本的es中,比如es 5.x里面,一般推薦在jvm.options文件里面去設置jvm相關的參數。
2、將機器上少於一半的內存分配給es
一個常見的問題就是將es進程的jvm heap size設置的過於大了。比如我們有一台64G的機器,可能我們甚至想要給es jvm size設置64G內存。但是這是錯誤的。大家可能會覺得說,直接將機器上的可用的內存都分配給es jvm heap,性能是絕對高的,因為大量的數據都可以緩存在內存里面。
雖然heap對於es來說是非常重要的,jvm heap被es用來存放很多內存中的數據結構來提供更快的操作性能。但是還有另外一個內存的用戶,那就是lucene。lucene的設計就是要使用底層的os filesystem cache來緩存數據結構。lucene的segment是保存在單獨的文件中的。因為這些segment是不可變的,所以這些文件實際上也從來不會改變。這樣的話,就可以更好的緩存這些文件,底層的os cache會將hot segment駐留在內存中以供更快的訪問。這些segment包括了倒排索引(為了全文檢索)以及正排索引(為了聚合操作)。lucene的性能是嚴重依賴於底層的os的,但是如果我們給了過多的內存到es的jvm heap,那么就沒有足夠的內存留給lucene。這會極大的影響性能。
這里想告訴大家的是,就是說,es的性能很大的一塊,其實是由有多少內存留給操作系統的os cache,供lucene去緩存索引文件,來決定的。所以說lucene的os cache有多少是非常重要的。
一般建議的是,將50%的內存分配給es jvm heap,然后留50%的內存給os cache。留給os cache的內存是不會不使用的,lucene會將剩下的內存全部用光,用來cache segment file。如果我們沒有對任何分詞的text field進行聚合操作,那么我們就不需要使用fielddata,我們甚至可以考慮給os cache更多的內存,因為fielddata是要用jvm heap。如果我們給jvm heap更少的內存,那么實際上es的性能反而會更好,因為更多的內存留給了lucene用os cache提升索引讀寫性能,同時es的jvm heap的gc耗時會更少。
es部署的機器上,內存是如何分配的,如何使用的,如何決定我們的操作系統的,我們該如何給jvm和os cache分配內存
3、不要給jvm分配超過32G內存
還有另外一個原因不要將過多的內存分配給es的jvm heap。如果heap小於32G的化,jvm會用一種技術來壓縮對象的指針,object pointer。在java中,所有的對象都會被分配到heap中,然后被一個pointer給引用。object pointer會指向heap中的對象,引用的是二進制格式的地址。
對於32位的系統來說,jvm最大的heap size就是4G,解釋一下,32位,0和1值,0和1在32位的組合是2^32次方的字節,除以1024就是多少k,再除以1024就是多少mb,再除以1024就是多少gb,最后算下來就是4G。對於64位的系統來說,heap size可以更大,但是64位的object pointer會耗費更多的空間,因為object pointer更大了。比浪費更多內存空間更惡劣的是,過大的object pointer會在cpu,main memory和LLC、L1等多級緩存間移動數據的時候,吃掉更多的帶寬。
所以jvm用了一種技術,叫做compressed oops來解決object pointer耗費過大空間的問題。這個技術的核心思想是,不要讓object pointer引用內存中的二進制地址,而是讓object pointer引用object offset。這就意味着32位的pointer可以引用400萬個對象,而不是400萬字節。這也意味着,使用32位的pointer,最大的heap大小可以到32G。此時只要heap size在32G以內,jvm就會自動啟用32位的object pointer,因為32位的對象指針,足夠引用32G的內存了,就可以用32位的pointer替代64位的pointer。但是32位的pointer比64位的pointer可以耗費更少的內存耗費。
如果你給jvm heap分配的內存小於32G,此時jvm會自動使用32位的object pointer,同時是讓pointer指向對象的offset,32位的object pointer就足以引用32G的內存,同時32位的pointer占用的內存空間很少,對cpu和memory之間移動數據的帶寬開銷也很少。這個過程就叫做compressed oops。
但是一旦我們越過了32G這個界限,就是給jvm heap分配了超過32G的內存,比較坑了。就沒有辦法用32位的pointer+引用object offset(偏移量)的模式了,因為32位的pointer最多引用32G的內存,超過了32G,就沒法用32位pointer。不用32位pointer,就只能用64位pointer,才能引用超過32G的內存空間。此時pointer就會退回到傳統的object pointer引用對象的二進制地址的模式,此時object pinter的大小會急劇增長,更多的cpu到內存的帶寬會被占據,更多的內存被耗費。實際上,不用compressed oops時,你如果給jvm heap分配了一個40~50G的內存的可用空間,實際上被object pointer可能都要占據十幾G的內存空間,可用的空間量,可能跟使用了compressed oops時的32GB內存的可用空間,20多個G,幾乎是一樣的。
因此,即使我們有很多內存,但是還是要分配給heap在32GB以內,否則的話浪費更多的內存,降低cpu性能,而且會讓jvm回收更大的heap。
綜上所述,如果你給jvm heap分配超過32G的內存,實際上是沒有什么意義的,因為用64位的pointer,1/3的內存都給object pointer給占據了,這段內存空間就浪費掉了。還不如分配32G以內,啟用compressed oops,可用空間跟你分配50個G的內存,是一樣的。
所以也正是因為32G的限制,一般來說,都是建議說,如果你的es要處理的數據量上億的話,幾億,或者十億以內的規模的話,建議,就是用64G的內存的機器比較合適,有個5台,差不多也夠了。給jvm heap分配32G,留下32G給os cache。
4、在32G以內的話具體應該設置heap為多大?
這個是根據具體情況而定的,不是固定死的,根據不同的jvm和平台而變。一般而言,將jvm heap size設置為31G比較安全一些。主要是要確保說,你設置的這個jvm heap大小,可以讓es啟用compressed oops這種優化機制。此外,可以給jvm option加入-XX:+PrintFlagsFinal,然后可以打印出來UseCompressedOops是否為true。這就可以讓我們找到最佳的內存設置。因為可以不斷調節內存大小,然后觀察是否啟用compressed oops。
舉例來說,如果在mac os上啟動一個java 1.7,同時將heap size設置為32600mb,那么compressed oops是會開啟的;但是如果設置為32766m,compressed oops就不會開啟。相反的是,使用jdk 1.8的化,分配32766m,compressed oops是會開啟的,設置為32767m,就不會開啟。所以說,這個東西不是固定的。根據不同的操作系統以及jvm版本而定。
在es啟動日志中,我們可以查看compressed oops是否開啟,比如下面的字樣:[2015-12-16 13:53:33,417][INFO ][env] [Illyana Rasputin] heap size [989.8mb], compressed ordinary object pointers [true]。
5、對於有1TB內存的超大內存機器該如何分配?
如果我們的機器是一台超級服務器,內存資源甚至達到了1TB,或者512G,128G,該怎么辦?首先es官方是建議避免用這種超級服務器來部署es集群的,但是如果我們只有這種機器可以用的話,我們要考慮以下幾點:
(1)我們是否在做大量的全文檢索?考慮一下分配4~32G的內存給es進程,同時給lucene留下其余所有的內存用來做os filesystem cache。所有的剩余的內存都會用來cache segment file,而且可以提供非常高性能的搜索,幾乎所有的數據都是可以在內存中緩存的,es集群的性能會非常高
(2)是否在做大量的排序或者聚合操作?聚合操作是不是針對數字、日期或者未分詞的string?如果是的化,那么還是給es 4~32G的內存即可,其他的留給es filesystem cache,可以將聚合好用的正排索引,doc values放在os cache中
(3)如果在針對分詞的string做大量的排序或聚合操作?如果是的化,那么就需要使用fielddata,這就得給jvm heap分配更大的內存空間。此時不建議運行一個節點在機器上,而是運行多個節點在一台機器上,那么如果我們的服務器有128G的內存,可以運行兩個es節點,然后每個節點分配32G的內存,剩下64G留給os cache。如果在一台機器上運行多個es node,建議設置:cluster.routing.allocation.same_shard.host: true。這會避免在同一台物理機上分配一個primary shard和它的replica shard。
cluster.routing.allocation.same_shard.host:默認值是false,如果設置為true,那么就不允許將一個primary shard和replica shard分配到同一個物理機上,也許這個物理機上啟動了多個es實例。
有可能你有一台超級服務器,32核CPU+128G內存,這個時候的話呢,可能你在這台機器上啟動兩個es進程,但是默認情況下,有可能一個shard的primary shard被分配到了這台物理機上的node1,同時這個primary shard的replica shard被分配到了這台物理機上的node2,此時,primary shard和replica shard就在同一台物理機上了。
可用性是比較低的,因為如果這台物理機掛掉了,比較慘烈了,primary shard和replica shard全部丟失
6、swapping
如果頻繁的將es進程的內存swap到磁盤上,絕對會是一個服務器的性能殺手。想象一下,內存中的操作都是要求快速完成的,如果需要將內存頁的數據從磁盤swap回main memory的化,性能會有多差。如果內存被swap到了磁盤,那么100微秒的操作會瞬間變成10毫秒,那么如果是大量的這種內存操作呢?這會導致性能急劇下降。
因此通常建議徹底關閉機器上的swap,swapoff -a,如果要永久性關閉,需要在/etc/fstab中配置
如果沒法完全關閉swap,那么可以嘗試調低swappiness至,這個值是控制os會如何將內存swap到磁盤的。這會在正常情況下阻止swap,但是在緊急情況下,還是會swap。一般用sysctl來設置,vm.swappiness = 1。如果swappiness也不能設置,那么就需要啟用mlockall,這就可以讓我們的jvm lock住自己的內存不被swap到磁盤上去,在elasticsearch.yml中可以設置:bootstrap.mlockall: true。
白話Elasticsearch71-ES生產集群部署之各個節點以daemon模式運行以及優雅關閉
官方指導
啟動ES https://www.elastic.co/guide/en/elasticsearch/reference/current/starting-elasticsearch.html#starting-elasticsearch
停止ES https://www.elastic.co/guide/en/elasticsearch/reference/current/stopping-elasticsearch.html
啟動 ES
可以從命令行啟動Elasticsearch,如下所示:
./bin/elasticsearch
- 1
默認情況下,Elasticsearch在前台運行,將其日志打印到標准輸出(stdout),可以通過按停止Ctrl-C。
后台運行
在生產環境中,會使用daemon進程的方式來啟動es,而不是直接采用前台進程的方式來啟動es,具體命令如下
./bin/elasticsearch -d -p pid
這樣es會在后端運行,並且會在es的home目錄下面生產一個pid的文件,pid文件中記錄了當前es的進程id
上面命令中的-d option用來指定es以daemon進程方式啟動,並且-p option指定將進程id記錄在指定文件中.
es啟動后,日志信息可以在ES_HOME/logs目錄中查看
此外,啟動es進程的時候,還可以直接覆蓋一些配置,使用-E即可
優雅的關閉 ES
停止ES https://www.elastic.co/guide/en/elasticsearch/reference/current/stopping-elasticsearch.html
優雅的關閉es,可以確保es關閉的很干凈,並且優雅關閉資源。舉例來說,如果node在一個合理的順序下關閉了,首先會將自己從cluster中優雅移除,fsync translog日志到磁盤中去,然后執行其他相關的cleanup活動。
如果我們將es用service的方式來運行,那么可以通過server管理功能來停止es。
如果我們是直接啟動es的,可以control-C停止es,或者是發送SEGTERM信號給es進程
jps | grep Elasticsearch
kill -SIGTERM 15516
- 1
- 2
- 3
優雅的關閉 ES停止ES https://www.elastic.co/guide/en/elasticsearch/reference/current/stopping-elasticsearch.html
在這里插入圖片描述
在這里插入圖片描述
優雅的關閉es,可以確保es關閉的很干凈,並且優雅關閉資源。舉例來說,如果node在一個合理的順序下關閉了,首先會將自己從cluster中優雅移除,fsync translog日志到磁盤中去,然后執行其他相關的cleanup活動。
如果我們將es用service的方式來運行,那么可以通過server管理功能來停止es。
如果我們是直接啟動es的,可以control-C停止es,或者是發送SEGTERM信號給es進程
jps | grep Elasticsearch
kill -SIGTERM 15516123在這里插入圖片描述
2、rolling upgrade(節點依次重啟策略)
rolling upgrade會讓es集群每次升級一個node,對於終端用戶來說,是沒有停機時間的。在一個es集群中運行多個版本,長時間的話是不行的,因為shard是沒法從一較新版本的node上replicate到較舊版本的node上的。
先部署一個es 5.3.2版本,將配置文件放在外部目錄,同時將data和log目錄都放在外部,然后插入一些數據,然后再開始下面的升級過程
adduser elasticsearch
passwd elasticsearch
chown -R elasticsearch /usr/local/elasticsearch
chown -R elasticsearch /var/log/elasticsearch
chown -R elasticsearch /var/data/elasticsearch
chown -R elasticsearch /etc/elasticsearch
su elasticsearch
elasticsearch -d -Epath.conf=/etc/elasticsearch
curl -XPUT 'http://localhost:9200/forum/article/1?pretty' -d '
{
"title": "first article",
"content": "this is my first article"
}'
(1)禁止shard allocation
停止一個node之后,這個node上的shard全都不可用了,此時shard allocation機制會等待一分鍾,然后開始shard recovery過程,也就是將丟失掉的primary shard的replica shard提升為primary shard,同時創建更多的replica shard滿足副本數量,但是這個過程會導致大量的IO操作,是沒有必要的。因此在開始升級一個node,以及關閉這個node之前,先禁止shard allocation機制:
curl -XPUT 'http://localhost:9200/_cluster/settings?pretty' -d '
{
"persistent": {
"cluster.routing.allocation.enable": "none"
}
}'
(2)停止非核心業務的寫入操作,以及執行一次flush操作
可以在升級期間繼續寫入數據,但是如果在升級期間一直寫入數據的話,可能會導致重啟節點的時候,shard recovery的時間變長,因為很多數據都是translog里面,沒有flush到磁盤上去。如果我們暫時停止數據的寫入,而且還進行一次flush操作,把數據都刷入磁盤中,這樣在node重啟的時候,幾乎沒有什么數據要從translog中恢復的,重啟速度會很快,因為shard recovery過程會很快。用下面這行命令執行flush:POST _flush/synced。但是flush操作是盡量執行的,有可能會執行失敗,如果有大量的index寫入操作的話。所以可能需要多次執行flush,直到它執行成功。
curl -XPOST 'http://localhost:9200/_flush/synced?pretty'
(3)停止一個node然后升級這個node
在完成node的shard allocation禁用以及flush操作之后,就可以停止這個node。
如果你安裝了一些插件,或者是自己設置過jvm.options文件的話,需要先將/usr/local/elasticsearch/plugins拷貝出來,作為一個備份,jvm.options也拷貝出來
將老的es安裝目錄刪除,然后將最新版本的es解壓縮,而且要確保我們絕對不會覆蓋config、data、log等目錄,否則就會導致我們丟失數據、日志、配置文件還有安裝好的插件。
kill -SIGTERM 15516
(4)升級plugin
可以將備份的plugins目錄拷貝回最新解壓開來的es安裝目錄中,包括你的jvm.options
自己去官網,找到各個plugin的git地址,git地址上,都有每個plugin version跟es version之間的對應關系。要檢查一下所有的plugin是否跟要升級的es版本是兼容的,如果不兼容,那么需要先用elasticsearch-plugin腳本重新安裝最新版本的plugin。
(5)啟動es node
接着要注意在啟動es的時候,在命令行里用-Epath.conf= option來指向一個外部已經配置好的config目錄。這樣的話最新版的es就會復用之前的所有配置了,而且也會根據配置文件中的地址,找到對應的log、data等目錄。然后再日志中查看這個node是否正確加入了cluster,也可以通過下面的命令來檢查:GET _cat/nodes。
elasticsearch -d -Epath.conf=/etc/elasticsearch
(6)在node上重新啟用shard allocation
一旦node加入了cluster之后,就可以重新啟用shard allocation
curl -XPUT 'http://localhost:9200/_cluster/settings?pretty' -d '
{
"persistent": {
"cluster.routing.allocation.enable": "all"
}
}'
(7)等待node完成shard recover過程
我們要等待cluster完成shard allocation過程,可以通過下面的命令查看進度:GET _cat/health。一定要等待cluster的status從yellow變成green才可以。green就意味着所有的primary shard和replica shard都可以用了。
curl -XGET 'http://localhost:9200/_cat/health?pretty'
在rolling upgrade期間,primary shard如果分配給了一個更新版本的node,是一定不會將其replica復制給較舊的版本的node的,因為較新的版本的數據格式跟較舊的版本是不兼容的。但是如果不允許將replica shard復制給其他node的話,比如說此時集群中只有一個最新版本的node,那么有些replica shard就會是unassgied狀態,此時cluster status就會保持為yellow。此時,就可以繼續升級其他的node,一旦其他node變成了最新版本,那么就會進行replica shard的復制,然后cluster status會變成green。
如果沒有進行過flush操作的shard是需要一些時間去恢復的,因為要從translog中恢復一些數據出來。可以通過下面的命令來查看恢復的進度:GET _cat/recovery。
(8)重復上面的步驟,直到將所有的node都升級完成
22.Elasticsearch生產集群中的索引管理(一)
1、創建索引
(1)創建索引的語法
用settings給這個索引在創建時可以添加一些設置,還有可以初始化一些type的mapping
curl -H "Content-Type:application/json" -XPUT 'http://elasticsearch02:9200/twitter?pretty' -d ' { "settings" : { "index" : { "number_of_shards" : 3, "number_of_replicas" : 2 } }, "mappings" : { "properties" : { "field1" : { "type" : "text" } } } }'
(2)索引創建返回消息的解釋
默認情況下,索引創建命令會在每個primary shard的副本開始進行復制以后,或者是請求超時以后,返回一個響應消息,類似下面這樣的。
{ "acknowledged" : true, "shards_acknowledged" : true, "index" : "twitter" }
acknowledged表明了這個索引有沒有創建成功。
shards_acknowledged表明了每個primary shard有沒有足夠數量的replica開始進行復制了。
有可能這兩個參數會為false,但是索引依然可以創建成功。因為這些參數僅僅是表明在請求超時之前,那兩個行為有沒有成功,也有可能請求超時了,在超時前都沒成功,但是超時后在es server端還是都執行了。
如果acknoledged是false,那么就可能是超時了,此時接受到響應消息的時候,cluster state都還沒變更,沒有加入新創建的index,但是也許之后還是會創建這個index。如果shards_acknowledged是false,那么可能在primary shard進行副本copy之前,就timeout了,但是此時也許index創建成功了,而且cluster state已經加入了新創建的index。
2、刪除索引
curl -XDELETE 'http://elasticsearch02:9200/twitter?pretty'
3、查詢索引設置信息
curl -XGET 'http://elasticsearch02:9200/twitter?pretty'
4、打開/關閉索引
curl -XPOST 'http://elasticsearch02:9200/twitter/_close?pretty' curl -XPOST 'http://elasticsearch02:9200/twitter/_open?pretty'
如果關閉了一個索引之后,那么這個索引是不會帶來任何的性能開銷了,只要保留這個索引的元數據即可,然后對這個索引的讀寫操作都不會成功。一個關閉的索引可以接着再打開,打開以后會進行shard recovery過程。
比如說你在做一些運維操作的時候,現在你要對某一個索引做一些配置,運維操作,修改一些設置,關閉索引,不允許寫入,成功以后再打開索引
5、壓縮索引
shrink命令可以將一個已有的索引壓縮成一個新的索引,同時primary shard會更少。因為以前提到過,primary shard因為涉及到document的hash路由問題,所以是不允許修改的。但是如果要減少index的primary shard,可以用shrink命令來壓縮index。但是壓縮后的shard數量必須可以被原來的shard數量整除。舉例來說,一個有8個primary shard的index可以被壓縮成4個,2個,或者1個primary shard的index。
壓縮索引,是這樣啊,如果你的索引中本來比如是要保留7天的數據,那么給了10個shard,但是現在需求變了,這個索引只要保留3天的數據就可以了,那么數據量變小了,就不需要10個shard了,就可以做shrink操作,5個shard。
shrink命令的工作流程如下:
(1)首先,它會創建一個跟source index的定義一樣的target index,但是唯一的變化就是primary shard變成了指定的數量
(2)接着它會將source index的segment file直接用hard-link的方式連接到target index的segment file,如果操作系統不支持hard-link,那么就會將source index的segment file都拷貝到target index的data dir中,會很耗時。如果用hard-link會很快
(3)最后,會將target index進行shard recovery恢復
如果要shrink index,那么這個index必須先被標記為read only,而且這個index的每個shard的某一個copy,可以是primary或者是replica,都必須被復制到一個節點上去。默認情況下,index的每個shard有可能在不同機器上的,比如說,index有5個shard,shard0和shard1在機器1上,shard2、shard3在機器2上,shard4在機器3上。現在還得把shard0,shard1,shard2,shard3,shard4全部拷貝到一個同一個機器上去,但是可以是shard0的replica shard。而且每個primary shard都必須存在。可以通過下面的命令來完成。其中index.routing.allocation.require._name必須是某個node的名稱,這個都是可以自己設置的。
curl -H "Content-Type:application/json" -XPUT 'http://elasticsearch02:9200/twitter/_settings?pretty' -d ' { "settings": { "index.routing.allocation.require._name": "node-elasticsearch-02", "index.blocks.write": true } }'
注意:"node-elasticsearch-02"這個是當前es節點的名稱,在elasticsearch.yml中配置的名稱
這個命令會花費一點時間將source index每個shard的一個copy都復制到指定的node上去,可以通過GET _cat/recovery?v命令來追蹤這個過程的進度。
等上面的shard copy relocate過程結束之后,就可以shrink一個index,用下面的命令即可:POST my_source_index/_shrink/my_target_index。如果target index被添加進了cluster state之后,這個命令就會立即返回,不是等待shrink過程完成之后才返回的。當然還可以用下面的命令來shrink的時候修改target index的設置,在settings里就可以設置target index的primary shard的數量。
curl -H "Content-Type:application/json" -XPOST 'http://elasticsearch02:9200/twitter/_shrink/twitter_shrinked?pretty' -d ' { "settings": { "index.number_of_replicas": 1, "index.number_of_shards": 1, "index.codec": "best_compression" } }'
當然也是需要監控整個shrink的過程的,用GET _cat/recovery?v即可。
6、rollover index
rollover命令可以將一個alias重置到一個新的索引上去,如果已經存在的index被認為太大或者數據太舊了。這個命令可以接收一個alias名稱,還有一系列的condition。如果索引滿足了condition,那么就會創建一個新的index,同時alias會指向那個新的index。比如下面的命令。舉例來說,有一個logs-0000001索引,給了一個別名是logs_write,接着發起了一個rollover的命令,如果logs_write別名之前指向的那個index,也就是logs-0000001,創建了超過7天,或者里面的document已經超過了1000個了,然后就會創建一個logs-000002的索引,同時logs_write別名會指向新的索引。
這個命令其實是很有用的,特別是針對這種用戶訪問行為日志的數據,或者是一些聯機事務系統的數據的進入,你可以寫一個shell腳本,每天0:00的時候就執行以下rollover命令,此時就判斷,如果說之前的索引已經存在了超過1天了,那么此時就創建一個新的索引出來,同時將別名指向新的索引。自動去滾動創建新的索引,保持每個索引就只有一個小時,一天,七天,三天,一周,一個月。
類似用es來做日志平台,就可能分布式電商平台,可能訂單系統的日志,單獨的一個索引,要求的是保留最近3天的日志就可以了。交易系統的日志,是單獨的一個索引,要求的是保留最近30天的日志。
我們來操作下看下對應的命令
curl -H "Content-Type:application/json" -XPUT 'http://elasticsearch02:9200/logs-000001?pretty' -d ' { "aliases": { "logs_write": {} } }'
在kibana上面執行的命令為:
PUT /logs-000001 { "aliases": { "logs_write": {} } }
創建一個索引logs-000001,給這個索引指定別名為logs_write
接下來向索引中添加數據
curl -H "Content-Type:application/json" -XPUT 'http://elasticsearch02:9200/logs-000001/_doc/1?pretty' -d ' { "userid": 1, "page": 1 }'
curl -H "Content-Type:application/json" -XPUT 'http://elasticsearch02:9200/logs-000001/_doc/2?pretty' -d ' { "userid": 2, "page": 2 }'
curl -H "Content-Type:application/json" -XPUT 'http://elasticsearch02:9200/logs-000001/_doc/3?pretty' -d ' { "userid": 3, "page": 3 }'
PUT /logs-000001/autuor/4 { "userid": 4, "page": 4 }
接下來我們設置rollover的條件,當索引超過一天或者文檔數目超過了3條,我們就自定創建一個新的索引,別名指向這個新的索引
curl -H "Content-Type:application/json" -XPOST 'http://elasticsearch02:9200/logs_write/_rollover?pretty' -d ' { "conditions": { "max_age": "1d", "max_docs": 3 } }'
POST /logs_write/_rollover { "conditions": { "max_age": "1d", "max_docs": 3 } }
這里命令中logs_write是索引的別名,上面命令執行成功之后,返回的命令如下
{ "acknowledged" : true, "shards_acknowledged" : true, "old_index" : "logs-000001", "new_index" : "logs-000002", "rolled_over" : true, "dry_run" : false, "conditions" : { "[max_age: 1d]" : false, "[max_docs: 3]" : true } }
logs_write就指向了新創建的索引logs-000002,不再指向logs-000001
這個過程常見於網站用戶行為日志數據,比如按天來自動切分索引,寫個腳本定時去執行rollover,就會自動不斷創建新的索引,但是別名永遠是一個,對於外部的使用者來說,用的都是最新數據的索引。
默認情況下,如果已經存在的那個索引是用-符號加上一個數字結尾的,比如說logs-000001,那么新索引的名稱就會是自動給那個數字加1,比如logs-000002,自動就是給一個6位的數字,而且會自動補零
但是我們也可以自己指定要的新的索引名稱,比如下面這樣:
POST /my_alias/_rollover/my_new_index_name { "conditions": { "max_age": "7d", "max_docs": 1000 } }
當然,還可以在rollover的時候,給新的index進行新的設置:
POST /logs_write/_rollover { "conditions" : { "max_age": "7d", "max_docs": 1000 }, "settings": { "index.number_of_shards": 2 } }
Elasticsearch生產集群中的索引管理(二)
1、mapping管理
下面這個命令是在創建索引
curl -H "Content-Type:application/json" -XPUT 'http://elasticsearch02:9200/twitter?pretty' -d ' { "mappings": { "properties": { "message": { "type": "text" } } } }'
PUT /book { "settings":{ "number_of_shards":5, "number_of_replicas":1 }, "mappings":{ "novel":{ "properties":{ "name":{ "type":"text", "index":true, "store":false }, "author":{ "type":"keyword" }, "count":{ "type":"long" }, "on-sale":{ "type":"date", "format":"yyyy-MM-dd HH:mm:ss ||yyyy-MM-dd||epoch_millis" }, "descr":{ "type":"text" } } } } }
下面這個命令是給一個已有的索引添加一個field
curl -H "Content-Type:application/json" -XPUT 'http://elasticsearch02:9200/twitter/_mapping?pretty' -d ' { "properties": { "user_name": { "type": "text" } } }'
POST /book/novel/_mapping { "properties": { "user_name": { "type": "text" } } }
查看索引mapping的信息為
curl -H "Content-Type:application/json" -XGET 'http://elasticsearch02:9200/twitter/_mapping?pretty'
2、索引別名管理
curl -H "Content-Type:application/json" -XPOST 'http://elasticsearch02:9200/_aliases?pretty' -d ' { "actions" : [ { "add" : { "index" : "twitter", "alias" : "twitter_prod" } } ] }'
POST /_aliases { "actions" : [ { "add" : { "index" : "book", "alias" : "twitter_prod" } } ] }
curl -H "Content-Type:application/json" -XPOST 'http://elasticsearch02:9200/_aliases?pretty' -d '{ "actions" : [ { "add" : { "index" : "twitter", "alias" : "twitter_prod" } } ]}'
給book這個索引設置別名為twitter_prod
刪除別名
curl -H "Content-Type:application/json" -XPOST 'http://elasticsearch02:9200/_aliases?pretty' -d ' { "actions" : [ { "remove" : { "index" : "twitter", "alias" : "twitter_prod" } } ] }'
POST /_aliases { "actions" : [ { "remove": { "index" : "book", "alias" : "twitter_prod" } } ] }
重命名alias的命令(先刪除再添加)
一個alias綁定多個index
POST /_aliases { "actions" : [ { "add" : { "indices" : ["test1", "test2"], "alias" : "alias1" } } ] }
POST /_aliases { "actions" : [ { "add" : { "indices" : ["test1", "test2"], "alias" : "alias1" } } ] }
將索引中的某部分數據保存到一個別名上面
POST /_aliases { "actions" : [ { "add" : { "index" : "test1", "alias" : "alias2", "filter" : { "term" : { "user" : "kimchy" } } } } ] }
刪除別名
DELETE /logs_20162801/_alias/current_day
查看別名
GET /_alias/2016
索引別名常常和之前講解的那個rollover結合起來,我們為了性能和管理方便,每天的數據都rollover出來一個索引,但是在對數據分析的時候,可能是這樣子的,有一個索引access-log,指向了當日最新的數據,用來計算實時數據的; 有一個索引access-log-7days,指向了7天的7個索引,可以讓我們進行一些周數據的統計和分析。
3、index settings管理
curl -H "Content-Type:application/json" -XPUT 'http://elasticsearch02:9200/twitter/_settings?pretty' -d ' { "index" : { "number_of_replicas" : 1 } }'
查看setting
curl -XGET 'http://elasticsearch02:9200/twitter/_settings?pretty'
經常可能要對index做一些settings的調整,常常和之前的index open和close結合起來
4、index template管理
我們可以定義一些index template,這樣template會自動應用到新創建的索引上去。template中可以包含settings和mappings,還可以包含一個pattern,決定了template會被應用到哪些index上。而且template僅僅在index創建的時候會被應用,修改template,是不會對已有的index產生影響的。
PUT /_template/template_access_log { "template": "access-log-*", "settings":{ "number_of_shards":5, "number_of_replicas":1 }, "mappings":{ "novel":{ "properties":{ "name":{ "type":"text", "index":true, "store":false }, "author":{ "type":"keyword" }, "count":{ "type":"long" }, "on-sale":{ "type":"date", "format":"yyyy-MM-dd HH:mm:ss ||yyyy-MM-dd||epoch_millis" }, "descr":{ "type":"text" } } } } }
上面就是創建一個模板,模板的正則表達式為"template": "access-log-*",,如果索引的名稱是以access-log開頭的就使用上面的這個模塊,template_access_log是模板的名稱
索引的type類型為novel
我們創建一個索引
PUT /access-log-32
上面的索引創建之后,默認就上面上面的模板
我們來查看索引的信息GET /access-log-32/
{ "access-log-32" : { "aliases" : { }, "mappings" : { "novel" : { "properties" : { "author" : { "type" : "keyword" }, "count" : { "type" : "long" }, "descr" : { "type" : "text" }, "name" : { "type" : "text" }, "on-sale" : { "type" : "date", "format" : "yyyy-MM-dd HH:mm:ss ||yyyy-MM-dd||epoch_millis" } } } }, "settings" : { "index" : { "creation_date" : "1602099132085", "number_of_shards" : "5", "number_of_replicas" : "1", "uuid" : "gAqr-dFuSrOPLuvsutdSKw", "version" : { "created" : "6081299" }, "provided_name" : "access-log-32" } } } }
刪除模板
curl -H "Content-Type:application/json" -XDELETE 'http://elasticsearch02:9200/_template/template_access_log?pretty'
DELETE /_template/template_access_log
查看模板的信息
GET /_template/template_access_log
執行命令之后的結果如下
{ "template_access_log" : { "order" : 0, "index_patterns" : [ "access-log-*" ], "settings" : { "index" : { "number_of_shards" : "5", "number_of_replicas" : "1" } }, "mappings" : { "novel" : { "properties" : { "descr" : { "type" : "text" }, "author" : { "type" : "keyword" }, "name" : { "index" : true, "store" : false, "type" : "text" }, "count" : { "type" : "long" }, "on-sale" : { "format" : "yyyy-MM-dd HH:mm:ss ||yyyy-MM-dd||epoch_millis", "type" : "date" } } } }, "aliases" : { } } }
1、indice stat
indice stat對index上發生的不同類型的操作都提供了統計。這個api提供了index level的統計信息,不過大多數統計信息也可以從node level獲取。
curl -H "Content-Type:application/json" -XGET 'http://elasticsearch02:9200/twitter/_stats?pretty'
GET /access-log-32/_stats
整個命令執行的結果如下
{ "_shards" : { "total" : 10, "successful" : 5, "failed" : 0 }, "_all" : { "primaries" : { "docs" : { "count" : 0, "deleted" : 0 }, "store" : { "size_in_bytes" : 1305 }, "indexing" : { "index_total" : 0, "index_time_in_millis" : 0, "index_current" : 0, "index_failed" : 0, "delete_total" : 0, "delete_time_in_millis" : 0, "delete_current" : 0, "noop_update_total" : 0, "is_throttled" : false, "throttle_time_in_millis" : 0 }, "get" : { "total" : 0, "time_in_millis" : 0, "exists_total" : 0, "exists_time_in_millis" : 0, "missing_total" : 0, "missing_time_in_millis" : 0, "current" : 0 }, "search" : { "open_contexts" : 0, "query_total" : 0, "query_time_in_millis" : 0, "query_current" : 0, "fetch_total" : 0, "fetch_time_in_millis" : 0, "fetch_current" : 0, "scroll_total" : 0, "scroll_time_in_millis" : 0, "scroll_current" : 0, "suggest_total" : 0, "suggest_time_in_millis" : 0, "suggest_current" : 0 }, "merges" : { "current" : 0, "current_docs" : 0, "current_size_in_bytes" : 0, "total" : 0, "total_time_in_millis" : 0, "total_docs" : 0, "total_size_in_bytes" : 0, "total_stopped_time_in_millis" : 0, "total_throttled_time_in_millis" : 0, "total_auto_throttle_in_bytes" : 104857600 }, "refresh" : { "total" : 25, "total_time_in_millis" : 0, "listeners" : 0 }, "flush" : { "total" : 5, "periodic" : 0, "total_time_in_millis" : 1 }, "warmer" : { "current" : 0, "total" : 10, "total_time_in_millis" : 0 }, "query_cache" : { "memory_size_in_bytes" : 0, "total_count" : 0, "hit_count" : 0, "miss_count" : 0, "cache_size" : 0, "cache_count" : 0, "evictions" : 0 }, "fielddata" : { "memory_size_in_bytes" : 0, "evictions" : 0 }, "completion" : { "size_in_bytes" : 0 }, "segments" : { "count" : 0, "memory_in_bytes" : 0, "terms_memory_in_bytes" : 0, "stored_fields_memory_in_bytes" : 0, "term_vectors_memory_in_bytes" : 0, "norms_memory_in_bytes" : 0, "points_memory_in_bytes" : 0, "doc_values_memory_in_bytes" : 0, "index_writer_memory_in_bytes" : 0, "version_map_memory_in_bytes" : 0, "fixed_bit_set_memory_in_bytes" : 0, "max_unsafe_auto_id_timestamp" : -1, "file_sizes" : { } }, "translog" : { "operations" : 0, "size_in_bytes" : 550, "uncommitted_operations" : 0, "uncommitted_size_in_bytes" : 275, "earliest_last_modified_age" : 0 }, "request_cache" : { "memory_size_in_bytes" : 0, "evictions" : 0, "hit_count" : 0, "miss_count" : 0 }, "recovery" : { "current_as_source" : 0, "current_as_target" : 0, "throttle_time_in_millis" : 0 } }, "total" : { "docs" : { "count" : 0, "deleted" : 0 }, "store" : { "size_in_bytes" : 1305 }, "indexing" : { "index_total" : 0, "index_time_in_millis" : 0, "index_current" : 0, "index_failed" : 0, "delete_total" : 0, "delete_time_in_millis" : 0, "delete_current" : 0, "noop_update_total" : 0, "is_throttled" : false, "throttle_time_in_millis" : 0 }, "get" : { "total" : 0, "time_in_millis" : 0, "exists_total" : 0, "exists_time_in_millis" : 0, "missing_total" : 0, "missing_time_in_millis" : 0, "current" : 0 }, "search" : { "open_contexts" : 0, "query_total" : 0, "query_time_in_millis" : 0, "query_current" : 0, "fetch_total" : 0, "fetch_time_in_millis" : 0, "fetch_current" : 0, "scroll_total" : 0, "scroll_time_in_millis" : 0, "scroll_current" : 0, "suggest_total" : 0, "suggest_time_in_millis" : 0, "suggest_current" : 0 }, "merges" : { "current" : 0, "current_docs" : 0, "current_size_in_bytes" : 0, "total" : 0, "total_time_in_millis" : 0, "total_docs" : 0, "total_size_in_bytes" : 0, "total_stopped_time_in_millis" : 0, "total_throttled_time_in_millis" : 0, "total_auto_throttle_in_bytes" : 104857600 }, "refresh" : { "total" : 25, "total_time_in_millis" : 0, "listeners" : 0 }, "flush" : { "total" : 5, "periodic" : 0, "total_time_in_millis" : 1 }, "warmer" : { "current" : 0, "total" : 10, "total_time_in_millis" : 0 }, "query_cache" : { "memory_size_in_bytes" : 0, "total_count" : 0, "hit_count" : 0, "miss_count" : 0, "cache_size" : 0, "cache_count" : 0, "evictions" : 0 }, "fielddata" : { "memory_size_in_bytes" : 0, "evictions" : 0 }, "completion" : { "size_in_bytes" : 0 }, "segments" : { "count" : 0, "memory_in_bytes" : 0, "terms_memory_in_bytes" : 0, "stored_fields_memory_in_bytes" : 0, "term_vectors_memory_in_bytes" : 0, "norms_memory_in_bytes" : 0, "points_memory_in_bytes" : 0, "doc_values_memory_in_bytes" : 0, "index_writer_memory_in_bytes" : 0, "version_map_memory_in_bytes" : 0, "fixed_bit_set_memory_in_bytes" : 0, "max_unsafe_auto_id_timestamp" : -1, "file_sizes" : { } }, "translog" : { "operations" : 0, "size_in_bytes" : 550, "uncommitted_operations" : 0, "uncommitted_size_in_bytes" : 275, "earliest_last_modified_age" : 0 }, "request_cache" : { "memory_size_in_bytes" : 0, "evictions" : 0, "hit_count" : 0, "miss_count" : 0 }, "recovery" : { "current_as_source" : 0, "current_as_target" : 0, "throttle_time_in_millis" : 0 } } }, "indices" : { "access-log-32" : { "uuid" : "gAqr-dFuSrOPLuvsutdSKw", "primaries" : { "docs" : { "count" : 0, "deleted" : 0 }, "store" : { "size_in_bytes" : 1305 }, "indexing" : { "index_total" : 0, "index_time_in_millis" : 0, "index_current" : 0, "index_failed" : 0, "delete_total" : 0, "delete_time_in_millis" : 0, "delete_current" : 0, "noop_update_total" : 0, "is_throttled" : false, "throttle_time_in_millis" : 0 }, "get" : { "total" : 0, "time_in_millis" : 0, "exists_total" : 0, "exists_time_in_millis" : 0, "missing_total" : 0, "missing_time_in_millis" : 0, "current" : 0 }, "search" : { "open_contexts" : 0, "query_total" : 0, "query_time_in_millis" : 0, "query_current" : 0, "fetch_total" : 0, "fetch_time_in_millis" : 0, "fetch_current" : 0, "scroll_total" : 0, "scroll_time_in_millis" : 0, "scroll_current" : 0, "suggest_total" : 0, "suggest_time_in_millis" : 0, "suggest_current" : 0 }, "merges" : { "current" : 0, "current_docs" : 0, "current_size_in_bytes" : 0, "total" : 0, "total_time_in_millis" : 0, "total_docs" : 0, "total_size_in_bytes" : 0, "total_stopped_time_in_millis" : 0, "total_throttled_time_in_millis" : 0, "total_auto_throttle_in_bytes" : 104857600 }, "refresh" : { "total" : 25, "total_time_in_millis" : 0, "listeners" : 0 }, "flush" : { "total" : 5, "periodic" : 0, "total_time_in_millis" : 1 }, "warmer" : { "current" : 0, "total" : 10, "total_time_in_millis" : 0 }, "query_cache" : { "memory_size_in_bytes" : 0, "total_count" : 0, "hit_count" : 0, "miss_count" : 0, "cache_size" : 0, "cache_count" : 0, "evictions" : 0 }, "fielddata" : { "memory_size_in_bytes" : 0, "evictions" : 0 }, "completion" : { "size_in_bytes" : 0 }, "segments" : { "count" : 0, "memory_in_bytes" : 0, "terms_memory_in_bytes" : 0, "stored_fields_memory_in_bytes" : 0, "term_vectors_memory_in_bytes" : 0, "norms_memory_in_bytes" : 0, "points_memory_in_bytes" : 0, "doc_values_memory_in_bytes" : 0, "index_writer_memory_in_bytes" : 0, "version_map_memory_in_bytes" : 0, "fixed_bit_set_memory_in_bytes" : 0, "max_unsafe_auto_id_timestamp" : -1, "file_sizes" : { } }, "translog" : { "operations" : 0, "size_in_bytes" : 550, "uncommitted_operations" : 0, "uncommitted_size_in_bytes" : 275, "earliest_last_modified_age" : 0 }, "request_cache" : { "memory_size_in_bytes" : 0, "evictions" : 0, "hit_count" : 0, "miss_count" : 0 }, "recovery" : { "current_as_source" : 0, "current_as_target" : 0, "throttle_time_in_millis" : 0 } }, "total" : { "docs" : { "count" : 0, "deleted" : 0 }, "store" : { "size_in_bytes" : 1305 }, "indexing" : { "index_total" : 0, "index_time_in_millis" : 0, "index_current" : 0, "index_failed" : 0, "delete_total" : 0, "delete_time_in_millis" : 0, "delete_current" : 0, "noop_update_total" : 0, "is_throttled" : false, "throttle_time_in_millis" : 0 }, "get" : { "total" : 0, "time_in_millis" : 0, "exists_total" : 0, "exists_time_in_millis" : 0, "missing_total" : 0, "missing_time_in_millis" : 0, "current" : 0 }, "search" : { "open_contexts" : 0, "query_total" : 0, "query_time_in_millis" : 0, "query_current" : 0, "fetch_total" : 0, "fetch_time_in_millis" : 0, "fetch_current" : 0, "scroll_total" : 0, "scroll_time_in_millis" : 0, "scroll_current" : 0, "suggest_total" : 0, "suggest_time_in_millis" : 0, "suggest_current" : 0 }, "merges" : { "current" : 0, "current_docs" : 0, "current_size_in_bytes" : 0, "total" : 0, "total_time_in_millis" : 0, "total_docs" : 0, "total_size_in_bytes" : 0, "total_stopped_time_in_millis" : 0, "total_throttled_time_in_millis" : 0, "total_auto_throttle_in_bytes" : 104857600 }, "refresh" : { "total" : 25, "total_time_in_millis" : 0, "listeners" : 0 }, "flush" : { "total" : 5, "periodic" : 0, "total_time_in_millis" : 1 }, "warmer" : { "current" : 0, "total" : 10, "total_time_in_millis" : 0 }, "query_cache" : { "memory_size_in_bytes" : 0, "total_count" : 0, "hit_count" : 0, "miss_count" : 0, "cache_size" : 0, "cache_count" : 0, "evictions" : 0 }, "fielddata" : { "memory_size_in_bytes" : 0, "evictions" : 0 }, "completion" : { "size_in_bytes" : 0 }, "segments" : { "count" : 0, "memory_in_bytes" : 0, "terms_memory_in_bytes" : 0, "stored_fields_memory_in_bytes" : 0, "term_vectors_memory_in_bytes" : 0, "norms_memory_in_bytes" : 0, "points_memory_in_bytes" : 0, "doc_values_memory_in_bytes" : 0, "index_writer_memory_in_bytes" : 0, "version_map_memory_in_bytes" : 0, "fixed_bit_set_memory_in_bytes" : 0, "max_unsafe_auto_id_timestamp" : -1, "file_sizes" : { } }, "translog" : { "operations" : 0, "size_in_bytes" : 550, "uncommitted_operations" : 0, "uncommitted_size_in_bytes" : 275, "earliest_last_modified_age" : 0 }, "request_cache" : { "memory_size_in_bytes" : 0, "evictions" : 0, "hit_count" : 0, "miss_count" : 0 }, "recovery" : { "current_as_source" : 0, "current_as_target" : 0, "throttle_time_in_millis" : 0 } } } } }
這里包括了doc數量,index size,segment的內存使用量,merge,flush,refresh,translog等底層機制的統計信息。
2、segment
查看low level的lucene的segment信息,可以用來查看shard和index的更多的信息,包括一些優化信息,因為delete而浪費的數據空間,等等。
查看low level的lucene的segment信息,可以用來查看shard和index的更多的信息,包括一些優化信息,因為delete而浪費的數據空間,等等。
我們來創建一個索引,給這個索引添加一條數據,我們來看下segement的信息
默認情況下,一個索引是5個分區,一個副本一個分區下面的文件是由多個segements組成的
POST /book/novel
{
}
PUT /book/novel/2 { "name": "盤龍", "author": "天下第一", "count": 1000, "on-sale": "2020-09-25", "descr": "sjdkjdfskjkjfsdkjkjfskjsfdkjfdkjs" }
GET /book/_segments
對應的結果為
{ "_shards" : { "total" : 10, "successful" : 5, "failed" : 0 }, "indices" : { "book" : { "shards" : { "0" : [ { "routing" : { "state" : "STARTED", "primary" : true, "node" : "2yARaxaeQ5mDZp9Wdp_g_Q" }, "num_committed_segments" : 0, "num_search_segments" : 0, "segments" : { } } ], "1" : [ { "routing" : { "state" : "STARTED", "primary" : true, "node" : "2yARaxaeQ5mDZp9Wdp_g_Q" }, "num_committed_segments" : 0, "num_search_segments" : 1, "segments" : { "_0" : { "generation" : 0, "num_docs" : 1, "deleted_docs" : 0, "size_in_bytes" : 2385, "memory_in_bytes" : 670, "committed" : false, "search" : true, "version" : "7.7.3", "compound" : true, "attributes" : { "Lucene50StoredFieldsFormat.mode" : "BEST_SPEED" } } } } ], "2" : [ { "routing" : { "state" : "STARTED", "primary" : true, "node" : "2yARaxaeQ5mDZp9Wdp_g_Q" }, "num_committed_segments" : 0, "num_search_segments" : 1, "segments" : { "_1" : { "generation" : 1, "num_docs" : 1, "deleted_docs" : 0, "size_in_bytes" : 4049, "memory_in_bytes" : 1476, "committed" : false, "search" : true, "version" : "7.7.3", "compound" : false, "attributes" : { "Lucene50StoredFieldsFormat.mode" : "BEST_SPEED" } } } } ], "3" : [ { "routing" : { "state" : "STARTED", "primary" : true, "node" : "2yARaxaeQ5mDZp9Wdp_g_Q" }, "num_committed_segments" : 0, "num_search_segments" : 0, "segments" : { } } ], "4" : [ { "routing" : { "state" : "STARTED", "primary" : true, "node" : "2yARaxaeQ5mDZp9Wdp_g_Q" }, "num_committed_segments" : 0, "num_search_segments" : 1, "segments" : { "_0" : { "generation" : 0, "num_docs" : 1, "deleted_docs" : 0, "size_in_bytes" : 2385, "memory_in_bytes" : 670, "committed" : false, "search" : true, "version" : "7.7.3", "compound" : true, "attributes" : { "Lucene50StoredFieldsFormat.mode" : "BEST_SPEED" } } } } ] } } } }
_3: 是segment的名稱,這個名稱跟這個segment files的文件名有關系,一個segment的所有文件都是用這個名稱開頭的
generation:每次新生成一個segment,就會遞增一個數值,segment名稱也就是這個數值
num_docs:在這個segment中存儲的沒有被刪除的document的數量
deleted_docs:在這個segment中存儲的被刪除的document數量,這個數值是無所謂的,因為每次segment merge的時候都會刪除這些document
size_in_bytes:這個segment占用的磁盤空間
memory_in_bytes:segment需要將一些數據緩存在內存中,這樣搜索性能才能更高,這個數值就是segment占用的內存的空間大小
committed:segment是否被sync到磁盤上去了,commit/sync的segment可以確保數據不會丟失,但是即使這個值是false也不要緊,因為數據同時被存儲在了translog里面,es進程重啟的時候,是可以重放translog中的日志來恢復數據的
search:這個segment能不被搜索,如果是false的話,可能這個segment已經被sync到磁盤上,但是還沒有進行refresh,所以不能被搜索
version:lucene的版本號
compound:如果是true的話,意味着lucene將這個segment所有的文件都merge成了一個文件,進而可以節省file descriptor的消耗
3、shard存儲信息
查詢索引shard copy的存儲信息,可以看到哪些節點上有哪些shard copy,shard copy的allocation id,每個shard copy的唯一標識,包括打開索引的時候遇到的報錯。默認情況下,會顯示至少有一個未分配的copy的shard,如果cluster health是yellow,會顯示至少有一個未分配的replica的shard,當cluster health是red,會顯示有未分配的primary的shard。但是用status=green可以看到每個shard的信息。
curl -H "Content-Type:application/json" -XGET 'http://elasticsearch02:9200/twitter/_shard_stores?pretty' curl -XGET 'http://elasticsearch02:9200/twitter/_shard_stores?status=green&pretty'
GET /book/_shard_stores
{ "indices" : { "book" : { "shards" : { "4" : { "stores" : [ { "2yARaxaeQ5mDZp9Wdp_g_Q" : { "name" : "2yARaxa", "ephemeral_id" : "AvkJI2xuRVe1HbZE0gwcnA", "transport_address" : "192.168.1.4:9300", "attributes" : { "ml.machine_memory" : "8445952000", "xpack.installed" : "true", "ml.max_open_jobs" : "20", "ml.enabled" : "true" } }, "allocation_id" : "ymqCAIuPSEq6aQGakqZ-dw", "allocation" : "primary" } ] }, "1" : { "stores" : [ { "2yARaxaeQ5mDZp9Wdp_g_Q" : { "name" : "2yARaxa", "ephemeral_id" : "AvkJI2xuRVe1HbZE0gwcnA", "transport_address" : "192.168.1.4:9300", "attributes" : { "ml.machine_memory" : "8445952000", "xpack.installed" : "true", "ml.max_open_jobs" : "20", "ml.enabled" : "true" } }, "allocation_id" : "EX6D9GpBQFqKNe6o5fn8cg", "allocation" : "primary" } ] }, "2" : { "stores" : [ { "2yARaxaeQ5mDZp9Wdp_g_Q" : { "name" : "2yARaxa", "ephemeral_id" : "AvkJI2xuRVe1HbZE0gwcnA", "transport_address" : "192.168.1.4:9300", "attributes" : { "ml.machine_memory" : "8445952000", "xpack.installed" : "true", "ml.max_open_jobs" : "20", "ml.enabled" : "true" } }, "allocation_id" : "fsHj6zvoRGWSwvTQU5ioMA", "allocation" : "primary" } ] }, "3" : { "stores" : [ { "2yARaxaeQ5mDZp9Wdp_g_Q" : { "name" : "2yARaxa", "ephemeral_id" : "AvkJI2xuRVe1HbZE0gwcnA", "transport_address" : "192.168.1.4:9300", "attributes" : { "ml.machine_memory" : "8445952000", "xpack.installed" : "true", "ml.max_open_jobs" : "20", "ml.enabled" : "true" } }, "allocation_id" : "c50uxaKIQLq5FU4LzFE8Gw", "allocation" : "primary" } ] }, "0" : { "stores" : [ { "2yARaxaeQ5mDZp9Wdp_g_Q" : { "name" : "2yARaxa", "ephemeral_id" : "AvkJI2xuRVe1HbZE0gwcnA", "transport_address" : "192.168.1.4:9300", "attributes" : { "ml.machine_memory" : "8445952000", "xpack.installed" : "true", "ml.max_open_jobs" : "20", "ml.enabled" : "true" } }, "allocation_id" : "nbxj6tw6QkiZTWEwqLMiIw", "allocation" : "primary" } ] } } } } }
0:shard id
stores:shard的每個copy的store信息
sPa3OgxLSYGvQ4oPs-Tajw:node id,持有一個copy的node信息
allocationi_id:copy的allocationid
allocation:shard copy的角色
5、flush
flush API可以讓我們去強制flush多個索引,索引flush以后,就會釋放掉這個索引占用的內存,因為會將os cache里的數據強制fsync到磁盤上去,同時還會清理掉translog中的日志。默認情況下,es會不定時自動觸發flush操作,以便於及時清理掉內存。POST twitter/_flush,這條命令即可。
flush命令可以接受下面兩個參數,wait_if_going,如果設置為true,那么flush api會等到flush操作執行完以后再返回,即使需要等待其他的flush操作先完成。默認的值是false,這樣的話,如果有其他flush操作在執行,就會報錯;force,如果沒有必要flush的話,是不是會強制一個flush
POST /book/_flush
6、refresh
refresh用來顯式的刷新一個index,這樣可以讓這個refresh之前執行的所有操作,都處於可見的狀態。POST twitter/_refresh
POST /book/_refresh
7、force merge
force merge API可以強制合並多個索引文件,可以將一個shard對應的lucene index的多個segment file都合並起來,可以減少segment file的數量。POST /twitter/_forcemerge。
POST /book/_forcemerge
Elasticsearch生產集群中的索引管理(四)
2、fielddata
fielddata cache,在對field進行排序或者聚合的時候,會用到這個cache。這個cache會將所有的field value加載到內存里來,這樣可以加速排序或者聚合的性能。但是每個field的field data cache的構建是很成本很高昂的,因此建議給機器提供充足的內存來保持fielddata cache。
indices.fielddata.cache.size,這個參數可以控制這個cache的大小,可以是30%這種相對大小,或者是12GB這種絕對大小,默認是沒有限制的。
fielddata的原理之前講解過了,其實是對分詞后的field進行排序或者聚合的時候,才會使用fielddata這種jvm內存數據結構。如果是對普通的未分詞的field進行排序或者聚合,其實默認是用的doc value數據結構,是在os cache中緩存的。
Fielddata針對text字段在默認時是禁用的,因為文本聚合占用大量的空間,查看文檔
https://www.cnblogs.com/sanduzxcvbnm/p/12092298.html
3、node query cache
query cache用來緩存query的結果,每個node都有一個query cache,使用的是LRU策略,會自動清理數據。但是query cache僅僅會對那些filter后的數據進行緩存,對search后的數據是不會進行緩存的。indices.queries.cache.size,控制query cache的大小,默認是jvm heap的10%。
如果只是要根據一些field進行等值的查詢或過濾,那么用filter操作,性能會比較好,query cache
對filter的查詢會做緩存的處理
4、index buffer
index buffer用來存儲最新索引的的document。如果這個buffer滿了之后,document就會被寫入一個segment file,但是此時其實是寫入os cache中,沒有用fsync同步到磁盤,這就是refresh過程,寫入os cache中,就可以被搜索到了。然后flush之后,就fsync到了磁盤上。indices.memory.index_buffer_size,控制index buffer的大小,默認是10%。indices.memory.min_index_buffer_size,buffer的最小大小,默認是48mb。
index buffer,增刪改document,數據先寫入index buffer,寫到磁盤文件里面去,不可見的,refresh刷入磁盤文件對應的os cache里面,還有translog一份數據
插入一個文檔首先會寫入到index buffer中
Elasticsearch生產集群中的索引管理(五)
segement合並的時候會將標記為delete的文檔真正的從內存和物理空間刪除,對於merger后台的線程如果是機械硬盤,默認參數設置為1
2、translog
默認情況下,對於索引的增刪改查為了保證數據的不丟失,都需要將translog從os cache保存到磁盤上面,也就是所謂的fsync操作成功之后,才對這次請求返回是否成功
2、默認情況下,當translog的日志文件大小默認達到了512M或者每隔5秒鍾,都會支持fsync操作,將將translog從os cache保存到磁盤上面
對於每一次文檔的增刪改查,我們不一定必須每執行一次請求都等待需要將translog從os cache保存到磁盤上面,這樣會大大提高效率
因為默認每隔5秒都會執行一次
fsync操作,將將translog從os cache保存到磁盤上面
如果es掛了,也之后丟失5秒內數據的操作
對於默認的5秒或者512M數據,執行fsync操作的參數,我們可以按照下面的參數進行修改
底層模塊深入解析之threadpool
Elasticsearch性能調優之慢查詢日志
es里面的操作,主要分為兩種,一種寫入(增刪改),另一種是查詢(搜索)
我們分別要識別出來,哪些寫入操作性能比較慢,哪些查詢操作性能比較慢,先要識別出來有性能問題的這些慢查詢,慢寫入,然后才能去考慮如何優化寫入的性能,如何優化搜索的性能
搜索慢查詢日志
無論是慢查詢日志,還是慢寫入日志,都是針對shard級別的,因為大家應該知道,無論你是執行增刪改,還是執行搜索,都是對某個數據執行寫入或者是搜索,其實都是到某個shard上面去執行的
shard上面執行的慢的寫入或者是搜索,都會記錄在針對這個shard的日志中
閾值的意思,就是說,什么叫做慢?搜索,5s叫做慢?還是10s叫做慢?或者是1s叫做慢?
比如說,你設置一個閾值,5s就是搜索的閾值,5s就叫做慢,那么一旦一個搜索請求超過了5s之后,就會記錄一條慢搜索日志到日志文件中
shard level的搜索慢查詢日志,輝將搜索性能較慢的查詢寫入一個專門的日志文件中。可以針對query phase和fetch phase單獨設置慢查詢的閾值,而具體的慢查詢閾值設置如下所示:
在elasticsearch.yml中,設置
index.search.slowlog.threshold.query.warn: 10s
index.search.slowlog.threshold.query.info: 5s
index.search.slowlog.threshold.query.debug: 2s
index.search.slowlog.threshold.query.trace: 500ms
index.search.slowlog.threshold.fetch.warn: 1s
index.search.slowlog.threshold.fetch.info: 800ms
index.search.slowlog.threshold.fetch.debug: 500ms
index.search.slowlog.threshold.fetch.trace: 200ms
quer超過10s會以warm的日志級別打印日常
超過5秒以info格式打印日志
而慢查詢日志具體的格式,都是在log4j2.properties中配置的,比如下面的配置:
appender.index_search_slowlog_rolling.type = RollingFile appender.index_search_slowlog_rolling.name = index_search_slowlog_rolling appender.index_search_slowlog_rolling.fileName = ${sys:es.logs}_index_search_slowlog.log appender.index_search_slowlog_rolling.layout.type = PatternLayout appender.index_search_slowlog_rolling.layout.pattern = [%d{ISO8601}][%-5p][%-25c] %.10000m%n appender.index_search_slowlog_rolling.filePattern = ${sys:es.logs}_index_search_slowlog-%d{yyyy-MM-dd}.log appender.index_search_slowlog_rolling.policies.type = Policies appender.index_search_slowlog_rolling.policies.time.type = TimeBasedTriggeringPolicy appender.index_search_slowlog_rolling.policies.time.interval = 1 appender.index_search_slowlog_rolling.policies.time.modulate = true logger.index_search_slowlog_rolling.name = index.search.slowlog logger.index_search_slowlog_rolling.level = trace logger.index_search_slowlog_rolling.appenderRef.index_search_slowlog_rolling.ref = index_search_slowlog_rolling logger.index_search_slowlog_rolling.additivity = false
索引慢寫入日志
可以用如下的配置來設置索引寫入慢日志的閾值:
index.indexing.slowlog.threshold.index.warn: 10s index.indexing.slowlog.threshold.index.info: 5s index.indexing.slowlog.threshold.index.debug: 2s index.indexing.slowlog.threshold.index.trace: 500ms index.indexing.slowlog.level: info index.indexing.slowlog.source: 1000
用下面的log4j.properties配置就可以設置索引慢寫入日志的格式:
appender.index_indexing_slowlog_rolling.type = RollingFile appender.index_indexing_slowlog_rolling.name = index_indexing_slowlog_rolling appender.index_indexing_slowlog_rolling.fileName = ${sys:es.logs}_index_indexing_slowlog.log appender.index_indexing_slowlog_rolling.layout.type = PatternLayout appender.index_indexing_slowlog_rolling.layout.pattern = [%d{ISO8601}][%-5p][%-25c] %marker%.10000m%n appender.index_indexing_slowlog_rolling.filePattern = ${sys:es.logs}_index_indexing_slowlog-%d{yyyy-MM-dd}.log appender.index_indexing_slowlog_rolling.policies.type = Policies appender.index_indexing_slowlog_rolling.policies.time.type = TimeBasedTriggeringPolicy appender.index_indexing_slowlog_rolling.policies.time.interval = 1 appender.index_indexing_slowlog_rolling.policies.time.modulate = true logger.index_indexing_slowlog.name = index.indexing.slowlog.index logger.index_indexing_slowlog.level = trace logger.index_indexing_slowlog.appenderRef.index_indexing_slowlog_rolling.ref = index_indexing_slowlog_rolling logger.index_indexing_slowlog.additivity = false
查詢慢於 10 秒輸出一個 WARN 日志。
獲取慢於 500 毫秒輸出一個 DEBUG 日志。
索引慢於 5 秒輸出一個 INFO 日志。
Elasticsearch性能調優之索引寫入性能優化
轉載自博客:es寫入性能優化對於skywalking和elk來說都是相當的經典呀
https://blog.csdn.net/lm324114/category_9764695.html
1、用bulk批量寫入
你如果要往es里面灌入數據的話,那么根據你的業務場景來,如果你的業務場景可以支持,可以做到,讓你將一批數據聚合起來,一次性寫入es,那么就盡量采用bulk的方式,每次批量寫個幾百條這樣子。
bulk批量寫入的性能比你一條一條寫入大量的document的性能要好很多。但是如果要知道一個bulk請求最佳的大小,需要對單個es node的單個shard做壓測。先bulk寫入100個document,然后200個,400個,以此類推,每次都將bulk size加倍一次。如果bulk寫入性能開始變平緩的時候,那么這個就是最佳的bulk大小。並不是bulk size越大越好,而是根據你的集群等環境具體要測試出來的,因為越大的bulk size會導致內存壓力過大,因此最好一個請求不要發送超過10mb的數據量。
2、使用多線程將數據寫入es
單線程發送bulk請求是無法最大化es集群寫入的吞吐量的。如果要利用集群的所有資源,就需要使用多線程並發將數據bulk寫入集群中。為了更好的利用集群的資源,這樣多線程並發寫入,可以減少每次底層磁盤fsync的次數和開銷。一樣,可以對單個es節點的單個shard做壓測,比如說,先是2個線程,然后是4個線程,然后是8個線程,16個,每次線程數量倍增。一旦發現es返回了TOO_MANY_REQUESTS的錯誤,JavaClient也就是EsRejectedExecutionException,那么就說明es是說已經到了一個並發寫入的最大瓶頸了,此時我們就知道最多只能支撐這么高的並發寫入了。
3、增加refresh間隔
默認的refresh間隔是1s,用index.refresh_interval參數可以設置,這樣會其強迫es每秒中都將內存中的數據寫入磁盤中,創建一個新的segment file。正是這個間隔,讓我們每次寫入數據后,1s以后才能看到。但是如果我們將這個間隔調大,比如30s,可以接受寫入的數據30s后才看到,那么我們就可以獲取更大的寫入吞吐量,因為30s內都是寫內存的,每隔30s才會創建一個segment file。
4、禁止refresh和replia
如果我們要一次性加載大批量的數據進es,可以先禁止refresh和replica復制,將index.refresh_interval設置為-1,將index.number_of_replicas設置為0即可。這可能會導致我們的數據丟失,因為沒有refresh和replica機制了。但是不需要創建segment file,也不需要將數據replica復制到其他的replica shasrd上面去。此時寫入的速度會非常快,一旦寫完之后,可以將refresh和replica修改回正常的狀態。
5、禁止swapping交換內存
可以將swapping禁止掉,有的時候,如果要將es jvm內存交換到磁盤,再交換回內存,大量磁盤IO,性能很差,需要鎖定es的內存
6、給filesystem cache更多的內存
filesystem cache被用來執行更多的IO操作,如果我們能給filesystem cache更多的內存資源,那么es的寫入性能會好很多。
7、使用自動生成的id
如果我們要手動給es document設置一個id,那么es需要每次都去確認一下那個id是否存在,這個過程是比較耗費時間的。如果我們使用自動生成的id,那么es就可以跳過這個步驟,寫入性能會更好。對於你的業務中的表id,可以作為es document的一個field。
8、用性能更好的硬件
我們可以給filesystem cache更多的內存,也可以使用SSD替代機械硬盤,避免使用NAS等網絡存儲,考慮使用RAID 0來條帶化存儲提升磁盤並行讀寫效率,等等。
9、index buffer
如果我們要進行非常重的高並發寫入操作,那么最好將index buffer調大一些,indices.memory.index_buffer_size,這個可以調節大一些,設置的這個index buffer大小,是所有的shard公用的,但是如果除以shard數量以后,算出來平均每個shard可以使用的內存大小,一般建議,但是對於每個shard來說,最多給512mb,因為再大性能就沒什么提升了。es會將這個設置作為每個shard共享的index buffer,那些特別活躍的shard會更多的使用這個buffer。默認這個參數的值是10%,也就是jvm heap的10%,如果我們給jvm heap分配10gb內存,那么這個index buffer就有1gb,對於兩個shard共享來說,是足夠的
Elasticsearch性能調優之搜索性能優化1、給filesysgtem cache更多的內存
es的搜索引擎嚴重依賴於底層的filesystem cache,你如果給filesystem cache更多的內存,盡量讓內存可以容納所有的indx segment file索引數據文件,那么你搜索的時候就基本都是走內存的,性能會非常高。
比如說,你,es節點有3台機器,每台機器,看起來內存很多,64G,總內存,64 * 3
每台機器給es jvm heap是32G,那么剩下來留給filesystem cache的就是每台機器才32g,總共集群里給filesystem cache的就是32 * 3 = 96gb內存
如果你此時,你整個,磁盤上索引數據文件,在3台機器上,一共占用了1T的磁盤容量,你的es數據量是1t
你覺得你的性能能好嗎?filesystem cache的內存才100g,十分之一的數據可以放內存,其他的都在磁盤,然后你執行搜索操作,大部分操作都是走磁盤,性能肯定差
歸根結底,你要讓es性能要好,最佳的情況下,就是你的機器的內存,至少可以容納你的總數據量的一半
比如說,你一共要在es中存儲1T的數據,那么你的多台機器留個filesystem cache的內存加起來綜合,至少要到512G,至少半數的情況下,搜索是走內存的,性能一般可以到幾秒鍾,2秒,3秒,5秒
如果最佳的情況下,我們自己的生產環境實踐經驗,最好是用es就存少量的數據,就是你要用來搜索的那些索引,內存留給filesystem cache的,就100G,那么你就控制在100gb以內,相當於是,你的數據幾乎全部走內存來搜索,性能非常之高,一般可以在1秒以內
盡量在es里,就存儲必須用來搜索的數據,比如說你現在有一份數據,有100個字段,其實用來搜索的只有10個字段,建議是將10個字段的數據,存入es,剩下90個字段的數據,可以放mysql,hadoop hbase,都可以,es中存儲簡單的搜索數據,具體的詳細列表信息存儲在mysql等數據庫中
這樣的話,es數據量很少,10個字段的數據,都可以放內存,就用來搜索,搜索出來一些id,通過id去mysql,hbase里面去查詢明細的數據
本質上就是要讓filesystem cache能夠存儲足夠多的segment file數據,這樣搜索走的就是內存,不再走磁盤,效率相當的高
2、用更快的硬件資源
(1)給filesystem cache更多的內存資源
(2)用SSD固態硬盤
(3)使用本地存儲系統,不要用NFS等網絡存儲系統
(4)給更多的CPU資源
3、document模型設計
document模型設計是非常重要的,很多操作,不要在搜索的時候才想去執行各種復雜的亂七八糟的操作。es能支持的操作就是那么多,不要考慮用es做一些它不好操作的事情。如果真的有那種操作,盡量在document模型設計的時候,寫入的時候就完成。另外對於一些太復雜的操作,比如join,nested,parent-child搜索都要盡量避免,性能都很差的。
兩個思路,在搜索/查詢的時候,要執行一些業務強相關的特別復雜的操作:
(1)在寫入數據的時候,就設計好模型,加幾個字段,把處理好的數據寫入加的字段里面
(2)自己用java程序封裝,es能做的,用es來做,搜索出來的數據,在java程序里面去做,比如說我們,基於es,用java封裝一些特別復雜的操作
es搜索的時候不要使用es提供復雜的api,這樣會影響搜索的性能,列如我們可以將復雜的操作的結果預先計算出來,然后在寫入數據的時候,就設計好模型,加幾個字段,把處理好的數據寫入加的字段里面
4、預先index data
為了性能,提前優化data index時的數據模型,比如說document有一個price field,然后大多數查詢都對一個固定的范圍,對這個field使用range范圍查詢,那么可以提前將這個price的范圍處理出來,寫入一個字段中。比如下面這樣:
PUT index/type/1 { "designation": "spoon", "price": 13 }
GET index/_search { "aggs": { "price_ranges": { "range": { "field": "price", "ranges": [ { "to": 10 }, { "from": 10, "to": 100 }, { "from": 100 } ] } } } }
我們完全可以增加一個price_range字段:
PUT index { "mappings": { "type": { "properties": { "price_range": { "type": "keyword" } } } } }
然后寫入的時候,直接計算出來這個range:
PUT index/type/1 { "designation": "spoon", "price": 13, "price_range": "10-100" }
然后搜索的時候,就可以直接用term查詢了,性能非常高:
GET index/_search { "aggs": { "price_ranges": { "terms": { "field": "price_range" } } } }
5、預熱filesystem cache
如果我們重啟了es,那么filesystem cache是空殼的,就需要不斷的查詢才能重新讓filesystem cache熱起來,我們可以先說動對一些數據進行查詢。
比如說,你本來一個查詢,要用戶點擊以后才執行,才能從磁盤加載到filesystem cache里,第一次執行要10s,以后每次就幾百毫秒
你完全可以,自己早上的時候,就程序執行那個查詢,預熱,數據就加載到filesystem cahce,程序執行的時候是10s,以后用戶真的來看的時候就才幾百毫秒
提前讓需要被搜索的索引的segement file數據都提交加載到filesystem cache,這樣查詢的時候都是通過查詢操作系統的filesystem cache,不再通過磁盤來進行查詢,效率就會相當的高
6、避免使用script腳本
說實話,一般是避免使用es script的,實際生產中更是少用,性能不高,盡量不要使用
總結:本質上要搜索的快,一定要保證操作系統的filesystem cache要足夠的大,你要搜索的索引的數據如果都能夠全部加載到filesystem cache中,那么性能最好
Elasticsearch性能調優之磁盤讀寫性能優化(減少磁盤空間的使用量)
聚合:doc values:就是數據本身的值
搜索:倒排索引,index
評分:norms
近似匹配:index_options(freqs)
任何一個功能不需要,就把對應的存儲的數據給干掉,這樣可以節約磁盤空間的占用,也可以優化磁盤的讀寫性能
默認情況下,es在寫入document到索引的時候,都會給大多數的field增加一份doc values,就是正排索引,用來進行聚合或者排序的。比如說,如果我們有一個叫做foo的數字類型field,我們要對這個字段運行histograms aggr聚合操作,但是可能我們並不需要對這個字段進行搜索,那么就可以禁止為這個字段生成倒排索引,只需要doc value正排索引即可。禁用倒排索引:
PUT index { "mappings": { "type": { "properties": { "foo": { "type": "integer", "index": false } } } } }
這樣字段foo就不能夠被搜索了,但是能夠做聚合、排序等操作
text類型的field會存儲norm值,用來計算doc的相關度分數,如果我們需要對一個text field進行搜索,但是不關心這個field的分數,那么可以禁用norm值
PUT index { "mappings": { "type": { "properties": { "foo": { "type": "text", "norms": false } } } } }
text field還會存儲出現頻率以及位置,出現頻率也是用來計算相關度分數的,位置是用來進行phrase query這種近似匹配操作的,如果我們不需要執行phrase query近似匹配,那么可以禁用位置這個屬性:
PUT index { "mappings": { "type": { "properties": { "foo": { "type": "text", "index_options": "freqs" } } } } }
此外,如果我們不關心相關度頻分,我們可以配置es僅僅為每個term索引對應的document,我們可以對這個field進行搜索,但是phrase query這種近似匹配會報錯,而且相關度評分會不准確:
PUT index { "mappings": { "type": { "properties": { "foo": { "type": "text", "norms": false, "index_options": "freqs" } } } } }
2、不要用默認的動態string類型映射
默認的動態string類型映射會將string類型的field同時映射為text類型以及keyword類型,這會浪費磁盤空間,因為我們不一定兩種都需要。通常來說,id field這種字段可能只需要keyword映射,而body field可能只需要text field。
text類型會被分詞構建倒排索引
keyword類型不會被分詞,對應的是正向排序
映射一個content,content: text,content.內置字段: keyword
可以通過手動設置mappings映射來避免字符串類型的field被自動映射為text和keyword:
PUT index { "mappings": { "type": { "dynamic_templates": [ { "strings": { "match_mapping_type": "string", "mapping": { "type": "keyword" } } } ] } } }
3、禁止_all field
_all field會將document中所有field的值都合並在一起進行索引,很耗費空空間,如果不需要一次性對所有的field都進行搜索,那么最好禁用_all field。
4、使用best_compression
_source field和其他field都很耗費磁盤空間,最好是對其使用best_compression進行壓縮。用elasticsearch.yml中的index.codec來設置,將其設置為best_compression即可。
5、用最小的最合適的數字類型
es支持4種數字類型,byte,short,integer,long。如果最小的類型就合適,那么就用最小的類型。
數據存儲占用空間少了,那么操作系統的file systemcache就能夠加載更多的數據,整個搜索的性能就會大大的加深
關於倒排索引和正向索引:參考自己的博客https://www.cnblogs.com/kebibuluan/p/13021918.html
es的存儲空間存儲的數據為:
1、文檔的元數據 doc values ,也就是正排索引。文檔的元數據適合做聚合或者排序
2、倒排索引,倒排索引主要用來對字段做搜索,搜索的時候通過搜索得到搜索的關鍵字屬於哪個文檔id,然后通過文檔id查詢得到改文檔的具體值,文檔寫入的時候
需要對文檔對分詞,分詞之后構建倒排索引,倒排索引也需要存儲到磁盤上面,一個字段如果設置了可以被搜索,就會構建倒排索引,被分詞的字段是不適合做聚合或者排序的,如果一定要多分詞的字段做聚合或者排序操作,一定要使用FieldData字段,不清楚的看自己的博客
https://www.cnblogs.com/kebibuluan/p/13021918.html
3、
1.ElasticSearch原理是倒排索引和正排索引的轉化版
2.DocValues滿足非analyed字段的正排索引轉化版,Fielddata對應analyed
3.DocValues存在於磁盤,消耗Lucene內存來提升效率,Fielddata存在於ElasticSearch內存(jvm)
元數據區存儲的就是doc values 正向索引數據
索引區存儲的是就是倒排索引的數據
Elasticsearch生產集群監控之基於cat API進行監控
es集群監控,最好是自己干吧,因為官方出了那種非常棒的x-pack做權限認證,監控,等等,做的都非常好,但是。。。是收費的。。。
自己做es集群監控,就是根據es的一些api,自己寫一個java web的應用,自己做前端界面,程序里不斷的每隔幾秒鍾,調用一次后端的接口,獲取到各種監控信息,然后用前端頁面顯示出來,開發開發一個可視化的es集群的監控的工作台
1、GET /_cat/aliases?v
看到集群中有哪些索引別名
alias index filter routing.index routing.search
alias1 test1 - - -
alias2 test1 * - -
alias3 test1 - 1 1
alias4 test1 - 2 1,2
2、GET /_cat/allocation?v
看到每個節點分配了幾個shard,對磁盤的占用空間大小,使用率,等等
shards disk.indices disk.used disk.avail disk.total disk.percent host ip node
5 260b 47.3gb 43.4gb 100.7gb 46 127.0.0.1 127.0.0.1 CSUXak2
3、GET /_cat/count?v
看每個索引的document數量
epoch timestamp count
1475868259 15:24:20 120
4、GET /_cat/fielddata?v
看每個節點的jvm heap內存中的fielddata內存占用情況(對分詞的field進行聚合/排序要用jvm heap中的正排索引,fielddata)
id host ip node field size
Nqk-6inXQq-OxUfOUI8jNQ 127.0.0.1 127.0.0.1 Nqk-6in body 544b
Nqk-6inXQq-OxUfOUI8jNQ 127.0.0.1 127.0.0.1 Nqk-6in soul 480b
5、GET /_cat/health?v
比較全面的看一個es集群的整體健康狀況,主要是看是green,yellow,red
epoch timestamp cluster status node.total node.data shards pri relo init unassign pending_tasks max_task_wait_time active_shards_percent
1475871424 16:17:04 elasticsearch green 1 1 5 5 0 0 0 0 - 100.0%
6、GET /_cat/indices?v
每個索引的具體的情況,比如有幾個shard,多少個document,被刪除的document有多少,占用了多少磁盤空間
health status index uuid pri rep docs.count docs.deleted store.size pri.store.size
yellow open twitter u8FNjxh8Rfy_awN11oDKYQ 1 1 1200 0 88.1kb 88.1kb
7、GET /_cat/master?v
看master node當前的具體的情況,哪個node是當前的master node
id host ip node
YzWoH_2BT-6UjVGDyPdqYg 127.0.0.1 127.0.0.1 YzWoH_2
8、GET /_cat/nodes?v
看每個node的具體的情況,就比如jvm heap內存使用率,內存使用率,cpu load,是什么角色
ip heap.percent ram.percent cpu load_1m load_5m load_15m node.role master name
127.0.0.1 65 99 42 3.07 mdi * mJw06l1
9、GET /_cat/pending_tasks?v
看當前pending沒執行完的task的具體情況,執行的是什么操作
insertOrder timeInQueue priority source
1685 855ms HIGH update-mapping [foo][t]
1686 843ms HIGH update-mapping [foo][t]
1693 753ms HIGH refresh-mapping [foo][[t]]
1688 816ms HIGH update-mapping [foo][t]
1689 802ms HIGH update-mapping [foo][t]
1690 787ms HIGH update-mapping [foo][t]
1691 773ms HIGH update-mapping [foo][t]
10、GET /_cat/plugins?v&s=component&h=name,component,version,description
看當前集群安裝了哪些插件
name component version description
U7321H6 analysis-icu 5.5.1 The ICU Analysis plugin integrates Lucene ICU module into elasticsearch, adding ICU relates analysis components.
U7321H6 analysis-kuromoji 5.5.1 The Japanese (kuromoji) Analysis plugin integrates Lucene kuromoji analysis module into elasticsearch.
U7321H6 analysis-phonetic 5.5.1 The Phonetic Analysis plugin integrates phonetic token filter analysis with elasticsearch.
U7321H6 analysis-smartcn 5.5.1 Smart Chinese Analysis plugin integrates Lucene Smart Chinese analysis module into elasticsearch.
U7321H6 analysis-stempel 5.5.1 The Stempel (Polish) Analysis plugin integrates Lucene stempel (polish) analysis module into elasticsearch.
U7321H6 analysis-ukrainian 5.5.1 The Ukrainian Analysis plugin integrates the Lucene UkrainianMorfologikAnalyzer into elasticsearch.
U7321H6 discovery-azure-classic 5.5.1 The Azure Classic Discovery plugin allows to use Azure Classic API for the unicast discovery mechanism
U7321H6 discovery-ec2 5.5.1 The EC2 discovery plugin allows to use AWS API for the unicast discovery mechanism.
U7321H6 discovery-file 5.5.1 Discovery file plugin enables unicast discovery from hosts stored in a file.
U7321H6 discovery-gce 5.5.1 The Google Compute Engine (GCE) Discovery plugin allows to use GCE API for the unicast discovery mechanism.
U7321H6 ingest-attachment 5.5.1 Ingest processor that uses Apache Tika to extract contents
U7321H6 ingest-geoip 5.5.1 Ingest processor that uses looksup geo data based on ip adresses using the Maxmind geo database
U7321H6 ingest-user-agent 5.5.1 Ingest processor that extracts information from a user agent
U7321H6 jvm-example 5.5.1 Demonstrates all the pluggable Java entry points in Elasticsearch
U7321H6 lang-javascript 5.5.1 The JavaScript language plugin allows to have javascript as the language of scripts to execute.
U7321H6 lang-python 5.5.1 The Python language plugin allows to have python as the language of scripts to execute.
U7321H6 mapper-attachments 5.5.1 The mapper attachments plugin adds the attachment type to Elasticsearch using Apache Tika.
U7321H6 mapper-murmur3 5.5.1 The Mapper Murmur3 plugin allows to compute hashes of a field's values at index-time and to store them in the index.
U7321H6 mapper-size 5.5.1 The Mapper Size plugin allows document to record their uncompressed size at index time.
U7321H6 store-smb 5.5.1 The Store SMB plugin adds support for SMB stores.
11、GET _cat/recovery?v
看shard recovery恢復的一個過程的具體情況
index shard time type stage source_host source_node target_host target_node repository snapshot files files_recovered files_percent files_total bytes bytes_recovered bytes_percent bytes_total translog_ops translog_ops_recovered translog_ops_percent
twitter 0 13ms store done n/a n/a node0 node-0 n/a n/a 0 0 100% 13 0 0 100% 9928 0 0 100.0%
12、GET /_cat/repositories?v
查看用於snapshotting的repository有哪些
id type
repo1 fs
repo2 s3
13、GET /_cat/thread_pool?v
看每個線程池的具體的情況
Z6MkIvC bulk 0 0 0
Z6MkIvC fetch_shard_started 0 0 0
Z6MkIvC fetch_shard_store 0 0 0
Z6MkIvC flush 0 0 0
Z6MkIvC force_merge 0 0 0
Z6MkIvC generic 0 0 0
Z6MkIvC get 0 0 0
Z6MkIvC index 0 0 0
Z6MkIvC listener 0 0 0
Z6MkIvC management 1 0 0
Z6MkIvC refresh 0 0 0
Z6MkIvC search 0 0 0
Z6MkIvC snapshot 0 0 0
Z6MkIvC warmer 0 0 0
14、GET _cat/shards?v
看每個shard的具體的情況
twitter 0 p STARTED 3014 31.1mb 192.168.56.10 H5dfFeA
twitter 0 r UNASSIGNED
15、GET /_cat/segments?v
看每個segement,索引segment文件的情況,在哪個node上,有多少個document,占用了多少磁盤空間,有多少數據在內存中,是否可以搜索
index shard prirep ip segment generation docs.count docs.deleted size size.memory committed searchable version compound
test 3 p 127.0.0.1 _0 0 1 0 3kb 2042 false true 6.5.1 true
test1 3 p 127.0.0.1 _0 0 1 0 3kb 2042 false true 6.5.1 true
16、GET /_cat/snapshots?v&s=id
看當前執行的snapshot的操作
id status start_epoch start_time end_epoch end_time duration indices successful_shards failed_shards total_shards
snap1 FAILED 1445616705 18:11:45 1445616978 18:16:18 4.6m 1 4 1 5
snap2 SUCCESS 1445634298 23:04:58 1445634672 23:11:12 6.2m 2 10 0 10
17、GET /_cat/templates?v&s=name
看當前有的那些tempalte,具體的情況是什么
name template order version
template0 te* 0
template1 tea* 1
template2 teak* 2 7

kibana的權限管控參看博客:
1、https://blog.csdn.net/snail_bi/article/details/103531415
狠難說!:
https://blog.csdn.net/snail_bi/article/details/103531415
狠難說!:
elk這塊kibana6.8版本之后是支持對權限做控制也支持租戶的,可以實現不同的用戶訪問不同的索引:
1、登錄kibana可以設置輸入用戶名和密碼;
2、A系統的用戶的日志存儲在A系統的對應的索引中,在kibana中可以創建A系統的一個管理員,設置管理員只能訪問A系統的索引;
3、B系統的用戶的日志存儲在B系統的對應的索引中,在kibana中可以創建B系統的一個管理員,設置管理員只能訪問B系統的索引;
狠難說!:
https://www.elastic.co/cn/blog/getting-started-with-elasticsearch-security
磁盤優化:可以參考下面這篇文章
如果一個字段不需要被索引,可以將index設置為false,這樣這個字段就不需要建立倒排索引,就就能節約空間
第二個如果一個字段需要被搜索,但是不需要進行聚合、排序等可以將doc_values設置為false
一般情況doc_values也是es的數據結構也是存儲在磁盤上面的,doc_values是用來做數據的聚合和排序的
如果一個字段不需要做聚合排序,可以將doc_values設置為false
對於一個字段,現在將index已經設置了true,但是也需要進行聚合或者排序,就需要使用到fileddata這個熟悉
Doc_values
默認情況下,大多數字段都已編入索引,這使它們可搜索。反向索引允許查詢在唯一的術語排序列表中查找搜索詞,並從中立即訪問包含該詞的文檔列表。
sort,aggregtion和訪問腳本中的字段值需要不同的數據訪問模式。除了查找術語和查找文檔外,我們還需要能夠查找文檔並查找其在字段中具有的術語。
Doc values是在文檔索引時構建的磁盤數據結構,這使這種數據訪問模式成為可能。它們存儲與_source相同的值,但以面向列的方式存儲,這對於排序和聚合而言更為有效。幾乎所有字段類型都支持Doc值,但對字符串字段除外。字符串一般用來設置搜索
默認情況下,所有支持doc值的字段均已啟用它們。如果您確定不需要對字段進行排序或匯總,也不需要通過腳本訪問字段值,則可以禁用doc值以節省磁盤空間:
比如我們可以通過如下的方式來使得city字段不可以做sort或aggregation:
前言:本文的目的是為后續磁盤空間利用優化做鋪墊。主要知識點來源於官網文檔
一、doc_value是什么
絕大多數的fields在默認情況下是indexed,因此字段數據是可被搜索的。倒排索引中按照一定順序存放着terms供搜索,當命中搜索時,返回包含term的document。
terms 中包含很多term
當Sorting、aggregations、scripts access to field這三種情況的時候,我們需要另外的data access模式。這種模式和上述在terms中尋找term並且返回document是不同的
Doc values 為on-disk 數據結構,在document索引時被創建。Doc values 存放的values和 _source這個meta-Fields是一致的。支持除了analyzed string 以外的所有類型。
二、doc_value特性
doc_value 默認情況下是enable的。
column-oriented 存放field,以便sort、aggregate、access the field from a script
disable doc_value:
PUT my_index { "mappings": { "my_type": { "properties": { "mystring": { "type": "keyword", "doc_values": false } } } } }
三、disable doc_value會怎樣
消極影響:sort、aggregate、access the field from script將會無法使用
積極影響:節省磁盤空間
。