1. ElasticSearch部署架构和容量规划
前面介绍了ElasticSearch原理和使用相关的内容,在生产环境如何比较科学的进行容量规划、部署、调优、排查问题呢,业界和官方也对相关的问题进行总结,我这边也结合自己的经验对这些使用ElasticSearch经常遇到的问题进行了总结。其中主要包括以下三大模块:
ElasticSearch有多种类型的节点,在前面概述和核心也已经介绍过了。在这里可以重新回顾下。ElasticSearch的部署节点类型如下:
主节点及其候选节点,负责集群状态(cluster state)的管理
配置项:node.master,默认为true
数据节点,负责数据存储及处理客户端请求
配置项:node.data,默认为true
ingest节点,负责数据处理,脚本执行
配置项:node.ingest,默认为true
协调节点
配置项:设置上面三个参数全部为false,那么它就是一个纯协调节点
机器学习节点,收费属于x-pack
在生产环境部署推荐配置整体思路就是:尽量是一个节点只承担一个角色。
因为不同的节点所需要的计算机资源都不一样。职责分离后可以按需扩展互不影响。
资源要求:中高CPU;中高内存;中低磁盘
一般在生产环境中配置3台
一个集群只有1台活跃的主节点,负责分片管理,索引创建,集群管理等操作
资源要求:CPU、内存、磁盘要求都高
资源要求:高配置CPU;中等配置的RAM;低配置的磁盘
资源要求:一般中高CPU;中高内存;低磁盘
协调节点扮演者负载均衡、结果的聚合,在大型的es集群中条件允许可以使用高配的cpu和内存。因为如果客户端发起了深度分页等请求可能会导致oom,这个在之前也有过分析。
注意:
如果和数据节点或者Coordinate节点混合部署,数据节点本来相对有比较大的内存占用。
而Coordinate节点有时候可能会有开销很高的查询导致OOM,这些甚至都有可能影响Master节点,导致集群的不稳定。
搭建一个es集群是由模式可循的。
这是一个基础版的职责分离的部署架构:
但是如果大量的聚合查询等操作,这种架构不太适合了。
当系统中有大量的复杂查询或者聚合时候,我们可增加Coordinating节点,增加查询的性能,这里增加了负载均衡层,通过负载均衡扩展时应用程序无感知。
这样部署部署相互影响,写入多的话,多部署ingetst节点,读的时候聚合查询较多可以多部署协调节点,存储数据量大,可以适当对数据节点进行调优。
我们知道数据有冷热之分,比如写入频繁的日志数据,近期的索引将会频繁写入。es根据数据这些特征引入了hot节点和warm节点。
使用ssd,该节点上的索引不断的有新文档写入和查询,对cpu、io的要求较高。
可以使用HDD,上面的索引不会有写入,查询较少。上面只保存只读索引或者旧索引,使用大容量便宜的机械硬盘。
配置步骤:
针对多机房灾备,ElasticSearch业界有多种不同的通用解决方案:
一个集群中的节点分布在不同的机房
应用程序同时将数据写入两个集群
应用程序先将数据写入消息队列,然后由下游的消费者消费并写入集群
ElasticSearch官方的跨集群复制功能,基于文档操作实现订阅复制
定期将索引备份到外部存储,如hdfs等设备
写请求交给网关,网关实时写入主集群,然后异步写备集群
如下是基于CCR跨集群复制的部署架构,因为篇幅有限,异地多活又是一个很大的话题,其它方案和其细节可以查阅相关资料。
我们知道当es集群的节点数大于索引的分片数时,集群将无法通过水平扩展提升集群的性能。而分片数过多,对于聚合查询以及集群的元数据管理也都有影响。我们可以总结为:
分片数量较多
优点:
缺点:
通常建议一个集群总分片数小于10w。
如何设计分片的数量呢?一个分片保持多大的数据量比较合适呢?
我们需要根据使用场景来设置:
避免使用非常大的分片,因为这会对群集从故障中恢复的能力产生负面影响。而每个分片也会消耗相应的文件句柄,内存和CPU资源,分片太多会互相竞争,影响性能。
主分片数一旦确定就无法更改,只能新建创建并对数据进行重新索引(reindex),虽然reindex会比较耗时,但至少能保证你不会停机。所以我们一定要科学的设计分片数。
这里摘录于官方关于分片大小的建议:
主分片与副本都能处理查询请求,它们的唯一区别在于只有主分片才能处理索引请求。副本对搜索性能非常重要,同时用户也可在任何时候添加或删除副本。额外的副本能给带来更大的容量,更高的呑吐能力及更强的故障恢复能力
3.1.3. 小结
根据实际经验我们稍微总结下:
对于数据量较小(100GB以下)的index
对于数据量较大(100GB以上)的index:
综合考虑整个index的shard数量,如果shard数量(不包括副本)超过50个,就很可能引发拒绝率上升的问题,此时可考虑把该index拆分为多个独立的index,分摊数据量,同时配合routing使用,降低每个查询需要访问的shard数量。
关闭交换分区的方法是:
这里是官方的jvm推荐配置链接:
https://www.elastic.co/cn/blog/a-heap-of-trouble
es的节点提供查询的时候使用较多的内存来存储查询缓存,es的lucene写入到磁盘也会先缓存在内存中,我们开启设计这个es节点时需要根据每个节点的存储数据量来进行判断。这里有一个流行的推荐比例配置:
示例:
有一个业务的数据量预估实际有1T,我们把副本设置1个,那么es中总数据量为2T。
这里31G表示的是jvm设置不超过32g否则不会使用java的指针压缩优化了。
前面也提到过,数据节点推荐使用ssd
可以考虑:
写入的目标在于增大写入的吞吐量,这里主要从两个方面进行优化:
这里可以针对myindex索引优化的示例:
首先有几个原则我们需要清楚:
我们可以通过health相关的api进行查看
我们可以使用profile api来定位慢查询。
在查询条件中设置profile为true的参数,将会显示查询经历的细节。
其结果为:
这里会返回一个shards列表。其中:
主要包含了如下信息:
Profile API让我们清楚地看到查询耗时。提供了有关子查询的详细信息,我们可以清楚地知道在哪个环节查询慢,另外返回的结果中,关于Lucene的详细信息也让我们深入了解到ES是如何执行查询的。
ES记录了两类慢日志:
慢搜索日志
用来记录哪些查询比较慢,每个节点可以设置不同的阈值。
之前我们已经详细分析了ES的搜索由两个阶段组成:
慢搜索日志给出了每个阶段所花费的时间和整个查询内容本身。慢搜索日志可以为查询和取回阶段单独设置以时间为单位的阈值,在定义好每个级别的时间后,通过level决定输出哪个级别的日志。
示例如下
前面参考官方链接:
https://www.elastic.co/guide/en/elasticsearch/reference/7.17/index-moles-slowlog.html
如果出现节点占用CPU很高,我们需要知道CPU在运行什么任务,一般通过线程堆栈来查看。
这里有两种方式可以查看哪些线程CPU占用率比较高:
这里推荐使用hot_threads api
通过返回的结果可以看到什么线程占用更高,正在做什么操作。更详细的内容可以参考官网:
https://www.elastic.co/guide/en/elasticsearch/reference/7.17/cluster-nodes-hot-threads.html
4.3.2 内存使用率过高
1)缓存类型
首先我们需要了解ES中的缓存类型,缓存主要分成如图所示三大类,如下图所示,一个es节点的内存结构:
Node Query Cache(Filter Context)
Shard Query Cache(Cache Query的结果)
Fielddata Cache
Segments Cache
(segments FST数据的缓存),为了加速查询,FST永驻堆内内存,无法被GC回收。该部分内存无法设置大小,长期占用50%~70%的堆内存,只能通过delete index,close index以及force-merge index释放内存
ES底层存储采用Lucene(搜索引擎),写入时会根据原始数据的内容,分词,然后生成倒排索引。查询时,先通过查询倒排索引找到数据地址(DocID)),再读取原始数据(行存数据、列存数据)。
但由于Lucene会为原始数据中的每个词都生成倒排索引,数据量较大。所以倒排索引对应的倒排表被存放在磁盘上。
这样如果每次查询都直接读取磁盘上的倒排表,再查询目标关键词,会有很多次磁盘IO,严重影响查询性能。为了解磁盘IO问题,Lucene引入排索引的二级索引FST[Finite State Transcer]。原理上可以理解为前缀树,加速查询
2)节点的内存查看
3)案例分析
如果节点出现了集群整体响应缓慢,也没有特别多的数据读写。但是发现节点在持续进行Full GC。
常见原因:
Segments个数过多,导致Full GC
我们可以通过查看ElasticSearch的内存分析命令发现:
segments.memory占用很大空间。
解决方案:
Field data cache 过大,导致Full GC
我们可以查看ElasticSearch的内存使用,发现fielddata.memory.size占用很大空间。同时,数据不存在写入和更新,也执行过segments merge。
解决方案:
复杂的嵌套聚合,导致集群Full GC
节点响应缓慢,持续进行Full GC。导出Dump分析。发现内存中有大量 bucket对象,查看日志,发现复杂的嵌套聚合
解决方案:
4)断路器
es有多种断路器,我们可以合理使用,避免不合理操作引发的OOM,每个断路器可以指定内存使用的限制。
关于es的断路器使用可以参考官网文档:
https://www.elastic.co/cn/blog/improving-node-resiliency-with-the-real-memory-circuit-breaker
在排查es问题时,我们会使用一些常见的命令来分析cpu、io、网络等问题。常见的命令如下
我们这里按照1s的频率输出磁盘信息
如果想查看和进程关联的信息,可以使用pidstat或者iotop。
例如,下面为iotop的输出结果
sar命令可以诊断操作系统内存相关情况。
PS:我们需要关闭内存交换,内存交换会严重损害性能 。
我们知道,操作系统有内核态和用户态,该命令可以输出相关信息
Recv-Q和Send-Q代表该连接在内核中等待发送和接收的数据长度。
如果改数据太多,可能原因为应用程序处理不及时或者对端的数据接收不及时,比如网络拥塞之类
本片文章先介绍了es的部署架构,回顾了es节点类型以及它们的配置方式,也了解了不同类型对硬件的要求不一样。然后总结了几种不同的架构模式,比如基础部署、读写分离、冷热分离、异地多活等架构模式,在生产环境中一般我们推荐读写分离架构模式,如果可以最好加上冷热分离,不过配置可能稍微复杂点。
对于容量规划与调优,首先要明确存储的数据量和使用场景,推荐内存磁盘比为:搜索类比例(1:16),日志类(1:48);比如2T的总数据,搜索如果要保持良好的性能的话,每个节点31*16=496G。每个节点实际有400G的存储空间。那么2T/400G,则需要5个es存储节点,每个节点分片数多少合适,文中也有介绍。副本分片数需要根据我们的容错需求。我们还总结了集群配置和jvm配置相关的优化。
es的使用优化,我们分别总结了写入和查询的优化。写入是其单次数据量、索引refresh、分词等情况都会影响其吞吐量,我们需要根据实际情况来优化。针对于查询,我们可以使用api工具进行分析,分析慢耗时发在在哪一步。当es集群出现异常时,如cpu过高、内存fullgc、卡顿、变红,我们逐一分析了可能的原因和解决办法,同时也介绍了一些常见的诊断工具和监控api。
我们需要先了解es内部运作的原理,这样才能根据实际情况正确的设置集群参数和数据模型,还需要结合实际工作遇到的问题不断的总结经验,才能用好ElasticSearch。
2. ES的存储系统
ES 内嵌式存储系统ES (内嵌式存储系统(embedded storage,ES))
内嵌式存储系统(embedded storage,ES),就是把存储介质内嵌在服务器中,就好比现在PC中的硬盘。
优点是安装简单,维护方便。
缺点是每个服务器所能够连接的存储介质很有限,同时存储容量和存取速度都受到服务器性能的限制。内嵌式存储系统的一个致使缺点是所存储信息的安全性和可用性必须依赖服务器,如果服务器出现故障,其所存储的信息将不可用。
所以说,内嵌式存储系统是一个封闭的系统。
3. elasticSearch理论篇—索引、节点、分片
传统我们检索文章,是逐个遍历找到对应关键词的位置;
而倒排索引,是通过分词策略,形成词与文章的映射关系表,这种词典+映射表即为倒排索引。
倒排索引的底层实现是基于:FST(Finite State Transcer)数据结构。
lucene [lu'sen] 从4+版本后开始大量使用的数据结构是FST。FST有两个优点:
利用es的分片预分配。
不能,因为分片数是 文档路由算法 中重要的元素:
shard = hash(routing) % number_of_primary_shards
动态修改分片将意味着几乎重新索引文档数据,这是比仅仅将分片从一个节点复制到另一个节点更重量级的操作。
一个分片存在于单个节点,一个节点可以包含多个分片。
elasticSearch天然具有分布式的特征,实现水平扩容时通过 分片预分配 。在创建索引时,选择合适的分片数。
随着数据量的增加,可以动态的增加节点数,elasticSearch将会自动将分片分配到新增的节点上,当重新分配完成时,每个分片将会有接近至少两倍于之前的运算速度。
elasticSearch中新添加的索引默认被指定了5个主分片。这意味着我们最多可以将那个索引分散到5个节点上,每一个节点一个分片。
不能,一个分片并不是没有代价的。
es适当的预分配是好的,但是上千个分片就有些糟糕。
ElasticSearch推荐的最大JVM堆空间是30~32G, 所以把你的分片最大容量限制为30GB, 然后再对分片数量做合理估算. 例如, 你认为你的数据能达到200GB, 推荐你最多分配7到8个分片。
在开始阶段, 一个好的方案是根据你的节点数量按照1.5~3倍的原则来创建分片. 例如,如果你有3个节点, 则推荐你创建的分片数最多不超过9(3x3)个。当性能下降时,增加节点,ES会平衡分片的放置。
对于基于日期的索引需求, 并且对索引数据的搜索场景非常少. 也许这些索引量将达到成百上千, 但每个索引的数据量只有1GB甚至更小. 对于这种类似场景, 建议只需要为索引分配1个分片。如日志管理就是一个日期的索引需求,日期索引会很多,但每个索引存放的日志数据量就很少。
副本分片 可以实现高可用。当持有主分片的节点挂掉之后,一个副本分片将会晋升为主分片的角色。
在索引写入时,副本分片做着和主分片相同的工作。新文档首先被索引进主分片然后在同步到其他所有的副本分片。增加副本分片并不会增加索引容量。
副本分片可以服务于读请求,如果索引偏向查询,那么可以通过增加副本的数目来提升查询性能。但也要为此增加额外的硬件资源。
当使用上面配置时,每一个分片的副本分片数量为1个。
一个拥有两个主分片一份副本的索引可以在四个节点中横向扩展
Elasticsearch: 权威指南 » 数据建模 » 扩容设计 » 扩容的单元
面试官:Elasticsearch如何设计索引?满分答案来了
elasticsearch 设置多少分片合适
新年手打,24道进阶必备Elasticsearch 面试真题(建议收藏!)
4. Elasticsearch之存储原理
倒排索引被写入磁盘后是不可变的,ES解决不变性和更新索引的方式是使用多个索引,利用新增的索引来反映修改,在查询时从旧的到新的依次查询,最后来一个结果合并。
ES底层是基于Lucene,最核心的概念就是 Segment(段) ,每个段本身就是一个倒排索引。
ES中的Index由多个段的集合和 commit point(提交点) 文件组成。
提交点文件中有一个列表存放着所有已知的段,下面是一个带有1个提交点和3个段的Index示意图:
Doc会先被搜集到内存中的Buffer内,这个时候还无法被搜索到,如下图所示:
每隔一段时间,会将buffer提交,在flush磁盘后打开新段使得搜索可见,详细过程如下:
下面展示了这个过程完成后的段和提交点的状态:
通过这种方式,可以使得新文档从被索引到可被搜索间的时间间隔在数分钟,但是还不够快。因为磁盘需要 fsync ,这个就成为性能瓶颈。我们前面提到过Doc会先被从buffer刷入段写入文件系统缓存(很快),那么就自然想到在这个阶段就让文档对搜索可见,随后再被刷入磁盘(较慢)。
Lucene支持对新段写入和打开,可以使文档在没有完全刷入硬盘的状态下就能对搜索可见,而且是一个开销较小的操作,可以频繁进行。
下面是一个已经将Docs刷入段,但还没有完全提交的示意图:
我们可以看到,新段虽然还没有被完全提交,但是已经对搜索可见了。
引入refresh操作的目的是提高ES的实时性,使添加文档尽可能快的被搜索到,同时又避免频繁fsync带来性能开销,依靠的就是文件系统缓存OS cache里缓存的文件可以被打开(open/reopen)和读取,而这个os cache实际是一块内存区域,而非磁盘,所以操作是很快的,这就是ES被称为近实时搜索的原因。
refresh默认执行的间隔是1秒,可以使用 refreshAPI 进行手动操作,但一般不建议这么做。还可以通过合理设置 refresh_interval 在近实时搜索和索引速度间做权衡。
index segment刷入到os cache后就可以打开供查询,这个操作是有潜在风险的,因为os cache中的数据有可能在意外的故障中丢失,而此时数据必备并未刷入到os disk,此时数据丢失将是不可逆的,这个时候就需要一种机制,可以将对es的操作记录下来,来确保当出现故障的时候,已经落地到磁盘的数据不会丢失,并在重启的时候可以从操作记录中将数据恢复过来。elasticsearch提供了translog来记录这些操作,结合os cached segments数据定时落盘来实现数据可靠性保证(flush)。
文档被添加到buffer同时追加到translog:
进行 refresh 操作,清空buffer,文档可被搜索但尚未 flush 到磁盘。translog不会清空:
每隔一段时间(例如translog变得太大),index会被flush到磁盘,新的translog文件被创建,commit执行结束后,会发生以下事件:
下面示意图展示了这个状态:
translog记录的是已经 在内存生成(segments)并存储到os cache但是还没写到磁盘的那些索引操作 (注意,有一种解释说,添加到buffer中但是没有被存入segment中的数据没有被记录到translog中,这依赖于写translog的时机,不同版本可能有变化,不影响理解),此时这些新写入的数据可以被搜索到,但是当节点挂掉后这些未来得及落入磁盘的数据就会丢失,可以通过trangslog恢复。
当然translog本身也是磁盘文件,频繁的写入磁盘会带来巨大的IO开销,因此对translog的追加写入操作的同样操作的是os cache,因此也需要定时落盘(fsync)。translog落盘的时间间隔直接决定了ES的可靠性,因为宕机可能导致这个时间间隔内所有的ES操作既没有生成segment磁盘文件,又没有记录到Translog磁盘文件中,导致这期间的所有操作都丢失且无法恢复。
translog的fsync是ES在后台自动执行的,默认是每5秒钟主动进行一次translog fsync,或者当translog文件大小大于512MB主动进行一次fsync,对应的配置是 index.translog.flush_threshold_period 和 index.translog.flush_threshold_size 。
当 Elasticsearch 启动的时候, 它会从磁盘中使用最后一个提交点去恢复已知的段,并且会重放 translog 中所有在最后一次提交后发生的变更操作。
translog 也被用来提供实时 CRUD 。当你试着通过ID来RUD一个Doc,它会在从相关的段检索之前先检查 translog 中最新的变更。
默认 translog 是每5秒或是每次请求完成后被 fsync 到磁盘(在主分片和副本分片都会)。也就是说,如果你发起一个index, delete, update, bulk请求写入translog并被fsync到主分片和副本分片的磁盘前不会反回200状态。
这样会带来一些性能损失,可以通过设为异步fsync,但是必须接受由此带来的丢失少量数据的风险:
flush 就是执行commit清空、干掉老translog的过程。默认每个分片30分钟或者是translog过于大的时候自动flush一次。可以通过flush API手动触发,但是只会在重启节点或关闭某个索引的时候这样做,因为这可以让未来ES恢复的速度更快(translog文件更小)。
满足下列条件之一就会触发冲刷操作:
整体流程:
删除一个ES文档不会立即从磁盘上移除,它只是被标记成已删除。因为段是不可变的,所以文档既不能从旧的段中移除,旧的段也不能更新以反映文档最新的版本。
ES的做法是,每一个提交点包括一个 .del 文件(还包括新段),包含了段上已经被标记为删除状态的文档。所以,当一个文档被做删除操作,实际上只是在 .del 文件中将该文档标记为删除,依然会在查询时被匹配到,只不过在最终返回结果之前会被从结果中删除。ES将会在用户之后添加更多索引的时候,在后台进行要删除内容的清理。
文档的更新操作和删除是类似的:当一个文档被更新,旧版本的文档被标记为删除,新版本的文档在新的段中索引。
该文档的不同版本都会匹配一个查询,但是较旧的版本会从结果中删除。
通过每秒自动刷新创建新的段,用不了多久段的数量就爆炸了,每个段消费大量文件句柄,内存,cpu资源。更重要的是,每次搜索请求都需要依次检查每个段。段越多,查询越慢。
ES通过后台合并段解决这个问题。ES利用段合并的时机来真正从文件系统删除那些version较老或者是被标记为删除的文档。被删除的文档(或者是version较老的)不会再被合并到新的更大的段中。
可见,段合并主要有两个目的:
ES对一个不断有数据写入的索引处理流程如下:
合并过程如图:
从上图可以看到,段合并之前,旧有的Commit和没Commit的小段皆可被搜索。
段合并后的操作:
合并完成后新的段可被搜索,旧的段被删除,如下图所示:
注意 :段合并过程虽然看起来很爽,但是大段的合并可能会占用大量的IO和CPU,如果不加以控制,可能会大大降低搜索性能。段合并的optimize API 不是非常特殊的情况下千万不要使用,默认策略已经足够好了。不恰当的使用可能会将你机器的资源全部耗尽在段合并上,导致无法搜索、无法响应。
5. ES数据存储可靠性和写入流程
https://www.elastic.co/guide/en/elasticsearch/guide/2.x/near-real-time.html
https://www.elastic.co/guide/en/elasticsearch/guide/2.x/merge-process.html
1、数据存储可靠性保证原理
1.1 translog机制
当一个文档写入Lucence后是存储在内存中的,即使执行了refresh操作仍然是在文件系统缓存中,如果此时服务器宕机,那么这部分数据将会丢失
当进行文档写操作时会先将文档写入Lucene,然后写入一份到translog,写入translog是落盘的
tips:如果对可靠性要求不是很高,也可以设置异步落盘,可以提高性能,由配置index.translog.rability和index.translog.sync_interval控制
tips:translog是追加写入,因此性能比较好
先写入Lucene再写入translog。原因是写入Lucene可能会失败,为了减少写入失败回滚的复杂度,因此先写入Lucene
1.2 flush操作
refresh_interval定时触发 或当translog达到index.translog.flush_threshold_size(默认512mb),ES会触发一次flush操作:先执行refresh操作将buffer中的数据生成segment,然后调用lucene的commit方法将所有内存中的segment fsync到磁盘,最后会清空translog中的数据(6.x版本为了实现sequenceIDs,不删除translog) 。
1.3 merge操作
refresh操作会产生大量的小segment,因此产生的每个文件都会消耗文件句柄,内存,CPU 使用等各种资源。更重要的是每个查询请求都要顺序检查每个segment; segment越多检索会越慢.
ES会运行一个检测任务,在后台把近似大小的segment合并成一个新的大segment,并删除旧segment
1.4、多副本机制
ES有多副本机制(默认是1个副本),一个分片的主副分片不能分片在同一个节点上,进一步保证数据的可靠性。
2、ES写索引的流程
6. es使用与原理6 -- 聚合分析剖析
有些聚合分析的算法,是很容易就可以并行的,比如说max
有些聚合分析的算法,是不好并行的,比如说,count(distinct),并不是说,在每个node上,直接就出一些distinct value,就可以的,因为数据可能会很多,假设图中的协调节点3百万个数据去重后还剩下100万distinct的数据,那么内存需要来存储这100万条数据,这是不可能的
es会采取近似聚合的方式,就是采用在每个node上进行近估计的方式,得到最终的结论,cuont(distcint),100万,1050万/95万 --> 5%左右的错误率
近似估计后的结果,不完全准确,但是速度会很快,一般会达到完全精准的算法的性能的数十倍
precision_threshold优化准确率和内存开销
brand去重,如果brand的unique value,在100个以内,小米,长虹,三星,TCL,HTL。。。
在多少个unique value以内,cardinality,几乎保证100%准确
cardinality算法,会占用precision_threshold * 8 byte 内存消耗,100 * 8 = 800个字节
占用内存很小。。。而且unique value如果的确在值以内,那么可以确保100%准确
100,数百万的unique value,错误率在5%以内
precision_threshold,值设置的越大,占用内存越大,1000 * 8 = 8000 / 1000 = 8KB,可以确保更多unique value的场景下,100%的准确
field,去重,count,这时候,unique value,10000,precision_threshold=10000,10000 * 8 = 80000个byte,80KB
doc value正排索引
搜索+聚合 是怎么实现的?
假设是倒排索引实现的
倒排索引来实现是非常不现实的,因为我们搜索的那个字段search_field 有可能是分词的,这就需要去扫描整个索引才能实现聚合操作,效率是及其低下的。
正排索引结构:
doc2: agg1
doc3: agg2
1万个doc --> 搜 -> 可能跟搜索到10000次,就搜索完了,就找到了1万个doc的聚合field的所有值了,然后就可以执行分组聚合操作了
doc value原理
1、doc value原理
(1)index-time生成
PUT/POST的时候,就会生成doc value数据,也就是正排索引
(2)核心原理与倒排索引类似
正排索引,也会写入磁盘文件中,然后呢,os cache先进行缓存,以提升访问doc value正排索引的性能
如果os cache内存大小不足够放得下整个正排索引,doc value,就会将doc value的数据写入磁盘文件中
(3)性能问题:给jvm更少内存,64g服务器,给jvm最多16g
es官方是建议,es大量是基于os cache来进行缓存和提升性能的,不建议用jvm内存来进行缓存,那样会导致一定的gc开销和oom问题
给jvm更少的内存,给os cache更大的内存
64g服务器,给jvm最多16g,几十个g的内存给os cache
os cache可以提升doc value和倒排索引的缓存和查询效率
2、column压缩
doc1: 550
doc2: 550
doc3: 500
合并相同值,550,doc1和doc2都保留一个550的标识即可
(1)所有值相同,直接保留单值
(2)少于256个值,使用table encoding模式:一种压缩方式
(3)大于256个值,看有没有最大公约数,有就除以最大公约数,然后保留这个最大公约数
重点:
对分词的field,直接执行聚合操作,会报错,大概意思是说,你必须要打开fielddata,然后将正排索引数据加载到内存中,才可以对分词的field执行聚合操作,而且会消耗很大的内存
先修改 字段的fielddata属性为true,再查 就能查找到数据
当然,我们也可以使用内置field(keyword)不分词,对string field进行聚合,如果对不分词的field执行聚合操作,直接就可以执行,不需要设置fieldata=true
分词field+fielddata的工作原理
doc value --> 不分词的所有field,可以执行聚合操作 --> 如果你的某个field不分词,那么在index-time,就会自动生成doc value --> 针对这些不分词的field执行聚合操作的时候,自动就会用doc value来执行
分词field,是没有doc value的。。。在index-time,如果某个field是分词的,那么是不会给它建立doc value正排索引的,因为分词后,占用的空间过于大,所以默认是不支持分词field进行聚合的
分词field默认没有doc value,所以直接对分词field执行聚合操作,是会报错的
对于分词field,必须打开和使用fielddata,完全存在于纯内存中。。。结构和doc value类似。。。如果是ngram或者是大量term,那么必将占用大量的内存。。。
如果一定要对分词的field执行聚合,那么必须将fielddata=true,然后es就会在执行聚合操作的时候,现场将field对应的数据,建立一份fielddata正排索引,fielddata正排索引的结构跟doc value是类似的,
但是只会讲fielddata正排索引加载到内存中来,然后基于内存中的fielddata正排索引执行分词field的聚合操作
如果直接对分词field执行聚合,报错,才会让我们开启fielddata=true,告诉我们,会将fielddata uninverted index,正排索引,加载到内存,会耗费内存空间
为什么fielddata必须在内存?因为大家自己思考一下,分词的字符串,需要按照term进行聚合,需要执行更加复杂的算法和操作,如果基于磁盘和os cache,那么性能会很差
我们是不是可以预先生成加载fielddata到内存中来???
query-time的fielddata生成和加载到内存,变为index-time,建立倒排索引的时候,会同步生成fielddata并且加载到内存中来,这样的话,对分词field的聚合性能当然会大幅度增强
7. 为什么我的ES文件浏览器不能浏览外置存储卡
我的也是,现在还只能用自带的文件浏览器查看..ES浏览器只能看内置存储卡的文件.只不过ES浏览器可以查看手机内存里面的文件.自带的看不了
我找到了..你用ES浏览器点左上角的收藏.再点根目录有个mnt的文件夹打开.里面sdcard就是内置存储卡
sdcard2就是外置存储卡.把sdcard2设为默认路径就可以了
8. PB级大规模Elasticsearch集群运维与调优实践
某中型互联网公司的游戏业务,使用了腾讯云的Elasticsearch产品,采用ELK架构存储业务日志。因为游戏业务本身的日志数据量非常大(写入峰值在100w qps),在服务客户的几个月中,踩了不少坑,经过数次优化与调整,把客户的ES集群调整的比较稳定,避免了在业务高峰时客户集群的读写异常,并且降低了客户的资金成本和使用成本。下面把服务客户过程中遇到的典型问题进行梳理,总结经验,避免再次踩坑。
解决方案架构师A: bellen, XX要上线一款新游戏,日志存储决定用ELK架构,他们决定在XX云和我们之间二选一,我们首先去他们公司和他们交流一下,争取拿下!
bellen: 好,随时有空!
。。。
和架构师一起前往该公司,跟负责底层组件的运维部门的负责人进行沟通。
XX公司运维老大:不要讲你们的PPT了,先告诉我你们能给我们带来什么!
bellen: 。。。呃,我们有很多优势。。。比如灵活地扩容缩容集群,还可以一键平滑升级集群版本,并且提供有跨机房容灾的集群从而实现高可用。。
XX公司运维老大:你说的这些别的厂商也有,我就问一个问题,我们现在要存储一年的游戏日志,不能删除数据,每天就按10TB的数据量算,一年也得有个3PB多的数据,这么大的数量,都放在SSD云盘上,我们的成本太高了,你们有什么方案既能够满足我们存储这么大数据量的需求,同时能够降低我们的成本吗?
bellen: 我们本身提供的有冷热模式的集群,热节点采用SSD云硬盘,冷节点采用SATA盘,采用ES自带的ILM索引生命周期管理功能定期把较老的索引从热节点迁移到冷节点上,这样从整体上可以降低成本。另外一方面,也可以定期把更老的索引通过snapshot快照备份到COS对象存储中,然后删除索引,这样成本就更低了。
XX公司运维老大:存储到COS就是冷存储呗,我们需要查询COS里的数据时,还得再把数据恢复到ES里?这样不行,速度太慢了,业务等不了那么长时间,我们的数据不能删除,只能放在ES里!你们能不能给我们提供一个API, 让老的索引数据虽然存储在COS里,但是通过这个API依然可以查询到数据,而不是先恢复到ES, 再进行查询?
bellen: 。。。呃,这个可以做,但是需要时间。是否可以采用hadoop on COS的架构,把存量的老的索引数据通过工具导入到COS,通过hive去查询,这样成本会非常低,数据依然是随时可查的。
XX公司运维老大:那不行,我们只想用成熟的ELK架构来做,再增加hadoop那一套东西,我们没那么多人力搞这个事!
bellen: 好吧,那可以先搞一个集群测试起来,看看性能怎么样。关于存量数据放在COS里但是也需要查询的问题,我们可以先制定方案,尽快实施起来。
XX公司运维老大:行吧,我们现在按每天10TB数据量预估,先购买一个集群,能撑3个月的数据量就行,能给一个集群配置的建议吗?
bellen: 目前支持单节点磁盘最大6TB, cpu和内存的话可以放到8核32G单节点,单节点跑2w qps写入没有问题,后面也可以进行纵向扩容和横向扩容。
XX公司运维老大:好,我们先测试一下。
N 天后,架构师A直接在微信群里反馈:"bellen, 客户反馈这边的ES集群性能不行啊,使用logstash消费kafka中的日志数据,跑了快一天了数据还没追平,这是线上的集群,麻烦紧急看一下吧。。"
我一看,一脸懵, 什么时候已经上线了啊,不是还在测试中吗?
XX公司运维小B: 我们购买了8核32G*10节点的集群,单节点磁盘6TB, 索引设置的10分片1副本,现在使用logstash消费kafka中的数据,一直没有追平,kafka中还有很多数据积压,感觉是ES的写入性能有问题。
随后我立即查看了集群的监控数据,发现cpu和load都很高,jvm堆内存使用率平均都到了90%,节点jvm gc非常频繁了,部分节点因为响应缓慢,不停的离线又上线。。
经过沟通,发现用户的使用姿势是filebeat+kafka+logstash+elasticsearch, 当前已经在kafka中存储了有10天的日志数据,启动了20台logstash进行消费,logstash的batch size也调到了5000,性能瓶颈是在ES这一侧。客户8核32G*10节点的集群,理论上跑10w qps没有问题,但是logstash消费积压的数据往ES写入的qps远不止10w,所以是ES扛不住写入压力了,所以只能对ES集群进行扩容,为了加快存量数据的消费速度,先纵向扩容单节点的配置到32核64GB,之后再横向增加节点,以保证ES集群能够最大支持100w qps的写入(这里需要注意的是,增加节点后索引的分片数量也需要调整)。
所以一般新客户接入使用ES时,必须要事先评估好节点配置和集群规模,可以从以下几个方面进行评估:
上述场景2遇到的问题是业务上线前没有对集群配置和规模进行合理的评估,导致上线后ES集群负载就很高,通过合理的扩容处理,集群最终抗住了写入压力。但是又有新的问题出现了。
因为kafka积压的数据比较多,客户使用logstash消费kafka数据时,反馈有两个问题:
经过分析客户logstash的配置文件,发现问题出现的原因主要是:
分析后,对kafka和logstash进行了如下优化:
通过上述优化,最终使得logstash机器资源都被充分利用上,很快消费完堆积的kafka数据,待消费速度追平生成速度后,logstash消费kafka一直稳定运行,没有出现积压。
另外,客户一开始使用的是5.6.4版本的logstash,版本较老,使用过程中出现因为单个消息体过长导致logstash抛异常后直接退出的问题:
通过把logstash升级至高版本6.8避免了这个问题(6.x版本的logstash修复了这个问题,避免了crash)。
客户的游戏上线有一个月了,原先预估每天最多有10TB的数据量,实际则是在运营活动期间每天产生20TB的数据,原先6TB*60=360TB总量的数据盘使用率也达到了80%。针对这种情况,我们建议客户使用冷热分离的集群架构,在原先60个热节点的基础上,增加一批warm节点存储冷数据,利用ILM(索引生命周期管理)功能定期迁移热节点上的索引到warm节点上。
通过增加warm节点的方式,客户的集群磁盘总量达到了780TB, 可以满足最多三个月的存储需求。但是客户的需求还没有满足:
XX公司运维老大:给我们一个能存放一年数据的方案吧,总是通过加节点扩容磁盘的方式不是长久之计,我们得天天盯着这个集群,运维成本很高!并且一直加节点,ES会扛不住吧?
bellen: 可以尝试使用我们新上线的支持本地盘的机型,热节点最大支持7.2TB的本地SSD盘,warm节点最大支持48TB的本地SATA盘。一方面热节点的性能相比云盘提高了,另外warm节点可以支持更大的磁盘容量。单节点可以支持的磁盘容量增大了,节点数量就不用太多了,可以避免踩到因为节点数量太多而触发的坑。
XX公司运维老大:现在用的是云盘,能替换成本地盘吗,怎么替换?
bellen: 不能直接替换,需要在集群中新加入带本地盘的节点,把数据从老的云盘节点迁移到新的节点上,迁移完成后再剔除掉旧的节点,这样可以保证服务不会中断,读写都可以正常进行。
XX公司运维老大:好,可以实施,尽快搞起来!
云盘切换为本地盘,是通过调用云服务后台的API自动实施的。在实施之后,触发了数据从旧节点迁移到新节点的流程,但是大约半个小时候,问题又出现了:
XX公司运维小B: bellen, 快看一下,ES的写入快掉0了。
bellen: 。。。
通过查看集群监控,发现写入qps直接由50w降到1w,写入拒绝率猛增,通过查看集群日志,发现是因为当前小时的索引没有创建成功导致写入失败。
紧急情况下,执行了以下操作定位到了原因:
经过了这次扩容操作,总结了如下经验:
在稳定运行了一阵后,集群又出问题了。。
XX公司运维小B: bellen, 昨晚凌晨1点钟之后,集群就没有写入了,现在kafka里有大量的数据堆积,麻烦尽快看一下?
bellen: 。。。
通过cerebro查看集群,发现集群处于yellow状态,然后发现集群有大量的错误日志:
然后再进一步查看集群日志,发现有"master not discovered yet..."之类的错误日志,检查三个master节点,发现有两个master挂掉,只剩一个了,集群无法选主。
登陆到挂了了master节点机器上,发现保活程序无法启动es进程,第一直觉是es进程oom了;此时也发现master节点磁盘使用率100%, 检查了JVM堆内存快照文件目录,发现有大量的快照文件,于是删除了一部分文件,重启es进程,进程正常启动了;但是问题是堆内存使用率太高,gc非常频繁,master节点响应非常慢,大量的创建索引的任务都超时,阻塞在任务队列中,集群还是无法恢复正常。
看到集群master节点的配置是16核32GB内存,JVM实际只分配了16GB内存,此时只好通过对master节点原地增加内存到64GB(虚拟机,使用的腾讯云CVM, 可以调整机器规格,需要重启),master节点机器重启之后,修改了es目录jvm.options文件,调整了堆内存大小,重新启动了es进程。
3个master节点都恢复正常了,但是分片还需要进行恢复,通过GET _cluster/health看到集群当前有超过10w个分片,而这些分片恢复还需要一段时间,通过调大"cluster.routing.allocation.node_concurrent_recoveries", 增大分片恢复的并发数量。实际上5w个主分片恢复的是比较快的了,但是副本分片的恢复就相对慢很多,因为部分副本分片需要从主分片上同步数据才能恢复。此时可以采取的方式是把部分旧的索引副本数量调为0, 让大量副本分片恢复的任务尽快结束,保证新索引能够正常创建,从而使得集群能够正常写入。
总结这次故障的根本原因是集群的索引和分片数量太多,集群元数据占用了大量的堆内存,而master节点本身的JVM内存只有16GB(数据节点有32GB), master节点频繁full gc导致master节点异常,从而最终导致整个集群异常。所以要解决这个问题,还是得从根本上解决集群的分片数量过多的问题。
目前日志索引是按照小时创建,60分片1副本,每天有24*60*2=2880个分片,每个月就产生86400个分片,这么多的分片可能会带来严重的问题。有以下几种方式解决分片数量过多的问题:
和客户沟通过后,客户表示可以接受方式1和方式2,但是方式3和4不能接受,因为考虑到存在磁盘故障的可能性,必须保留一个副本来保证数据的可靠性;另外还必须保证所有数据都是随时可查询的,不能关闭。
在场景5中,虽然通过临时给master节点增加内存,抗住了10w分片,但是不能从根本上解决问题。客户的数据是计划保留一年的,如果不进行优化,集群必然扛不住数十万个分片。所以接下来需要着重解决集群整体分片数量过多的问题,在场景5的最后提到了,用户可以接受开启shrink以及降低索引创建粒度(经过调整后,每两个小时创建一个索引),这在一定程度上减少了分片的数量,能够使集群暂时稳定一阵。
辅助客户在kibana上配置了如下的ILM策略:
在warm phase, 把创建时间超过360小时的索引从hot节点迁移到warm节点上,保持索引的副本数量为1,之所以使用360小时作为条件,而不是15天作为条件,是因为客户的索引是按小时创建的,如果以15天作为迁移条件,则在每天凌晨都会同时触发15天前的24个索引一共24*120=2880个分片同时开始迁移索引,容易引发场景4中介绍的由于迁移分片数量过多导致创建索引被阻塞的问题,所以以360小时作为条件,则在每个小时只会执行一个索引的迁移,这样把24个索引的迁移任务打平,避免其它任务被阻塞的情况发生。
同时,也在warm phase阶段,设置索引shrink,把索引的分片数缩成5个,因为老的索引已经不执行写入了,所以也可以执行force merge, 强制把segment文件合并为1个,可以获得更好的查询性能。
另外,设置了ILM策略后,可以在索引模板里增加index.lifecycle.name配置,使得所有新创建的索引都可以和新添加的ILM策略关联,从而使得ILM能够正常运行。
客户使用的ES版本是6.8.2, 在运行ILM的过程中, 也发现一些问题:
这是因为shrink操作需要新把索引完整的一份数据都迁移到一个节点上,然后在内存中构建新的分片元数据,把新的分片通过软链接指向到几个老的分片的数据,在ILM中执行shrink时,ILM会对索引进行如下配置:
问题是索引包含副本,而主分片和副本分片又不能在同一个节点上,所以会出现部分分片无法分配的情况(不是全部,只有一部分),这里应该是触发了6.8版本的ILM的bug,需要查看源码才能定位解决这个bug,目前还在研究中。当前的workaround是通过脚本定期扫描出现unassigned shards的索引,修改其settings:
优先保证分片先从hot节点迁移到warm节点,这样后续的shrink才能顺利执行(也可能执行失败,因为60个分片都在一个节点上,可能会触发rebalance, 导致分片迁移走,shrink的前置条件又不满足,导致执行失败)。要完全规避这个问题,还得在ILM策略中设置,满足创建时间超过360个小时的索引,副本直接调整为0,但是客户又不接受,没办法。
在场景5和6中,介绍了10w个分片会给集群带来的影响和通过开启shrink来降低分片数量,但是仍然有两个需要重点解决的问题:
可以估算一下,按小时建索引,60分片1副本,一年的分片数为24*120*365=1051200个分片,执行shrink后分片数量24*10*350 + 24*120*15 = 127200(15天内的新索引为了保障写入性能和数据可靠性,仍然保持60分片1副本,旧的索引shrink为5分片1副本), 仍然有超过10w个分片。结合集群一年总的存储量和单个分片可以支持的数据量大小进行评估,我们期望集群总体的分片数量可以稳定为6w~8w,怎么优化?
可以想到的方案是执行数据冷备份,把比较老的索引都冷备到其它的存储介质上比如HDFS,S3,腾讯云的COS对象存储等,但是问题是这些冷备的数据如果也要查询,需要先恢复到ES中才可查,恢复速度比较慢,客户无法接受。由此也产生了新的想法,目前老的索引仍然是1副本,可以把老索引先进行冷备份,再把副本调为0,这样做有以下几点好处:
经过和客户沟通,客户接受了上述方案,计划把老索引冷备到腾讯云的对象存储COS中,实施步骤为:
其中步骤1的实施可以通过脚本实现,本案例中采用腾讯云SCF云函数进行实施,方便快捷可监控。实施要点有:
在实施完步骤1之后,就可以批量把对索引进行过备份的索引副本数都调为0, 这样一次性释放了很多磁盘空间,并且显着降低了集群整体的分片数量。
接下来实施步骤2,需要每天执行一次快照,多创建时间较久的索引进行备份,实施比较简单,可以通过crontab定时执行脚本或者使用腾讯云SCF执行。
步骤2实施之后,就可以修改ILM策略,开启cold phase, 修改索引副本数量为0:
此处的timing是创建时间20天后,需要保证步骤2中对过去老索引数据备份先执行完成才可以进入到cold phase.
通过老索引数据冷备并且降低索引副本,我们可以把集群整体的分片数量维持在一个较低的水位,但是还有另外一个问题待解决,也即shrink失败的问题。刚好,我们可以利用对老索引数据冷备并且降低索引副本的方案,来彻底解决shrink失败的问题。
在场景5中有提到,shrink失败归根接地是因为索引的副本数量为1, 现在我们可以吧数据备份和降低副本提前,让老索引进入到ILM的warm phase中时已经是0副本,之后再执行shrink操作就不会有问题了;同时,因为副本降低了,索引从hot节点迁移到warm节点迁移的数据量也减少了一半,从而降低了集群负载,一举两得。
因此,我们需要修改ILM策略,在warm phase就把索引的副本数量调整为0, 然后去除cold phase。
另外一个可选的优化项是,对老的索引进行冻结,冻结索引是指把索引常驻内存的一些数据从内存中清理掉(比如FST, 元数据等), 从而降低内存使用量,而在查询已经冻结的索引时,会重新构建出临时的索引数据结构存放在内存中,查询完毕再清理掉;需要注意的是,默认情况下是无法查询已经冻结的索引的,需要在查询时显式的增加"ignore_throttled=false"参数。
经过上述优化,我们最终解决了集群整体分片数量过多和shrink失败的问题。在实施过程中引入了额外的定时任务脚本实施自动化快照,实际上在7.4版本的ES中,已经有这个功能了,特性名称为 SLM (快照生命周期管理),并且可以结合ILM使用,在ILM中增加了"wait_for_snapshot"的ACTION, 但是却只能在delete phase中使用,不满足我们的场景。
在上述的场景4-7中,我们花费大量的精力去解决问题和优化使用方式,保证ES集群能够稳定运行,支持PB级别的存储。溯本回原,如果我们能有一个方案使得客户只需要把热数据放在SSD盘上,然后冷数据存储到COS/S3上,但同时又使冷数据能够支持按需随时可查,那我们前面碰到的所有问题都迎刃而解了。可以想象得到的好处有:
而这正是目前es开源社区正在开发中的Searchable Snapshots功能,从 Searchable Snapshots API 的官方文档上可以看到,我们可以创建一个索引,将其挂载到一个指定的快照中,这个新的索引是可查询的,虽然查询时间可能会慢点,但是在日志场景中,对一些较老的索引进行查询时,延迟大点一般都是可以接受的。
所以我认为,Searchable Snapshots解决了很多痛点,将会给ES带了新的繁荣!
经历过上述运维和优化ES集群的实践,我们总结到的经验有:
从一开始和客户进行接触,了解客户诉求,逐步解决ES集群的问题,最终使得ES集群能够保持稳定,这中间的经历让我真真正正的领悟到"实践出真知",只有不断实践,才能对异常情况迅速做出反应,以及对客户提的优化需求迅速反馈。
9. ES集群原理与搭建
查看集群健康状况:URL+ /GET _cat/health
Cluster
代表一个集群,集群中有多个节点,其中有一个为主节点,这个主节点是可以通过选举产生的,主从节点是对于集群内部来说的。es的一个概念就是去中心化,字面上理解就是无中心节点,这是对于集群外部来说的,因为从外部来看es集群,在逻辑上是个整体,你与任何一个节点的通信和与整个es集群通信是等价的。
Shards
代表索引分片,es可以把一个完整的索引分成多个分片,这样的好处是可以把一个大的索引拆分成多个,分布到不同的节点上。构成分布式搜索。分片的数量只能在索引创建前指定,并且索引创建后不能更改。
replicas
代表索引副本,es可以设置多个索引的副本,副本的作用一是提高系统的容错性,当某个节点某个分片损坏或丢失时可以从副本中恢复。二是提高es的查询效率,es会自动对搜索请求进行负载均衡。
Recovery
代表数据恢复或叫数据重新分布,es在有节点加入或退出时会根据机器的负载对索引分片进行重新分配,挂掉的节点重新启动时也会进行数据恢复。
(2)、ES为什么要实现集群
在单台ES服务器节点上,随着业务量的发展索引文件慢慢增多,会影响到效率和内存存储问题等。
我们可以采用ES集群,将单个索引的分片到多个不同分布式物理机器上存储,从而可以实现高可用、容错性等。
ES集群中索引可能由多个分片构成,并且每个分片可以拥有多个副本。通过将一个单独的索引分为多个分片,我们可以处理不能在一个单一的服务器上面运行的大型索引,简单的说就是索引的大小过大,导致效率问题。不能运行的原因可能是内存也可能是存储。由于每个分片可以有多个副本,通过将副本分配到多个服务器,可以提高查询的负载能力。
(3)、ES是如何解决高并发
ES是一个分布式全文检索框架,隐藏了复杂的处理机制,内部使用 分片机制、集群发现、分片负载均衡请求路由。
Shards 分片:代表索引分片,es可以把一个完整的索引分成多个分片,这样的好处是可以把一个大的索引拆分成多个,分布到不同的节点上。构成分布式搜索。分片的数量只能在索引创建前指定,并且索引创建后不能更改。
Replicas分片:代表索引副本,es可以设置多个索引的副本,副本的作用一是提高系统的容错性,当某个节点某个分片损坏或丢失时可以从副本中恢复。二是提高es的查询效率,es会自动对搜索请求进行负载均衡。
1、每个索引会被分成多个分片shards进行存储,默认创建索引是分配5个分片进行存储。每个分片都会分布式部署在多个不同的节点上进行部署,该分片成为primary shards。
注意:索引的主分片primary shards定义好后,后面不能做修改。
2、为了实现高可用数据的高可用,主分片可以有对应的备分片replics shards,replic shards分片承载了负责容错、以及请求的负载均衡。
注意: 每一个主分片为了实现高可用,都会有自己对应的备分片,主分片对应的备分片不能存放同一台服务器上。主分片primary shards可以和其他replics shards存放在同一个node节点上。
3、documnet routing(数据路由)
当客户端发起创建document的时候,es需要确定这个document放在该index哪个shard上。这个过程就是数据路由。
路由算法:shard = hash(routing) % number_of_primary_shards
如果number_of_primary_shards在查询的时候取余发生的变化,无法获取到该数据
注意:索引的主分片数量定义好后,不能被修改
高可用视图分析(下图所示:上面的图,如果节点1与节点2宕机了,es集群数据就不完整了。下面图,如果节点1与节点2宕机了,es集群数据还是完整的)
(1)、服务器环境
准备三台服务器集群
| 服务器名称 | IP地址 |
| node-1 | 192.168.212.182 |
| node-2 | 192.168.212.183 |
| node-3 | 192.168.212.184 |
(2)、关闭防火墙
(3)、**** http://192.168.212.185:9200/_cat/nodes?pretty
*号表示为master节点
注意:
注意克隆data文件会导致数据不同步
报该错误解决办法 :
failed to send join request to master
因为克隆导致data文件也克隆呢,直接清除每台服务器data文件。