目錄

階段一:Elasticsearch概念與架構(gòu)
Elasticsearch的功能
Elasticsearch-Linux安裝
Elasticsearch核心概念
Elasticsearch基礎(chǔ)分布式架構(gòu)
Elasticsearch的shard和replica機(jī)制、單node環(huán)境shard分配
橫向擴(kuò)容過程,如何超出擴(kuò)容極限,以及如何提升容錯(cuò)性
階段二:ElasticSearch分布式文件架構(gòu)
7.分布式文件系統(tǒng)-document各種操作內(nèi)部原理
階段一:Elasticsearch概念與架構(gòu)
Elasticsearch的功能
(1)分布式的搜索引擎和數(shù)據(jù)分析引擎
(2)全文檢索,結(jié)構(gòu)化檢索,數(shù)據(jù)分析
(3)對(duì)海量數(shù)據(jù)進(jìn)行近實(shí)時(shí)的處理
Elasticsearch-Linux安裝
把程序放到后臺(tái)運(yùn)行: nohup ./your_command &
1.下載
wget https://artifacts.elastic.co/downloads/elasticsearch/elasticsearch-6.0.0.tar.gz
2.解壓授權(quán)(es 規(guī)定 root 用戶不能啟動(dòng) es,所以需要使用一個(gè)其他用戶來啟動(dòng) 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.啟動(dòng)(切換到普通用戶)
cd elasticsearch-6.0.0
sh ./bin/elasticsearch
(如果報(bào)錯(cuò)jdk版本問題,可以修改系統(tǒng)環(huán)境變量;但是本機(jī)環(huán)境變量使用系統(tǒng)自帶的jdk1.7,由于其他業(yè)務(wù)需要,不能改變,可以在bin/elasticsearch-env下配置臨時(shí)變量
JAVA_HOME=/usr/java/jdk1.8.0_144)
4.訪問測(cè)試
curl localhost:9200
注:這里不能直接使用IP,需要配置(在配置前先停了線程),下面是開始配置。
5.停止es
cd elasticsearch-6.0.0/bin
ps -ef |grep elasticsearch
kill -9 上面查出來的進(jìn)程號(hào)(第一行用戶名后第一個(gè))
6.修改
config/elasticsearch.yml文件里面的:network.host: 0.0.0.0
7.重啟
sh elasticsearch (-d后臺(tái)啟動(dòng))
發(fā)現(xiàn)報(bào)錯(cuò):
前三個(gè)錯(cuò)誤:
ERROR: [4] bootstrap checks failed
#文件句柄太少,至少要65536
[1]: max file descriptors [4096] for elasticsearch process is too low, increase to at least [65536]
#大線程數(shù)太少,至少2048個(gè)(經(jīng)典的2048游戲)
[2]: max number of threads [1024] for user [king] is too low, increase to at least [2048]
#虛擬內(nèi)存太少,至少262144
[3]: max virtual memory areas vm.max_map_count [65530] is too low, increase to at least [262144]
修改:
1.更改文件句柄數(shù)
[root@localhost ~]# vi /etc/security/limits.conf
在文件中加入如下內(nèi)容(*表示任何用戶)
* soft nofile 65536
* hard nofile 131072
* soft nproc 2048
* hard nproc 4096
2.增加線程數(shù)
[root@localhost ~]# vi /etc/security/limits.d/90-nproc.conf
將其中的
* soft nproc 1024
1
修改為
* soft nproc 2048
3.增加虛擬內(nèi)存
[root@localhost ~]# vim /etc/sysctl.conf
在其中添加
vm.max_map_count=655360
使配置生效(完成后最好換個(gè)客戶端重啟):
sysctl -p
第四個(gè)錯(cuò)誤:
[4]system call filters failed to install; check the logs and fix your configuration or disable system call filters at your own risk
原因:
這是在因?yàn)镃entos6不支持SecComp,而ES5.2.0默認(rèn)bootstrap.system_call_filter為true進(jìn)行檢測(cè),所以導(dǎo)致檢測(cè)失敗,失敗后直接導(dǎo)致ES不能啟動(dòng)。
解決:
在elasticsearch.yml中配置bootstrap.system_call_filter為false,注意要在Memory下面:
bootstrap.memory_lock: false
bootstrap.system_call_filter: false
8.再次重啟(最好換另外一個(gè)客戶端)
[esuser@localhost bin]$ ./elasticsearch
[root@localhost ~]# curl xxx.xx.30.27:9200
9.配置防火墻
這個(gè)時(shí)候可以在本機(jī)通過本機(jī)ip訪問,還沒有開防火墻,外網(wǎng)是不可以訪問的。
1) 重啟后生效
開啟: chkconfig iptables on
關(guān)閉: chkconfig iptables off
2) 即時(shí)生效,重啟后失效
開啟: service iptables start
關(guān)閉: service iptables stop
我是臨時(shí)關(guān)閉防火墻。
Elasticsearch-Windows安裝
1、安裝JDK,至少1.8.0_73以上版本,java -version
2、下載和解壓縮Elasticsearch安裝包,目錄結(jié)構(gòu)
3、啟動(dòng)Elasticsearch:bin\elasticsearch.bat,es本身特點(diǎn)之一就是開箱即用,如果是中小型應(yīng)用,數(shù)據(jù)量少,操作不是很復(fù)雜,直接啟動(dòng)就可以用了
4、檢查ES是否啟動(dòng)成功:http://localhost:9200/?pretty
name: node名稱
cluster_name: 集群名稱(默認(rèn)的集群名稱就是elasticsearch)
version.number: 5.2.0,es版本號(hào)
{
"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安裝包,使用里面的開發(fā)界面,去操作elasticsearch,作為我們學(xué)習(xí)es知識(shí)點(diǎn)的一個(gè)主要的界面入口
7、啟動(dòng)Kibana:bin\kibana.bat
8、進(jìn)入Dev Tools界面
9、GET _cluster/health

Elasticsearch核心概念
(1)Near Realtime(NRT):近實(shí)時(shí),兩個(gè)意思,從寫入數(shù)據(jù)到數(shù)據(jù)可以被搜索到有一個(gè)小延遲(大概1秒);基于es執(zhí)行搜索和分析可以達(dá)到秒級(jí)
(2)Cluster:集群,包含多個(gè)節(jié)點(diǎn),每個(gè)節(jié)點(diǎn)屬于哪個(gè)集群是通過一個(gè)配置(集群名稱,默認(rèn)是elasticsearch)來決定的,對(duì)于中小型應(yīng)用來說,剛開始一個(gè)集群就一個(gè)節(jié)點(diǎn)很正常
(3)Node:節(jié)點(diǎn),集群中的一個(gè)節(jié)點(diǎn),節(jié)點(diǎn)也有一個(gè)名稱(默認(rèn)是隨機(jī)分配的),節(jié)點(diǎn)名稱很重要(在執(zhí)行運(yùn)維管理操作的時(shí)候),默認(rèn)節(jié)點(diǎn)會(huì)去加入一個(gè)名稱為“elasticsearch”的集群,如果直接啟動(dòng)一堆節(jié)點(diǎn),那么它們會(huì)自動(dòng)組成一個(gè)elasticsearch集群,當(dāng)然一個(gè)節(jié)點(diǎn)也可以組成一個(gè)elasticsearch集群
(4)Document&field:文檔,es中的最小數(shù)據(jù)單元,一個(gè)document可以是一條客戶數(shù)據(jù),一條商品分類數(shù)據(jù),一條訂單數(shù)據(jù),通常用JSON數(shù)據(jù)結(jié)構(gòu)表示,每個(gè)index下的type中,都可以去存儲(chǔ)多個(gè)document。一個(gè)document里面有多個(gè)field,每個(gè)field就是一個(gè)數(shù)據(jù)字段。
product document
{
"product_id": "1",
"product_name": "高露潔牙膏",
"product_desc": "高效美白",
"category_id": "2",
"category_name": "日化用品"
}
(5)Index:索引,包含一堆有相似結(jié)構(gòu)的文檔數(shù)據(jù),比如可以有一個(gè)客戶索引,商品分類索引,訂單索引,索引有一個(gè)名稱。一個(gè)index包含很多document,一個(gè)index就代表了一類類似的或者相同的document。比如說建立一個(gè)product index,商品索引,里面可能就存放了所有的商品數(shù)據(jù),所有的商品document。
(6)Type:類型,每個(gè)索引里都可以有一個(gè)或多個(gè)type,type是index中的一個(gè)邏輯數(shù)據(jù)分類,一個(gè)type下的document,都有相同的field,比如博客系統(tǒng),有一個(gè)索引,可以定義用戶數(shù)據(jù)type,博客數(shù)據(jù)type,評(píng)論數(shù)據(jù)type。
商品index,里面存放了所有的商品數(shù)據(jù),商品document
但是商品分很多種類,每個(gè)種類的document的field可能不太一樣,比如說電器商品,可能還包含一些諸如售后時(shí)間范圍這樣的特殊field;生鮮商品,還包含一些諸如生鮮保質(zhì)期之類的特殊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
每一個(gè)type里面,都會(huì)包含一堆document
{
"product_id": "2",
"product_name": "長(zhǎng)虹電視機(jī)",
"product_desc": "4k高清",
"category_id": "3",
"category_name": "電器",
"service_period": "1年"
}
{
"product_id": "3",
"product_name": "基圍蝦",
"product_desc": "純天然,冰島產(chǎn)",
"category_id": "4",
"category_name": "生鮮",
"eat_period": "7天"
}
(7)shard:?jiǎn)闻_(tái)機(jī)器無法存儲(chǔ)大量數(shù)據(jù),es可以將一個(gè)索引中的數(shù)據(jù)切分為多個(gè)shard,分布在多臺(tái)服務(wù)器上存儲(chǔ)。有了shard就可以橫向擴(kuò)展,存儲(chǔ)更多數(shù)據(jù),讓搜索和分析等操作分布到多臺(tái)服務(wù)器上去執(zhí)行,提升吞吐量和性能。每個(gè)shard都是一個(gè)lucene index。
(8)replica:任何一個(gè)服務(wù)器隨時(shí)可能故障或宕機(jī),此時(shí)shard可能就會(huì)丟失,因此可以為每個(gè)shard創(chuàng)建多個(gè)replica副本。replica可以在shard故障時(shí)提供備用服務(wù),保證數(shù)據(jù)不丟失,多個(gè)replica還可以提升搜索操作的吞吐量和性能。primary shard(建立索引時(shí)一次設(shè)置,不能修改,默認(rèn)5個(gè)),replica shard(隨時(shí)修改數(shù)量,默認(rèn)1個(gè)),默認(rèn)每個(gè)索引10個(gè)shard,5個(gè)primary shard,5個(gè)replica shard,最小的高可用配置,是2臺(tái)服務(wù)器。

