目录
1、什么是distributed document store(分布式文档存储)
(3)_id or custom routing value(手动指定routing value)
(1)consistency:one(primary shard),all(all shard),quorum(default)
(3)如果节点数少于quorum数量,可能导致quorum不齐全,进而导致无法执行任何写操作
(4)quorum不齐全时,wait,默认1分钟,timeout(默认毫秒),100,30s
1、什么是distributed document store(分布式文档存储)
Elasticsearch在跑起来以后,其实起到的第一个最核心的功能,就是一个分布式的文档数据存储系统。ES是分布式的。文档数据存储系统。文档数据,存储系统。
文档数据:es可以存储和操作json文档类型的数据,而且这也是es的核心数据结构。
存储系统:es可以对json文档类型的数据进行存储,查询,创建,更新,删除,等等操作。其实已经起到了一个什么样的效果呢?其实ES满足了这些功能,就可以说已经是一个NoSQL的存储系统了。
2、图解剖析document数据路由原理
(1)document路由到shard上是什么意思?
一个index的数据会被分为多片,每片都在一个shard中。所以说,一个document,只能存在于一个shard中。当客户端创建document时,es此时就需要决定说,这个document是放在这个index的哪个shard上。这个过程就称之为document routing,数据路由
(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,也可以手动指定,
a、相同的routing值,每次过来,从hash函数中,产出的hash值一定是相同的
b、无论hash值是几,无论是什么数字,对number_of_primary_shards求余数,结果一定是在0~number_of_primary_shards-1之间这个范围内的。
(3)_id or custom routing value(手动指定routing value)
默认的routing就是_id,也可以在发送请求的时候,手动指定一个routing value,比如说put /index/type/id?routing=user_id
手动指定routing value是很有用的,可以保证说,某一类document一定被路由到一个shard上去,那么在后续进行应用级别的负载均衡,以及提升批量读取的性能的时候,是很有帮助的
(4)primary shard数量不可变的谜底
假设有3个primary shard,P0、P1、P2,创建一个document,假设_id=1,hash=21,数据路由:21%3=0,这个document放在P0上,现在增加一个primary shard,执行GET /index/type/1,获取这个document,现在路由这个document在哪个shard上,此时 _id=1,hash=21,21%4=1,会去P1上找,结果没有找到,就会间接导致数据丢失。所以primary shard一旦index建立,是不允许修改的,但replica shard可以随时修改
3、图解剖析document增删改内部实现原理
(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都搞定之后,就返回响应结果给客户端
4、图解写一致性原理以及quorum机制深入剖析
(1)consistency:one(primary shard),all(all shard),quorum(default)
我们在发送任何一个增删改操作的时候,比如说put /index/type/id,都可以带上一个consistency参数,指明我们想要的写一致性是什么?例如:put /index/type/id?consistency=quorum
a、one:要求我们这个写操作,只要有一个primary shard是active活跃可用的,就可以执行
b、all:要求我们这个写操作,必须所有的primary shard和replica shard都是活跃的,才可以执行这个写操作
c、quorum:默认的值,要求所有的shard中,必须是大部分的shard都是活跃的,可用的,才可以执行这个写操作(例如如果shard总共有3个primary,和replica=1的话,那么总共要求有3个shard是活跃的,才可以执行写操作)
(2)quorum机制,写之前必须确保大多数shard都可用,int( (primary + number_of_replicas) / 2 ) + 1,当number_of_replicas>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是活跃的,如果你不特殊处理的话,导致我们的单节点集群就无法工作。
假设1个primary shard,replica=3,quorum=((1+3)/2)+1=3,要求1个primary shard + 3个replica shard = 4个shard,其中必须有3个shard要处于active状态,如果这个时候只有2台机器的话,会出现什么情况呢?
(4)quorum不齐全时,wait,默认1分钟,timeout(默认毫秒),100,30s
等待期间,期望活跃的shard数量可以增加,最后实在不行,就会timeout
我们其实可以在写操作的时候,加一个timeout参数,比如说put /index/type/id?timeout=30,这个就是说自己去设定quorum不齐全的时候,es的timeout时长,可以缩短,也可以增长
5、document查询内部原理
(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就都有了
6、bulk api的奇特json格式与底层性能优化关系
{"action": {"meta"}}\n
{"data"}\n
{"action": {"meta"}}\n
{"data"}\n
(1)如果采用比较良好的json数组格式,缺点
允许任意的换行,整个可读性非常棒,es拿到那种标准格式的json串以后,要按照下述流程去进行处理
a、将json数组解析为JSONArray对象,这个时候,整个数据,就会在内存中出现一份一模一样的拷贝,一份数据是json文本,一份数据是JSONArray对象
b、解析json数组里的每个json,对每个请求中的document进行路由
c、为路由到同一个shard上的多个请求,创建一个请求数组
d、将这个请求数组序列化
e、将序列化后的请求数组发送到对应的节点上去
缺点:耗费更多内存,更多的jvm gc开销
我们之前提到过bulk size最佳大小的那个问题,一般建议说在几千条那样,然后大小在10MB左右,所以说,可怕的事情来了。假设说现在100个bulk请求发送到了一个节点上去,然后每个请求是10MB,100个请求,就是1000MB = 1GB,然后每个请求的json都copy一份为jsonarray对象,此时内存中的占用就会翻倍,就会占用2GB的内存,甚至还不止。因为弄成jsonarray之后,还可能会多搞一些其他的数据结构,2GB+的内存占用。
占用更多的内存可能就会积压其他请求的内存使用量,比如说最重要的搜索请求,分析请求,等等,此时就可能会导致其他请求的性能急速下降
另外的话,占用内存更多,就会导致java虚拟机的垃圾回收次数更多,更频繁,每次要回收的垃圾对象更多,耗费的时间更多,导致es的java虚拟机停止工作线程的时间更多
(2)现在的奇特格式优点
(1)不用将其转换为json对象,不会出现内存中的相同数据的拷贝,直接按照换行符切割json
(2)对每两个一组的json,读取meta,进行document路由
(3)直接将对应的json发送到node上去
最大的优势在于,不需要将json数组解析为一个JSONArray对象,形成一份大数据的拷贝,浪费内存空间,尽可能地保证性能