Elasticsearch基础知识补齐

Elasticsearch基础知识补齐

前面的一些学习笔记都是简单记录了一下 CURDMapping, 这篇博文就记录一下 Es 的一些基础知识

分片的管理

主副分片

文档的数据是存储到索引中的,而索引的数据是存储在分片上的,而分片是位于节点上的。

分片 shard 有主分片 primary shard 和复制分片 replica shard 两种,其中主分片是主要存储的分片,可以进行读写操作;副本分片是主分片的备份,可以进行读操作不支持写操作
查询可以在主分片或副本分片上进行查询,这样可以提供查询效率。但数据的修改只发生在主分片上

分片是面向索引的,分片上的数据属于同一个索引,在我们创建索引的时候,可以指定主分片和副本分片的数量,默认是5个主分片5个副本分片
索引的replica shard的数量可以修改,但primary shard的数量不可以修改。一个Primary Shard可以有多个Replica Shard,默认创建是1个。

为了保证数据的不丢失,通常来说Replica Shard不能与其对应的Primary Shard处于同一个节点中。因为万一这个节点损坏了,那么存储在这个节点上的原数据(primary shard)和备份数据(replica shard)就全部丢失了,但是可以和其他primary shardreplica shard放在一起

replica shardprimary shard的副本分片,负责承载一定的读请求,当primary shard都挂掉后,其中一个replica shard会变成primary shard来维持写功能。

分片的均衡分配

分片是分配到节点上的,但它会默认地均衡分配。

所谓均衡分配,以情况举例:priX代表主分片,repX代表副本分片

  1. 索引有1个priA,1个repA,但当前只有一个节点A,那么priA分配到A节点repA没有分配。优先分配主分片。
  2. 索引有1个priA,1个repA,当前有两个节点A和B,那么priA分配到A节点repA分配到B节点priA分配到B节点也有可能)。
  3. 索引当前有2个priA,4个repA,有3个节点,那么现在每台节点上有两个分片(但要考虑主分片不能与自己的副本分片同在一个节点上,在下面的主副分片的排斥中由一个例子)。

当后续新增节点的时候,会自动再次重新均衡分配。

主副分片的排斥

考虑到备份的安全性,不应该让主分片和副本分片位于一个节点上,不然可能完全丢失数据。(比如你为了避免丢失钥匙,你给你家的门准备两条钥匙,你有一个钱包和一个背包,结果你把两条钥匙都放到钱包中,某天你钱包丢了,于是你回不了家了。所以你应该把钥匙分开放。)

对应的排斥情况就是:

  1. 索引有1个priA,1个repA,但当前只有一个节点A,那么priA分配到A节点;repA没有分配。
  2. 索引有1个priA,1个repA,当前有两个节点A和B,那么priA分配到A节点;repA分配到B节点(priA分配到B节点也有可能)。

请注意,主分片与副本分片不能在一起,但副本分片和副本分片能存放在一起

  • 下面再举个例子

你有一个索引,索引有2个主分片,4个副本分片每个主分片对应两个副本分片,3个节点

主分片1名Pir1,他的两个副本分片是 Rep1Rep2
主分片2名Pir2,他的两个副本分片是 Rep3Rep4

那么综合考虑了均衡分配和主副分片的互斥之后,可能有以下结果

es/fen-pian-.png

容错性

节点是有可能宕机的,宕机后,那么这个节点的数据起码会暂时性的丢失,那么对于不同情况下,最多可以宕机多少个节点呢?下面举例:pri = x代表主分片数量为X,rep是副本分片

  1. 如果你只有一个节点,那么容错性为0,你不能宕机,宕机不完全意味着数据完全丢失,但暂停服务还是有的。
  2. 如果你有两个节点,pri = 2,rep = 2,那么此时分片分配应该是 [P1R2, P2R1] ,此时容错性为一个,因为某个节点上有完整的两个分片的数据 此处一提,假设丢失了P2R1,那么R1R2中的R2会升级成primary shard来保持写功能
  3. 我们可以综合均衡分片和排斥性来考虑我们需要的节点数、主分片和副本分片数量。

数据路由

每一个 document 会存储到唯一的一个 primary shared 和其副本分片 replica shard 中,我们是怎么根据 ID 来知道这个 document 存储在哪个分片的呢?
ElasticSearch 会自动根据 documentid 值来进行计算,最终得出一个小于分片数量的数值,这个数值就是分片在 ElasticSearch 中的序号,最终得出应该存储到哪个分片上。

类似原理举例,假设我现在有4个主分片,那么我给它们标序号0,1,2,3。现在进来一个ID为15的数据,我经过一系列计算之后,15入参之后假设得到243这个数值,然后我们使用243来对4求余,余数是3,所以就把这个数据放在序号为3的分片上。

依据这个原理,存储数据的时候就知道把数据放在哪个分片上;读取数据的时候也知道从哪个分片上读取数据。

稍微提一下,在 ElasticSearch 全文搜索完成之后,此时内部得到的是 ID 组成的数组,内部再会根据 ID 来查找数据

集群

首先,每一个 ElasticSearch 服务端就是一个集群节点,当我们启动一个 elasticsearch 时,就相当于启动了一个集群节点。

那么,多个节点之间如何建立联系呢?发现机制

当我们启动一个节点的时候,这个节点会自动创建一个集群,集群的名称默认为 elasticsearch(也可以在config/elasticsearch.yml配置cluster.name),当我们再次启动一个节点的时候,它首先会尝试寻找名称为 elasticsearch 的集群,然后加入其中,(所有的都是先尝试寻找,没有再自己创建),当节点加入到集群中后,这个集群就算是建立起来了。

健康状态

当集群建立后,我们可以使用 API 来查看集群状态

es/es-cluster-status.png

