Elasticsearch系列---补充几个知识点

概要

bulk api有趣的json格式

前面《简单入门实战》一节中,有介绍bulk的使用示例,你们必定很奇怪,还有这么有趣的JSON格式,必须严格照他的换行来作,我想把JSON搞得美观可读性好一点,竟然给我报错!java

{"action": {"meta"}}\n
{"data"}\n
{"action": {"meta"}}\n
{"data"}\n

它为何要这样规定?node

咱们想一想bulk设计的初衷,批处理的执行效率确定是第一优先级,此时效率>可读性,若是咱们容许随意换行,用标准格式的JSON串,会有什么区别?算法

若是是标准格式的JSON串,处理流程通常会是这样:json

  1. 将整个json数组所有加载,解析为JSONArray对象,这时内存中同时有json串文本和JSONArray对象。
  2. 循环遍历JSONArray对象,获取每一个请求中的document进行路由信息。
  3. 把路由到同一个shard的请求合在一组,开辟一个新的请求数组,将JSONObject放在数组里。
  4. 序列化请求数组,发送到对应的节点上去。
  5. 收集各节点的响应,汇总后返回给Coordinate Node。
  6. Coordinate Node收到全部的汇总信息,返回给客户端。

这种方式惟一的缺点就是占用内存多,一份json串,解析为JSONArray对象,内存占用翻番,bulk里面多则几千条请求,若是JSON报文大一点,这内存耗费不是开玩笑的,若是bulk占用的内存过多,就可能会挤压其余请求的内存使用量,如搜索请求、数据分析请求等,总体性能会急速降低,严重的状况可能会触发Full GC,会致使整个JVM工做线程暂停。segmentfault

再看看现有的格式定义:除了delete操做占一行,其余操做都是占两行的,ES收到bulk请求时,就能够简单的按行进行切割,也不用转成json对象了,切割完的JSON读取里面的meta信息,直接路由到相应的shard,收集完响应返回便可。
这样的好处切割逻辑更简单,都是处理小json字符串,内存快拿快放,整个ES避免对内存的大块占用,尽量保证性能。api

增删改文档内部原理

增删改的过程总体与查询文档过程一致,只是多了一个数据同步的步骤,整个过程如图所示:数组

增删改过程图示

类似的步骤不赘述。
步骤3的前提是primary shard操做成功,异步请求,全部的replica都返回成功后,node2响应操做成功的消息给Coordinate Node,最后Coordinate Node向客户端返回成功消息,此时全部的primary shard和replica shard均已完成数据同步,数据是一致的。架构

查询文档内部原理

当咱们使用客户端(Java或Restful API)向Elasticsearch搜索文档数据时,能够向任意一个node发送请求,此时接受请求的node就是Coordinate Node,整个过程如图所示:并发

查询过程图示

  1. Coordinate Node接收到请求后,根据_id信息或routing信息,肯定该document的路由信息,即在哪一个shard里,好比说P0。
  2. Coordinate Node转发请求,使用round-robin随机轮询算法 ,在primary shard或replica shard随机挑一个,让读请求负载均衡,如node-3的R0-1
  3. 接收请求的node-3搜索完成后,响应结果给Coordinate Node。
  4. Coordinate Node将响应结果返回给客户端。

注意一个问题,若是document还在创建索引过程当中,可能只有primary shard有,任何一个replica shard都没有,此时可能会没法读取到document,可是等document完成索引创建后,primary shard和replica shard就都有了,这个时间间隔,大概1秒左右。负载均衡

写一致性要求

Elasticsearch在尝试执行一个写操做时,能够带上consistency参数,声明咱们的写一致性的级别,正确地使用这个级别,为了不因分区故障执行写操做,致使数据不一致,这个参数有三个值供选择:

  • one:只要有一个primary shard是active活跃可用的,就能够执行写操做
  • all:必须全部的primary shard和replica shard都是活跃的,才能够执行这个写操做
  • quorum:默认的值,要求全部的shard中,必须是大部分的shard都是活跃的,可用的,才能够执行这个写操做
这个大部分,该怎么算呢?

这个大部分,叫规定数量(quorum),有个计算公式:

int( (primary + number_of_replicas) / 2 ) + 1

  • primary 即一个索引下的primary shard数量;
  • number_of_replicas即每一个primary shard拥有的副本数量,注意不是一个索引全部的副本数量。

若是一个索引有3个primary shard,每一个shard拥有1个replica shard,共6个shard,这样number_of_replicas就是1,代入公式计算:
quorum = int ((3 + 1) / 2) + 1 = 3

因此6个shard中必须有3个是活跃的,才让你写,若是你只启用2个node,这样活跃的replica shard只会有1个,加上primarys shard ,结果最可能是2。这样是达不到quorun的值,所以将没法索引和删除任何文档。
此时你必须启动3个节点,才能知足quorum写一致性的要求。

quorum不够时的超时处理

若是写操做检查前,活跃的shard不够致使没法写入时,Elasticsearch会等待,但愿宕机的node可以恢复,默认60秒,可使用timeout参数修改默认值。

单node的写一致性

照上面的公式算,1个node的,1个索引1个primary shard,number_of_replicas为1的状况,计算公式:

quorum = int ((1 + 1) / 2) + 1 = 2

实际只有一个primary shard是活跃的,岂不是永远没法写入?我研发机器只启动一个node,不照样增删改查?

原来是Elasticsearch为了不单一node的没法写入问题,加了判断逻辑:只有number_of_replicas大于1的时候,quorum才会生效。

小结

本篇从性能优先的角度简单对bulk的设计做了一些补充,并对文档查询,写操做的原理过程,一致性级别,quorum的计算作了一些简单讲解,谢谢。

专一Java高并发、分布式架构,更多技术干货分享与心得,请关注公众号:Java架构社区
Java架构社区.jpg

相关文章
相关标签/搜索