ElasticSearch
定义
”一个便于检索的数据库“
基于 Lucene 的开源搜索引擎,分布式、可扩展、每个字段都能被索引。
能做什么?
- 海量搜索
- NoSQL 数据库
- 对海量数据进行进实时的处理
- 日志数据分析,ELK 技术,ES 进行复杂的数据分析
架构设计
设计目标:为了更好的写入(索引)和查询(搜索)
自底向上:
- 网关,es 索引的持久化存储方式
- Lucene,为 es 提供 api 工具包
- 索引模块,搜索模块,字段映射,river 数据同步
- 自动发现,es 的自动发现节点机制
- 通信层,es 和客户端的交互方式
- 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 查询结果汇总归并后作为最终的分片查询结果,然后返回。
倒排索引
也常被称为反向索引,是一种索引方法,它是文档检索系统中最常用的数据结构。
索引原理
es 索引本质:让数据安全快速写入,并且能快速搜索到。
es 的索引过程:对文档的增删改查,以及文档对应的倒排索引的更新。
对原文档的操作(写、读、更新)
写操作
写操作必须在 primary shard (主分片)完全成功后才能拷贝至其对应的 replicas (附属分片)上,默认情况下主分片等待所有备份完成索引后才返回客户端。
- 客户端向 Node 1 发送索引文档请求。
- Node 1 根据文档 ID (_id 字段) 计算(对 id 做哈希然后取模)出该文档应该属于 shard0,然后请求路由到 Node 3 的 P0 分片上。
- Node 3 在 P0 上执行了请求。如果请求成功,则将请求并行的路由至 Node 1,Node 2 的 R0 上。当所有的 Replicas 报告成功后,Node 3 向请求的 Node (Node 1) 发送成功报告,Node 1 再报告至 Client。
- 当客户端收到执行成功后,操作已经在 Primary shard 和所有的 replicas shards 上执行成功了。
读操作
一个文档可以在 primary shard 和所有的 replica shards 上读取
- 客户端发送 Get 请求到 Node 1。
- Node 1 根据文档 ID (_id 字段) 计算出该文档应该属于 shard0,且 shard0 的所有拷贝存在于所有3个节点上。这次,他将路由至 Node 2。
- Node 2 将文档返回给 Node 1,Node 1 将文档返回给客户端。对于读请求,请求节点 (Node 1) 将在每次请求到来时选择一个不同的 replica shard 来达到负载均衡。使用轮询策略轮询所有的 replica shards。
更新操作
结合了以上的两个操作:读、写
- 客户端发送更新操作请求至 Node 1。
- Node 1 将请求路由至 Node 3,Primary shard 所在的位置。
- Node 3 从 P0 读取文档,改变 source 字段的 JSON 内容,然后试图重新对修改后的数据在 P0 做索引。如果此时这个文档已经被其他的进程修改了,那么它将重新执行 3 步骤,这个过程如果超过了 retryon_conflict 设置的次数,就放弃。
- 如果 Node 3 成功更新了文档,它将并行地把新版本的文档同步到 Node 1 和 Node 2 的 replica shards 重新建立索引。一旦所有的 replica shards 报告成功,Node 3 向被请求的节点(Node 1)返回成功,然后 Node 1 向客户端返回成功。
生成倒排索引
如果仅仅只是生成文档,那么 es 的搜索性能会很低,所以,在建立索引时,会产生一个对应的倒排索引(Inverted Index)。
es 引擎把文档数据写入到倒排索引的数据结构中,建立起分词 (Term) -> 文档 (Document) 的映射关系。
这些倒排索引会存放在段 (segment) 中,段的写入会落盘,缓存 buffer 会实时更新。
倒排索引包括两个部分:
- 有序的数据字典 Dictionary(包括单词 Term 和它出现的频率)
- 单词 Term 对应的 Postings(即存在这个单词的文件)
为了优化搜索,segment 不仅只提供了倒排,还提供了 document values field cache,解决:排序、聚合等问题。
列式存储:将索引中某一个字段值全部读取到内存中进行操作,用空间换时间。
es 的搜索机制
搜索过程
搜索过程由两个阶段组成:查询阶段,获取阶段
查询阶段(Query Phase):在此阶段,协调节点将搜索请求路由到索引(index)中的所有分片(shards)(包括:主要或副本)。分片独立执行搜索,并根据相关性分数创建一个优先级排序结果。所有分片将匹配的文档和相关分数的文档 ID 返回协调节点。协调节点创建一个新的优先级队列,并对全局结果进行排序。可以有很多文档匹配结果,但默认情况下,每个分片将前10个结果发送到协调节点,协调创建优先级队列。
获取阶段(Fetch Phase):在协调节点对所有结果进行排序,并通过文档 id,从分片中得到原始文档,再返回到协调节点。
搜索相关性:
- 文档指定字段,与 query 相关性越强,文档的得分越高
- 评分默认算法:tf / idf(术语频率/逆文档频率)