返回结果解析:

  • epoch 时间戳
  • timestamp 时间
  • cluster 集群名
  • status 状态集群状态解析看下面。
  • node.total 集群中的节点数
  • node.data 集群中的数据节点数
  • shards 集群中总的分片数量
  • pri 主分片数量
  • relo 副本分片数量
  • init 初始化中的分片数
  • unassign 没有被分配的分片的数量
  • pending_tasks 待处理的任务数
  • max_task_wait_time 最大任务等待时间
  • activeds_percent active的分片数量

集群状态解析 yellow\red\green

集群状态受当前的 primary sharedreplica shared 的数量影响。
当每个索引的 primary sharedreplica shared 都是 active 的时候,状态为 green ;什么是 activeshard 是位于节点上的,一个 shard 被分配到了运行的节点上,那么此时就是 active 的,如果 shard 没有分配到节点上,那么就是 inactive

当每个索引的 primary shared 都是 active 的,但 replica shared 不完全是 active 的时候,状态为 yellow ;
当每个索引的 primary shared 不完全是 active 的时候,此时发生了数据丢失,状态为 red.

  • 举个例子

当前节点中只有一个索引A,索引A当前有2个priA,4个repA,那么此时需要两个节点才可以变green
一个的时候就不说了,此时所有副本分片都inactive;两个节点的时候,由于每个主分片有两个副本分片,此时的分配是一个主分片+两个副本分片注意互斥性

为什么现在是yellow?

当我们第一次启动的时候,因为我启动了 kibana, kibana 会默认为我们创建一个名为 kibana 的索引,这个索引的 primary shardreplica shard 都为1,由于此时只有一个节点,所以会优先分配 primary shard ,而忽略replica shard(不要忘了基于备份的安全性的 shard 排斥考虑:主分片和副本分片不能位于同一个节点上),所以此时就符合了每个索引的primary shared都是active的,但replica shared不全是active,所以此时是 yellow.
你可以尝试启动多一个elasticsearch节点来调整状态。

请求的处理

提供服务

节点是提供服务的单位,请求是发到节点上的。节点接收到请求后,会对请求进行处理:

  • 读请求:

当接受读请求,如果是根据ID来获取数据的读请求,那么它会选择有这个ID的数据的分片来获取数据(可以根据ID来判断该分片上是否有这份数据);如果是搜索类的请求,首先会根据索引表来搜索,得出相关文档的ID,然后根据ID从这个索引的相关分片来获取数据(如果有2个pri,2个rep,那么搜索的分片可能是p1r2p2r1p1p2,r1r2,只要能完整地获取索引的所有数据即可)。

  • 写请求:

当接收写请求,节点会选择根据ID来计算应该把这个数据存储到哪个主分片上,然后通过主分片来修改数据,主分片修改完成后,会将数据同步到副本分片上。由于存在一个同步过程,同步完成之前,某个分片上可能不存在刚刚插入的数据,但概率较小,因为同步是极快的(NRT)

再次提醒,主分片有读和写的能力,副本分片只可以读,所以数据的更新都发生在主分片上

协调节点cordination node

索引的数据是存储在节点上的,当一个请求发到节点上的时候,可能这个节点上并没有这个索引的数据,那么这个时候就需要把请求转发给另一个节点了,这时候原本的节点就是一个协调节点

请求分发的负载均衡

一个索引存储在多个主分片和副本分片上,索引的数据会平均分配到每一个主分片中,然后每一个副本分片拷贝对应主分片的数据。
对于数据存储,数据是存储在分片上的,而分片位于节点上,在上面说了分片会均衡分配到每一个节点上,这样也保证了节点上的数据量是平均的。

除此之外,对于读取某一个主分片及其副本分片上的数据的时候,会使用轮询算法来将读请求平均分配(大概意思就是,假设现在对于主分片1有三个副本分片,那么总数为4,假设分别编号1、2、3、4,那么可能地,第一次请求交给了1,那么第二次请求要交给2,第三次要交给3。。。以此类推,超过4则从头开始)。

文档的数据类型

ElasticSearch 主要有以下这几种数据类型:

  • 字符类:
text:是存储字符串的类型,在 elasticsearch 中存储会分词的字符串数据一般用text
keyword:也是存储字符串的类型,在elasticsearch中用于存储不会分词的、结构化的字符串数据
  • 整数类型:integerlongshortbyte
  • 浮点数类型:doublefloat
  • 日期类型:date
  • 布尔类型:boolean
  • 数组类型:array
  • 对象类型:object

除了上述的类型之外,还有一些例如half_floatscaled_floatbinaryip等等类型,由于不是非常基础的内容,所以这里不讲,有兴趣的可以自查。

keyword

  • 我们定义mapping的时候有定义一个keyword,这是什么?有什么用?

ElasticSearch对于一些类型的字段,例如text类型的字段,默认是会进行分词的。但如果我们并不想分词呢?一些数据我们想要非常精确地查找,并且只找到我们搜索的数据的时候,这个字段是不应该分词的。那么我们可以使用keyword来存储完整的原有的数据,keyword会作为一个索引词,然后我们针对字段.keyword来搜索。

理论上,这个不分词的字段的数据应该是比较简短的,太长的话可能就没有必要不分词了。所以在定义keyword的时候还可以提供"ignore_above": 数值来限制超过多少个字符就不使用原有数据创建keyword
现在版本中,对于默认分词的字段,现在会默认附加一个keyword

keyword适用于不分词的搜索的情况,在keyword中的数据不会分词。

您的支持是对我最大的鼓励!

发表于: 作者:憧憬。
关注互联网以及分享全栈工作经验的原创个人博客和技术博客,热爱编程,极客精神
Github 新浪微博 SegmentFault 掘金专栏