Elasticsearch基礎(chǔ)分布式架構(gòu)
1、Elasticsearch對(duì)復(fù)雜分布式機(jī)制的透明隱藏特性
2、Elasticsearch的垂直擴(kuò)容與水平擴(kuò)容
3、增減或減少節(jié)點(diǎn)時(shí)的數(shù)據(jù)rebalance
4、master節(jié)點(diǎn)
5、節(jié)點(diǎn)對(duì)等的分布式架構(gòu)

Elasticsearch的shard和replica機(jī)制、單node環(huán)境shard分配
(1)index包含多個(gè)shard
(2)每個(gè)shard都是一個(gè)最小工作單元,承載部分?jǐn)?shù)據(jù),lucene實(shí)例,完整的建立索引和處理請(qǐng)求的能力
(3)增減節(jié)點(diǎn)時(shí),shard會(huì)自動(dòng)在nodes中負(fù)載均衡
(4)primary shard和replica shard,每個(gè)document肯定只存在于某一個(gè)primary shard以及其對(duì)應(yīng)的replica shard中,不可能存在于多個(gè)primary shard
(5)replica shard是primary shard的副本,負(fù)責(zé)容錯(cuò),以及承擔(dān)讀請(qǐng)求負(fù)載
(6)primary shard的數(shù)量在創(chuàng)建索引的時(shí)候就固定了,replica shard的數(shù)量可以隨時(shí)修改
(7)primary shard的默認(rèn)數(shù)量是5,replica默認(rèn)是1,默認(rèn)有10個(gè)shard,5個(gè)primary shard,5個(gè)replica shard
(8)primary shard不能和自己的replica shard放在同一個(gè)節(jié)點(diǎn)上(否則節(jié)點(diǎn)宕機(jī),primary shard和副本都丟失,起不到容錯(cuò)的作用),但是可以和其他primary shard的replica shard放在同一個(gè)節(jié)點(diǎn)上
------------------------------------------------------------------------------------------------
(1)單node環(huán)境下,創(chuàng)建一個(gè)index,有3個(gè)primary shard,3個(gè)replica shard
(2)集群status是yellow
(3)這個(gè)時(shí)候,只會(huì)將3個(gè)primary shard分配到僅有的一個(gè)node上去,另外3個(gè)replica shard是無法分配的
(4)集群可以正常工作,但是一旦出現(xiàn)節(jié)點(diǎn)宕機(jī),數(shù)據(jù)全部丟失,而且集群不可用,無法承接任何請(qǐng)求
PUT /test_index
{
"settings" : {
"number_of_shards" : 3,
"number_of_replicas" : 1
}
}
(1)replica shard分配:3個(gè)primary shard,3個(gè)replica shard,1 node
(2)primary ---> replica同步
(3)讀請(qǐng)求:primary/replica
(1)primary&replica自動(dòng)負(fù)載均衡,6個(gè)shard,3 primary,3 replica
(2)每個(gè)node有更少的shard,IO/CPU/Memory資源給每個(gè)shard分配更多,每個(gè)shard性能更好
(3)擴(kuò)容的極限,6個(gè)shard(3 primary,3 replica),最多擴(kuò)容到6臺(tái)機(jī)器,每個(gè)shard可以占用單臺(tái)服務(wù)器的所有資源,性能最好
(4)超出擴(kuò)容極限,動(dòng)態(tài)修改replica數(shù)量,9個(gè)shard(3primary,6 replica),擴(kuò)容到9臺(tái)機(jī)器,比3臺(tái)機(jī)器時(shí),擁有3倍的讀吞吐量
(5)3臺(tái)機(jī)器下,9個(gè)shard(3 primary,6 replica),資源更少,但是容錯(cuò)性更好,最多容納2臺(tái)機(jī)器宕機(jī),6個(gè)shard只能容納0臺(tái)機(jī)器宕機(jī)
(6)這里的這些知識(shí)點(diǎn),你綜合起來看,就是說,一方面告訴你擴(kuò)容的原理,怎么擴(kuò)容,怎么提升系統(tǒng)整體吞吐量;另一方面要考慮到系統(tǒng)的容錯(cuò)性,怎么保證提高容錯(cuò)性,讓盡可能多的服務(wù)器宕機(jī),保證數(shù)據(jù)不丟失
(1)9 shard,3 node
(2)master node宕機(jī),自動(dòng)master選舉,red
(3)replica容錯(cuò):新master將replica提升為primary shard,yellow
(4)重啟宕機(jī)node,master copy replica到該node,使用原有的shard并同步宕機(jī)后的修改,green

