定义

”一个便于检索的数据库“

基于 Lucene 的开源搜索引擎,分布式、可扩展、每个字段都能被索引。

能做什么?

  • 海量搜索
  • NoSQL 数据库
  • 对海量数据进行进实时的处理
  • 日志数据分析,ELK 技术,ES 进行复杂的数据分析

架构设计

设计目标:为了更好的写入(索引)和查询(搜索)

自底向上:

  1. 网关,es 索引的持久化存储方式
  2. Lucene,为 es 提供 api 工具包
  3. 索引模块,搜索模块,字段映射,river 数据同步
  4. 自动发现,es 的自动发现节点机制
  5. 通信层,es 和客户端的交互方式
  6. Restful api,封装的一些 crud 操作
Restful api

对于向 es 插入数据、检索数据、删除数据等操作,es 提供了 Java api 和 RESTful api 两种方式来与之通信。

transport

通信模块,节点间数据传输都依赖于该模块,它有两种实现,一种是基于 netty 实现的 nettytransport,主要用于节点间的通信。另一种是 localtransport,主要是用于同一个 jvm 上的节点通信。

discovery script

自动发现模块,集群中节点的自动发现和 Master 节点的选举。p2p 通信。

Master 节点维护集群的全局状态(比如节点加入和离开时进行 shard 的重新分配)

Master 节点选取,bully 算法+延迟选举+半数选票

故障检测:主节点->其他节点,其他节点->主节点

重要模块

Index 模块:对写入数据的管理和组织

Search 模块:用来提供信息搜索

Mapping映射模块:类似于数据库表字段的定义,并且它决定了各个字段能否被搜索,以及搜索方式

River 模块:es 的一个数据源,向 es 同步数据。river data -> es

Lucene

一个全文检索引擎框架,java 类库,提供底层 api,每个 es 节点上都有一个 Lucene 引擎支持。

gateway

存储索引的文件系统,支持多种文件类型

核心原理

几个重要概念

index type document mapping node shard segment serach
索引 类型 文档 映射 节点 分片 倒排索引

从数据库角度来看

Relational database Elasticsearch
Database Index
Table Type
Row Document
Column Field
Schema Mapping
Index Everything can index
SQL Query DSL
SELECT * FROM table … GET http://…
UPDATE table SET … PUT http://…

索引 index

es 将数据存储于一个或多个索引中,索引是具有类似特性的文档的集合。类比传统的关系型数据库领域来说,索引相当于 SQL 中的一个数据库

类型 type

类型是索引内部的逻辑分类或分区(category/partition),一个索引内部可定义一个或多个类型(type)。通常,会为具有一组共同字段的文档定义一个类型。

文档 document

文档是可被索引的基础信息单元,它是包含了一个或多个域的容器,基于 JSON 格式进行表示。

映射 mapping

用来定义一个文档以及其所包含的字段如何被存储和索引,可以在映射中事先定义字段的数据类型、分词器等属性。映射可以分为静态映射和动态映射。

静态映射:事先定义字段的数据类型、分词器等属性。

动态映射:根据写入的字段进行类型推测。

节点 node

运行了单个实例的 es 主机称为节点(一个 es 实例就是一个 node),可以存储数据、参与集群索引及搜索操作。

分片 shard

es 提供了将索引划分成多少份的能力,这些份就叫做分片。相当于一桶水用了 N 个杯子装。每个分片其内部都是一个全功能且独立的索引(Lucene Index)。创建索引时,用户可指定其分片的数量,默认数量为5个,一个分片只能存放 2,147,483,519 个 docs。

主分片和备分片:主分片和备分片不会出现在同一个节点上(防止单点故障)

分片和节点的配合,让 es 的分布式愿望得以实现。

node + shard 实现 es 的扩容

Node 1 和 Node 2 上各有一个分片被迁移到了新的 Node 3 节点

整体负载降低。性能提升

我们这个拥有6个分片(3个主分片和3个副本分片)的索引可以最大扩容到6个节点,每个节点上存在一个分片,并且每个分片拥有所在节点的全部资源。

那如何实现更多的扩容?如果我们想要扩容超多6个节点怎么办呢?

主分片的数量是确定的,增加备分片的数量,实现更高的吞吐量。

段 segment

Elasticsearch 中的每个分片包含多个 segment,每一个 segment 都是一个倒排索引;在查询时,会把所有的 segment 查询结果汇总归并后作为最终的分片查询结果,然后返回。

