文章目录
9.1 ElasticSearch的概念和原理
9.1.1 Lucene的介绍
1.Lucene简介
ElasticSearch的底层存储基于Lucene实现。
2.倒排索引
倒排索引:关键词、文档ID、频度。搜索引擎的关键是建立倒排索引。
由于不是根据文档来确定字段,而是根据字段来确定文档ID,因此被称为倒排索引。
3.Lucene的架构
4.Lucene的全文检索流程
Lucene的全文检索流程包括两个过程:索引创建、索引查询。
1)创建索引
(1)获取文档:Lucene中的文档指要索引和搜索的原始内容。
(2)构建文档对象:每个文档对象都包含一个唯一的文档id和多个Field。
Field的属性:
- Indexed(是否索引)
- Tokenized(是否分词)
- Stored(是否存储):是否存储字段原始值。
(3)分析文档:analyzer(character filters、tokenizer、token filters)。
- 原文档:Lucene is a Java full-text search engine。
- 分析后:lucene、java、full、search、engine。
(4)创建索引:倒排索引的一般表示是:关键词、文档ID、频度。
2)查询索引
(1)用户查询接口:搜索关键字的提交、搜索结果的展示。
(2)创建查询对象:HTTP协议、RESTFul风格、JSON格式。
(3)执行查询:在索引中查找Field为指定字段且关键字为指定词语的Term,然后根据Term找到对应的文档id列表。
(4)返回查询结果:将查询到的文档id列表返回到用户查询接口。
5.Lucene的使用
生成的索引数据:
- .cfe和.cfs的文件表示复合文件(Compound File);
- .si的文件表示段信息(Segments Info);
- segments_1表示第一个段文件(Segments File);
- write.lock表示锁文件,用以阻止多个indexWriter向同一个文件写数据。
9.1.2 ElasticSearch的特点
高容量、高吞吐、高可用、支持多维度数据分析和处理、API简单易用、支持插件机制。
9.1.3 ElasticSearch的应用场景
全文检索、分布式数据库、日志分析、运维监控、BI系统。
9.1.4 ElasticSearch的数据模型
Index、Type(7.x版本之后废弃)、Document、Field、Mapping、Shard。
9.1.5 ElasticSearch分布式架构
1.集群节点角色
MasterNode(主节点)、DataNode(数据节点)、CoordinatingNode(协调节点)、IngestNode(提取节点)、TribeNode(部落节点)。
(1)MasterNode(主节点):负责集群范围内的操作。
主要负责集群节点状态的维护、索引的创建删除、数据的Rebalance、分片的分配等工作。
(2)DataNode(数据节点):处理与数据相关的操作。
负责集群中数据的索引创建和检索,具体操作包括数据的索引、搜索、聚合等。
(3)IngestNode(提取节点):在索引之前执行数据预处理。
通过拦截文档的Bulk和Index请求,然后加以转换,最终将文档传回Bulk和Index API,用户可以定义一个管道,指定一系列预处理器。
(4)CoordinatingNode(协调节点):充当智能负载平衡器。
(5)TribeNode(部落节点):在多个集群之间充当联合客户端,用于实现跨集群访问。
5.4.0版本以后废弃,替代方案为cross-cluster Search。
2.集群选举原理
集群选举的触发:集群启动、集群重启、Master失效。
(1)Bully算法。
该算法假定所有节点都有一个唯一的id,使用该id对节点进行排序,每次都会选出存活的进程中id最大或最小的节点作为候选者。
(2)集群脑裂问题。
脑裂现象指在分布式集群中各节点之间由于网络分区而不能正常通信,使得原本为一个整体的集群分裂为两个或多个集群,从而导致系统混乱、服务异常、数据不一致的现象。为防止脑裂需要配置:
ElasticSearch基于该配置在集群选主的时候会做如下判断:
- 触发选主:在选举临时Master之前,参选的节点数需要达到法定数量。
- 决定Master:在选出临时Master之后,得票数需要达到法定数量,才确认选主成功。
- Gateway选举元信息:向有Master资格的节点发起请求,获取元数据,获取的响应数量必须达到法定数量,也就是参与元信息选举的节点数。
- Master发布集群状态:成功向节点发布集群状态信息的数量要达到法定数量。
- NodesFaultDetection事件中是否触发rejoin:当发现有节点连不上时,会执行removeNode。接着审视此时的法定数量是否大于discovery.zen.minimum_master_nodes配置,如果不大于,则主动放弃Master身份执行rejoin以避免脑裂。
(3)选举原则。
- 所有节点都会参与选举和投票,但只有拥有Master角色的节点投票才有效。
- 每个节点计算已知节点中id最小的节点,并向该节点投票。
- 如果一个节点获取足够多票数(discovery.zen.minimum_master_nodes=N/2+1),并且该节点也为自己投票,那么它将成为Leader角色,开始发布集群状态。
3.集群状态
4.数据路由规则
数据路由(Routing)规则用于确定文档存储在哪个索引(Index)的哪个分片(Shard)上。
routing是一个可变值,默认是文档的_id,也可以设置成一个自定义的值。索引的主分片数量在确定后就不能再修改,因为如果主分片数量发生变化,则之前路由的所有分片都会失效。
在使用时,所有API(get、index、delete、bulk、update以及mget)都接收一个叫作routing的路由参数,通过这个参数应用程序可以自定义文档到分片的映射。一个自定义的路由参数可以用来确保所有相关的文档(例如所有属于同一个用户的文档)都被存储到同一个分片中。
5.文档分片和副本策略
文档分片原则:
- 每个索引都由一个或多个分片组成,文档根据路由规则分配到不同分片上。
- 每个分片都对应一个Lucene实例,一个分片只能存放Integer.MAX_VALUE-128=2 147 483 519个文档。
- 分片主要用于数据的横向分布,ElasticSearch中的分片会被尽可能平均地分配到不同节点上,当有新的节点加入时,ElasticSearch会自动感知并对数据进行relocation操作,保障集群内数据的均衡分布。
文档副本策略:
- 为了防止单节点服务器故障,ElasticSearch会将主分片和副本分片分配在不同节点上。ElasticSearch的默认配置是一个索引包含5个分片,每个分片都有1个副本(即5 Primary+5 Replica=10个分片)。
9.1.6 ElasticSearch的写操作流程
1.ElasticSearch的写操作
写操作:索引的创建、删除,文档的创建、删除、更新。
先在主分片上执行写操作,当主分片上执行成功时,根据集群的数据一致性要求,将在其他副本分片上执行写操作,只有达到一致性要求的节点都执行成功后才向客户端发送成功响应。
2.数据写入一致性:Consistency
通过Consistency设置写操作的一致性级别:one(仅主要分片)、all(主分片和所有副本分片)、默认的Quorum(大部分分片)。
9.1.7 ElasticSearch的读操作流程
在处理读取请求时,协调节点在每次收到客户端请求的时候都会通过轮询所有副本分片来达到负载均衡。如果在某节点上未查询到对应的文档数据,则继续向其他节点轮询,直到查询到文档对应的数据后才返回,否则向客户端报告文档不存在。
9.1.8 ElasticSearch中的Translog
倒排索引被加载到内存使用,使用fsync系统调用来序列化到磁盘。
- segment:lucene使用segment来存储数据,segment存于内存。
- commit point:lucene使用commit point来存储segment的元数据,commit point存于磁盘。
1.ElasticSearch Translog的介绍
每个分片都对应一个事务日志文件Translog,记录了所有与更新相关的事务操作日志(例如add/update/delete)。
Translog提供了数据没有被刷盘的一个持久化存储纪录,主要用来恢复数据。当ElasticSearch重启时,它会在磁盘中使用最后一个提交点(Commit Point)去恢复已知的段数据,并且会重放Translog中所有在最后一次提交后发生的变更操作。
2.ElasticSearch的数据更新和Translog操作流程
写操作
为了提高写入效率,将数据同时写入内存缓冲区和Translog文件。
refresh操作
- 所有在内存缓冲区中的文档被写入到一个新的segment中;
- 打开segment使得里面的文档能够被搜索到;
- 清空内存缓冲区。
flush操作
- 通过fsync系统调用把新的segment同步到磁盘;
- 把新的commit point写入磁盘;
- 删除旧的translog文件。
Translog的刷新策略:
- index.translog.durability:是否在每次index、delete、update、bulk请求后都去执行fsync和提交事务日志的操作,具体参数设置如下:
①request:每次请求均执行fsync和提交操作。它可保障发生硬件故障时,所有确认的写操作都将被写入磁盘。
②sync:每隔sync_interval时间将会执行fsync和提交操作。当发生硬件故障时,所有确认的写操作在上次自动提交后都会被丢弃。 - index.translog.sync_interval:每间隔多久事务日志执行fsync操作和提交写操作。默认为5s,设置的值需要大于等于100ms。
- index.translog.flush_threshold_size:当事务日志中存储的数据大于该值时,则启动刷新操作,产生一个新的Commit Point。默认值为512MB。
- index.translog.retention.size:保留事务日志的总大小。当恢复备份数据时,太多事务日志文件将增大基于sync操作的概率;如果事务日志不够,则备份恢复将会回退到基于sync的文件。默认值为512MB,在ElasticSearch 7.0.0及更高版本中,该配置已经被废弃。
- index.translog.retention.age:事务日志保留的最长时间,默认为12h,在ElasticSearch 7.0.0及更高版本中,该配置已经被废弃。
9.1.9 ElasticSearch段合并
1.段合并的介绍
由于自动刷新流程每秒都会创建一个新的段,这样会导致短时间内段的数量迅速增加。而段的数量太多将会引起性能瓶颈。可以通过段合并来解决这个问题。段合并在进行索引和搜索时会自动进行。
2.段合并的流程
- 在索引的时候,Refresh操作会创建新的段并将段打开以供搜索使用。
- 合并进程选择一小部分大小相似的段,并且在后台将它们合并到更大的段中。该操作并不会中断索引和搜索。
- 在合并结束后,老的段被删除,新的段被Flush到磁盘,再打开新的段对外提供搜索,删除老的段数据。
段合并性能,默认值为20MB/s,对于机械磁盘20MB/s是合理的设置,但如果磁盘是SSD则考虑提高到100~200MB/s,设置API如下:
关掉段合并限流,使段合并速度尽可能快,上限为磁盘允许的最大读写速度:
在elasticsearch.yml配置中设置段合并的并发度:
9.1.10 ElasticSearch的集群扩容
- 垂直扩容:加大现有节点的内存、CPU、磁盘。
- 水平扩容:集群中加入新节点。
集群发现(Cluster Discovery)机制:在启动一个新的节点后,该节点会发现集群并自动加入集群,集群会自动在各个分片之间执行数据的均衡处理。
9.2 ElasticSearch的应用
9.2.1 ElasticSearch的安装
修改集群配置文件elasticsearch.yml:
cluster.name: elasticsearch
node.name: elasticsearch_001
path.data: /path/to/data1,/path/to/data2
path.logs: /path/to/logs
discovery.zen.minimum_master_nodes: 2
# 本节点应该去尝试连接的节点。当一个节点联系到单播列表中的成员时,它就会得到整个集群的所有节点的状态,然后会联系Master节点并加入集群
# discovery.zen.ping.unicast.hosts: ["host1", "host2:port"]
bootstrap.memory_lock: true
#cluster.name: 配置集群名称
#node.name: 配置节点名称
#bootstrap.memory_lock: 无需修改
#network.host: 修改为本机ip
#discovery.zen.ping.unicast.hosts: 修改为本机ip
#discovery.zen.minimum_master_nodes: 无需修改
启动报错:
修改elasticsearch-env.bat添加set JAVA_HOME=“%ES_HOME%\jdk”,配置使用自带JDK:
启动成功。
9.2.2 ElasticSearch的配置和性能调优
1.JVM性能调优
修改jvm.options设置堆内存,堆内存最小值(Xms)与最大值(Xmx)设置相同,一般为系统内存的一半,防止JVM内存震荡:
需要注意的是,Lucene还需要使用大量非堆内存。Lucene的段分别存储在单个文件中,因为段是不可变的,对缓存友好的,所以在使用段数据时操作系统会把这些段文件缓存起来,以便更快地访问。同时,Lucene可以利用操作系统底层机制来缓存内存数据,加速查询效率。
Lucene的性能取决于与操作系统交互的速度,而这些交互都需要大量的非JVM堆内存,如果把全部内存都分配给JVM堆内存,则将导致Lucene在运行过程中因资源不足而性能下降。一般建议将系统的一半内存分配给JVM堆内存,另外一半内存预留给Lucene和操作系统。
2.操作系统的性能调优
(1)设置文件句柄:Linux中的每个进程默认打开的最大文件句柄数都是1 024,对于服务器进程来说该值太小,可以通过修改/etc/security/limits.conf来增大打开的最大文件句柄数,一般建议设置为65 535。
(2)设置虚拟内存:max_map_count定义了进程能拥有的最多内存区域,一般建议设置为102 400。
(3)关闭Swap:Swap空间是一块磁盘空间,操作系统使用这块空间保存从内存中交互换出的操作系统不常用的Page数据,这样可以分配出更多的内存做Page Cache。通过Swap可以提升系统的吞吐量和I/O性能,但ElasticSearch需要一个所有内存操作都能够被快速执行的环境,服务一旦使用到了Swap内存,就会大大降低数据的存取效率,严重影响性能。
4)开启mlockall:打开配置文件中的mlockall开关。它的作用是允许JVM锁住内存,禁止操作系统将内存交换出去。elasticsearch.yml文件中的设置:bootstrap.memory_lock: true
3.Elasticsearch为什么快?
3.1 优化
服务器:
- 文件句柄数尽量大
- 虚拟内存尽量大
- 关闭内存交换
ES:
- JVM内存尽量大
- 开启JVM锁定内存
- 数据批量处理时,使用滚动查询而不是分页查询
3.2 为什么快?
- 倒排索引(词组->文档)
- doc values正排索引(文档->词组)(分组、聚合、排序)
- 读取内存
- 负载均衡
3.3 记忆
数据模型
倒排索引
分片策略
数据路由
写操作(一致性要求)
读操作(负载均衡)
节点角色
集群状态
脑裂问题
性能调优
为什么快