階段二:ElasticSearch分布式文件架構(gòu)
1、_index元數(shù)據(jù)
2、_type元數(shù)據(jù)
3、_id元數(shù)據(jù)
{
"_index": "test_index",
"_type": "test_type",
"_id": "1",
"_version": 1,
"found": true,
"_source": {
"test_content": "test test"
}
}
1.1、_index元數(shù)據(jù)
(1)代表一個(gè)document存放在哪個(gè)index中
(2)類似的數(shù)據(jù)放在一個(gè)索引,非類似的數(shù)據(jù)放不同索引:product index(包含了所有的商品),sales index(包含了所有的商品銷售數(shù)據(jù)),inventory index(包含了所有庫存相關(guān)的數(shù)據(jù))。如果你把比如product,sales,human resource(employee),全都放在一個(gè)大的index里面,比如說company index,不合適的。
(3)index中包含了很多類似的document:類似是什么意思,其實(shí)指的就是說,這些document的fields很大一部分是相同的,你說你放了3個(gè)document,每個(gè)document的fields都完全不一樣,這就不是類似了,就不太適合放到一個(gè)index里面去了。
(4)索引名稱必須是小寫的,不能用下劃線開頭,不能包含逗號(hào):product,website,blog
1.2、_type元數(shù)據(jù)
(1)代表document屬于index中的哪個(gè)類別(type)
(2)一個(gè)索引通常會(huì)劃分為多個(gè)type,邏輯上對(duì)index中有些許不同的幾類數(shù)據(jù)進(jìn)行分類:因?yàn)橐慌嗤臄?shù)據(jù),可能有很多相同的fields,但是還是可能會(huì)有一些輕微的不同,可能會(huì)有少數(shù)fields是不一樣的,舉個(gè)例子,就比如說,商品,可能劃分為電子商品,生鮮商品,日化商品,等等。
(3)type名稱可以是大寫或者小寫,但是同時(shí)不能用下劃線開頭,不能包含逗號(hào)
1.3、_id元數(shù)據(jù)
(1)代表document的唯一標(biāo)識(shí),與index和type一起,可以唯一標(biāo)識(shí)和定位一個(gè)document
(2)我們可以手動(dòng)指定document的id(put /index/type/id),也可以不指定,由es自動(dòng)為我們創(chuàng)建一個(gè)id
1、手動(dòng)指定document id
(1)根據(jù)應(yīng)用情況來說,是否滿足手動(dòng)指定document id的前提:
一般來說,是從某些其他的系統(tǒng)中,導(dǎo)入一些數(shù)據(jù)到es時(shí),會(huì)采取這種方式,就是使用系統(tǒng)中已有數(shù)據(jù)的唯一標(biāo)識(shí),作為es中document的id。舉個(gè)例子,比如說,我們現(xiàn)在在開發(fā)一個(gè)電商網(wǎng)站,做搜索功能,或者是OA系統(tǒng),做員工檢索功能。這個(gè)時(shí)候,數(shù)據(jù)首先會(huì)在網(wǎng)站系統(tǒng)或者IT系統(tǒng)內(nèi)部的數(shù)據(jù)庫中,會(huì)先有一份,此時(shí)就肯定會(huì)有一個(gè)數(shù)據(jù)庫的primary key(自增長(zhǎng),UUID,或者是業(yè)務(wù)編號(hào))。如果將數(shù)據(jù)導(dǎo)入到es中,此時(shí)就比較適合采用數(shù)據(jù)在數(shù)據(jù)庫中已有的primary key。
如果說,我們是在做一個(gè)系統(tǒng),這個(gè)系統(tǒng)主要的數(shù)據(jù)存儲(chǔ)就是es一種,也就是說,數(shù)據(jù)產(chǎn)生出來以后,可能就沒有id,直接就放es一個(gè)存儲(chǔ),那么這個(gè)時(shí)候,可能就不太適合說手動(dòng)指定document id的形式了,因?yàn)槟阋膊恢纈d應(yīng)該是什么,此時(shí)可以采取下面要講解的讓es自動(dòng)生成id的方式。
(2)put /index/type/id
PUT /test_index/test_type/2
{
"test_content": "my test"
}
2、自動(dòng)生成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)自動(dòng)生成的id,長(zhǎng)度為20個(gè)字符,URL安全,base64編碼,GUID,分布式系統(tǒng)并行生成時(shí)不可能會(huì)發(fā)生沖突
2.1、_source元數(shù)據(jù)
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元數(shù)據(jù):就是說,我們?cè)趧?chuàng)建一個(gè)document的時(shí)候,使用的那個(gè)放在request body中的json串,默認(rèn)情況下,在get的時(shí)候,會(huì)原封不動(dòng)的給我們返回回來。
2.2、定制返回結(jié)果
定制返回的結(jié)果,指定_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)語法與創(chuàng)建文檔是一樣的,如果document id不存在,那么就是創(chuàng)建;如果document id已經(jīng)存在,那么就是全量替換操作,替換document的json串內(nèi)容
(2)document是不可變的,如果要修改document的內(nèi)容,第一種方式就是全量替換,直接對(duì)document重新建立索引,替換里面所有的內(nèi)容
(3)es會(huì)將老的document標(biāo)記為deleted,然后新增我們給定的一個(gè)document,當(dāng)我們創(chuàng)建越來越多的document的時(shí)候,es會(huì)在適當(dāng)?shù)臅r(shí)機(jī)在后臺(tái)自動(dòng)刪除標(biāo)記為deleted的document
3.2、document的強(qiáng)制創(chuàng)建
(1)創(chuàng)建文檔與全量替換的語法是一樣的,有時(shí)我們只是想新建文檔,不想替換文檔,如果強(qiáng)制進(jìn)行創(chuàng)建呢?
(2)PUT /index/type/id?op_type=create,PUT /index/type/id/_create
3.3、document的刪除
(1)DELETE /index/type/id
(2)不會(huì)理解物理刪除,只會(huì)將其標(biāo)記為deleted,當(dāng)數(shù)據(jù)越來越多的時(shí)候,在后臺(tái)自動(dòng)刪除
4.1、批量查詢的好處
就是一條一條的查詢,比如說要查詢100條數(shù)據(jù),那么就要發(fā)送100次網(wǎng)絡(luò)請(qǐng)求,這個(gè)開銷還是很大的
如果進(jìn)行批量查詢的話,查詢100條數(shù)據(jù),就只要發(fā)送1次網(wǎng)絡(luò)請(qǐng)求,網(wǎng)絡(luò)請(qǐng)求的性能開銷縮減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是一個(gè)index下的不同type種的話
GET /test_index/_mget
{
"docs" : [
{
"_type" : "test_type",
"_id" : 1
},
{
"_type" : "test_type",
"_id" : 2
}
]
}
(4)如果查詢的數(shù)據(jù)都在同一個(gè)index下的同一個(gè)type下,最簡(jiǎn)單了
GET /test_index/test_type/_mget
{
"ids": [1, 2]
}4.3、mget的重要性
可以說mget是很重要的,一般來說,在進(jìn)行查詢的時(shí)候,如果一次性要查詢多條數(shù)據(jù)的話,那么一定要用batch批量操作的api
盡可能減少網(wǎng)絡(luò)開銷次數(shù),可能可以將性能提升數(shù)倍,甚至數(shù)十倍,非常非常之重要
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"} }每一個(gè)操作要兩個(gè)json串,語法如下:
{"action": {"metadata"}}
{"data"}
舉例,比如你現(xiàn)在要?jiǎng)?chuàng)建一個(gè)文檔,放bulk里面,看起來會(huì)是這樣子的:
{"index": {"_index": "test_index", "_type", "test_type", "_id": "1"}}
{"test_field1": "test1", "test_field2": "test2"}
有哪些類型的操作可以執(zhí)行呢?
(1)delete:刪除一個(gè)文檔,只要1個(gè)json串就可以了
(2)create:PUT /index/type/id/_create,強(qiáng)制創(chuàng)建
(3)index:普通的put操作,可以是創(chuàng)建文檔,也可以是全量替換文檔
(4)update:執(zhí)行的partial update操作
bulk api對(duì)json的語法,有嚴(yán)格的要求,每個(gè)json串不能換行,只能放一行,同時(shí)一個(gè)json串和一個(gè)json串之間,必須有一個(gè)換行
bulk操作中,任意一個(gè)操作失敗,是不會(huì)影響其他的操作的,但是在返回結(jié)果里,會(huì)告訴你異常日志
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會(huì)加載到內(nèi)存里,如果太大的話,性能反而會(huì)下降,因此需要反復(fù)嘗試一個(gè)最佳的bulk size。一般從1000~5000條數(shù)據(jù)開始,嘗試逐漸增加。另外,如果看大小的話,最好是在5~15MB之間