倒排索引

也常被称为反向索引,是一种索引方法,它是文档检索系统中最常用的数据结构。

image-20190916162714323

索引原理

es 索引本质:让数据安全快速写入,并且能快速搜索到。

es 的索引过程:对文档的增删改查,以及文档对应的倒排索引的更新。

对原文档的操作(写、读、更新)

写操作

写操作必须在 primary shard (主分片)完全成功后才能拷贝至其对应的 replicas (附属分片)上,默认情况下主分片等待所有备份完成索引后才返回客户端。

  1. 客户端向 Node 1 发送索引文档请求。
  2. Node 1 根据文档 ID (_id 字段) 计算(对 id 做哈希然后取模)出该文档应该属于 shard0,然后请求路由到 Node 3 的 P0 分片上。
  3. Node 3 在 P0 上执行了请求。如果请求成功,则将请求并行的路由至 Node 1,Node 2 的 R0 上。当所有的 Replicas 报告成功后,Node 3 向请求的 Node (Node 1) 发送成功报告,Node 1 再报告至 Client。
  4. 当客户端收到执行成功后,操作已经在 Primary shard 和所有的 replicas shards 上执行成功了。
读操作

一个文档可以在 primary shard 和所有的 replica shards 上读取

  1. 客户端发送 Get 请求到 Node 1。
  2. Node 1 根据文档 ID (_id 字段) 计算出该文档应该属于 shard0,且 shard0 的所有拷贝存在于所有3个节点上。这次,他将路由至 Node 2。
  3. Node 2 将文档返回给 Node 1,Node 1 将文档返回给客户端。对于读请求,请求节点 (Node 1) 将在每次请求到来时选择一个不同的 replica shard 来达到负载均衡。使用轮询策略轮询所有的 replica shards。
更新操作

结合了以上的两个操作:读、写

  1. 客户端发送更新操作请求至 Node 1。
  2. Node 1 将请求路由至 Node 3,Primary shard 所在的位置。
  3. Node 3 从 P0 读取文档,改变 source 字段的 JSON 内容,然后试图重新对修改后的数据在 P0 做索引。如果此时这个文档已经被其他的进程修改了,那么它将重新执行 3 步骤,这个过程如果超过了 retryon_conflict 设置的次数,就放弃。
  4. 如果 Node 3 成功更新了文档,它将并行地把新版本的文档同步到 Node 1 和 Node 2 的 replica shards 重新建立索引。一旦所有的 replica shards 报告成功,Node 3 向被请求的节点(Node 1)返回成功,然后 Node 1 向客户端返回成功。

生成倒排索引

如果仅仅只是生成文档,那么 es 的搜索性能会很低,所以,在建立索引时,会产生一个对应的倒排索引(Inverted Index)。

es 引擎把文档数据写入到倒排索引的数据结构中,建立起分词 (Term) -> 文档 (Document) 的映射关系。

这些倒排索引会存放在段 (segment) 中,段的写入会落盘,缓存 buffer 会实时更新。

image-20190916170640677

倒排索引包括两个部分:

  1. 有序的数据字典 Dictionary(包括单词 Term 和它出现的频率)
  2. 单词 Term 对应的 Postings(即存在这个单词的文件)

为了优化搜索,segment 不仅只提供了倒排,还提供了 document values field cache,解决:排序、聚合等问题。

列式存储:将索引中某一个字段值全部读取到内存中进行操作,用空间换时间。

es 的搜索机制

搜索过程

image-20190916171659797

搜索过程由两个阶段组成:查询阶段,获取阶段

查询阶段(Query Phase):在此阶段,协调节点将搜索请求路由到索引(index)中的所有分片(shards)(包括:主要或副本)。分片独立执行搜索,并根据相关性分数创建一个优先级排序结果。所有分片将匹配的文档和相关分数的文档 ID 返回协调节点。协调节点创建一个新的优先级队列,并对全局结果进行排序。可以有很多文档匹配结果,但默认情况下,每个分片将前10个结果发送到协调节点,协调创建优先级队列。

获取阶段(Fetch Phase):在协调节点对所有结果进行排序,并通过文档 id,从分片中得到原始文档,再返回到协调节点。

image-20190916172347548

搜索相关性:

  1. 文档指定字段,与 query 相关性越强,文档的得分越高
  2. 评分默认算法:tf / idf(术语频率/逆文档频率)

image-20190916172838769