文章目录
- 1.什么是ElasticSearch?
- 1.为什么要使用Elasticsearch?
- 1.Elasticsearch中的倒排索引是什么?
- 1.索引、类型、文档
- 1.映射是什么?
- 1.ElasticSearch中的集群、节点是什么?
- 1.分片是什么?
- 1.副本
- 1.集群演示
- 1.ES的数据在内存还是在磁盘?
- 1.了解一下ES的“不可变”
- 1.文档删除
- 1.文档刷新、文档合并
- 1.文档冲突
- 1.文档展示
- 1.ElasticSearch优化方式
- 2.Elasticsearch是如何实现Master选举的?
- 2.Elasticsearch 集群脑裂问题?
- 2.Elasticsearch中的节点(比如共20个),其中的10个选了一个master,另外10个选了另一个master,怎么办?
- 2.详细描述一下Elasticsearch索引文档的过程。
- 2.详细描述一下Elasticsearch更新和删除文档的过程
- 2.详细描述一下Elasticsearch搜索的过程
- 2.Elasticsearch中的分析器是什么?
- 2.在并发情况下,Elasticsearch 如果保证读写一致?
- 2.如何监控 Elasticsearch 集群状态?
- 2.Elasticsearch 与 solr 的区别?
1.什么是ElasticSearch?
Elasticsearch是一个基于Lucene
的搜索引擎
。具有良好的全文搜索功能
。
Lucene是apache的一个开放源代码的全文检索引擎工具包
1.为什么要使用Elasticsearch?
在百万级别的数据库中,使用模糊查询
来查询某个字段,这就会导致导致商品查询是全表扫面
,效率非常低下,
ElasticSearch使用了倒排索引
,倒排索引以关键字为key,然后value中记录了这个关键字的位置信息,就可以实现快速查询。
1.Elasticsearch中的倒排索引是什么?
倒排索引以关键字为key,然后value中记录了这个关键字的位置信息,就可以实现快速查询。
倒排索引涉及到分词,面试官很可能问到你分词;而且倒排索引中极可能问到你词条、词典、倒排表
分词:我们要用分词器,比如常见的IK中文分词器,作为插件来使用,在里面我们还可以自定义词典(比如人名什么的,防止错误分词)
分词设置:我们可以设置类型为keyword或text来说明该词能不能进行分词(keyword类型的不能被分词,text类型的可以被分词)
词条:索引中最小存储和查询单元(英文中词条一般就是一个单词,中文中一般就是一个词组)
词典:是词条的集合。它的底层是B+树或Hash表
倒排表:以关键字为key,然后value中记录了这个关键字的位置信息,比如“zhangsan:101 109 106 108”是一个倒排项,倒排表自然就是倒排项的集合了
1.索引、类型、文档
以前是索引———类型————文档
类比于 数据库——数据表———数据
你可以觉得文档听起来不比类型的范围大吗,类型听起来不比索引的范围大吗?事实上,它就像“共和国”和“中华人民共和国”的范围一样,共和国肯定包括中华人民共和国,文档它就是一张精确的表,一个类型下面肯定有很多个文档,同样的一个索引下面有一堆类型。
从7.0版本以后不再有"类型
"的说法了,文档就是直接存储在索引下面
1.映射是什么?
MySQL中一张表有哪些字段,这些字段是否为空、什么类型、长度是多少、默认值是多少;
对于ElasticSearch的索引也一样,它规定了哪些字段可以被查询,哪些字段可以进行分词操作啊,这些规则就是映射
举例
新加映射
基于上一步的age、email、name字段的映射,我们现在想要新加一个字段的映射时得这么做
PUT /my_index/_mapping
{
"properties": {
"employee-id": {
"type": "keyword",
"index": false #表示该字段只是一个冗余存储的字段,不能被拿去检索。
}
}
}
修改映射
不能更新映射:对于已经存在的字段映射,我们不能更新。更新必须创建新的索引,进行数据迁移。
1.ElasticSearch中的集群、节点是什么?
分布式:一个大业务分拆多个子业务,部署在不同的服务器上。一个节点垮了,那这个大业务就不可访问了。
集群:同一个业务,部署在多个服务器上
微服务:与分布式比较相似,微服务化的核心就是将传统的一站式应用,根据业务`拆分成`一个一个的服务,`一个服务做一件事`,服务之间互相协调、互相配合,拥有自己独立的数据库,并且能够被独立地部署到生产环境。
群集是多个节点的集合(当然也可以是单节点集群),它们共同保存您的整个数据,并提供群集索引和搜索功能
。
节点是属于集群一部分。它存储数据
并参与群集索引和搜索功能
。
1.分片是什么?
一个完整的数据切成几片,这就是分片概念。一个索引可以存储大量的数据,但是在单节点上受到了硬件的限制(你的磁盘不够用),意味着在单节点上不可能数据存的很大,所以我们需要把一个完整的索引数据拆分成几块,每一块放到不同的服务器节点上来统一提供服务,把它们合在一块就是一个完整的索引数据。每一部分每一块就是我们称之为分片。
分片很重要,主要有两方面的原因:
- 允许你水平分割扩展你的内容容量。
- 允许你在分片之上进行分布式的、并行的操作,进而提高性能/吞吐量。
把一张表分成男生数据和女生数据,想访问男的就取男的这张表,想访问女的就取女的这张表,这样你的请求就被负载开了,吞吐量和性能自然就可以提升。
1.副本
你的分片突然down掉了怎么办?所以需要给数据加一个副本/备份
1.集群演示
1.单节点集群
如果你现在只启动了一个节点
2.启动两个节点
一个节点会出现单点故障
问题,启动两个节点就会故障转移
3.启动三个节点
4.水平扩容
5.节点down掉
6.路由计算
7.案例演示
客户端请求集群的协调节点,协调节点里面进行路由计算将请求转换到指定的节点,主分片将数据保存然后发送给副本保存。
1.ES的数据在内存还是在磁盘?
数据主要存在磁盘,但是为了快速访问磁盘上的数据,也会有一部分数据是常驻内存里的。
1.了解一下ES的“不可变”
全文检索会为整个文档集合建立一个很大的倒排索引并将其写入到磁盘。倒排索引被写入磁盘后是不可改变的。
如何在保留不变性的前提下实现倒排索引的更新?
不用直接重写整个倒排索引,我们可以引入段的概念,每一段本身都是一个倒排索引。新文档被收集到缓存区中,不时地提交缓存,一个新的段(一个追加的倒排索引),被写入磁盘。新的段被开启,让它包含的文档可见以被搜索。缓存被清空,等待接收新的文档。
ES的数据搜索是分段搜索,ES中每一段就是一个倒排索引,最新的数据更新会体现到最新的段中,最新的段落盘之后ES才能进行数据搜索。
1.文档删除
刚刚说了,段时不可改变的,那我要是删除数据怎么办呢?我们使用逻辑删除,不是真正的删除,查询时如果发现该数据被逻辑删除了就过滤掉它,也就是不显示给前台。
那什么时候真正的删除呢?倒排索引可以合并的嘛,当我们进行合并的时候那些被逻辑删除的就会被真正删除。
1.文档刷新、文档合并
另一种问法:ES写入数据的过程
我们之前说过数据的写流程:客户端请求集群的协调节点,协调节点里面进行路由计算将请求转换到指定的节点,主分片将数据保存然后发送给副本保存。
写入延时=主分片延时+并行写入副本的最大延时。所以副本多虽然更安全但是写入效率也会低。
那么具体的写操作是如何进行的?
写入请求到达我们分片的时候先写入到存放在内存的索引当中,然后再刷入到lucene的底层文件segment中;
写入segment完毕后再执行refresh操作将数据refresh到缓冲区,然后每隔30分钟左右数据将flush到磁盘中。
1.为什么要translog?
内存中的数据刷写到磁盘的时候突然机器宕机了,内存中的数据也就丢失了,所以ES中有translog记录,
有了translog,服务器down机后再起来,就能很快恢复写入的过程。
这里要注意的是,translog也是先存在内存里的,然后默认5秒刷一次写到硬盘里。
2.写入日志的顺序
数据库是先写入我们的日志再写入内存,而ES是先写入内存再写入日志,因为内存的写入会有很复杂的逻辑很容易失败(比如分词、过滤、转换)。
3.为什么要有缓冲区?
落盘后才能进行数据查询!!!
数据写入到缓存比写入到磁盘快很多,以前我们是落盘以后用户才能查询,现在当数据写入缓冲区就可以给查询了,速度大大提供高。
1.文档冲突
并发修改时可能出现冲突,ES使用乐观锁的版本号的方式来避免冲突。
悲观锁:在修改数据之前先锁定,再修改的方式被称之为悲观并发控制(又名“悲观锁”,Pessimistic Concurrency Control,缩写“PCC”)。
之所以叫做悲观锁,是因为这是一种对数据的修改抱有悲观态度的并发控制方式。我们一般认为数据被并发修改的概率比较大,所以需要在修改之前先加锁。
乐观锁( Optimistic Locking ) 是相对悲观锁而言的,乐观锁假设数据一般情况下不会造成冲突,所以在数据进行提交更新的时候,才会正式对数据的冲突与否进行检测,如果发现冲突了,则让返回用户错误的信息,让用户决定如何去做。
相对于悲观锁,在对数据库进行处理的时候,乐观锁并不会使用数据库提供的锁机制。一般的实现乐观锁的方式就是记录数据版本。
1.文档展示
使用Kibana
1.ElasticSearch优化方式
硬件、内存——分片、副本——(5)(6)(7)
(1)硬件的选则
Elasticsearch重度使用磁盘,当磁盘速度提升之后,集群的整体性能会大幅度提高。所以优化磁盘:
- 使用固态硬盘,他们比机械磁盘优秀多了。
- 使用多块硬盘,并允许Elasticsearch把数据分配到它们上面。
- 不要使用远程挂载的存储,比如NFS或者SMB/CIFS。这个引入的延迟对性能来说完全是背道而驰的。
(2)内存设置
我们设置堆内存-Xms和-Xmx不要太大,让我们的Lucence可用内存大一些(听老师的意思是Lucence可以内存大小其实就是缓存大小,缓存大了,存储的数据更多,写磁盘落盘的次数就会少很多)
(3)分片策略
一个分片的底层即为一个 Lucene 索引,会消耗一定cpu、内存等。
所以合理设置分片数,需要根据业务来设置。比如设置分片数不超过节点数的 3 倍,防止一个节点怀里导致大量副本分片丢失。
(4)减少副本数量
副本多了,自然写的效率很低很多
(5)减少Redresh次数,如果对搜索时效性不高时,适当延长Refresh周期(例如由1秒变为30秒)
内存中的数据如果频繁refresh到缓存中,缓存中的数据因为要定期flush到磁盘中,磁盘满了的时候就需要合并就会影响我们的效率
(6)加大缓存设置
缓存中的数据因为要定期flush到磁盘中,磁盘满了的时候就需要合并就会影响我们的效率。缓存大了,存储的数据更多,写磁盘落盘的次数就会少很多
(7)合理使用合并
磁盘满了的时候就需要合并就会影响我们的效率。(ES合并段计算量庞大会消耗大量的IO)所以ES采用保守的合并策略——定期合并
2.Elasticsearch是如何实现Master选举的?
Elasticsearch的选举是ZenDiscovery模块负责的,主要包含Ping(节点之间通过这个RPC来发现彼此)和Unicast(单播模块包含一个主机列表以控制哪些节点需要ping通)这两部分;对所有可以成为master的节点(node.master: true)根据nodeId字典排序。
每次选举每个节点都把自己所知道节点排一次序,然后选出第一个节点让它做master节点。
如果对某个节点的投票数达到一定的值(可以成为master节点数n/2+1)并且该节点自己也选举自己,那这个节点就是master。否则重新选举一直到满足上述条件。
补充:master节点的职责主要包括集群、节点和索引的管理,不负责文档级别的管理;data节点可以关闭http功能。
2.Elasticsearch 集群脑裂问题?
集群中有多个master就是集群脑裂。造成的原因可能是网络延迟什么的导致导致一些节点访问不到master, 认为master 挂掉了从而选举出新的master
脑裂问题解决方案:
- 调大节点状态的响应时间,默认为3s,可以适当调大,如果master在该响应时间的范围内没有做出响应应答,判断该节点已经挂掉了。调大参数可适当减少误判。
- 角色分离:即master节点与data节点分离,限制角色
2.Elasticsearch中的节点(比如共20个),其中的10个选了一个master,另外10个选了另一个master,怎么办?
当集群master候选数量不小于3个时,可以通过设置最少投票通过数量超过所有候选节点一半以上来解决脑裂问题;
当候选数量为两个时,只能修改为唯一的一个master候选,其他作为data节点,避免脑裂问题。
2.详细描述一下Elasticsearch索引文档的过程。
这里的
索引文档
应该理解为文档写入 ES,创建索引
的过程,也就是数据写流程
客户端请求集群的协调节点,协调节点里面进行路由计算将请求转换到指定的节点,主分片将数据保存然后发送给副本保存。
①如果面试官再问:第二步中的文档获取分片的过程?
回答:借助路由算法获取hash(id) % 主分片数量
②数据怎么写入分片的?
写入请求到达我们分片的时候先写入到内存中的索引当中,然后再刷入到lucene的底层文件segment中;
写入segment完毕后每隔1秒再执行refresh操作将数据refresh到缓冲区,然后每隔30分钟左右数据将flush到磁盘中。
当然,为了防止数据出现问题在索引数据之后会写入translog日志中
2.详细描述一下Elasticsearch更新和删除文档的过程
ElasticSearch中段是不可改变的,那我要是删除数据怎么办呢?我们使用逻辑删除,不是真正的删除,查询时如果发现该数据被逻辑删除了就过滤掉它,也就是不显示给前台。
那什么时候真正的删除呢?倒排索引可以合并的嘛,当我们进行合并的时候那些被逻辑删除的就会被真正删除。
2.详细描述一下Elasticsearch搜索的过程
搜索被执行成一个两阶段过程,查询和取回。
在初始查询
阶段时,查询会广播到
索引中每一个分片(主分片或者副本分片)。 每个分片在本地执行搜索
然后返回给协调节点,协调队列合并产生一个全局排序后的结果列表。
接下来就是 取回
阶段,协调节点辨别出哪些文档需要被取回
并向相关的分片提交多个 GET 请求
拿到具体的内容。一旦所有的文档都被取回了,协调节点返回结果给客户端。
2.Elasticsearch中的分析器是什么?
倒排索引涉及到分词,面试官很可能问到你分词;而且倒排索引中极可能问到你词条、词典、倒排表
分词:我们要用分词器,比如常见的IK中文分词器,作为插件来使用,在里面我们还可以自定义词典(比如人名什么的,防止错误分词)
分词设置:我们可以设置类型为keyword或text来说明该词能不能进行分词(keyword类型的不能被分词,text类型的可以被分词)
2.在并发情况下,Elasticsearch 如果保证读写一致?
(1)并发修改时可能出现冲突,ES使用乐观锁的版本号的方式来避免冲突。
悲观锁:在修改数据之前先锁定,再修改的方式被称之为悲观并发控制(又名“悲观锁”,Pessimistic Concurrency Control,缩写“PCC”)。
之所以叫做悲观锁,是因为这是一种对数据的修改抱有悲观态度的并发控制方式。我们一般认为数据被并发修改的概率比较大,所以需要在修改之前先加锁。
乐观锁( Optimistic Locking ) 是相对悲观锁而言的,乐观锁假设数据一般情况下不会造成冲突,所以在数据进行提交更新的时候,才会正式对数据的冲突与否进行检测,如果发现冲突了,则让返回用户错误的信息,让用户决定如何去做。
相对于悲观锁,在对数据库进行处理的时候,乐观锁并不会使用数据库提供的锁机制。一般的实现乐观锁的方式就是记录数据版本。
(2)一致性还体现在主分片和副本的一致性上面。另外对于写操作,一致性级别支持 quorum/one/all,默认为 quorum,即一半以上的成功了就可以往下走。如果我们取one那就是主分片保存成功了就可以往下走,副本暂时可以不用考虑。如果我们取all,那就是所有主分片和副本全部成功了才能往下走。
2.如何监控 Elasticsearch 集群状态?
通过 Kibana 监控 Elasticsearch。你可以实时查看你的集群健康状态和性能,也可以分析过去的集群、索引和节点指标。
2.Elasticsearch 与 solr 的区别?
1)背景
他们都是基于 Lucene 搜索服务器基础上开发,一款优秀的,高性能的企业级搜索服务器,【为什么是高性能的?是因为他们都是基于分词技术构建的倒排索引的方式进行查询】
2)主要区别
- 当实时建立索引的时候,solr 会产生 io 阻塞,而 es 不会,es 查询性能要高于 solr
- 在不断动态添加数据的时候,solr 的检索效率会变得低下,而 es 没有什么变化
- Solr 利用 zookeeper 进行分布式管理,而 es 自带有分布式系统的管理功能,
- Solr 一般都要部署到 web 服务器上,比如 tomcat,启动 tomcat 的时候需要配置 tomcat 和 solr 的 关联 【 Solr 的本质,是一个动态的 web项目】
- Solr支持更多格式的数据 【xml、json、csv 】等,而 es 仅仅支持
json 文件
格式
14.说说Elasticsearch常用的调优手段?
设计阶段调优
(1)根据业务增量需求,采取基于日期模板创建索引,通过 roll over API 滚动索引;(2)使用别名进行索引管理;
(3)每天凌晨定时对索引做 force_merge 操作,以释放空间;
(4)采取冷热分离机制,热数据存储到 SSD,提高检索效率;冷数据定期进行 shrink操作,以缩减存储;
(5)采取 curator 进行索引的生命周期管理;
(6)仅针对需要分词的字段,合理的设置分词器;
(7)Mapping 阶段充分结合各个字段的属性,是否需要检索、是否需要存储等。………
写入调优
(1)写入前副本数设置为 0;
(2)写入前关闭 refresh_interval 设置为-1,禁用刷新机制;
(3)写入过程中:采取 bulk 批量写入;
(4)写入后恢复副本数和刷新间隔;
(5)尽量使用自动生成的 id。
查询调优
(1)禁用 wildcard;
(2)禁用批量 terms(成百上千的场景);
(3)充分利用倒排索引机制,能 keyword 类型尽量 keyword;
(4)数据量大时候,可以先基于时间敲定索引再检索;
(5)设置合理的路由机制。
其他调优
部署调优,业务调优等。
上面的提及一部分,面试者就基本对你之前的实践或者运维经验有所评估了。
15.Elasticsearch 在部署时,对 Linux 的设置有哪些优化方法?
(1)64 GB 内存的机器是非常理想的, 但是 32 GB 和 16 GB 机器也是很常见的。少于 8 GB 会适得其反。
(2)如果你要在更快的 CPUs 和更多的核心之间选择,选择更多的核心更好。多个内核提供的额外并发远胜过稍微快一点点的时钟频率。
(3)如果你负担得起 SSD,它将远远超出任何旋转介质。 基于 SSD 的节点,查询和索引性能都有提升。如果你负担得起,SSD 是一个好的选择。
(4)即使数据中心们近在咫尺,也要避免集群跨越多个数据中心。绝对要避免集群跨越大的地理距离。
(5)请确保运行你应用程序的 JVM 和服务器的 JVM 是完全一样的。 在Elasticsearch 的几个地方,使用 Java 的本地序列化。
(6)通过设置 gateway.recover_after_nodes、gateway.expected_nodes、 gateway.recover_after_time 可以在集群重启的时候避免过多的分片交换,这可能会让数
据恢复从数个小时缩短为几秒钟。
(7)Elasticsearch 默认被配置为使用单播发现,以防止节点无意中加入集群。只有在同一台机器上运行的节点才会自动组成集群。最好使用单播代替组播。
(8)不要随意修改垃圾回收器(CMS)和各个线程池的大小。
(9)把你的内存的(少于)一半给 Lucene(但不要超过 32 GB!),通过ES_HEAP_SIZE环境变量设置。
(10)内存交换到磁盘对服务器性能来说是致命的。如果内存交换到磁盘上,一个100 微秒的操作可能变成 10 毫秒。 再想想那么多 10 微秒的操作时延累加起来。 不难看出 swapping 对于性能是多么可怕。
(11)Lucene 使用了大 量 的文件。同时,Elasticsearch 在节点和 HTTP 客户端之间进行通信也使用了大量的套接字。 所有这一切都需要足够的文件描述符。你应该增加你的文件描述符,设置一个很大的值,如 64,000。
16.客户端在和集群连接时,如何选择特定的节点执行请求?
TransportClient 利用 transport 模块远程连接一个 elasticsearch 集群。它并不加入到集群中,只是简单的获得一个或者多个初始化的 transport 地址,并以 轮询 的方式与这些地址进行通信。
7.Elasticsearch对于大数据量(上亿量级)的聚合如何实现?
Elasticsearch 提供的首个近似聚合是cardinality 度量。它提供一个字段的基数,即该字段的distinct或者unique值的数目。它是基于HLL算法的。HLL 会先对我们的输入作哈希运算,然后根据哈希运算的结果中的 bits 做概率估算从而得到基数。其特点是:可配置的精度,用来控制内存的使用(更精确 = 更多内存);小的数据集精度是非常高的;我们可以通过配置参数,来设置去重需要的固定内存使用量。无论数千还是数十亿的唯一值,内存使用量只与你配置的精确度相关 。
18.对于 GC 方面,在使用 Elasticsearch 时要注意什么?
(1)倒排词典的索引需要常驻内存,无法 GC,需要监控 data node 上 segmentmemory 增长趋势。
(2)各类缓存,field cache, filter cache, indexing cache, bulk queue 等等,要设置合理的大小,并且要应该根据最坏的情况来看 heap 是否够用,也就是各类缓存全部占满的时候,还有 heap 空间可以分配给其他任务吗?避免采用 clear cache等“自欺欺人”的方式来释放内存。
(3)避免返回大量结果集的搜索与聚合。确实需要大量拉取数据的场景,可以采用scan &
scroll api 来实现。
(4)cluster stats 驻留内存并无法水平扩展,超大规模集群可以考虑分拆成多个集群通过 tribe node 连接。
(5)想知道 heap 够不够,必须结合实际应用场景,并对集群的 heap 使用情况做持续的监控。
(6)根据监控数据理解内存需求,合理配置各类circuit breaker,将内存溢出风险降低到最低