Elasticsearch 性能调优指南
目录
1、通用优化策略
1.1 通用最小化法则
1.2 职责单一原则
1.3 其他
2、写性能调优
2.1 基本原则
2.2 优化手段
2.2.1 增加 flush 时间间隔,
2.2.2 增加refresh_interval的参数值
2.2.3 增加Buffer大小,
2.2.4 关闭副本
2.2.5 禁用swap
2.2.6 使用多个工作线程
2.2.7 避免使用稀疏数据
2.2.8 max_result_window参数
3、查询调优
3.1 读写性能不可兼得
3.2 优化手段
3.2.1 避免单次召回大量数据
3.2.2 避免单个文档过大
3.2.3 单次查询10条文档 好于 10次查询每次一条
3.2.4 数据建模
3.2.5 给系统留足够的内存
3.2.6 预索引
3.2.7 使用filter代替query
3.2.8 避免深度分页
3.2.9 使用 Keyword 类型
3.2.10 避免使用脚本
4、索引结构优化
4.1 一句废话
4.2 案例
4.2.1 背景
4.2.2 痛点
4.2.3 思路及解决方案
4.3 总结
5、硬件优化
5.1 简述
5.2 节点
5.3 分片
5.3.1 分片创建策略
5.3.2 分片分配策略
5.3.3 分片的数量
5.3.4 分片的大小决策
5.4 内存
5.5 磁盘
5.6 CPU
5.7 网络
5.8 总结
6、架构优化:
7、Mpping结构和索引字段优化:
性能调优是一件大而细的活儿。技术开发没有银弹,也就是本质上是没有所谓可应对任何场景的通用"最优配置"的。如果有,那么出厂何必不直接给出呢?所以理解每一项优化配置的含义很重。在当前情况下为最优配置,但是换一种场景就未必了。
废话不多说,直接上干货!
1、通用优化策略
虽然没有通用最优解,但是的确存在一些通用的优化策略。
1.1 通用最小化法则
所谓通用最小化,其实很好理解,比如:能用short绝不用int, 能用1,绝不用2。对于搜索引擎级海量数据的优化,在数据存储每个bit尤为珍贵。了解 ES 内部存储机制的小伙伴一定知道,其底层对倒排表的存储涉及多种压缩算法,其可谓对每个bit的使用发挥到了极致!举个例子:
上面图片为英汉词典中截取的一个小片段,英汉词典按照字典序排列,这就很方便我们去发现问题。假设业务要求我们要存储一个英汉对照的数据表,常规思想就是为其创建两个字段,分别是“word_en” 、“word_cn”,当然名字是无所谓的。但是这带来一个很大的问题:搜索引擎级的数据往往是海量数据,以亿为单位计算的,这就要求我们必须在各个方面都不能用这种常规手段来处理。比如
在数据结构层面,基于B+Trees的数据结构就非常不适用于全文检索这种场景,因为B+Trees中节点大小是固定的,当索引字段单位数据量增大,就会造成节点分离,进而大大加深树的深度,造成不可估量的磁盘IO。这一点我将用一篇单独的文章详细讲解,此处不再赘述。
其次,海量数据可能涉及大量所谓“重复数据”,这里的重复不仅仅指的是keyword 层面或term层面,而要精细到char这种级别,简单来说,就是你不能说我两个字段值全完重叠才算做重复,而是如果 Term B 以 Term A 为前缀后缀,或者 Term B 和 Term A 有公共前缀或后缀均可视为重复存储。
试想,假如列中包含 10亿 数量级的数据,而英文字幕无非就 26 个,也就是说,字幕 a 我们可能重复存储了上亿次。即便是中文,ES在底层存储的时候,也会通过ASCII来转移为字幕,最终以 bits 存储,这种问题,数量级越大,越严重。实际上这些有公共前缀或公共后缀的地方,我们完全可以只存储一次以追求更高的效率。
ES 在数据存储上采用的 FST 这种模型,在保证了高性能的前体系,带来了指数级的存储效率提升,一个TB级的索引,通过FST存储,其构建的模型大小在1GB左右。比如下 图二 就是 图一中词项字典的 FST模型。图三为其二进制序列的十进制展示。
这里我们只借鉴思想,而不探究原理,FST 的模型建立过程非常负责,我在关于倒排索引的讲解中会有详细的介绍。
当然,此法则绝不仅仅局限于在数据存储层面,思想层面的应用还可扩展更多层面,如索引拆分,模型拆分,数据结构优化,业务分离等。
举个例子:在上述字符串的重复存储问题上面,我们做一下思维扩展,aabbc 和 aabbdd 很容易想到其中 aabb 为其公共前缀,但如果是数字呢? 比如数字 5和数字 10 ,他们的公共前缀又是什么?答案是 5 ,10 = 5 + 5,那如果是 2、5、10 呢,这种情况,他们的存储方式就变成了 2、3、5。因为 2 是 2、 5、10 公共前缀,而 5 是 5 和 10 的公共前缀,讲到这里,不知道你是否理解了这种 通用最小化 层面的思想。借助这种设计思想,其实还有很多可以扩展的地方。这里不一一列举了,因为我也列举不完。如果你真正理解了,你就会发现,这样的例子遍布于和我们生活息息相关的各个场景。
面向对象的语言开发者可能在刚接触语言开发的时候,听到最多的一句话就是“面向对象”,什么是封装、继承、多态,如何提高代码的复用效率。代码封装,不仅仅为了代码美观,还可以大大减小最终生成文件的大小,提高代码的存储和执行效率。这本质也是“通用最小化法则”的一种实现。
再举一个例子:很多重负载业务,都追求极致的轻量化代码或组件,一个典型的例子,我们用 beats 代替 logstash,最重要的原因就是 beats 的轻量化处理,使其在代替 logstash 完成数据采集的前提下,不挤占业务系统的资源。Logstash 虽然功能强大,但是其基于 Jvm 的特性就导致了其需要通过大量的资源占用来换取。
1.2 职责单一原则
职责单一的设计是为了当某个单一职责所负责的业务的集群或节点无法满足其业务需要的时候,方便定向扩展。而且可以更均衡的分配所有资源。常见的操作如:
功能分离:本质上也利于服务的轻量化,我曾和百度负责搜索引擎开发的一位朋友聊天的时候聊过这个话题,百度内部就是基于 Elasticsearch 的源码做修改,删除对其业务不需要的代码,对 ES做轻量化处理
业务分离:最简单常见的场景,当我在全文检索服务的时候,应避免在服务期间去执行大量的聚合分析。
读写分离:常见操作,不做过多解释
冷热分离:基于索引生命周期管理策略下的性能动态分配策略。
1.3 其他
避免单索引业务重耦合
命名规范
开启自适应副本选择(ARS),6.1版本支持,7.0默认开启,
2、写性能调优
2.1 基本原则
写性能调优是建立在对Elasticsearch的写入原理之上。ES 数据写入具有一定的延时性,这是为了减少频繁的索引文件产生。默认情况下 ES 每秒生成一个 segment 文件,当达到一定阈值的时候 会执行merge,merge 过程发生在 JVM中,频繁的生成 Segmen 文件可能会导致频繁的触发 FGC,导致 OOM。为了避免避免这种情况,通常采取的手段是降低 segment 文件的生成频率,手段有两个,一个是 增加时间阈值,另一个是增大 Buffer的空间阈值,因为缓冲区写满也会生成 Segment 文件。
生产经常面临的写入可以分为两种情况:
高频低量:高频的创建或更新索引或文档一般发生在 处理 C 端业务的场景下。
低频高量:一般情况为定期重建索引或批量更新文档数据。
在搜索引擎的业务场景下,用户一般并不需要那么高的写入实时性。比如你在网站发布一条征婚信息,或者二手交易平台发布一个商品信息。其他人并不是马上能搜索到的,这其实也是正常的处理逻辑。这个延时的过程需要处理很多事情,业务层面比如:你的信息需要后台审核。你发布的内容在搜索服务中需要建立索引,而且你的数据可能并不会马上被写入索引,而是等待要写入的数据达到一定数量之后,批量写入。这种操作优点类似于我们快递物流的场景,只有当快递数量达到一定量级的时候,比如能装满整个车的时候,快递车才会发车。因为反正是要跑一趟,装的越多,平均成本越低。这和我们数据写入到磁盘的过程是非常相似的,我们可以把一条文档数据看做是一个快递,而快递车每次发车就是向磁盘写入数据的一个过程。这个过程不宜太多,太多只会降低性能,就是体现在运输成本上面。而对于我们数据写入而言就是体现在我们硬件性能损耗上面。
2.2 优化手段
以下为常见 数据写入的调优手段,写入调优均以提升写入吞吐量和并发能力为目标,而非提升写入实时性。
2.2.1 增加 flush 时间间隔,
目的是减小数据写入磁盘的频率,减小磁盘IO频率。
2.2.2 增加refresh_interval的参数值
目的是减少segment文件的创建,减少segment的merge次数,merge是发生在jvm中的,有可能导致full GC,增加refresh会降低搜索的实时性。
ES的 refresh 行为非常昂贵,并且在正在进行的索引活动时经常调用,会降低索引速度,这一点在索引写入原理中介绍过,了解索引的写入原理,可以关注我的博客Elastic开源社区。
默认情况下,Elasticsearch 每秒定期刷新索引,但仅在最近 30 秒内收到一个或多个搜索请求的索引上。
如果没有搜索流量或搜索流量很少(例如每 5 分钟不到一个搜索请求)并且想要优化索引速度,这是最佳配置。此行为旨在在不执行搜索的默认情况下自动优化批量索引。建议显式配置此配置项,如 30秒。
2.2.3 增加Buffer大小,
本质也是减小refresh的时间间隔,因为导致segment文件创建的原因不仅有时间阈值,还有buffer空间大小,写满了也会创建。 默认最小值 48MB< 默认值 JVM 空间的10% < 默认最大无限制
2.2.4 关闭副本
当需要单次写入大量数据的时候,建议关闭副本,暂停搜索服务,或选择在检索请求量谷值区间时间段来完成。
第一是减小读写之间的资源抢占,读写分离
第二,当检索请求数量很少的时候,可以减少甚至完全删除副本分片,关闭segment的自动创建以达到高效利用内存的目的,因为副本的存在会导致主从之间频繁的进行数据同步,大大增加服务器的资源占用。
具体可通过则设置index.number_of_replicas 为0以加快索引速度。没有副本意味着丢失单个节点可能会导致数据丢失,因此数据保存在其他地方很重要,以便在出现问题时可以重试初始加载。初始加载完成后,可以设置index.number_of_replicas改回其原始值。
2.2.5 禁用swap
大多数操作系统尝试将尽可能多的内存用于文件系统缓存,并急切地换掉未使用的应用程序内存。这可能导致部分 JVM 堆甚至其可执行页面被换出到磁盘。
交换对性能和节点稳定性非常不利,应该不惜一切代价避免。它可能导致垃圾收集持续几分钟而不是几毫秒,并且可能导致节点响应缓慢甚至与集群断开连接。在Elastic分布式系统中,让操作系统杀死节点更有效。
2.2.6 使用多个工作线程
发送批量请求的单个线程不太可能最大化 Elasticsearch 集群的索引容量。为了使用集群的所有资源,应该从多个线程或进程发送数据。除了更好地利用集群的资源外,还有助于降低每个 fsync 的成本。
确保注意TOO_MANY_REQUESTS (429)响应代码(EsRejectedExecutionException使用 Java 客户端),这是 Elasticsearch 告诉我们它无法跟上当前索引速度的方式。发生这种情况时,应该在重试之前暂停索引,最好使用随机指数退避。
与调整批量请求的大小类似,只有测试才能确定最佳工作线程数量是多少。这可以通过逐渐增加线程数量来测试,直到集群上的 I/O 或 CPU 饱和。
2.2.7 避免使用稀疏数据
2.2.8 max_result_window参数
max_result_window是分页返回的最大数值,默认值为10000。max_result_window本身是对JVM的一种保护机制,通过设定一个合理的阈值,避免初学者分页查询时由于单页数据过大而导致OOM。
在很多业务场景中经常需要查询10000条以后的数据,当遇到不能查询10000条以后的数据的问题之后,网上的很多答案会告诉你可以通过放开这个参数的限制,将其配置为100万,甚至1000万就行。但是如果仅仅放开这个参数就行,那么这个参数限制的意义有何在呢?如果你不知道这个参数的意义,很可能导致的后果就是频繁的发生OOM而且很难找到原因,设置一个合理的大小是需要通过你的各项指标参数来衡量确定的,比如你用户量、数据量、物理内存的大小、分片的数量等等。通过监控数据和分析各项指标从而确定一个最佳值,并非越大越好
3、查询调优
3.1 读写性能不可兼得
首先要明确一点:鱼和熊掌不可兼得。读写性能调优在很多场景下是只能二选一的。牺牲 A 换 B 的行为非常常见。索引本质上也是通过空间换取时间。写生写入实时性就是为了提高检索的性能。
当你在二手平台或者某垂直信息网站发布信息之后,是允许有信息写入的延时性的。但是检索不行,甚至 1 秒的等待时间对用户来说都是无法接受的。满足用户的要求甚至必须做到10 ms以内。
3.2 优化手段
3.2.1 避免单次召回大量数据
搜索引擎最擅长的事情是从海量数据中查询少量相关文档,而非单次检索大量文档。非常不建议动辄查询上万数据。如果有这样的需求,建议使用滚动查询
3.2.2 避免单个文档过大
鉴于默认http.max_content_length设置为 100MB,Elasticsearch 将拒绝索引任何大于该值的文档。您可能决定增加该特定设置,但 Lucene 仍然有大约 2GB 的限制。
即使不考虑硬性限制,大型文档通常也不实用。大型文档对网络、内存使用和磁盘造成了更大的压力,即使对于不请求的搜索请求也是如此,_source因为 Elasticsearch_id在所有情况下都需要获取文档的文件系统缓存有效。对该文档进行索引可能会占用文档原始大小的倍数的内存量。Proximity Search(例如短语查询)和高亮查询也变得更加昂贵,因为它们的成本直接取决于原始文档的大小。
有时重新考虑信息单元应该是什么是有用的。例如,您想让书籍可搜索的事实并不一定意味着文档应该包含整本书。使用章节甚至段落作为文档可能是一个更好的主意,然后在这些文档中拥有一个属性来标识它们属于哪本书。这不仅避免了大文档的问题,还使搜索体验更好。例如,如果用户搜索两个单词fooand bar,则不同章节之间的匹配可能很差,而同一段落中的匹配可能很好。
3.2.3 单次查询10条文档 好于 10次查询每次一条
批量请求将产生比单文档索引请求更好的性能。但是每次查询多少文档最佳,不同的集群最佳值可能不同,为了获得批量请求的最佳阈值,建议在具有单个分片的单个节点上运行基准测试。首先尝试一次索引 100 个文档,然后是 200 个,然后是 400 个等。在每次基准测试运行中,批量请求中的文档数量翻倍。当索引速度开始趋于平稳时,就可以获得已达到数据批量请求的最佳大小。在相同性能的情况下,当大量请求同时发送时,太大的批量请求可能会使集群承受内存压力,因此建议避免每个请求超过几十兆字节。
3.2.4 数据建模
很多人会忽略对 Elasticsearch 数据建模的重要性。
nested属于object类型的一种,是Elasticsearch中用于复杂类型对象数组的索引操作。Elasticsearch没有内部对象的概念,因此,ES在存储复杂类型的时候会把对象的复杂层次结果扁平化为一个键值对列表。
特别是,应避免连接。Nested 可以使查询慢几倍,Join 会使查询慢数百倍。两种类型的使用场景应该是:Nested针对字段值为非基本数据类型的时候,而Join则用于 当子文档数量级非常大的时候。
关于数据建模,在我的博客中有详细的讲解,此处不再赘述
3.2.5 给系统留足够的内存
Lucene的数据的fsync是发生在OS cache的,要给OS cache预留足够的内从大小,详见JVM调优。
3.2.6 预索引
利用查询中的模式来优化数据的索引方式。例如,如果所有文档都有一个price字段,并且大多数查询 range 在固定的范围列表上运行聚合,可以通过将范围预先索引到索引中并使用聚合来加快聚合速度。
3.2.7 使用filter代替query
query和filter的主要区别在: filter是结果导向的而query是过程导向。query倾向于“当前文档和查询的语句的相关度”而filter倾向于“当前文档和查询的条件是不是相符”。即在查询过程中,query是要对查询的每个结果计算相关性得分的,而filter不会。另外filter有相应的缓存机制,可以提高查询效率。
3.2.8 避免深度分页
避免单页数据过大,可以参考百度或者淘宝的做法。es提供两种解决方案 scroll search 和 search after。关于深度分页的详细原理,推荐阅读:详解Elasticsearch深度分页问题
3.2.9 使用 Keyword 类型
并非所有数值数据都应映射为数值字段数据类型。Elasticsearch为 查询优化数字字段,例如integeror long。如果不需要范围查找,对于 term查询而言,keyword 比 integer 性能更好。
3.2.10 避免使用脚本
Scripting是Elasticsearch支持的一种专门用于复杂场景下支持自定义编程的强大的脚本功能。相对于 DSL 而言,脚本的性能更差,DSL能解决 80% 以上的查询需求,如非必须,尽量避免使用 Script
4、索引结构优化
4.1 一句废话
本质上,索引结构取决于业务,业务场景不同,最合适的索引结构也不同。下面我通过一个真实案例来解释这个问题。
4.2 案例
4.2.1 背景
某公司是提供SMS短信服务的,其主要客户群体为各大银行系统。其业务主要是为客户提供短信发送服务,并且要保存所有
4.2.2 痛点
痛点1:索引过于庞大
就短信发送而言并无太大问题,但是在项目初期,在建立短信发送记录的时候,并没有在意索引结构的设计,而是将新产生的数据不断的追加到一个索引中,但是后期发现短信发送量级过于庞大,每天都产生上几百GB甚至是TB级的日志数据,后期的优化手段就是把一个单独的大索引,通过Rollover Index,每天创建一个单独的索引。短期内问题得到了解决
痛点2:索引太多
基于滚动索引的方案在短期内的确解决了单个索引过大而带来的性能下降,因为80%的请求都是基于近期数据而言的,但是随着时间周期的拉长,剩余 20% 的请求的问题日渐突出。的确存在一部分用户,需要查询跨周期范围特别大的数据,比如,工商银行某客户要查询 近三年以来短信发送记录,造成的结果就是需要跨一千多个索引来查询。这种问题,时间越久,就越明显。
4.2.3 思路及解决方案
对于这种需求场景而言,其实索引结构设计的很不合理。固然我们很容易将数据与时间绑定,但是当前场景明显是一个垂直业务。换句话说,索引的拆分不应该简单按照时间进行拆分,而是按照业务属性和业务量。比如:我们要查询某个手机号3年的发送记录,在执行查询之前,我们就能通过手机号的自身属性确定查询范围,如手机号归属地、所属运营商等。北京的手机号,无论如何也不会涉及到上海的数据。所以中国移动在北京和上海的数据就可以保存两个索引,因为他们是互不相干的。中国移动和中国联通的数据,也是互不相干的。这样一来,一个索引可能就被拆成了几百个索引,在检索之前,就可以根据业务属性迅速确定要查询的所有数据所在的索引。
在此基础之上通过Rollover index来创建索引还要根据总量以及每日增量来确定索引创建的粒度大小。这个大小要结合群节点数量、结构分配及角色分配、分片数量的最优原则来确定。比如如果数据量每天很少,那就把粒度改成周或者月,让索引有一个更加合理的大小,过大过小都不好。至于索引和分片大小数量的优化配置,我的文章里有单独介绍。
举个例子:当我们80%的请求落在近三个月,90%的请求都落在近一个月,那其实我们有必要为近三个月单独创建一个索引或者将数据缓存起来,又或者通过冷热集群的方案来做隔离部署。把更优质的资源分配给更需要性能的业务数据上。
然而问题到此还未真正的彻底解决,因为时序数据是具有流转性特点的。近三个月的数据,其实等过三个月就变成了历史数据,本身部署在 hot phase 的数据就要相应的流转到 warm,也有可能需要对数据压缩或冷冻,以提高数据的存储效率降低成本。
有些数据大概率常年是不需要提供任何查询,但是我们不能丢弃,比如银行的转账记录可能要保存十年甚至三十年。平常这些数据我们是用不到的,对于普通用户一般能查询半年或一年,最多三年的记录。但是这些数据因为有可能涉及犯罪信息,当国家或政府需要银行协助调查的时候,银行有保存义务,需要协助国家调查提供数据。这种事情发生的概率很小但是它的确存在。所以可以通过快照或可搜索快照保存。这样代价就很低。
到这里其实还能继续优化,因为即便索引已经合理拆分,但是如果随着业务的继续膨胀以及时间周期的不断拉长,仍然会面临以上问题,那么解决方案就是我们通过数据流来创建索引的生命周期管理策略,数据流在开源社区或者我的个人博客中有单独的讲解,此处不再赘述。
4.3 总结
5、硬件优化
5.1 简述
es的默认配置是一个非常合理的默认配置,绝大多数情况下是不需要修改的,如果不理解某项配置的含义,没有经过验证就贸然修改默认配置,可能造成严重的后果。比如max_result_window这个设置,默认值是1W,这个设置是分页数据每页最大返回的数据量,冒然修改为较大值会导致OOM。ES没有银弹,不可能通过修改某个配置从而大幅提升ES的性能,通常出厂配置里大部分设置已经是最优配置,只有少数和具体的业务相关的设置,事先无法给出最好的默认配置,这些可能是需要我们手动去设置的。关于配置文件,如果你做不到彻底明白配置的含义,不要随意修改。
jvm heap分配:7.x 版本默认1GB,这个值太小,很容易导致OOM。Jvm heap大小不要超过物理内存的50%,最大也不要超过32GB(compressed oop),它可用于其内部缓存的内存就越多,但可供操作系统用于文件系统缓存的内存就越少,heap过大会导致GC时间过长
5.2 节点
相同角色的节点,避免使用差异较大的服务器配置,
避免使用“超大杯”服务器(SS:Super Server),比如128核CPU,1 T的内存,2T的固态硬盘。这样可能会产生较大的资源浪费。
等量的配置,使用较少的物理机好于使用较多的虚拟机。比如一个一个五台4核16G的物理机,好于10甚至11台2核8G的虚拟机,这里不仅仅是虚拟机本身可能也会消耗一部分性能的问题,也涉及数据安全的问题。
避免在同一台服务器上部署多个节点,会增加集群管理的难度。
5.3 分片
5.3.1 分片创建策略
分片产生的目的是为了实现分布式,而分布式的好处之一就是实现“高可用性”(还包括高性能如提高吞吐量等会在后面内容展开讲),分片的分配策略极大程度上都是围绕如何提高可用性而来的,如分片分配感知、强制感知等。
互联网开发没有“银弹”,分片的数量分配也没有适用于所有场景的最佳值,创建分片策略的最佳方法是使用您在生产中看到的相同查询和索引负载在生产硬件上对生产数据进行基准测试。分片的分配策略主要从两个指标来衡量:即数量和单个分片的大小。
5.3.2 分片分配策略
ES使用数据分片(shard)来提高服务的可用性,将数据分散保存在不同的节点上以降低当单个节点发生故障时对数据完整性的影响,同时使用副本(repiica)来保证数据的完整性。关于分片的默认分配策略,在7.x之前,默认5个primary shard,每个primary shard默认分配一个replica,即5主1副,而7.x之后,默认1主1副
ES在分配单个索引的分片时会将每个分片尽可能分配到更多的节点上。但是,实际情况取决于集群拥有的分片和索引的数量以及它们的大小,不一定总是能均匀地分布。
Paimary只能在索引创建时配置数量,而replica可以在任何时间分配,并且primary支持读和写操作,而replica只支持客户端的读取操作,数据由es自动管理,从primary同步。
ES不允许Primary和它的Replica放在同一个节点中,并且同一个节点不接受完全相同的两个Replica
同一个节点允许多个索引的分片同时存在。
5.3.3 分片的数量
避免分片过多:大多数搜索会命中多个分片。每个分片在单个 CPU 线程上运行搜索。虽然分片可以运行多个并发搜索,但跨大量分片的搜索会耗尽节点的搜索线程池。这会导致低吞吐量和缓慢的搜索速度。
分片越少越好:每个分片都使用内存和 CPU 资源。在大多数情况下,一小组大分片比许多小分片使用更少的资源。
5.3.4 分片的大小决策
分片的合理容量:10GB-50GB。虽然不是硬性限制,但 10GB 到 50GB 之间的分片往往效果很好。根据网络和用例,也许可以使用更大的分片。在索引的生命周期管理中,一般设置50GB为单个索引的最大阈值。
堆内存容量和分片数量的关联:小于20分片/每GB堆内存,一个节点可以容纳的分片数量与节点的堆内存成正比。例如,一个拥有 30GB 堆内存的节点最多应该有 600 个分片。如果节点超过每 GB 20 个分片,考虑添加另一个节点。
5.4 内存
根据业务量不同,内存的需求也不同,一般生产建议不要少于16G。ES是比较依赖内存的,并且对内存的消耗也很大,内存对ES的重要性甚至是高于CPU的,所以即使是数据量不大的业务,为了保证服务的稳定性,在满足业务需求的前提下,我们仍需考虑留有不少于20%的冗余性能。一般来说,按照百万级、千万级、亿级数据的索引,我们为每个节点分配的内存为16G/32G/64G就足够了,太大的内存,性价比就不是那么高了。
5.5 磁盘
对于ES来说,磁盘可能是最重要的了,因为数据都是存储在磁盘上的,当然这里说的磁盘指的是磁盘的性能。磁盘性能往往是硬件性能的瓶颈,木桶效应中的最短板。ES应用可能要面临不间断的大量的数据读取和写入。生产环境可以考虑把节点冷热分离,“热节点”使用SSD做存储,可以大幅提高系统性能;冷数据存储在机械硬盘中,降低成本。另外,关于磁盘阵列,可以使用raid 0。
5.6 CPU
CPU对计算机而言可谓是最重要的硬件,但对于ES来说,可能不是他最依赖的配置,因为提升CPU配置可能不会像提升磁盘或者内存配置带来的性能收益更直接、显著。当然也不是说CPU的性能就不重要,只不过是说,在硬件成本预算一定的前提下,应该把更多的预算花在磁盘以及内存上面。通常来说单节点cpu 4核起步,不同角色的节点对CPU的要求也不同。服务器的CPU不需要太高的单核性能,更多的核心数和线程数意味着更高的并发处理能力。现在PC的配置8核都已经普及了,更不用说服务器了。
5.7 网络
ES是天生自带分布式属性的,并且ES的分布式系统是基于对等网络的,节点与节点之间的通信十分的频繁,延迟对于ES的用户体验是致命的,所以对于ES来说,低延迟的网络是非常有必要的。因此,使用扩地域的多个数据中心的方案是非常不可取的,ES可以容忍集群跨多个机房,可以有多个内网环境,支持跨AZ部署,但是不能接受多个机房跨地域构建集群,一旦发生了网络故障,集群可能直接GG,即使能够保证服务正常运行,维护这样(跨地域单个集群)的集群带来的额外成本可能远小于它带来的额外收益。
5.8 总结
集群需要多少种配置(内存型/IO型/运算型),每种配置需要多少数量,通常需要和产品运营和运维测试商定,视业务量和服务器的承载能力而定,并留有一定的余量。
一个合理的ES集群配置应不少于5台服务器,避免脑裂时无法选举出新的Master节点的情况,另外可能还需要一些其他的单独的节点,比如ELK系统中的Kibana、Logstash等。
6、架构优化:
架构层面,非一言两语可详述,推荐阅读:从单机到百万节点:Elasticsearch高可用集群架构部署方案
合理的分配角色和每个节点的配置,在部署集群的时候,应该根据多方面的情况去评估集群需要多大规模去支撑业务。这个是需要根据在你当前的硬件环境下测试数据的写入和搜索性能,然后根据你目前的业务参数来动态评估的,比如:业务数据的总量、每天的增量、查询的并发以及QPS以及峰值的请求量。
节点并非越多越好,会增加主节点的压力
分片并非越多越好,从deep pageing 的角度来说,分片越多,JVM开销越大,负载均衡(协调)节点的转发压力也越大,查询速度也越慢。单个分片也并非越大越好,一般来说单个分片大小控制在30-50GB。
7、Mpping结构和索引字段优化:
doc_values:正排索引,对于不需要聚合的字段,关闭正排索引可节省资源,提高查询速度
fielddata:可以理解为“runtime_doc_values”,doc_value 为 index time 正排索引。fielddata会消耗JVM空间,如果执行大量数据的聚合使用 fielddata,会造成 OOM
尽量不要使用 dynamic mapping
ignore_above:字段保留的长度,越小越好
调整_source字段,通过include和exclude过滤
store:开辟另一块存储空间,可以节省带宽
注意:_sourse设置为false,则不存储源数据,可以节省磁盘,并且不影响搜索。但是禁用_source必须三思而后行,禁用后将导致以下后果:
update,update_by_query和reindex不可用。
高亮失效
reindex失效,原本可以修改的mapping部分参数将无法修改,并且无法升级索引
无法查看元数据和聚合搜索
影响索引的容灾能力
禁用_all字段:_all字段的包含所有字段分词后的Term,作用是可以在搜索时不指定特定字段,从所有字段中检索,ES 6.0之前需要手动关闭
关闭 Norms 字段:计算评分用的,如果你确定当前字段将来不需要计算评分,设置false可以节省大量的磁盘空间,有助于提升性能。常见的比如filter和agg字段,都可以设为关闭。
关闭 index_options(谨慎使用,高端操作):此设置用于在index time过程中哪些内容会被添加到倒排索引的文件中,例如TF,docCount、postion、offsets等,减少option的选项可以减少在创建索引时的CPU占用率,不过在实际场景中很难确定业务是否会用到这些信息,除非是在一开始就非常确定用不到,否则不建议删除
enabled:是否创建倒排索引,对于不需要查询的字段,关闭正排索引可节省资源,提高查询速度。
推荐阅读:
从单机到百万节点的ES高可用集群架构部署方案:https://es-cn.blog.csdn.net/article/details/119812971?spm=1001.2014.3001.5502
详解Elasticsearch深度分页问题:https://es-cn.blog.csdn.net/article/details/120800632?spm=1001.2014.3001.5502
相关文章:
Elasticsearch 性能调优指南
目录 1、通用优化策略 1.1 通用最小化法则 1.2 职责单一原则 1.3 其他 2、写性能调优 2.1 基本原则 2.2 优化手段 2.2.1 增加 flush 时间间隔, 2.2.2 增加refresh_interval的参数值 2.2.3 增加Buffer大小, 2.2.4 关闭副本 2.2.5 禁用swap 2…...
学习Boost一:学习方法和学习目的
学习目的 Boost 的学习目的: 因为从知乎和CSND上根据了解内容来看,Boost作为一个历史悠久的开源库,已经脱离了一个单纯的库的概念了,他因庞大的涉及面应当被称之为库集。 并且,因为boost库优秀的试用反馈和开发人员的…...

