ElasticSearch 详解
1. ES 简介
Elasticsearch 是一个基于 Lucene 实现的搜索服务器。它提供了一个分布式多用户能力的全文搜索引擎,基于 RESTful web 接口。Elasticsearch是用Java语言开发的,并作为Apache许可条款下的开放源码发布,是一种流行的企业级搜索引擎。Elasticsearch用于云计算中,能够达到实时搜索,稳定,可靠,快速,安装使用方便。
ES 的特点:
-
分布式实时文件存储,可以将每一个字段都编入索引,使其可以被检索
-
可以作为一个大型分布式集群(数百台服务器)技术,处理PB级数据
-
Elasticsearch不是什么新技术,主要是将全文检索、数据分析以及分布式技术,合并在了一起,才形成了独一无二的ES
什么是 Lucene:
Lucene 就是一个jar包,里面包含了各种建立倒排索引的方法,java开发的时候只需要导入这个jar包就可以开发了。
Lucene 的查询原理:https://blog.****.net/weixin_44981707/article/details/114437027
ES 和 Lucene的区别:
ES的底层就是 Lucene,ES是分布式的,Lucene 就是一个检索工具,不是分布式的。Lucene 有两个难以解决的问题:
- 数据越大,存不下来,那么就需要多台服务器进行存储,并作统一管理。Lucene不支持分布式的,那就需要安装多个 Lucene 然后通过代码来合并搜索结果,这样很不好
- 数据要考虑安全性,一台服务器挂了,那么上面的数据不就消失了
ES 就是分布式的集群,每一个节点其实就是隔离的 Lucene。ES 在 Lucene 基础上(即利用Lucene的功能)提供了一个分布式的、基于JSON的REST API 来更方便地使用 Lucene的功能。
ES 同时提供其他支持功能,如线程池,队列,节点/集群监控API,数据监控API,集群管理等。
2. ES 集群
一个集群就是由一个或多个节点组织在一起,它们共同持有整个的数据,并一起提供索引和搜索功能。
一个集群由一个唯一的名字标识,这个名字默认就是“elasticsearch”。一个节点只能通过指定某个集群的名字,来加入这个集群。
这里假设一个集群有3个节点,索引有5个分片和备份,为了保证高可用,需要保证同一分片的备份不在同一个节点上。
2.1 节点 node
一个节点是集群中的一个服务器,作为集群的一部分,它存储数据,参与集群的索引和搜索功能。和集群类似,一个节点也是由一个名字来标识的,
一个节点可以通过配置集群名称的方式来加入一个指定的集群。默认情况下,每个节点都会被安排加入到一个叫做“elasticsearch”的集群中,这意味着,如果你在你的网络中启动了若干个节点,并假定它们能够相互发现彼此,它们将会自动地形成并加入到一个叫做“elasticsearch”的集群中。
在一个集群里,可以拥有任意多个节点。而且,如果当前你的网络中没有运行任何Elasticsearch节点,这时启动一个节点,会默认创建并加入一个叫做“elasticsearch”的集群。
2.2 分片和复制 shards&replicas
一个索引可以存储超出单个结点硬件限制的大量数据。比如,一个具有10亿文档的索引占据1TB的磁盘空间,而任一节点都没有这样大的磁盘空间;或者单个节点处理搜索请求,响应太慢。
为了解决这个问题,Elasticsearch提供了将索引划分成多份的能力,这些份就叫做分片。当你创建一个索引的时候,你可以指定你想要的分片的数量。
每个分片本身也是一个功能完善并且独立的“索引”,这个“索引”可以被放置到集群中的任何节点上。
分片很重要,主要有两方面的原因:
- 允许你水平分割你的数据
- 允许你的分片在不同的机器上部署,达到扩容的目的
- 允许你在分片(潜在地,位于多个节点上)之上进行分布式的、并行的操作,进而提高性能/吞吐量。
在一个网络/云的环境里,机器挂载是很场景的事情。这种情况下,有一个故障转移机制就显得非常重要。为此目的,Elasticsearch 允许你创建分片的一份或多份拷贝,这些拷贝叫做复制分片,或者直接叫复制。
复制之所以重要,有两个主要原因:
- 在分片/节点失败的情况下,提供了高可用性。因为这个原因,注意到复制分片从不与原/主要(original/primary)分片置于同一节点上。
- 扩展你的搜索量/吞吐量,因为搜索可以在所有的复制上并行运行。
总之,每个索引可以被分成多个分片。一个索引也可以被复制0次(意思是没有复制)或多次。一旦复制了,每个索引就有了主分片(作为复制源的原来的分片)和复制分片(主分片的拷贝)之别。
3. 数据插入查询
3.1 数据插入的过程
- shard_num = hash(routing) % num_primary_shards,计算出文档要分配到的分片,在从集群元数据中找出对应主分片的位置
- 请求接着会发送给对应的 Primary Shard,在Primary Shard上执行成功后
- 从Primary Shard上将请求同时发送给多个Replica Shard,请求在多个Replica Shard上执行成功并返回给Primary Shard后,写入请求执行成功
- 返回结果给客户端。
ES 为了减少磁盘IO保证读写性能,一般是每隔一段时间(比如5分钟)才会把 Lucene 的 Segment 写入磁盘持久化。为了保证写入 Lucene 内存的数据不丢失,引入 Translog。
在每一个 Shard 中,写入流程分为两部分,先写入 Lucene,再写入 TransLog。写入请求到达 Shard 后,先写 Lucene文件,创建好索引,此时索引还在内存里面,接着去写 TransLog,写完 TransLog 后,刷新 TransLog 数据到磁盘上,写磁盘成功后,请求返回给用户。(TransLog 只是记录少量命令操作而已)
3.2 数据查询流程
- 协调节点将检索请求广播到每个分片上
- 每个分片本地执行检索请求,构建检索匹配的优先队列(返回 doc_id )
- 协调节点整合全局搜索结果集 doc_id ,进行排序等(如果返回 20 个 doc_id ,可能我只要 10 个)
- 协调节点通过 doc_id ,提交多个获取数据的请求,每个请求根据 doc_id 路由到指定的分片上(是路由到主分片还是副分片,可以通过轮询策略等)
- 每个分片将数据返回给协调节点,协调节点将结果数据返回给客户端