您好,登錄后才能下訂單哦!
目錄
階段一:Elasticsearch概念與架構
Elasticsearch的功能
Elasticsearch-Linux安裝
Elasticsearch核心概念
Elasticsearch基礎分布式架構
Elasticsearch的shard和replica機制、單node環境shard分配
橫向擴容過程,如何超出擴容極限,以及如何提升容錯性
階段二:ElasticSearch分布式文件架構
7.分布式文件系統-document各種操作內部原理
階段一:Elasticsearch概念與架構
Elasticsearch的功能
(1)分布式的搜索引擎和數據分析引擎
(2)全文檢索,結構化檢索,數據分析
(3)對海量數據進行近實時的處理
Elasticsearch-Linux安裝
把程序放到后臺運行: nohup ./your_command &
1.下載
wget https://artifacts.elastic.co/downloads/elasticsearch/elasticsearch-6.0.0.tar.gz
2.解壓授權(es 規定 root 用戶不能啟動 es,所以需要使用一個其他用戶來啟動 es)
useradd esuser
passwd esuser
cd /home/esuser/
tar zxvf elasticsearch-6.0.0.tar.gz
chown -R esuser:esuser elasticsearch-6.0.0
3.啟動(切換到普通用戶)
cd elasticsearch-6.0.0
sh ./bin/elasticsearch
(如果報錯jdk版本問題,可以修改系統環境變量;但是本機環境變量使用系統自帶的jdk1.7,由于其他業務需要,不能改變,可以在bin/elasticsearch-env下配置臨時變量
JAVA_HOME=/usr/java/jdk1.8.0_144)
4.訪問測試
curl localhost:9200
注:這里不能直接使用IP,需要配置(在配置前先停了線程),下面是開始配置。
5.停止es
cd elasticsearch-6.0.0/bin
ps -ef |grep elasticsearch
kill -9 上面查出來的進程號(第一行用戶名后第一個)
6.修改
config/elasticsearch.yml文件里面的:network.host: 0.0.0.0
7.重啟
sh elasticsearch (-d后臺啟動)
發現報錯:
前三個錯誤:
ERROR: [4] bootstrap checks failed
#文件句柄太少,至少要65536
[1]: max file descriptors [4096] for elasticsearch process is too low, increase to at least [65536]
#最大線程數太少,至少2048個(經典的2048游戲)
[2]: max number of threads [1024] for user [king] is too low, increase to at least [2048]
#虛擬內存太少,至少262144
[3]: max virtual memory areas vm.max_map_count [65530] is too low, increase to at least [262144]
修改:
1.更改文件句柄數
[root@localhost ~]# vi /etc/security/limits.conf
在文件中加入如下內容(*表示任何用戶)
* soft nofile 65536
* hard nofile 131072
* soft nproc 2048
* hard nproc 4096
2.增加線程數
[root@localhost ~]# vi /etc/security/limits.d/90-nproc.conf
將其中的
* soft nproc 1024
1
修改為
* soft nproc 2048
3.增加虛擬內存
[root@localhost ~]# vim /etc/sysctl.conf
在其中添加
vm.max_map_count=655360
使配置生效(完成后最好換個客戶端重啟):
sysctl -p
第四個錯誤:
[4]system call filters failed to install; check the logs and fix your configuration or disable system call filters at your own risk
原因:
這是在因為Centos6不支持SecComp,而ES5.2.0默認bootstrap.system_call_filter為true進行檢測,所以導致檢測失敗,失敗后直接導致ES不能啟動。
解決:
在elasticsearch.yml中配置bootstrap.system_call_filter為false,注意要在Memory下面:
bootstrap.memory_lock: false
bootstrap.system_call_filter: false
8.再次重啟(最好換另外一個客戶端)
[esuser@localhost bin]$ ./elasticsearch
[root@localhost ~]# curl xxx.xx.30.27:9200
9.配置防火墻
這個時候可以在本機通過本機ip訪問,還沒有開防火墻,外網是不可以訪問的。
1) 重啟后生效
開啟: chkconfig iptables on
關閉: chkconfig iptables off
2) 即時生效,重啟后失效
開啟: service iptables start
關閉: service iptables stop
我是臨時關閉防火墻。
Elasticsearch-Windows安裝
1、安裝JDK,至少1.8.0_73以上版本,java -version
2、下載和解壓縮Elasticsearch安裝包,目錄結構
3、啟動Elasticsearch:bin\elasticsearch.bat,es本身特點之一就是開箱即用,如果是中小型應用,數據量少,操作不是很復雜,直接啟動就可以用了
4、檢查ES是否啟動成功:http://localhost:9200/?pretty
name: node名稱
cluster_name: 集群名稱(默認的集群名稱就是elasticsearch)
version.number: 5.2.0,es版本號
{
"name" : "4onsTYV",
"cluster_name" : "elasticsearch",
"cluster_uuid" : "nKZ9VK_vQdSQ1J0Dx9gx1Q",
"version" : {
"number" : "5.2.0",
"build_hash" : "24e05b9",
"build_date" : "2017-01-24T19:52:35.800Z",
"build_snapshot" : false,
"lucene_version" : "6.4.0"
},
"tagline" : "You Know, for Search"
}
5、修改集群名稱:elasticsearch.yml
6、下載和解壓縮Kibana安裝包,使用里面的開發界面,去操作elasticsearch,作為我們學習es知識點的一個主要的界面入口
7、啟動Kibana:bin\kibana.bat
8、進入Dev Tools界面
9、GET _cluster/health
Elasticsearch核心概念
(1)Near Realtime(NRT):近實時,兩個意思,從寫入數據到數據可以被搜索到有一個小延遲(大概1秒);基于es執行搜索和分析可以達到秒級
(2)Cluster:集群,包含多個節點,每個節點屬于哪個集群是通過一個配置(集群名稱,默認是elasticsearch)來決定的,對于中小型應用來說,剛開始一個集群就一個節點很正常
(3)Node:節點,集群中的一個節點,節點也有一個名稱(默認是隨機分配的),節點名稱很重要(在執行運維管理操作的時候),默認節點會去加入一個名稱為“elasticsearch”的集群,如果直接啟動一堆節點,那么它們會自動組成一個elasticsearch集群,當然一個節點也可以組成一個elasticsearch集群
(4)Document&field:文檔,es中的最小數據單元,一個document可以是一條客戶數據,一條商品分類數據,一條訂單數據,通常用JSON數據結構表示,每個index下的type中,都可以去存儲多個document。一個document里面有多個field,每個field就是一個數據字段。
product document
{
"product_id": "1",
"product_name": "高露潔牙膏",
"product_desc": "高效美白",
"category_id": "2",
"category_name": "日化用品"
}
(5)Index:索引,包含一堆有相似結構的文檔數據,比如可以有一個客戶索引,商品分類索引,訂單索引,索引有一個名稱。一個index包含很多document,一個index就代表了一類類似的或者相同的document。比如說建立一個product index,商品索引,里面可能就存放了所有的商品數據,所有的商品document。
(6)Type:類型,每個索引里都可以有一個或多個type,type是index中的一個邏輯數據分類,一個type下的document,都有相同的field,比如博客系統,有一個索引,可以定義用戶數據type,博客數據type,評論數據type。
商品index,里面存放了所有的商品數據,商品document
但是商品分很多種類,每個種類的document的field可能不太一樣,比如說電器商品,可能還包含一些諸如售后時間范圍這樣的特殊field;生鮮商品,還包含一些諸如生鮮保質期之類的特殊field
type,日化商品type,電器商品type,生鮮商品type
日化商品type:product_id,product_name,product_desc,category_id,category_name
電器商品type:product_id,product_name,product_desc,category_id,category_name,service_period
生鮮商品type:product_id,product_name,product_desc,category_id,category_name,eat_period
每一個type里面,都會包含一堆document
{
"product_id": "2",
"product_name": "長虹電視機",
"product_desc": "4k高清",
"category_id": "3",
"category_name": "電器",
"service_period": "1年"
}
{
"product_id": "3",
"product_name": "基圍蝦",
"product_desc": "純天然,冰島產",
"category_id": "4",
"category_name": "生鮮",
"eat_period": "7天"
}
(7)shard:單臺機器無法存儲大量數據,es可以將一個索引中的數據切分為多個shard,分布在多臺服務器上存儲。有了shard就可以橫向擴展,存儲更多數據,讓搜索和分析等操作分布到多臺服務器上去執行,提升吞吐量和性能。每個shard都是一個lucene index。
(8)replica:任何一個服務器隨時可能故障或宕機,此時shard可能就會丟失,因此可以為每個shard創建多個replica副本。replica可以在shard故障時提供備用服務,保證數據不丟失,多個replica還可以提升搜索操作的吞吐量和性能。primary shard(建立索引時一次設置,不能修改,默認5個),replica shard(隨時修改數量,默認1個),默認每個索引10個shard,5個primary shard,5個replica shard,最小的高可用配置,是2臺服務器。
Elasticsearch基礎分布式架構
1、Elasticsearch對復雜分布式機制的透明隱藏特性
2、Elasticsearch的垂直擴容與水平擴容
3、增減或減少節點時的數據rebalance
4、master節點
5、節點對等的分布式架構
Elasticsearch的shard和replica機制、單node環境shard分配
(1)index包含多個shard
(2)每個shard都是一個最小工作單元,承載部分數據,lucene實例,完整的建立索引和處理請求的能力
(3)增減節點時,shard會自動在nodes中負載均衡
(4)primary shard和replica shard,每個document肯定只存在于某一個primary shard以及其對應的replica shard中,不可能存在于多個primary shard
(5)replica shard是primary shard的副本,負責容錯,以及承擔讀請求負載
(6)primary shard的數量在創建索引的時候就固定了,replica shard的數量可以隨時修改
(7)primary shard的默認數量是5,replica默認是1,默認有10個shard,5個primary shard,5個replica shard
(8)primary shard不能和自己的replica shard放在同一個節點上(否則節點宕機,primary shard和副本都丟失,起不到容錯的作用),但是可以和其他primary shard的replica shard放在同一個節點上
------------------------------------------------------------------------------------------------
(1)單node環境下,創建一個index,有3個primary shard,3個replica shard
(2)集群status是yellow
(3)這個時候,只會將3個primary shard分配到僅有的一個node上去,另外3個replica shard是無法分配的
(4)集群可以正常工作,但是一旦出現節點宕機,數據全部丟失,而且集群不可用,無法承接任何請求
PUT /test_index
{
"settings" : {
"number_of_shards" : 3,
"number_of_replicas" : 1
}
}
(1)replica shard分配:3個primary shard,3個replica shard,1 node
(2)primary ---> replica同步
(3)讀請求:primary/replica
(1)primary&replica自動負載均衡,6個shard,3 primary,3 replica
(2)每個node有更少的shard,IO/CPU/Memory資源給每個shard分配更多,每個shard性能更好
(3)擴容的極限,6個shard(3 primary,3 replica),最多擴容到6臺機器,每個shard可以占用單臺服務器的所有資源,性能最好
(4)超出擴容極限,動態修改replica數量,9個shard(3primary,6 replica),擴容到9臺機器,比3臺機器時,擁有3倍的讀吞吐量
(5)3臺機器下,9個shard(3 primary,6 replica),資源更少,但是容錯性更好,最多容納2臺機器宕機,6個shard只能容納0臺機器宕機
(6)這里的這些知識點,你綜合起來看,就是說,一方面告訴你擴容的原理,怎么擴容,怎么提升系統整體吞吐量;另一方面要考慮到系統的容錯性,怎么保證提高容錯性,讓盡可能多的服務器宕機,保證數據不丟失
(1)9 shard,3 node
(2)master node宕機,自動master選舉,red
(3)replica容錯:新master將replica提升為primary shard,yellow
(4)重啟宕機node,master copy replica到該node,使用原有的shard并同步宕機后的修改,green
階段二:ElasticSearch分布式文件架構
1、_index元數據
2、_type元數據
3、_id元數據
{
"_index": "test_index",
"_type": "test_type",
"_id": "1",
"_version": 1,
"found": true,
"_source": {
"test_content": "test test"
}
}
1.1、_index元數據
(1)代表一個document存放在哪個index中
(2)類似的數據放在一個索引,非類似的數據放不同索引:product index(包含了所有的商品),sales index(包含了所有的商品銷售數據),inventory index(包含了所有庫存相關的數據)。如果你把比如product,sales,human resource(employee),全都放在一個大的index里面,比如說company index,不合適的。
(3)index中包含了很多類似的document:類似是什么意思,其實指的就是說,這些document的fields很大一部分是相同的,你說你放了3個document,每個document的fields都完全不一樣,這就不是類似了,就不太適合放到一個index里面去了。
(4)索引名稱必須是小寫的,不能用下劃線開頭,不能包含逗號:product,website,blog
1.2、_type元數據
(1)代表document屬于index中的哪個類別(type)
(2)一個索引通常會劃分為多個type,邏輯上對index中有些許不同的幾類數據進行分類:因為一批相同的數據,可能有很多相同的fields,但是還是可能會有一些輕微的不同,可能會有少數fields是不一樣的,舉個例子,就比如說,商品,可能劃分為電子商品,生鮮商品,日化商品,等等。
(3)type名稱可以是大寫或者小寫,但是同時不能用下劃線開頭,不能包含逗號
1.3、_id元數據
(1)代表document的唯一標識,與index和type一起,可以唯一標識和定位一個document
(2)我們可以手動指定document的id(put /index/type/id),也可以不指定,由es自動為我們創建一個id
1、手動指定document id
(1)根據應用情況來說,是否滿足手動指定document id的前提:
一般來說,是從某些其他的系統中,導入一些數據到es時,會采取這種方式,就是使用系統中已有數據的唯一標識,作為es中document的id。舉個例子,比如說,我們現在在開發一個電商網站,做搜索功能,或者是OA系統,做員工檢索功能。這個時候,數據首先會在網站系統或者IT系統內部的數據庫中,會先有一份,此時就肯定會有一個數據庫的primary key(自增長,UUID,或者是業務編號)。如果將數據導入到es中,此時就比較適合采用數據在數據庫中已有的primary key。
如果說,我們是在做一個系統,這個系統主要的數據存儲就是es一種,也就是說,數據產生出來以后,可能就沒有id,直接就放es一個存儲,那么這個時候,可能就不太適合說手動指定document id的形式了,因為你也不知道id應該是什么,此時可以采取下面要講解的讓es自動生成id的方式。
(2)put /index/type/id
PUT /test_index/test_type/2
{
"test_content": "my test"
}
2、自動生成document id
(1)post /index/type
POST /test_index/test_type
{
"test_content": "my test"
}
{
"_index": "test_index",
"_type": "test_type",
"_id": "AVp4RN0bhjxldOOnBxaE",
"_version": 1,
"result": "created",
"_shards": {
"total": 2,
"successful": 1,
"failed": 0
},
"created": true
}
(2)自動生成的id,長度為20個字符,URL安全,base64編碼,GUID,分布式系統并行生成時不可能會發生沖突
2.1、_source元數據
put /test_index/test_type/1
{
"test_field1": "test field1",
"test_field2": "test field2"
}
get /test_index/test_type/1
{
"_index": "test_index",
"_type": "test_type",
"_id": "1",
"_version": 2,
"found": true,
"_source": {
"test_field1": "test field1",
"test_field2": "test field2"
}
}
_source元數據:就是說,我們在創建一個document的時候,使用的那個放在request body中的json串,默認情況下,在get的時候,會原封不動的給我們返回回來。
2.2、定制返回結果
定制返回的結果,指定_source中,返回哪些field
GET /test_index/test_type/1?_source=test_field1,test_field2
{
"_index": "test_index",
"_type": "test_type",
"_id": "1",
"_version": 2,
"found": true,
"_source": {
"test_field2": "test field2"
}
}
3.1、document的全量替換
(1)語法與創建文檔是一樣的,如果document id不存在,那么就是創建;如果document id已經存在,那么就是全量替換操作,替換document的json串內容
(2)document是不可變的,如果要修改document的內容,第一種方式就是全量替換,直接對document重新建立索引,替換里面所有的內容
(3)es會將老的document標記為deleted,然后新增我們給定的一個document,當我們創建越來越多的document的時候,es會在適當的時機在后臺自動刪除標記為deleted的document
3.2、document的強制創建
(1)創建文檔與全量替換的語法是一樣的,有時我們只是想新建文檔,不想替換文檔,如果強制進行創建呢?
(2)PUT /index/type/id?op_type=create,PUT /index/type/id/_create
3.3、document的刪除
(1)DELETE /index/type/id
(2)不會理解物理刪除,只會將其標記為deleted,當數據越來越多的時候,在后臺自動刪除
4.1、批量查詢的好處
就是一條一條的查詢,比如說要查詢100條數據,那么就要發送100次網絡請求,這個開銷還是很大的
如果進行批量查詢的話,查詢100條數據,就只要發送1次網絡請求,網絡請求的性能開銷縮減100倍
4.2、mget的語法
(1)一條一條的查詢 GET /test_index/test_type/1 GET /test_index/test_type/2 (2)mget批量查詢 GET /_mget { "docs" : [ { "_index" : "test_index", "_type" : "test_type", "_id" : 1 }, { "_index" : "test_index", "_type" : "test_type", "_id" : 2 } ] } { "docs": [ { "_index": "test_index", "_type": "test_type", "_id": "1", "_version": 2, "found": true, "_source": { "test_field1": "test field1", "test_field2": "test field2" } }, { "_index": "test_index", "_type": "test_type", "_id": "2", "_version": 1, "found": true, "_source": { "test_content": "my test" } } ] } (3)如果查詢的document是一個index下的不同type種的話 GET /test_index/_mget { "docs" : [ { "_type" : "test_type", "_id" : 1 }, { "_type" : "test_type", "_id" : 2 } ] } (4)如果查詢的數據都在同一個index下的同一個type下,最簡單了 GET /test_index/test_type/_mget { "ids": [1, 2] }
4.3、mget的重要性
可以說mget是很重要的,一般來說,在進行查詢的時候,如果一次性要查詢多條數據的話,那么一定要用batch批量操作的api
盡可能減少網絡開銷次數,可能可以將性能提升數倍,甚至數十倍,非常非常之重要
5.1、bulk語法
POST /_bulk { "delete": { "_index": "test_index", "_type": "test_type", "_id": "3" }} { "create": { "_index": "test_index", "_type": "test_type", "_id": "12" }} { "test_field": "test12" } { "index": { "_index": "test_index", "_type": "test_type", "_id": "2" }} { "test_field": "replaced test2" } { "update": { "_index": "test_index", "_type": "test_type", "_id": "1", "_retry_on_conflict" : 3} } { "doc" : {"test_field2" : "bulk test1"} }
每一個操作要兩個json串,語法如下:
{"action": {"metadata"}}
{"data"}
舉例,比如你現在要創建一個文檔,放bulk里面,看起來會是這樣子的:
{"index": {"_index": "test_index", "_type", "test_type", "_id": "1"}}
{"test_field1": "test1", "test_field2": "test2"}
有哪些類型的操作可以執行呢?
(1)delete:刪除一個文檔,只要1個json串就可以了
(2)create:PUT /index/type/id/_create,強制創建
(3)index:普通的put操作,可以是創建文檔,也可以是全量替換文檔
(4)update:執行的partial update操作
bulk api對json的語法,有嚴格的要求,每個json串不能換行,只能放一行,同時一個json串和一個json串之間,必須有一個換行
bulk操作中,任意一個操作失敗,是不會影響其他的操作的,但是在返回結果里,會告訴你異常日志
POST /test_index/_bulk { "delete": { "_type": "test_type", "_id": "3" }} { "create": { "_type": "test_type", "_id": "12" }} { "test_field": "test12" } { "index": { "_type": "test_type" }} { "test_field": "auto-generate id test" } { "index": { "_type": "test_type", "_id": "2" }} { "test_field": "replaced test2" } { "update": { "_type": "test_type", "_id": "1", "_retry_on_conflict" : 3} } { "doc" : {"test_field2" : "bulk test1"} } POST /test_index/test_type/_bulk { "delete": { "_id": "3" }} { "create": { "_id": "12" }} { "test_field": "test12" } { "index": { }} { "test_field": "auto-generate id test" } { "index": { "_id": "2" }} { "test_field": "replaced test2" } { "update": { "_id": "1", "_retry_on_conflict" : 3} } { "doc" : {"test_field2" : "bulk test1"} }
5.2、bulk size最佳大小
bulk request會加載到內存里,如果太大的話,性能反而會下降,因此需要反復嘗試一個最佳的bulk size。一般從1000~5000條數據開始,嘗試逐漸增加。另外,如果看大小的話,最好是在5~15MB之間
(1)_version元數據
PUT /test_index/test_type/6 { "test_field": "test test" } { "_index": "test_index", "_type": "test_type", "_id": "6", "_version": 1, "result": "created", "_shards": { "total": 2, "successful": 1, "failed": 0 }, "created": true } 第一次創建一個document的時候,它的_version內部版本號就是1;以后,每次對這個document執行修改或者刪除操作,都會對這個_version版本號自動加1;哪怕是刪除,也會對這條數據的版本號加1 { "found": true, "_index": "test_index", "_type": "test_type", "_id": "6", "_version": 4, "result": "deleted", "_shards": { "total": 2, "successful": 1, "failed": 0 } }
會發現,在刪除一個document之后,可以從一個側面證明,它不是立即物理刪除掉的,因為它的一些版本號等信息還是保留著的。先刪除一條document,再重新創建這條document,其實會在delete version基礎之上,再把version號加1
es提供了一個feature,就是說,你可以不用它提供的內部_version版本號來進行并發控制,可以基于你自己維護的一個版本號來進行并發控制。舉個列子,加入你的數據在mysql里也有一份,然后你的應用系統本身就維護了一個版本號,無論是什么自己生成的,程序控制的。這個時候,你進行樂觀鎖并發控制的時候,可能并不是想要用es內部的_version來進行控制,而是用你自己維護的那個version來進行控制。
什么是partial update?
PUT /index/type/id,創建文檔&替換文檔,就是一樣的語法
一般對應到應用程序中,每次的執行流程基本是這樣的:
(1)應用程序先發起一個get請求,獲取到document,展示到前臺界面,供用戶查看和修改
(2)用戶在前臺界面修改數據,發送到后臺
(3)后臺代碼,會將用戶修改的數據在內存中進行執行,然后封裝好修改后的全量數據
(4)然后發送PUT請求,到es中,進行全量替換
(5)es將老的document標記為deleted,然后重新創建一個新的document
partial update
post /index/type/id/_update
{
"doc": {
"要修改的少數幾個field即可,不需要全量的數據"
}
}
看起來,好像就比較方便了,每次就傳遞少數幾個發生修改的field即可,不需要將全量的document數據發送過去
圖解partial update實現原理以及其優點
Partial update相比全量請求的優缺點:
所有的查詢、修改和寫回操作,都發生在es中的一個shard內部,避免了所有的網絡數據傳輸的開銷(如果全量請求的話,會從es中找一批數據放回Java應用中,然后Java應用修改,傳回es中修改請求,這就是兩次網絡開銷,而partial update只在一個shard中操作所有)
7.1.document數據路由原理(shard為什么不可變)
(1)document路由到shard上是什么意思?
(2)路由算法:shard = hash(routing) % number_of_primary_shards
舉個例子,一個index有3個primary shard,P0,P1,P2
每次增刪改查一個document的時候,都會帶過來一個routing number,默認就是這個document的_id(可能是手動指定,也可能是自動生成)
routing = _id,假設_id=1
會將這個routing值,傳入一個hash函數中,產出一個routing值的hash值,hash(routing) = 21
然后將hash函數產出的值對這個index的primary shard的數量求余數,21 % 3 = 0
就決定了,這個document就放在P0上。
決定一個document在哪個shard上,最重要的一個值就是routing值,默認是_id,也可以手動指定,相同的routing值,每次過來,從hash函數中,產出的hash值一定是相同的
無論hash值是幾,無論是什么數字,對number_of_primary_shards求余數,結果一定是在0~number_of_primary_shards-1之間這個范圍內的。0,1,2。
(3)_id or custom routing value
默認的routing就是_id
也可以在發送請求的時候,手動指定一個routing value,比如說put /index/type/id?routing=user_id
手動指定routing value是很有用的,可以保證說,某一類document一定被路由到一個shard上去,那么在后續進行應用級別的負載均衡,以及提升批量讀取的性能的時候,是很有幫助的
(4)primary shard數量不可變的謎底
7.2.es增刪改內部原理
(1)客戶端選擇一個node發送請求過去,這個node就是coordinating node(協調節點)
(2)coordinating node,對document進行路由,將請求轉發給對應的node(有primary shard)
(3)實際的node上的primary shard處理請求,然后將數據同步到replica node
(4)coordinating node,如果發現primary node和所有replica node都搞定之后,就返回響應結果給客戶端
7.3.寫一致性原理以及quorum機制
(1)consistency,one(primary shard),all(all shard),quorum(default)
我們在發送任何一個增刪改操作的時候,比如說put /index/type/id,都可以帶上一個consistency參數,指明我們想要的寫一致性是什么?
put /index/type/id?consistency=quorum
one:要求我們這個寫操作,只要有一個primary shard是active活躍可用的,就可以執行
all:要求我們這個寫操作,必須所有的primary shard和replica shard都是活躍的,才可以執行這個寫操作
quorum:默認的值,要求所有的shard中,必須是大部分的shard都是活躍的,可用的,才可以執行這個寫操作
(2)quorum機制,寫之前必須確保大多數shard都可用,int( (primary + number_of_replicas) / 2 ) + 1,當number_of_replicas>1時才生效
quroum = int( (primary + number_of_replicas) / 2 ) + 1
舉個例子,3個primary shard,number_of_replicas=1,總共有3 + 3 * 1 = 6個shard
quorum = int( (3 + 1) / 2 ) + 1 = 3
所以,要求6個shard中至少有3個shard是active狀態的,才可以執行這個寫操作
(3)如果節點數少于quorum數量,可能導致quorum不齊全,進而導致無法執行任何寫操作
3個primary shard,replica=1,要求至少3個shard是active,3個shard按照之前學習的shard&replica機制,必須在不同的節點上,如果說只有2臺機器的話,是不是有可能出現說,3個shard都沒法分配齊全,此時就可能會出現寫操作無法執行的情況
es提供了一種特殊的處理場景,就是說當number_of_replicas>1時才生效,因為假如說,你就一個primary shard,replica=1,此時就2個shard
(1 + 1 / 2) + 1 = 2,要求必須有2個shard是活躍的,但是可能就1個node,此時就1個shard是活躍的,如果你不特殊處理的話,導致我們的單節點集群就無法工作
(4)quorum不齊全時,wait,默認1分鐘,timeout,100,30s
等待期間,期望活躍的shard數量可以增加,最后實在不行,就會timeout
我們其實可以在寫操作的時候,加一個timeout參數,比如說put /index/type/id?timeout=30,這個就是說自己去設定quorum不齊全的時候,es的timeout時長,可以縮短,也可以增長
7.4.es查詢內部原理
1、客戶端發送請求到任意一個node,成為coordinate node
2、coordinate node對document進行路由,將請求轉發到對應的node,此時會使用round-robin隨機輪詢算法,在primary shard以及其所有replica中隨機選擇一個,讓讀請求負載均衡
3、接收請求的node返回document給coordinate node
4、coordinate node返回document給客戶端
5、特殊情況:document如果還在建立索引過程中,可能只有primary shard有,任何一個replica shard都沒有,此時可能會導致無法讀取到document,但是document完成索引建立之后,primary shard和replica shard就都有了
7.5.json格式
bulk api奇特的json格式
{"action": {"meta"}}\n
{"data"}\n
{"action": {"meta"}}\n
{"data"}\n
[{
"action": {
},
"data": {
}
}]
1、bulk中的每個操作都可能要轉發到不同的node的shard去執行
2、如果采用比較良好的json數組格式
允許任意的換行,整個可讀性非常棒,讀起來很爽,es拿到那種標準格式的json串以后,要按照下述流程去進行處理
(1)將json數組解析為JSONArray對象,這個時候,整個數據,就會在內存中出現一份一模一樣的拷貝,一份數據是json文本,一份數據是JSONArray對象
(2)解析json數組里的每個json,對每個請求中的document進行路由
(3)為路由到同一個shard上的多個請求,創建一個請求數組
(4)將這個請求數組序列化
(5)將序列化后的請求數組發送到對應的節點上去
3、耗費更多內存,更多的jvm gc開銷
我們之前提到過bulk size最佳大小的那個問題,一般建議說在幾千條那樣,然后大小在10MB左右,所以說,可怕的事情來了。假設說現在100個bulk請求發送到了一個節點上去,然后每個請求是10MB,100個請求,就是1000MB = 1GB,然后每個請求的json都copy一份為jsonarray對象,此時內存中的占用就會翻倍,就會占用2GB的內存,甚至還不止。因為弄成jsonarray之后,還可能會多搞一些其他的數據結構,2GB+的內存占用。
占用更多的內存可能就會積壓其他請求的內存使用量,比如說最重要的搜索請求,分析請求,等等,此時就可能會導致其他請求的性能急速下降
另外的話,占用內存更多,就會導致java虛擬機的垃圾回收次數更多,跟頻繁,每次要回收的垃圾對象更多,耗費的時間更多,導致es的java虛擬機停止工作線程的時間更多
4、現在的奇特格式
{"action": {"meta"}}\n
{"data"}\n
{"action": {"meta"}}\n
{"data"}\n
(1)不用將其轉換為json對象,不會出現內存中的相同數據的拷貝,直接按照換行符切割json
(2)對每兩個一組的json,讀取meta,進行document路由
(3)直接將對應的json發送到node上去
5、最大的優勢在于,不需要將json數組解析為一個JSONArray對象,形成一份大數據的拷貝,浪費內存空間,盡可能地保證性能
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。