c语言每日一练(1)
前言: 每日一练系列,每一期都包含5道选择题,2道编程题,博主会尽可能详细地进行讲解,令初学者也能听的清晰。每日一练系列会持续更新,暑假时三天之内必有一更,到了开学之后,将看学业情…...
iOS开发-CocoaLumberjack日志库实现Logger日志功能
iOS开发-Logger日志功能实现 在iOS开发中,常用CocoaLumberjack来作为日志功能实现的日志框架 一、CocoaLumberjack是什么? CocoaLumberjack 是 支持 iOS 和 Mac 平台的日志框架,使用简单,功能强大且不失灵活,它的主…...

深度学习(34)—— StarGAN(2)
深度学习(34)—— StarGAN(2) 完整项目在这里:欢迎造访 文章目录 深度学习(34)—— StarGAN(2)1. build model(1)generator(2&#…...
use lua
-- basic.lua print("hello ".."world") local a 1 --only this file can see b 2 -- global see -- not declare vaiable all asign to nil print(fuck) -- 字符串可以"" , ,[[]] -- 一些数值运算支持,进制数,科学数&a…...

网络——初识网络
网络基础 文章目录 网络基础计算机网络产生的背景认识网络协议网络协议初识协议分层OSI七层模型TCP/IP四层模型网络传输基本流程协议报头 认识IP地址认识MAC地址ifconfig查看主机地址ifconfig查看主机地址 计算机网络产生的背景 独立模式:计算机之间相互独立 早期的…...

调试技巧(2)
6. 如何写出好(易于调试)的代码 6.1 优秀的代码: 代码运行正常bug很少效率高可读性高可维护性高注释清晰文档齐全 常见的coding技巧: 使用assert尽量使用const养成良好的编码风格添加必要的注释避免编码的陷阱。 这里讲一下assert…...

骨传导耳机真不伤耳吗?骨传导耳机有什么好处?
骨传导耳机真不伤耳吗?骨传导耳机有什么好处? 我先来说说骨传导耳机的工作原理吧,骨传导是一种传声方式,声波通过颅骨、颌骨等头部骨头的振动,将声音传到内耳。其实骨传导的现象我们很常见,就像我们平时嗑瓜…...

mac切换jdk版本
查询mac已有版本 1、打开终端,输入: /usr/libexec/java_home -V注意:输入命令参数区分大小写(必须是-V) 2.目前本地装有两个版本的jdk xxxxedydeMacBook-Pro-9 ~ % /usr/libexec/java_home -V Matching Java Virtual Machines (2):20.0.1 (…...

go 基本语法(简单案例)
!注: go中 对变量申明很是严格,申明了,在没有使用的情况下,也会产生编译错误 1.行分隔符 一行就是代码,无;分割,如果需要在一行展示,需要以;分割,…...

Permute 3 for mac音视频格式转换
Permute是一款Mac平台上的媒体格式转换软件,由Chaotic Software开发。它可以帮助用户快速地将各种音频、视频和图像文件转换成所需格式,并提供了一些常用工具以便于用户进行编辑和处理。 Permute的主要特点包括: - 支持大量格式:支…...

线程概念linux
何为线程: 线程是程序中负责执行的单位,它可以被看作是进程的一部分,是进程的子任务。线程与进程的区别在于,进程是一个资源单位,而线程是进程的一部分,它只有栈这个独立的资源,其他资源如代码…...

【Yolov5+Deepsort】训练自己的数据集(1)| 目标检测追踪 | 轨迹绘制
📢前言:本篇是关于如何使用YoloV5Deepsort训练自己的数据集,从而实现目标检测与目标追踪,并绘制出物体的运动轨迹。本章讲解的为第一个内容:简单介绍YoloV5Deepsort中所用到的目标检测,追踪及sort&Depp…...

express学习笔记4 - 热更新以及express-boom
我们每次改动代码的时候都要重启项目,现在我们给项目添加一个热更新 npm install --save-dev nodemon # or using yarn: yarn add nodemon -D 在package.json添加一行代码 "dev": "nodemon ./bin/www" 重启项目 然后随便做改动ÿ…...
Ajax_02学习笔记(源码 + 图书管理业务 + 以及 个人信息修改功能)
Ajax_02 01_Bootstrap框架-控制弹框的使用 代码 <!-- 引入bootstrap.css --> <link href"https://cdn.jsdelivr.net/npm/bootstrap5.2.2/dist/css/bootstrap.min.css" rel"stylesheet"><button type"button" class"btn btn…...
Python-数据类型转换
当涉及数据类型转换时,Python提供了多种内置函数来执行不同类型之间的转换 以下是每个方法的详细说明和示例案例 整数和浮点数转换: int(x, base10): 将给定的参数x转换为整数。x可以是一个整数、浮点数或字符串。如果x是字符串,则可以提供…...

DASCTF 2023 0X401七月暑期挑战赛 Web方向 EzFlask ez_cms MyPicDisk 详细题解wp
EzFlask 源码直接给了 CtrlU查看带缩进的源码 import uuidfrom flask import Flask, request, session # 导入黑名单列表 from secret import black_list import jsonapp Flask(__name__) # 为 Flask 应用设置一个随机的 secret_key app.secret_key str(uuid.uuid4())# 检查…...

数据结构-链表
🗡CSDN主页:d1ff1cult.🗡 🗡代码云仓库:d1ff1cult.🗡 🗡文章栏目:数据结构专栏🗡 目录 目录 代码总览: 接口slist.h: slist.c: 1.什么是链表 1.1链…...

大数据Flink(五十五):Flink架构体系
文章目录 Flink架构体系 一、 Flink中的重要角色 二、Flink数据流编程模型 三、Libraries支持...
Python|GIF 解析与构建(5):手搓截屏和帧率控制
目录 Python|GIF 解析与构建(5):手搓截屏和帧率控制 一、引言 二、技术实现:手搓截屏模块 2.1 核心原理 2.2 代码解析:ScreenshotData类 2.2.1 截图函数:capture_screen 三、技术实现&…...
在软件开发中正确使用MySQL日期时间类型的深度解析
在日常软件开发场景中,时间信息的存储是底层且核心的需求。从金融交易的精确记账时间、用户操作的行为日志,到供应链系统的物流节点时间戳,时间数据的准确性直接决定业务逻辑的可靠性。MySQL作为主流关系型数据库,其日期时间类型的…...
【Java学习笔记】Arrays类
Arrays 类 1. 导入包:import java.util.Arrays 2. 常用方法一览表 方法描述Arrays.toString()返回数组的字符串形式Arrays.sort()排序(自然排序和定制排序)Arrays.binarySearch()通过二分搜索法进行查找(前提:数组是…...

【机器视觉】单目测距——运动结构恢复
ps:图是随便找的,为了凑个封面 前言 在前面对光流法进行进一步改进,希望将2D光流推广至3D场景流时,发现2D转3D过程中存在尺度歧义问题,需要补全摄像头拍摄图像中缺失的深度信息,否则解空间不收敛…...
Python爬虫(二):爬虫完整流程
爬虫完整流程详解(7大核心步骤实战技巧) 一、爬虫完整工作流程 以下是爬虫开发的完整流程,我将结合具体技术点和实战经验展开说明: 1. 目标分析与前期准备 网站技术分析: 使用浏览器开发者工具(F12&…...
【Web 进阶篇】优雅的接口设计:统一响应、全局异常处理与参数校验
系列回顾: 在上一篇中,我们成功地为应用集成了数据库,并使用 Spring Data JPA 实现了基本的 CRUD API。我们的应用现在能“记忆”数据了!但是,如果你仔细审视那些 API,会发现它们还很“粗糙”:有…...

JUC笔记(上)-复习 涉及死锁 volatile synchronized CAS 原子操作
一、上下文切换 即使单核CPU也可以进行多线程执行代码,CPU会给每个线程分配CPU时间片来实现这个机制。时间片非常短,所以CPU会不断地切换线程执行,从而让我们感觉多个线程是同时执行的。时间片一般是十几毫秒(ms)。通过时间片分配算法执行。…...

【电力电子】基于STM32F103C8T6单片机双极性SPWM逆变(硬件篇)
本项目是基于 STM32F103C8T6 微控制器的 SPWM(正弦脉宽调制)电源模块,能够生成可调频率和幅值的正弦波交流电源输出。该项目适用于逆变器、UPS电源、变频器等应用场景。 供电电源 输入电压采集 上图为本设计的电源电路,图中 D1 为二极管, 其目的是防止正负极电源反接, …...

基于Springboot+Vue的办公管理系统
角色: 管理员、员工 技术: 后端: SpringBoot, Vue2, MySQL, Mybatis-Plus 前端: Vue2, Element-UI, Axios, Echarts, Vue-Router 核心功能: 该办公管理系统是一个综合性的企业内部管理平台,旨在提升企业运营效率和员工管理水…...
从面试角度回答Android中ContentProvider启动原理
Android中ContentProvider原理的面试角度解析,分为已启动和未启动两种场景: 一、ContentProvider已启动的情况 1. 核心流程 触发条件:当其他组件(如Activity、Service)通过ContentR…...