ElasticSearch性能优化
ES基础概念介绍:
- 索引:类似于MySQL中的表,它是具有相同特征的一个数据集。
- 文档:格式为JSON格式,类似于MySQL中的一条数据,它是数据存储的基本数据单元,每一条文档都有一个唯一的ID。
- 查询:用户向ES发起的ResultFul格式的请求,以JSON格式编写。
性能优化的原因:
- 提高查询的效率,降低用户的响应时间。
- 降低对资源的消耗(CPU、IO、内存、网络)
- 支持大量的并发。
性能优化正文
硬件角度
从底层出发,优先考虑硬件对性能的影响。
电脑的硬件一般就是:CPU、内存、硬盘、网卡。
在木桶效应的影响下,我们需要确保这些硬件方面不会出现短板。
CPU
要考虑性能,肯定要考虑并发、并行。并发和并行对CPU的核数有要求。CPU要选取8核以上的,以便提高并发和并行度。
内存
ES对内存的操作主要体现在:
- 将热点数据的索引片段和查询结果缓存到内存。
- 在写数据的时候也会先将数据存放在内存的buffer缓冲区。
- 在内存中对查询的语句进行解析和预处理。
- 在内存中进行文档相关性分析和得分的计算。
上述是ES对内存的使用情况,可以得知对查询的响应速度影响很大。而且ES是基于Java编写的,所以这些对内存的操作大多是以在JVM中的堆区域中实现的。
众所周知JVM的堆是垃圾回收的主要对象,而当堆内存超过32G的时候,垃圾回收的开销会明显上升,影响系统新能,所以堆内存一般小于32G为最佳。
JVM又需要与操作系统做交互,对于硬盘中数据的读取一般需要操作系统来操作内存对硬盘数据进行缓存,以提高读写性能,通常情况下一般剩下内存的50%给操作系统来进性数据缓存操作。
硬盘
所有数据不可能都缓存到内存中,大部分数据还是要存在于硬盘中的。这个时候硬盘的读写速度也很关键。一般选取固态硬盘,并且预留25%左右的存储空间用于合并和其它操作。
网卡
网络就不必多说了,更低的延迟和更高的带宽,不论是在集群之间交互还是在给用户的反馈方面都更优。
集群
在ES的集群搭建中有两个重要的点:
- 分片:单个分片的大小一般不超过50G,在20-30G最佳
- 副本数:副本是用于保证数据安全以及读性能的,节点少的时候一个副本即可,节点大于50的时候副本数一般大于2
定义优化
分词器(analyzer)
- 标准分词器(ES默认):按照unicode文本分割算法,将文本按照单词边界分割,同时去除标点符号。
- 基础分词器:根据非字母字符拆分词项,并将词项转换成小写,但是不会进行符号的过滤。
- 空格分词器:根据空格分词。
- 字符串类型分词器:根据字符串类型进行分组,比如根据字母、数字、标点划分为不同的词项。
- 正则表达式分词器
- 汉语分词器(IK分词器、智能中文smartcn分词器)
- 英语分词器
- 关键字分词器:不进行分词处理
- 路径分词器:按照路径中的’/'分割符,将路径分解为不同的层次部分。
字段类型(type)
- 字符串类型(keyword、text)
- 地理空间索引(geo_point、geo_shape):处理地理位置相关的索引。
- 数值类型(integer、long、float、double):对数值类型进行范围查询,聚合计算等。
- 布尔类型(boolean)
- 二进制类型(binary)
- 日期类型(date)
- 复杂类型(object、nested):object是以json格式定义的对象、nested与object类似,但它用于存储嵌套对象。
- IP地址类型(ip)
- 范围类型(integer_range、float_range、date_range、long_range)
- 合并数据类型(join):实现父子关系数据建模,通常表示父子文档和子文档的关系。
- 文本多字段:在同一字段定义多个类型,以支持更多的匹配方式。
- 标识符类型(completion):用于实现高效的建议功能,通常用于自动补全和提示框。
查询优化
通配符查询
原因:ES支持使用通配符(*
或?
)进行查询,通配符出现在开头会走全表扫描。
解决方案:避免在开头使用通配符,非要用的话建议使用前缀查询或更高效的分词器(ngram 或 edge ngram),
深度分页
原因:避免深度分页,因为深度分页的时候会从相关节点上取到from+size数量的数据,在协调节点中进行合并排序,最后再返回size条数据。当分页量巨大的时候不但会导致查询缓慢,更严重会内存溢出。
解决方案:可以**使用 Scroll API 或 Search After **来替代传统的 “from + size” 分页方式。Scroll API 通过在初始查询时返回一个 scroll_id,后续查询使用该 scroll_id 来获取下一页数据,它适用于需要一次性获取大量数据的场景,但不适合实时交互场景,因为它会占用一定的资源。例如,在进行数据导出时,可以使用 Scroll API 分批次获取大量数据。Search After 则是基于游标的分页方式,它使用上一页最后一条记录的排序字段值作为游标,来获取下一页的数据,这种方式更适合实时交互场景,性能也更好。例如,在一个新闻列表页面,用户不断点击 “下一页” 查看更多新闻时,使用 Search After 可以快速响应用户请求,提高用户体验。
过滤器
原因:通常情况下的查询还需要计算相关得分,之后根据得分进行排序,此举是为了优化用户体验。但对于一些简单情况下的字段,就没必要计算得分,只需要筛选条件是否满足就行了。
解决方案:使用过滤器进行筛选,过滤器筛选只判断是否满足条件,不会进行得分计算。并且过滤器筛选出的数据会被缓存,下次如果还是同样的过滤条件,结果就能被直接返回了。
精确匹配
使用精确匹配能够快速定位到数据,避免对字段进行不必要的扫描匹配,例如根据id或者订单号进行查询。
缓存与索引生命周期
缓存的好处毋庸置疑,能够降低查找速度,提高吞吐量。
ES提供了多种缓存机制,包括节点查询缓存和分片请求缓存。
节点查询缓存
节点查询缓存主要用于缓存过滤器查询的结果,当缓存满的时候会淘汰使用频率最低的数据。
可以使用indices.queries.cache.size来调整节点查询缓存的大小,默认值为10%。
分片请求缓存
分片请求缓存的作用是缓存整个请求的结果,当缓存满的时候会淘汰使用频率最低的数据。index.requests.cache.size参数控制其占用内存大小,默认值为 1%。
索引生命周期管理
索引生命周期管理(Index Lifecycle Management,ILM)是根据数据的冷热程度对索引进行管理的过程,它能有效提升系统性能并降低存储成本。在实际应用中,数据的访问频率和重要性会随着时间的推移而发生变化。例如,在日志分析场景中,最近几天的日志数据通常会被频繁查询和分析,属于热数据;而几个月前的日志数据访问频率较低,属于冷数据。
通过 ILM,可以将热数据存储在高性能的存储介质上,并保持较高的索引性能;将冷数据迁移到成本较低的存储介质上,如大容量的机械硬盘。ILM 还可以根据设定的策略对索引进行诸如关闭、删除等操作,以释放系统资源。例如,可以设置一个策略,当索引中的数据超过 30 天未被访问时,将其从热节点迁移到冷节点,并将索引状态设置为只读;当数据超过 90 天时,直接删除该索引。这样可以确保系统始终保持高效运行,同时合理利用存储资源 。
监控与调优
监控
- ES自带监控工具:ES内置监控工具
- _cluster/stats API 可以获取集群级别的统计信息,包括文档数量、存储大小、索引操作次数等。通过这些信息,可以了解集群整体的负载情况和数据规模。
- _nodes/stats API 则用于获取节点级别的统计信息,如 CPU 使用率、内存使用量、磁盘 I/O 等。这对于定位单个节点的性能问题非常有帮助。比如,当发现某个节点的 CPU 使用率持续过高时,可以通过该 API 进一步查看是哪些操作导致了 CPU 资源的大量消耗。
- _indices/stats API 能获取索引级别的统计信息,如索引的分片数量、文档数量、搜索耗时等。通过分析这些指标,可以对索引的性能进行评估和优化。例如,通过查看索引的搜索耗时指标,可以发现哪些索引的查询性能较差,进而针对性地进行优化。
- 第三方监控工具:除了 Elasticsearch 自带的监控工具外,还有许多第三方监控工具可以与 Elasticsearch 集成,实现更全面、更直观的监控。Prometheus 和 Grafana 是两款非常流行的开源监控工具,它们可以与 Elasticsearch 无缝集成,提供强大的数据收集、分析和可视化功能。Prometheus 通过elasticsearch - exporter从 Elasticsearch 中获取监控指标,如查询响应时间、吞吐量、缓存命中率等。这些指标被收集后,存储在 Prometheus 的时间序列数据库中。Grafana 则使用 Prometheus 上的指标数据进行绘图展示,用户可以创建各种监控图表和告警规则。例如,可以创建一个查询响应时间的折线图,实时监控查询性能的变化;还可以设置阈值告警,当查询响应时间超过某个阈值时,通过邮件、短信等方式发送告警通知。Zabbix 也是一款常用的监控工具,它可以对 Elasticsearch 集群进行全面的监控,包括集群状态、节点性能、索引健康等。Zabbix 通过自定义脚本或插件与 Elasticsearch 进行交互,获取监控数据,并提供丰富的告警功能,确保在集群出现问题时能够及时通知管理员。
性能指标
ES(Elasticsearch)常见的性能指标如下:
索引相关指标
- 索引速度:指每秒能索引的文档数量,反映了ES摄入数据的能力,若索引速度慢可能影响数据实时性。
- 索引大小:即索引占用的磁盘空间,可评估存储需求和规划硬件资源,索引过大可能导致查询性能下降。
- 文档数:索引中存储的文档数量,有助于了解数据规模和评估对性能的影响。
查询相关指标
- 查询响应时间:指从客户端发送查询请求到收到响应的时间,是衡量查询性能的关键指标,直接影响用户体验。
- 查询吞吐量:即每秒能处理的查询数量,体现系统处理查询的能力,高吞吐量意味着能应对大量并发查询。
- 缓存命中率:查询结果在缓存中命中的比例,高命中率可减少磁盘I/O,提高查询性能。
集群健康指标
- 集群状态:分为绿色、黄色、红色。绿色表示所有分片都正常;黄色表示主分片正常,但部分副本分片未分配;红色表示有主分片不可用,会影响数据完整性和查询性能。
- 节点数:集群中的节点数量,合理的节点数可保证性能和高可用,过多或过少都可能有问题。
- 分片数:索引被拆分成的分片数量,影响数据分布和查询并行度,分片过多会增加管理开销,过少则影响性能。
资源指标
- CPU使用率:节点CPU的使用情况,过高可能导致进程阻塞,影响ES性能。
- 内存使用率:ES进程占用的内存量,内存不足可能导致数据缓存不充分,增加磁盘I/O。
- 磁盘I/O:包括读写速度和I/O等待时间,磁盘I/O性能影响索引和查询速度,I/O瓶颈会导致性能下降。
- 网络带宽:节点间数据传输和客户端与集群通信使用的网络带宽,带宽不足会影响数据传输和集群性能。
持续调优
- 定期性能测试:定期对 Elasticsearch 集群进行性能测试是持续优化查询性能的重要手段。可以使用专门的性能测试工具,如 Rally,它是 Elastic 官方提供的基准测试工具,能够模拟各种真实场景下的查询请求,对集群的性能进行全面评估。通过定期运行性能测试,可以及时发现随着数据量增长、业务变化等因素导致的性能问题。例如,每隔一段时间对电商搜索集群进行一次性能测试,模拟不同的搜索关键词、查询条件和并发用户数,记录查询的响应时间、吞吐量等指标。如果发现性能指标下降,就需要深入分析原因,可能是数据量增加导致索引性能下降,或者是新的业务需求引入了复杂的查询逻辑。针对这些问题,可以采取相应的优化措施,如重新设计索引、优化查询语句等。
- 实时监控与告警:建立实时监控与告警机制,能够及时发现集群性能的异常变化,并采取相应的措施进行处理。通过使用第三方监控工具,如 Prometheus 和 Grafana,可以实时收集和展示 Elasticsearch 的各种性能指标,并设置合理的阈值告警。当指标超出阈值时,系统会自动发送告警通知,如邮件、短信或即时通讯工具提醒。例如,设置查询响应时间的阈值为 500 毫秒,当某个查询的平均响应时间超过这个阈值时,立即触发告警,通知管理员进行排查和优化。这样可以在性能问题影响业务之前及时发现并解决,保障系统的稳定运行。
- 根据业务变化调整策略:随着业务的发展和变化,数据量、查询模式和用户需求都会发生改变,因此需要根据实际情况及时调整 Elasticsearch 的优化策略。例如,当业务规模扩大,数据量急剧增加时,可能需要增加集群节点数量,调整分片和副本配置,以提高系统的存储和处理能力;如果业务中引入了新的查询需求,如复杂的聚合查询或地理位置查询,就需要对索引进行相应的优化,选择合适的索引类型和字段映射,以满足新的查询要求。定期评估业务需求的变化,对 Elasticsearch 的配置和查询策略进行调整,能够确保系统始终保持良好的性能表现,满足业务的发展需求。