(1)_version元數(shù)據(jù)
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
}
第一次創(chuàng)建一個(gè)document的時(shí)候,它的_version內(nèi)部版本號(hào)就是1;以后,每次對(duì)這個(gè)document執(zhí)行修改或者刪除操作,都會(huì)對(duì)這個(gè)_version版本號(hào)自動(dòng)加1;哪怕是刪除,也會(huì)對(duì)這條數(shù)據(jù)的版本號(hào)加1
{
"found": true,
"_index": "test_index",
"_type": "test_type",
"_id": "6",
"_version": 4,
"result": "deleted",
"_shards": {
"total": 2,
"successful": 1,
"failed": 0
}
}會(huì)發(fā)現(xiàn),在刪除一個(gè)document之后,可以從一個(gè)側(cè)面證明,它不是立即物理刪除掉的,因?yàn)樗囊恍┌姹咎?hào)等信息還是保留著的。先刪除一條document,再重新創(chuàng)建這條document,其實(shí)會(huì)在delete version基礎(chǔ)之上,再把version號(hào)加1

es提供了一個(gè)feature,就是說,你可以不用它提供的內(nèi)部_version版本號(hào)來進(jìn)行并發(fā)控制,可以基于你自己維護(hù)的一個(gè)版本號(hào)來進(jìn)行并發(fā)控制。舉個(gè)列子,加入你的數(shù)據(jù)在mysql里也有一份,然后你的應(yīng)用系統(tǒng)本身就維護(hù)了一個(gè)版本號(hào),無論是什么自己生成的,程序控制的。這個(gè)時(shí)候,你進(jìn)行樂觀鎖并發(fā)控制的時(shí)候,可能并不是想要用es內(nèi)部的_version來進(jìn)行控制,而是用你自己維護(hù)的那個(gè)version來進(jìn)行控制。
什么是partial update?
PUT /index/type/id,創(chuàng)建文檔&替換文檔,就是一樣的語法
一般對(duì)應(yīng)到應(yīng)用程序中,每次的執(zhí)行流程基本是這樣的:
(1)應(yīng)用程序先發(fā)起一個(gè)get請(qǐng)求,獲取到document,展示到前臺(tái)界面,供用戶查看和修改
(2)用戶在前臺(tái)界面修改數(shù)據(jù),發(fā)送到后臺(tái)
(3)后臺(tái)代碼,會(huì)將用戶修改的數(shù)據(jù)在內(nèi)存中進(jìn)行執(zhí)行,然后封裝好修改后的全量數(shù)據(jù)
(4)然后發(fā)送PUT請(qǐng)求,到es中,進(jìn)行全量替換
(5)es將老的document標(biāo)記為deleted,然后重新創(chuàng)建一個(gè)新的document
partial update
post /index/type/id/_update
{
"doc": {
"要修改的少數(shù)幾個(gè)field即可,不需要全量的數(shù)據(jù)"
}
}
看起來,好像就比較方便了,每次就傳遞少數(shù)幾個(gè)發(fā)生修改的field即可,不需要將全量的document數(shù)據(jù)發(fā)送過去
圖解partial update實(shí)現(xiàn)原理以及其優(yōu)點(diǎn)

