1、为什么要使用ElasticSearch?
系统中的数据,随着业务的发展和时间的推移, 将会非常多, 而业务中往往采用模糊查询进行数据的搜索,而模糊查询会导致查询引擎放弃索引,从而导致系统查询数据时都是全表扫描,在百万级别的数据库中查询效率是非常低下的,而我们使用ElasticSearch做一个全文索引,将经常查询的系统功能中的某些字段放入 ElasticSearch索引库里,可以提高查询速度。
2、ElasticSearch 的 master 选举流程是怎样的
ElasticSearch 的选举是 ZenDiscovery 模块负责的,主要包含 Ping (节点之间通过这个 RPC 来发现彼此)和 Unicast (单播模块包含一个主机列表以控制哪些节点需要 ping 通)这两部分
1、对所有可以成为 master 的节点(node.master: true)根据 nodeId 字典排序,每次选举每个节点都把自
己所知道节点排一次序,然后选出第一个(第 0 位)节点,暂且认为它是 master 节点。
2、如果对某个节点的投票数达到一定的值(可以成为 master需要的节点数为: n/2+1 )并且该节点自己也选举自己,如果都符合,那这个节点就是 master ,否则重新选举一直到满足上述条件。
master节点的职责主要包括集群、节点和索引的管理,不负责文档级别的管理,此时master节点可以关闭node.data功能。
3、ElasticSearch集群的脑裂问题
3.1、出现原因
网络问题:集群间的网络延迟导致一些节点访问不到master,认为master挂掉了从而选举出新的master;
节点负载:主节点的角色既是master又是data,当访问量大时可能会导致ElasticSearch停止响应造成大面积延迟,其他节点得不到master的响应从而认为master挂掉了从而选举出新的master;
内存回收:data节点上的ES进程占用的内存较大,从而引发JVM的规模的内存回收,造成ES失去响应。
3.2、解决方案
减少误判:可以设置
discovery.zen.ping_timeout
节点状态的响应时间,该参数的意思是,如果master在该响应时间内没有做出响应,则判断该节点宕机,默认为 3s。可以适当增大响应时间来减少其他节点对master状态的误判;选举触发 : 可以设置
discovery.zen.minimum_master_nodes
,该参数是用于控制选举行为发生的最小集群主节点数量。当备选主节点的个数大于等于该参数的值,且备选主节点中有该参数个节点认为主节点挂了,进行选举。默认值是1,官方建议为( n/2)+1 个,其中n为主节点个数(即有资格成为主节点的节点个数);角色分离:即将master节点和data节点分离,限制角色。
主节点配置为:
node.master: true
、node.data: false
从节点配置为:
node.master: false
、node.data: true
4、Elasticsearch索引文档的流程?
1、一个文档请求发送到任意集群节点上;
2、获得请求的节点成为协调节点默认使用文档ID参与计算,以便为路由提供合适的分片;
shard = hash(document_id) % (num_of_primary_shards)
3、当分片所在节点接收来自协调节点的请求后,会将请求的文档写入到Memory Buffer中,然后定时(默认是1s)写入FileSystem Cache,这个过程称为refresh;
4、在某些情况中,Memory Buffer 和 FileSystem Cache 中的数据可能会丢失,ElasticSearch通过translog的机制来保证数据的可靠性。它的机制是:接收到请求后,同时写入到translog中,只有当FileSystem cache的数据写如此盘中时,才会将translog清除掉,这个过程称为flush;
注:在flush的过程中,内存中的缓存将会被清除掉内容被写入一个新段,段的 fsync 将创建一个新的提交点, 并将内容刷新到磁盘,旧的 translog 将被删除并开始一个新的 translog。flush触发的时机是定时触发(默认30min)或者translog文件太大(默认512M)。
5、ElasticSearch更新和删除文档的流程
虽然删除和更新文档也是写操作,但是由于ElasticSearch的文档不可变性,所以不能通过删除或修改文档来执行变更操作。
当执行删除请求时,我们的文档本质并没有被删除,而是由于磁盘上的每一个段都有对应的一个.del文件,删除的文档会在.del文件中被标记为删除。此时,虽然文档还是能够在查询过程中被匹配出来,但是他会在结果中被过滤掉。
当执行更新请求时,由于我们ElasticSearch中存在一个版本号,所以此时旧版本的文档会在.del文件上被标记为删除,而新版本的文档则会被索引到一个新段。此时,我们能够同时查询到两个版本的文档,但是在结果中,旧版本的文档会被过滤掉,只会返回最新版本的文档。
当执行段合并时,此时会真的将.del文件中被标记删除的文档执行物理删除。
6、ElasticSearch的搜索流程
搜索被执行成一个两阶段过程,称为 Query Then Fetch;
1、在初始查询阶段,查询会广播到索引中每一个分片拷贝(主分片或者副本分片)。 每个分片在本地执行搜索并构建一个匹配文档的大小为 from + size 的优先队列。PS:在搜索的时候是会查询 Filesystem Cache 的,但是有部分数据还在 Memory Buffer,所以搜索是近实时的。
2、每个分片返回各自优先队列中所有文档的 ID 和排序值 给协调节点,协调节点合并这些值到自己的优先队列中来产生一个全局排序后的结果列表。
3、接下来就是取回阶段,协调节点辨别出哪些文档需要被取回并向相关的分片提交多个 GET 请求。每个分片加载并丰富文档,接着返回文档给协调节点。一旦所有的文档都被取回了, 协调节点返回结果给客户端。
Query Then Fetch 的搜索类型在文档相关性打分的时候参考的是本分片的数据,这样在文档数量较少 的时候可能不够准确,DFS Query Then Fetch 增加了一个预查询的处理,询问 Term 和 Document frequency,这个评分更准确,但是性能会变差。
7、ElasticSearch在部署时,对Linux的设置有哪些优化方法?
1、使用内存更高的机器部署ElasticSearch(64G最优,不要少于8G);
2、选择更多核心数的机器;
3、负担得起的话,使用SSD会远远超过任何旋转介质,查询和索引性能都会有所提升;
4、确保运行你应用程序的 JVM 和服务器的 JVM 是完全一样的。 在 Elasticsearch 的几个地方,使用Java的本地序列化;
5、通过设置gateway.recover_after_nodes、gateway.expected_nodes、gateway.recover_after_time 可以在集群重启的时候避免过多的分片交换,这可能会让数据恢复从数个小时缩短为几秒钟;
6、不要随意修改垃圾回收器(CMS)和各个线程池的大小;
7、把内存的(少于)一半给 Lucene(但不要超过 32 GB!),可以通过 ES_HEAP_SIZE 环境变量设置。
补充:在索引阶段性能提升的方法:
1、使用批量请求并调整其大小:每次批量数据 5–15 MB 大是个不错的起始点;
2、使用SSD;
3、段和合并:ElasticSearch 默认值是 20 MB/s,对机械磁盘应该是个不错的设置。如果你用的是 SSD, 可以考虑提高到 100–200 MB/s。如果你在做批量导入,完全不在意搜索,你可以彻底关掉合并限流。 另外还可以增加 index.translog.flush_threshold_size 设置,从默认的 512 MB 到更大一些的值,比如 1 GB,这可以在一次清空触发的时候在事务日志里积累出更大的段;
4、如果你的搜索结果不需要近实时的准确度,考虑把每个索引的 index.refresh_interval (刷新到文件系统缓存)由1s改到 30s;
5、如果你在做大批量导入,考虑通过设置 index.number_of_replicas: 0 关闭副本。
8、在GC方面,在使用 ElasticSearch 时要注意什么?
1、倒排词典的索引需要常驻内存,无法 GC,需要监控 data node 上 segment memory 增长趋势;
2、field cache, filter cache, indexing cache, bulk queue 等等各类缓存,要设置合理的大小,并且要应该根据最坏的情况来看 heap 是否够用,避免采用 clear cache 等“自欺欺人”的方式来释放内存;
3、避免返回大量结果集的搜索与聚合。确实需要大量拉取数据的场景,可以采用 scan & scroll api 来实现。
9、 对于大数据量(上亿量级)的聚合如何实现?
ElasticSearch 提供的首个近似聚合是 cardinality 度量。它提供一个字段的基数,即该字段的 distinct 或者 unique 值的数目。它是基于 HLL 算法的。HLL 会先对我们的输入作哈希运算,然后根据哈希运算的结果中的bits 做概率估算从而得到基数。其特点是:可配置的精度,用来控制内存的使用(更精确 = 更多内存);小的数据集精度是非常高的;我们可以通过配置参数,来设置去重需要的固定内存使用量。无论数千还是数十亿的唯一值,内存使用量只与你配置的精确度相关。
10、在并发情况下,ElasticSearch 如果保证读写一致?
可以通过版本号使用乐观锁并发控制,以确保新版本不会被旧版本覆盖,由应用层来处理具体的冲突;
对于写操作,一致性级别支持 quorum[半数]/one[主分片]/all[所有分片],默认为 quorum,即只有当大多数分片可用时才允许写操作。但即使大多数可用,也可能存在因为网络等原因导致写入副本失败,这样该副本被认为故障,分片将会在一个不同的节点上重建。
对于读操作,可以设置 replication 为 sync(默认),这使得操作在主分片和副本分片都完成后才会返回; 如果设置 replication 为 async 时,也可以通过设置搜索请求参数_preference 为 primary 来查询主分片, 确保文档是最新版本。
11、Elasticsearch 中的集群、节点、索引、文档是什么?
1、集群是一个或多个节点(服务器)的集合,它们共同保存您的整个数据,并提供跨所有节点的联合索引和搜索功能。群集由唯一名称标识,默认情况下为 “elasticsearch“ 。此名称很重要,因为如果节点设置为按名称加入群集,则该节点只能是集群的一部分;
2、节点是属于集群一部分(单个服务器)。它用来存储数据并参与群集索引和搜索功能;
3、索引就像关系数据库中的数据库。它有一个定义多种类型的映射。索引是逻辑名称空间,映射到一个或多个主分片,并且可以有零个或多个副本分片。 旧版本的索引相当于MySQL 的数据库,新版本对标的是数据库表;
4、文档类似于关系数据库中的每一行数据。不同之处在于索引中的每个文档可以具有不同的结构(字段),但是对于通用字段应该具有相同的数据类型。
12、Elasticsearch 中的倒排索引是什么?
倒排索引是搜索引擎的核心。搜索引擎的主要目标是在查找发生搜索条件的文档时提供快速搜索。 ES中的倒排索引 其实就是 Lucene 的倒排索引,区别于传统的正向索引,倒排索引会再存储数据时将关键词和数据进行关联,保存到倒排表中,然后在查询时,将查询内容进行分词后在倒排表中进行查询,最后匹配数据即可。