Partial update相比全量請(qǐng)求的優(yōu)缺點(diǎn):
所有的查詢、修改和寫回操作,都發(fā)生在es中的一個(gè)shard內(nèi)部,避免了所有的網(wǎng)絡(luò)數(shù)據(jù)傳輸?shù)拈_銷(如果全量請(qǐng)求的話,會(huì)從es中找一批數(shù)據(jù)放回Java應(yīng)用中,然后Java應(yīng)用修改,傳回es中修改請(qǐng)求,這就是兩次網(wǎng)絡(luò)開銷,而partial update只在一個(gè)shard中操作所有)
7.1.document數(shù)據(jù)路由原理(shard為什么不可變)
(1)document路由到shard上是什么意思?
(2)路由算法:shard = hash(routing) % number_of_primary_shards
舉個(gè)例子,一個(gè)index有3個(gè)primary shard,P0,P1,P2
每次增刪改查一個(gè)document的時(shí)候,都會(huì)帶過來一個(gè)routing number,默認(rèn)就是這個(gè)document的_id(可能是手動(dòng)指定,也可能是自動(dòng)生成)
routing = _id,假設(shè)_id=1
會(huì)將這個(gè)routing值,傳入一個(gè)hash函數(shù)中,產(chǎn)出一個(gè)routing值的hash值,hash(routing) = 21
然后將hash函數(shù)產(chǎn)出的值對(duì)這個(gè)index的primary shard的數(shù)量求余數(shù),21 % 3 = 0
就決定了,這個(gè)document就放在P0上。
決定一個(gè)document在哪個(gè)shard上,最重要的一個(gè)值就是routing值,默認(rèn)是_id,也可以手動(dòng)指定,相同的routing值,每次過來,從hash函數(shù)中,產(chǎn)出的hash值一定是相同的
無論hash值是幾,無論是什么數(shù)字,對(duì)number_of_primary_shards求余數(shù),結(jié)果一定是在0~number_of_primary_shards-1之間這個(gè)范圍內(nèi)的。0,1,2。
(3)_id or custom routing value
默認(rèn)的routing就是_id
也可以在發(fā)送請(qǐng)求的時(shí)候,手動(dòng)指定一個(gè)routing value,比如說put /index/type/id?routing=user_id
手動(dòng)指定routing value是很有用的,可以保證說,某一類document一定被路由到一個(gè)shard上去,那么在后續(xù)進(jìn)行應(yīng)用級(jí)別的負(fù)載均衡,以及提升批量讀取的性能的時(shí)候,是很有幫助的
(4)primary shard數(shù)量不可變的謎底
7.2.es增刪改內(nèi)部原理
(1)客戶端選擇一個(gè)node發(fā)送請(qǐng)求過去,這個(gè)node就是coordinating node(協(xié)調(diào)節(jié)點(diǎn))
(2)coordinating node,對(duì)document進(jìn)行路由,將請(qǐng)求轉(zhuǎn)發(fā)給對(duì)應(yīng)的node(有primary shard)
(3)實(shí)際的node上的primary shard處理請(qǐng)求,然后將數(shù)據(jù)同步到replica node
(4)coordinating node,如果發(fā)現(xiàn)primary node和所有replica node都搞定之后,就返回響應(yīng)結(jié)果給客戶端
7.3.寫一致性原理以及quorum機(jī)制
(1)consistency,one(primary shard),all(all shard),quorum(default)
我們?cè)诎l(fā)送任何一個(gè)增刪改操作的時(shí)候,比如說put /index/type/id,都可以帶上一個(gè)consistency參數(shù),指明我們想要的寫一致性是什么?
put /index/type/id?consistency=quorum
one:要求我們這個(gè)寫操作,只要有一個(gè)primary shard是active活躍可用的,就可以執(zhí)行
all:要求我們這個(gè)寫操作,必須所有的primary shard和replica shard都是活躍的,才可以執(zhí)行這個(gè)寫操作
quorum:默認(rèn)的值,要求所有的shard中,必須是大部分的shard都是活躍的,可用的,才可以執(zhí)行這個(gè)寫操作
(2)quorum機(jī)制,寫之前必須確保大多數(shù)shard都可用,int( (primary + number_of_replicas) / 2 ) + 1,當(dāng)number_of_replicas>1時(shí)才生效
quroum = int( (primary + number_of_replicas) / 2 ) + 1
舉個(gè)例子,3個(gè)primary shard,number_of_replicas=1,總共有3 + 3 * 1 = 6個(gè)shard
quorum = int( (3 + 1) / 2 ) + 1 = 3
所以,要求6個(gè)shard中至少有3個(gè)shard是active狀態(tài)的,才可以執(zhí)行這個(gè)寫操作
(3)如果節(jié)點(diǎn)數(shù)少于quorum數(shù)量,可能導(dǎo)致quorum不齊全,進(jìn)而導(dǎo)致無法執(zhí)行任何寫操作
3個(gè)primary shard,replica=1,要求至少3個(gè)shard是active,3個(gè)shard按照之前學(xué)習(xí)的shard&replica機(jī)制,必須在不同的節(jié)點(diǎn)上,如果說只有2臺(tái)機(jī)器的話,是不是有可能出現(xiàn)說,3個(gè)shard都沒法分配齊全,此時(shí)就可能會(huì)出現(xiàn)寫操作無法執(zhí)行的情況
es提供了一種特殊的處理場(chǎng)景,就是說當(dāng)number_of_replicas>1時(shí)才生效,因?yàn)榧偃缯f,你就一個(gè)primary shard,replica=1,此時(shí)就2個(gè)shard
(1 + 1 / 2) + 1 = 2,要求必須有2個(gè)shard是活躍的,但是可能就1個(gè)node,此時(shí)就1個(gè)shard是活躍的,如果你不特殊處理的話,導(dǎo)致我們的單節(jié)點(diǎn)集群就無法工作
(4)quorum不齊全時(shí),wait,默認(rèn)1分鐘,timeout,100,30s
等待期間,期望活躍的shard數(shù)量可以增加,最后實(shí)在不行,就會(huì)timeout
我們其實(shí)可以在寫操作的時(shí)候,加一個(gè)timeout參數(shù),比如說put /index/type/id?timeout=30,這個(gè)就是說自己去設(shè)定quorum不齊全的時(shí)候,es的timeout時(shí)長(zhǎng),可以縮短,也可以增長(zhǎng)
7.4.es查詢內(nèi)部原理
1、客戶端發(fā)送請(qǐng)求到任意一個(gè)node,成為coordinate node
2、coordinate node對(duì)document進(jìn)行路由,將請(qǐng)求轉(zhuǎn)發(fā)到對(duì)應(yīng)的node,此時(shí)會(huì)使用round-robin隨機(jī)輪詢算法,在primary shard以及其所有replica中隨機(jī)選擇一個(gè),讓讀請(qǐng)求負(fù)載均衡
3、接收請(qǐng)求的node返回document給coordinate node
4、coordinate node返回document給客戶端
5、特殊情況:document如果還在建立索引過程中,可能只有primary shard有,任何一個(gè)replica shard都沒有,此時(shí)可能會(huì)導(dǎo)致無法讀取到document,但是document完成索引建立之后,primary shard和replica shard就都有了
7.5.json格式
bulk api奇特的json格式
{"action": {"meta"}}
{"data"}
{"action": {"meta"}}
{"data"}
[{
"action": {
},
"data": {
}
}]
1、bulk中的每個(gè)操作都可能要轉(zhuǎn)發(fā)到不同的node的shard去執(zhí)行
2、如果采用比較良好的json數(shù)組格式
允許任意的換行,整個(gè)可讀性非常棒,讀起來很爽,es拿到那種標(biāo)準(zhǔn)格式的json串以后,要按照下述流程去進(jìn)行處理
(1)將json數(shù)組解析為JSONArray對(duì)象,這個(gè)時(shí)候,整個(gè)數(shù)據(jù),就會(huì)在內(nèi)存中出現(xiàn)一份一模一樣的拷貝,一份數(shù)據(jù)是json文本,一份數(shù)據(jù)是JSONArray對(duì)象
(2)解析json數(shù)組里的每個(gè)json,對(duì)每個(gè)請(qǐng)求中的document進(jìn)行路由
(3)為路由到同一個(gè)shard上的多個(gè)請(qǐng)求,創(chuàng)建一個(gè)請(qǐng)求數(shù)組
(4)將這個(gè)請(qǐng)求數(shù)組序列化
(5)將序列化后的請(qǐng)求數(shù)組發(fā)送到對(duì)應(yīng)的節(jié)點(diǎn)上去
3、耗費(fèi)更多內(nèi)存,更多的jvm gc開銷
我們之前提到過bulk size最佳大小的那個(gè)問題,一般建議說在幾千條那樣,然后大小在10MB左右,所以說,可怕的事情來了。假設(shè)說現(xiàn)在100個(gè)bulk請(qǐng)求發(fā)送到了一個(gè)節(jié)點(diǎn)上去,然后每個(gè)請(qǐng)求是10MB,100個(gè)請(qǐng)求,就是1000MB = 1GB,然后每個(gè)請(qǐng)求的json都copy一份為jsonarray對(duì)象,此時(shí)內(nèi)存中的占用就會(huì)翻倍,就會(huì)占用2GB的內(nèi)存,甚至還不止。因?yàn)榕蒵sonarray之后,還可能會(huì)多搞一些其他的數(shù)據(jù)結(jié)構(gòu),2GB+的內(nèi)存占用。
占用更多的內(nèi)存可能就會(huì)積壓其他請(qǐng)求的內(nèi)存使用量,比如說最重要的搜索請(qǐng)求,分析請(qǐng)求,等等,此時(shí)就可能會(huì)導(dǎo)致其他請(qǐng)求的性能急速下降
另外的話,占用內(nèi)存更多,就會(huì)導(dǎo)致java虛擬機(jī)的垃圾回收次數(shù)更多,跟頻繁,每次要回收的垃圾對(duì)象更多,耗費(fèi)的時(shí)間更多,導(dǎo)致es的java虛擬機(jī)停止工作線程的時(shí)間更多
4、現(xiàn)在的奇特格式
{"action": {"meta"}}
{"data"}
{"action": {"meta"}}
{"data"}
(1)不用將其轉(zhuǎn)換為json對(duì)象,不會(huì)出現(xiàn)內(nèi)存中的相同數(shù)據(jù)的拷貝,直接按照換行符切割json
(2)對(duì)每?jī)蓚€(gè)一組的json,讀取meta,進(jìn)行document路由
(3)直接將對(duì)應(yīng)的json發(fā)送到node上去
5、大的優(yōu)勢(shì)在于,不需要將json數(shù)組解析為一個(gè)JSONArray對(duì)象,形成一份大數(shù)據(jù)的拷貝,浪費(fèi)內(nèi)存空間,盡可能地保證性能
另外有需要云服務(wù)器可以了解下創(chuàng)新互聯(lián)scvps.cn,海內(nèi)外云服務(wù)器15元起步,三天無理由+7*72小時(shí)售后在線,公司持有idc許可證,提供“云服務(wù)器、裸金屬服務(wù)器、高防服務(wù)器、香港服務(wù)器、美國(guó)服務(wù)器、虛擬主機(jī)、免備案服務(wù)器”等云主機(jī)租用服務(wù)以及企業(yè)上云的綜合解決方案,具有“安全穩(wěn)定、簡(jiǎn)單易用、服務(wù)可用性高、性價(jià)比高”等特點(diǎn)與優(yōu)勢(shì),專為企業(yè)上云打造定制,能夠滿足用戶豐富、多元化的應(yīng)用場(chǎng)景需求。
網(wǎng)站欄目:ElasticSearch基本原理和分布式文件系統(tǒng)-創(chuàng)新互聯(lián)
當(dāng)前路徑:http://www.chinadenli.net/article16/docddg.html
成都網(wǎng)站建設(shè)公司_創(chuàng)新互聯(lián),為您提供定制開發(fā)、動(dòng)態(tài)網(wǎng)站、搜索引擎優(yōu)化、網(wǎng)站建設(shè)、服務(wù)器托管、網(wǎng)站排名
聲明:本網(wǎng)站發(fā)布的內(nèi)容(圖片、視頻和文字)以用戶投稿、用戶轉(zhuǎn)載內(nèi)容為主,如果涉及侵權(quán)請(qǐng)盡快告知,我們將會(huì)在第一時(shí)間刪除。文章觀點(diǎn)不代表本網(wǎng)站立場(chǎng),如需處理請(qǐng)聯(lián)系客服。電話:028-86922220;郵箱:631063699@qq.com。內(nèi)容未經(jīng)允許不得轉(zhuǎn)載,或轉(zhuǎn)載時(shí)需注明來源: 創(chuàng)新互聯(lián)
猜你還喜歡下面的內(nèi)容