Elasticsearch 是一个实时分布式搜索数据分析引擎,内部使用lucene做索引与搜索,能够解决常规和各种类型数据的存储及检索需求,典型的应用场景有:数据分析,站内搜索,ELK,电商等,主要特点为:
- 灵活的检索、排序策略;
- 集群分布式,易扩展,平行扩缩容;
- 数据分片主备机制,系统安全高可用;
- 准实时索引;
- 高性能的检索,易用的接口(REST风格);
- 丰富的生态kibana可视化界面
业内互联网厂家应用及优化汇总参考
- 一: 腾讯云Elasticsearch集群规划及性能优化实践 ........* (202009)
- 【天机阁】百亿级实时计算系统性能优化 .............* (202101)
- 99.999%,提升ElasticSearch稳定性的秘密 ........... (202101)
- PB级大规模Elasticsearch集群运维与调优实践 ........ (202101)
- 腾讯万亿级 Elasticsearch 内存效率提升解密 ........ (202101)
- 二: 滴滴ElasticSearch千万级TPS写入性能翻倍技术剖析 ...... (202008)
- 滴滴ElasticSearch平台跨版本升级以及平台重构之路 .. (202003)
- 三: 京东使用 Elasticsearch 实现日均5亿订单查询 ........*(202009)
- 京东Elasticsearch使用ChubaoFS实现计算存储分离 ....(202003)
- Prometheus在京东开源项目ChubaoFS中的使用 ....... (201911)
- 四: 携程Elasticsearch数据同步实践 ...................... (202011)
- 五: 阿里云Elasticsearch性能优化实践 ................. * (201811)
一: 腾讯云Elasticsearch集群规划及性能优化实践
1. 集群规模评估
1.1 计算资源评估: 计算资源的评估主要是评估单节点的CPU和内存。
- ES的计算资源一般消耗在写入和查询过程,经过总结大量ES集群的运维经验,2C8G 的配置大概能支持 5k doc/s 的写入,32C64G 的配置大概能支撑 5w doc/s的写入能力。
1.2 存储资源评估: 存储资源的评估主要是评估磁盘的类型及容量大小
- 对于冷热分离的集群,则默认使用SSD作为热节点,高性能云盘作为温节点。
- 腾讯云ES支持单节点挂载多块云硬盘,且经过性能压测,3块盘相比于1块盘,吞吐量大约有2.8倍的提升。因此如果对写入速度及IO性能要求较高,可选择挂载多块 SSD 磁盘。
1.3 节点数量评估: 节点数量的评估主要是评估集群数据节点的数量
- 在同等集群性能的情况下,建议优先选择高配置少节点的集群。例如 32C64G*3 节点的集群相比于 8C16G*12 节点的集群,在集群稳定性和扩容的便捷性上都有一定的优势。
- 因为高配置的集群如果遇到性能瓶颈需要扩容,则只需要横向扩容,即向集群中加入更多同等配置的节点即可;而低配置的集群在扩容节点配置时,则需要纵向扩容。
集群规模评估准则: 这里结合我们的运维经验,给出集群规模评估的几点参考建议:
- 32C64G单节点配置通常可承载5W次/s的写入;
- 入量和数据量较大时,优先选择32C64G的节点配置;
- 1T的数据量预计需消耗2-4GB的内存空间;
- 搜索场景优先选择大内存节点配置;
- 存储容量 = 源数据 * (1 + 副本数量) * 1.45 * (1 + 预留空间) ≈ 源数据 * (1 + 副本数量) * 2.2
2. 索引配置评估
索引配置的评估主要评估两点:
- 如何划分索引? 在使用 index 时,建议做好定期切换索引的计划。对于日志场景来说,写入不大的情况下建议按天创建索引,而写入较大的情况下,则建议按小时创建索引。如何设置索引主分片数?云上的索引主分片数默认是5个,具体的大小则需要业务根据具体的场景及数据量来优化。定期滚动索引的好处主要包括:
- 能够控制单个索引的大小,提升读写性能;
- 同时能够防止单个索引太大,影响故障恢复的时间;
- 另外也能避免热索引过大,从而影响快照备份恢复的时间
索引配置评估准则: 索引配置的评估可根据下面几点准则进行评估
- 单个分片大小控制在 30-50GB
- 集群总分片数量控制在 3w 以内
- 1GB 的内存空间支持 20-30 个分片为佳
- 一个节点建议不超过 1000 个分片
- 索引分片数量建议和节点数量保持一致
- 集群规模较大时建议设置专用主节点
- 专用主节点配置建议在 8C16G 以上
- 如果是时序数据,建议结合冷热分离+ILM( index lifecycle management) 索引生命周期管理 (参考: Elasticsearch7.X ILM索引生命周期管理(冷热分离))
特别说明
- 集群分片总数的大小控制上,我们经过一些性能测试发现:当集群的总分片数超过 10w 个以后,创建索引时间会增长到分钟级。
- 尤其是对于写入量在百万 qps 以上的集群,如果总分片数在 10W+,且索引是自动创建的,那么就经常会在每次切换新索引时候,出现写入陡降、集群不可用的情况。
3. ES写入性能优化
3.1 写入数据不指定doc_id,让 ES 自动生成
- 索引中每一个 doc 都有一个全局唯一的 doc_id,这个 doc_id 可自定义,也可以让ES自动生成。
- 如果自定义的话,则ES在写入过程中会多一步判断的过程,即先Get下该 doc_id 是否已经存在。如果存在的话则执行 Update 操作,不存在则创建新的 doc。
- 因此如果我们对索引 doc_id 没有特别要求,则建议让ES自动生成 doc_id,这样可提升一定的写入性能。
3.2 对于规模较大的集群,建议提前创建好索引,且使用固定的 Index mapping
-
这一条优化建议在上面也提到了,因为创建索引及新加字段都是更新元数据操作,需要 master 节点将新版本的元数据同步到所有节点。
- 因此在集群规模比较大,写入qps较高的场景下,特别容易出现master更新元数据超时的问题,这可导致 master 节点中有大量的 pending_tasks 任务堆积,从而造成集群不可用,甚至出现集群无主的情况。
3.3 对于数据实时性要求不高的场景,适当增加 refresh_interval 时间
- ES默认的 refresh_interval 是1s,即 doc 写入1s后即可被搜索到。
- 如果业务对数据实时性要求不高的话,如日志场景,可将索引模版的 refresh_interval 设置成30s,这能够避免过多的小 segment 文件的生成及段合并的操作。
3.4 对于追求写入效率的场景,可以将正在写入的索引设置为单副本,写入完成后打开副本
- 越来越多的外部客户正选择将自建的ES集群迁移到腾讯云上来,客户通常是使用 logstash 来迁移数据,由于自建集群中完整保留了数据,因此这时候可以将云上的正在写入的索引副本设置为0, 这样可最快完成集群迁移工作。数据迁移完成后再将副本打开即可。
3.5 使用 Bulk 接口批量写入数据,每次 bulk 数据量大小控制在 10M 左右
- ES为了提升写入性能,提供了 Bulk 批量写入的API,通常客户端会准备好一批数据往ES中写入,ES收到 Bulk 请求后则根据routing 值进行分发,将该批数据组装成若干分子集,然后异步得发送给各分片所在的节点。
- 这样能够大大降低写入请求时的网络交互和延迟。通常我们建议一次Bulk的数据量控制在10M以下,一次Bulk的doc数在 10000 上下浮动。
3.6 使用自定义 routing 功能,尽量将请求转发到较少的分片
- 上面我们提到ES提供了Bulk接口支持将数据批量写入到索引,虽然协调节点是异步得将数据发送给所有的分片,但是却需要等待所有的分片响应后才能返回给客户端,因此一次Bulk的延迟则取决于响应最慢的那个分片所在的节点。这就是分布式系统的长尾效应。
- 因此,我们可以自定义 routing 值,将一次Bulk尽量转发到较少的分片上
3.7 尽量选择 SSD 磁盘类型,并且可选择挂载多块云硬盘
- 云上目前提供多种类型的磁盘可用选择,其中1T的 SSD 云盘吞吐量为 260M/s,高性能云盘为 150M/s。因此使用SSD磁盘对于写入性能和IO性能都会有一定的提升
- 另外腾讯云现在也提供了多盘的能力,相对于单盘节点来说,3块盘的吞吐量大约有2.8倍的提升。
3.8 冻结历史索引,释放更多的内存空间
- 我们知道ES的索引有三种状态,分别是 Open状态、Frozen状态和 Close状态
- Open状态的索引:由于是通过将倒排索引以FST数据结构的方式加载进内存中,因此索引是能够被快速搜索的,且搜索速度也是最快的。但是需要消耗大量的内存空间,且这部分内存为常驻内存,不会被GC的。1T的索引预计需要消耗2-4GB的JVM堆内存空间。
- Frozen状态的索引:特点是可被搜索,但是由于它不占用内存,只是存储在磁盘上,因此冻结索引的搜索速度是相对比较慢的。如果我们集群中的数据量比较大,历史数据也不能被删除,则可以考虑使用下面的API将历史索引冻结起来,这样便可释放出较多的内存空间。
二:【天机阁】百亿级实时计算系统性能优化
背景:
在传统单机系统的使用过程中,如果某个请求响应过慢或是出错,开发人员可以通过查看日志快速定位到具体服务。而随着业务的越来越复杂,架构由单体逐渐演变为微服务架构。特别是随着容器, Serverless等技术的广泛应用,它将庞大的单体应用拆分成多个子系统和公共的组件单元。这一理念带来了许多好处:复杂系统的拆分简化与隔离、公共模块的重用性提升与更合理的资源分配、大大提升了系统变更迭代的速度以及可扩展性。但反之,业务架构也随之变的越来越复杂,一个看似简单的业务后台可能有几百甚至几千个服务在支撑,当接口出现问题时,开发人员很难及时从错综复杂的服务调用中找到问题的根源,从而错失了止损的黄金时机,排查问题的过程也需要耗费大量的时间和人力成本。为了应对这一问题,业界诞生了许多优秀的面向Devops的诊断分析系统,包括Logging、Metric、Tracing. 三者互相重叠,又各自专注于自己的领域,将三者结合起来就可以快速定位问题。天机阁正是腾讯研发的集三位于一体的分布式链路追踪系统,提供了海量服务下的链路追踪、故障定位、架构梳理、容量评估等能力。
系统架构:
从数据流转角度来看,天机阁整体可以分为数据生产链路与消费链路,其中数据生产链路主要包括数据接入层、数据处理层、数据存储层。整体如下图所示
- 数据接入层: 主要负责数据采集工作,天机阁支持http+json、http+proto、grpc等多种数据上报方式,业务可以采用对应语言的SDK进行数据上报。根据业务上报环境,可选择Kafka、虫洞等多种数据接入方式,为减少数据传输耗时,提升系统的容错能力,天机阁提供了上海、广州、深圳等多个不同区域的接入通道,数据接入时会根据Idc机器所在区域自动进行“就近接入”。
- 数据处理层: 基于Flink构建的天机阁流式计算平台。主要处理三部分数据:
- 第一部分是Metric模调数据的计算工作,结果同步至Druid。
- 第二部分是日志数据,基于DataStream模式对数据进行实时消费,同步至ES日志集群。
- 第三部分是Trace数据,基于KeyedStream的分组转换模式,根据业务Traceid进行Keyby,将一条Stream流划分为逻辑上不相交的分组,把相同Traceid的数据实时汇聚到同一个窗口,再对数据进行统计聚合,生成拓扑图、调用链、调用树等数据模型,结果同步至Hbase与ES。
- 数据存储层: ES主要用于用于建立热门Trace的倒排索引以及存储日志数据,Harbo/Druid系统用于存储模调数,Hbase用于存储调用链,拓扑图,关系链等数据。
随着进入量的上涨,ES集群内部写入峰值达到80w/s,日均文档总量达到280亿,索引占用总量达到 67T,每天新增索引量达到1000+,而每日文档新增存储总量达到10T;
机器配置采用为:64个4C 16g的数据节点,平均CPU使用率在45-50%之间;最大CPU使用率在80%左右;内存使用率60%左右,而磁盘平均使用率达到了53%
伴随业务量的极速上涨主要暴露出来的问题为:
- 集群内部分片过多; 分片过多的缺点主要有以下三个方面:
- ES每个索引的分片都是一个Lucene索引,它会占用消耗CPU、内存、文件句柄
- 分片过多,可能导致一个节点聚集大量分片,产生资源竞争
- ES在计算相关度词频统计信息的时候也是基于分片维度的,如果分片过多,也会导致数据过少相关度计算过低
- 分片大小不均匀
- 部分索引的分片容量超过50G,侧面反应了这些索引分片策略的不合理,最终会导致索引的查询性能变慢
- 写入耗时过大,部分索引查询性能慢
- ES写入耗时达到(1500ms-2000ms),此外分片过大也直接影响到索引的查询性能
- 索引创建过慢(1分钟),大量写入被拒绝
- 集群没有设置主节点,导致创建索引时,数据节点要充当临时主节点的角色,写入量较小的时候,影响不大,当写入压力过大时,会加剧数据节点的负载,影响索引的创建速度。
- 当出现密集型索引创建时,这个问题被无限放大,索引创建同时也会伴随大量的元数据移动,更加剧了节点负载,从而导致大量数据写入被拒绝现象。
- 而写入被拒绝最终会导致上游Flink集群剧烈抖动(写入失败抛出大量异常),以致于索引创建高峰期经常出现2-3小时的集群不可用状态。
- 系统出现大量异常日志
- ES服务器异常,主要分为两类,一类是:数据解析异常,另一类是:Fields_limit异常
- 索引的容量管理与维护困难
- 主要是解决大规模以及日益增长数据场景下,集群的自动化容量管理与生命周期管理的问题
ES优化思路图:
优化点1:优化集群内部分片过多、分片不合理、节点负载不均等问题
其中主要涉及了二个问题:
- 如何确定索引单个分片大小?-> 小于40G
- 如何确定集群中分片数量?-> 节点堆内存*节点数*200 = 2万左右
总而言之,查询和写入的性能与索引的大小是正相关的,要保证高性能,一定要限制索引的大小。
而索引的大小取决于分片与段的大小,分片过小,可能导致段过小,进而导致开销增加,分片过大可能导致分片频繁Merge,产生大量IO操作,影响写入性能。通过阅读相关文档,我提炼了以下三条原则:
- 分片大小控制50G以内,最好是20-40G,以均衡查询和写入性能。
- 每个节点可以存储的分片数量与可用堆内存成正比,一条很好的经验法则:“确保每个节点配置的每G堆内存,分片数在20个以下”。
- 分片数为节点数整数倍,确保分片能在节点之间均衡分布。
当然最好的方法是根据自身业务场景来确定分片大小,看业务是注重读还是注重写以及对数据实时性、可靠性的要求。
一般而言:当用户遇到性能问题时,原因通常都可回溯至数据的索引方式以及集群中的分片数量。对于涉及多租户和用到时序型索引的用例,这一点尤为突出。
优化点2:优化写入性能
- 减少集群副本分片数,过多副本会导致ES内部写扩大。
- ES集群主用于构建热门Trace索引用于定位问题,业务特性是写入量大而数据敏感度不高。所以我们可以采用经济实惠的配置,去掉过多副本,维护单副本保证数据冗余已经足够,另外对于部分超大索引,我们也会采用0副本的策略。
- 索引设计方面,id自动生成(舍弃幂等),去掉打分机制,去掉DocValues策略,嵌套对象类型调整为Object对象类型。此处优化的目的是通过减少索引字段,降低Indexing Thread线程的IO压力,经过多次调整选择了最佳参数。
- 根据ES官方提供的优化手段进行调整,包括Refresh,Flush时间,Index_buffer_size等。
- 客户端API升级,将之前ES原生的批量API升级为Transport API,策略为当数据缓存到5M(灵活调整)大小时,进行批量写入(经过性能测试)
上述优化,其实是对ES集群一种性能的取舍,牺牲数据可靠性以及搜索实时性来换取极致的写入性能。但其实ES只是存储热门数据,天机阁有专门的Hbase集群对全量数据进行备份,详细记录上报日志流水,保证数据的可靠性。
优化点3:优化索引创建方式
- 触发试创建索引改为预创建索引模式
- 申请专用主节点用于索引创建工作
优化点4:优化ES服务器异常
- 调整字段映射模式,Dynamic-Mapping动态映射可能导致字段映射出现问题,这里修改为手动映射
- 调整Limit Feild限制,修改ES索引字段上限
- 业务层加入数据清洗算子,过滤脏数据以及埋点错误导致Tag过多的Span,保护存储
优化点5:ES集群分通道部署
- 目前天机阁只有一个公共集群,所有业务都在同一个集群中创建索引,这种方式虽然具备了一定的可扩展性。但是随着业务量的进一步增长,集群规模也会逐渐变的巨大,从而容易达到系统的性能瓶颈,无法满足扩展性需要,且当大集群中有索引出现问题时,容易影响到其他业务。
- 所以我们从业务维度对公共集群进行解耦,按通道做set化部署,将不同通道业务,就近路由到不同集群,各集群可按需灵活扩展。
优化点6:基于ILM + Rollover + 别名实现索引自动化生命周期管理与容量管理
- 天机阁是典型的日志型时序索引,根据应用Appid按天定时生成索引,索引的生命周期默认为7天,其中当天的数据会被频繁写入与查询,第二、三天的数据偶尔被查询,后面几天的数据只有少数重度业务使用者才会查询到。这样的特性会衍生出来几个问题:
- ES索引分片数一旦创建便无法更改,这种机制无法应对业务忽然放量导致的索引容量激增的问题,通常只能通过手动Reindex来解决,而Reindex过程也会影响到业务写入性能。
- 根据日志索引存储具备的特点,不同时间阶段可以重新对分片数、副本数、Segment进行针对性调整,对冷数据进行归档处理,从而更好的利用机器资源。
- 需要创建额外的定时任务来删除索引,特别是当集群中索引过多时,密集型的索引删除操作,短时间内也会造成集群的波动。
- 我们希望构建一个优雅的索引自动化运维管理系统,而这个系统主要解决两个问题:
- 自动化索引生命周期管理: 创建索引生命周期管理,并定义不同阶段的索引策略,以此来实现ES索引自动化优化与生命周期管理而不需要引入第三方服务。
- 自动化索引容量管理:当集群索引超过设定容量大小时,可以自动进行滚动,生成新的索引,而上游业务不需要感知。
索引自动化管理优化:ES6.7以后,官方推出了ILM(index lifestyle management)索引生命周期管理策略,能同时控制多个索引的生命流转,配合索引模板、别名、Rollover能实现自动化索引生命周期与容量的管理闭环。
- Hot阶段:可读,可写,索引会被频繁查询。
- Warm:可读,不可写,此时可对数据进行归档,采用Shrink与Forcemerge,减少索引副本与主分片数,并强制进行Segment合并,能够减少数据内存与磁盘的使用。
- Cold:不可写入,很久没被更新,查询慢。可对索引进行冻结操作,此时集群将对索引进行落盘操作,业务需要指定特定的参数才能查询到数据。
- Delete:删除操作。将触发索引删除事件。
天机阁使用ILM 策略配合分级索引模板可以比较优雅的实现索引的自动化管理过程。
ILM 策略主要分为四个阶段:热、温、冷和删除。对于定义好的各个阶段的相应策略,ILM 会始终顺序执行。我们只需要根据索引每个阶段的数据特性定义合适的管理方式,诸如:
- 索引滚动更新用于管理每个索引的大小;
- 强制合并操作可用于优化索引;
- 冻结操作可用于减少集群的存储压力
ILM可以高效的进行索引生命周期与容量自动化管理,使用起来也很简单。但是还是有不少要注意的地方:
- 切换策略后索引不会马上生效,旧数据仍然写入旧索引,只有触发Rollover生成新索引,新策略才会生效。
- 每个阶段的生效时间是以Hot阶段触发Rollover为起始时间的基础上再加业务配置时间。
- 如果不想使用Rollover,可以直接进行关闭,也可以实现只对索引进行生命周期的管理操作。
- 腾讯云ES最好采用 白金版 + 6.8以上版本。
优化后整体架构图
Flink实时计算系统是天机阁链路追踪平台的重要组成部分,数据经过Flink窗口进行实时计算聚合最终sink到ES与Hbase等底层存储,而日益增长的数据量给计算集群带来了很大的挑战。
面对这些问题,我们重新梳理了整个链路架构,找到系统的瓶颈所在,并展开了一系列有效的优化措施。而在未来,我们会继续在大数据领域的探索研究工作,更进一步的打磨系统数据处理能力,提供更好的服务。
整体从计算层、存储层、架构、服务质量等几个维度对系统进行了优化,同时也加强了系统的容灾能力
- 自定义计数器实现热Key自动发现与降级。
- 存储过载保护,当QPS超过压测阈值时,触发降级逻辑。
- 通过druid 预聚合方式完善对业务的多维监控
三:京东使用 Elasticsearch 实现日均5亿订单查询
背景:
京东到家订单中心系统业务中,无论是外部商家的订单生产,或是内部上下游系统的依赖,订单查询的调用量都非常大,造成了订单数据读多写少的情况。我们把订单数据存储在MySQL中,但显然只通过DB来支撑大量的查询是不可取的。同时对于一些复杂的查询,MySQL支持得不够友好,所以订单中心系统使用了Elasticsearch来承载订单查询的主要压力。目前订单中心ES集群存储数据量达到10亿个文档,日均查询量达到5亿。
ES 集群架构演进之路
1、初始阶段:订单中心ES初始阶段如一张白纸,架设方案基本没有,很多配置都是保持集群默认配置。整个集群部署在集团的弹性云上,ES集群的节点以及机器部署都比较混乱。同时按照集群维度来看,一个ES集群会有单点问题,显然对于订单中心业务来说也是不被允许的。
2、集群隔离阶段:
- 和很多业务一样,ES集群采用的混布的方式。但由于订单中心ES存储的是线上订单数据,偶尔会发生混布集群抢占系统大量资源,导致整个订单中心ES服务异常。
- 显然任何影响到订单查询稳定性的情况都是无法容忍的,所以针对于这个情况,先是对订单中心ES所在的弹性云,迁出那些系统资源抢占很高的集群节点,ES集群状况稍有好转。但随着集群数据不断增加,弹性云配置已经不太能满足ES集群,且为了完全的物理隔离,最终干脆将订单中心ES集群部署到高配置的物理机上,ES集群性能又得到提升。
3、节点副本调优阶段
- ES的性能跟硬件资源有很大关系,当ES集群单独部署到物理机器上时,集群内部的节点并不是独占整台物理机资源,在集群运行的时候同一物理机上的节点仍会出现资源抢占的问题。所以在这种情况下,为了让ES单个节点能够使用最大程度的机器资源,采用每个ES节点部署在单独一台物理机上方式。但紧接着,问题又来了,如果单个节点出现瓶颈了呢?我们应该怎么再优化呢?
- ES查询的原理,当请求打到某号分片的时候,如果没有指定分片类型(Preference参数)查询,请求会负载到对应分片号的各个节点上。而集群默认副本配置是一主一副,针对此情况,我们想到了扩容副本的方式,由默认的一主一副变为一主二副,同时增加相应物理机。
- 整个集群有一套主分片,二套副分片(一主二副),从网关节点转发过来的请求,会在打到数据节点之前通过轮询的方式进行均衡。集群增加一套副本并扩容机器的方式,增加了集群吞吐量,从而提升了整个集群查询性能。
- 当然分片数量和分片副本数量并不是越多越好,分片数越大,集群横向扩容规模也更大,根据分片路由的单ID查询吞吐量也能大大提升,但聚合的分页查询性能则将降低;分片数越小,集群横向扩容规模也更小,单ID的查询性能也会下降,但分页查询的性能将会提升。
4、主从集群调整阶段
- 到此,订单中心的ES集群已经初具规模,但由于订单中心业务时效性要求高,对ES查询稳定性要求也高,如果集群中有节点发生异常,查询服务会受到影响,从而影响到整个订单生产流程。很明显这种异常情况是致命的,所以为了应对这种情况,我们初步设想是增加一个备用集群,当主集群发生异常时,可以实时的将查询流量降级到备用集群。
- 为了更好地控制ES数据写入,我们采用业务双写的方式来搭设主备集群。每次业务操作需要写入ES数据时,同步写入主集群数据,然后异步写入备集群数据。同时由于大部分ES查询的流量都来源于近几天的订单,且订单中心数据库数据已有一套归档机制,将指定天数之前已经关闭的订单转移到历史订单库。
- 所以归档机制中增加删除备集群文档的逻辑,让新搭建的备集群存储的订单数据与订单中心线上数据库中的数据量保持一致。同时使用ZK在查询服务中做了流量控制开关,保证查询流量能够实时降级到备集群。在此,订单中心主从集群完成,ES查询服务稳定性大大提升。
遇到的一些坑
1、实时性要求高的查询走DB
- 对于ES写入机制,新增的文档会被收集到Indexing Buffer,然后写入到文件系统缓存中,到了文件系统缓存中就可以像其他的文件一样被索引到。然而默认情况文档从Indexing Buffer到文件系统缓存(即Refresh操作)是每秒分片自动刷新,所以这就是我们说ES是近实时搜索而非实时的原因:文档的变化并不是立即对搜索可见,但会在一秒之内变为可见。
- 当前订单系统ES采用的是默认Refresh配置,故对于那些订单数据实时性比较高的业务,直接走数据库查询,保证数据的准确性。
2、避免深分页查询
- ES集群的分页查询支持from和size参数,查询的时候,每个分片必须构造一个长度为from+size的优先队列,然后回传到网关节点,网关节点再对这些优先队列进行排序找到正确的size个文档。
- 假设在一个有6个主分片的索引中,from为10000,size为10,每个分片必须产生10010个结果,在网关节点中汇聚合并60060个结果,最终找到符合要求的10个文档。
- 由此可见,当from足够大的时候,就算不发生OOM,也会影响到CPU和带宽等,从而影响到整个集群的性能。所以应该避免深分页查询,尽量不去使用。
3、FieldData与Doc Values
- FieldData: 线上查询出现偶尔超时的情况,通过调试查询语句,定位到是跟排序有关系。排序在es1.x版本使用的是FieldData结构,FieldData占用的是JVM Heap内存,JVM内存是有限,对于FieldData Cache会设定一个阈值。如果空间不足时,使用最久未使用(LRU)算法移除FieldData,同时加载新的FieldData Cache,加载的过程需要消耗系统资源,且耗时很大。所以导致这个查询的响应时间暴涨,甚至影响整个集群的性能。针对这种问题,解决方式是采用Doc Values。
- Doc Values:Doc Values是一种列式的数据存储结构,跟FieldData很类似,但其存储位置是在Lucene文件中,即不会占用JVM Heap。随着ES版本的迭代,Doc Values比FieldData更加稳定,Doc Values在2.x起为默认设置。
四:京东Elasticsearch使用ChubaoFS实现计算存储分离
ES在京东的应用场景:
1、 补充关系型数据库的结构化数据查询
- 主要应用的业务是商品、促销、优惠券、订单、收银台、物流、对账、评论等大数据量查询。此场景的核心诉求是高性能、稳定性和高可用性,部分场景会有检索要求,通常用于加速关系型数据库,业务系统通过 binlog 同步或业务双写完成数据同步。
2、全文检索功能
- 主要的应用场景是应用、安全、风控、交易等操作日志,以及京东部分品类商品搜索。此类日志化场景对写要求很高,查询性能及高可用等要求相对较低,大的业务写会达到数千万 / 秒,存储以 PB 为单位来计算。
- 这些场景对磁盘、内存有比较高的要求,因此,京东也做了相应优化,用于减少内存消耗,提升磁盘整体使用率,使用更廉价的磁盘来降低成本等等。
3、实时数据分析引擎,形成统计报表
- 主要应用的业务是物流单的各种分析、订单数据分析、用户画像等。因为业务数据分析纬度较多,flink、storm 等流式分析对于某些报表场景不太适用,批处理实时性又成为问题,所以近实时分析的 Elasticsearch 就成为了这些业务的选择。
在应用 Elasticsearch 的 5 年时间中,京东从最初的几个场景应用变成了覆盖各条业务线,从最初的几台机器变成了现在的上千机器和几千集群的量级,运维压力也随之而来了。目前,京东在日常运维 ELasticsearch 集群时,主要面临以下几个问题:
- IO 读写不均匀,部分节点 IO 压力非常大;
- 冷数据节点存储量受限制于单机的最大存储;
- close 后的索引节点故障无法进行 recovery,导致数据丢失的风险。
为了解决这些问题,京东应用了 ChubaoFS。ChubaoFS 是京东自研的、为云原生应用提供高性能、高可用、可扩展、 稳定性的分布式文件系统,设计初衷是为了京东容器集群提供持久化存储方案,同时也可作为通用云存储供业务方使用,帮助有状态应用实现计算与存储分离。
ChubaoFS 支持多种读写模型,支持多租户,兼容 POSIX 语义和 S3 协议。ChubaoFS 设计的每个 pod 可以共享一个存储卷,或者每个 pod 一个存储卷,当容器所在的物理机宕机后,容器的数据可以随着容器被同时调度到其他宿主机上, 保障数据可靠存储。
无状态实例阶段
- 随着业务的不断增长,集群数量及消耗的服务器资源成比例上升,京东 Elasticsearch 实例上升为上万个,维护的集群快速增长为上千个,集群规模从几个到几十个不等。但是整体资源的利用率却相对较低,磁盘使用率仅为 28% 左右,日常平均读写 IO 在 10~20M/ 秒(日志分区 IO 在 60-100M / 秒)。造成资源浪费的原因是集群规模普遍较小,为保证突发情况下,读写请求对 IO 的要求,我们一般会为集群分配较为富余的资源,物理机分配的容器也会控制在一定量级。
- 我们做个假设,如果大量的服务器 IO 都可以共享,那么某个集群突发请求对 IO 的影响其实可以忽略的。基于这种假设以及对提高磁盘使用率的迫切需要,我们考虑引入了公司内部部署的 ChubaoFS 作为存储,将 Elasticsearch 作为无状态的实例进行存储计算分离。
- 得益于 ChubaoFS 是为大规模容器集群挂载而设计的通用文件系统,我们几乎是零成本接入的,只需在物理机上安装相应的客户端,就可以将 ChubaoFS 当成本地文件系统来用。集成之后我们对 ChubaoFS 的性能进行了一系列对比。从测试结果可以看出,Elasticsearch 集成 ChubaoFS 之后,在不同副本数情况下, index benchmark 性能和本地磁盘差距在 110%~120% 左右,仅有略微的下降;merge benchmark 性能在 replica > 0 时,Elasticsearch 使用 ChubaoFS 优于本地磁盘。refrElasticsearchh 和 flush benchmark 性能 ChubaoFS 不及本地磁盘。
目前使用效果
集成 ChubaoFS 之后,我们先是灰度运行了一段时间,效果表现良好之后,我们将京东日志所有的 Elasticsearch 集群底层全部切换为 ChubaoFS。切换之后,我们在这些方面获得了更好的效果:
- 节约资源:在采用 ChubaoFS 之前,我们使用了 500 台物理机器,并且每个机器平时大概有 80% 的磁盘 IO 能力处于闲置状态。采用 ChubaoFS 之后,ChubaoFS 的集群规模约为 50 台,Elasticsearch 托管到公司的容器平台,实现弹性可扩展。
- 管理和运维更加简单便捷:采用 ChubaoFS 之后,我们不用再担心某个机器的硬盘故障,或者某个机器的读写负载不均衡的问题。
- GC 频率明显降低:由于 ChubaoFS 底层对文件作了副本支持,业务层 Elasticsearch 将副本置为 0,原先 segment 挤占堆内存导致 FullGC 现象明显,接入 ChubaoFS 后,GC 频率明显降低。
五: 阿里云Elasticsearch性能优化实践 (201811)
Elasticsearch是一款流行的分布式开源搜索和数据分析引擎,具备高性能、易扩展、容错性强等特点。它强化了Apache Lucene的搜索能力,把掌控海量数据索引和查询的方式提升到一个新的层次。本文结合开源社区和阿里云平台的实践经验,探讨如何调优Elasticsearch的性能提高索引和查询吞吐量。
一. Elasticsearch部署建议
1.选择合理的硬件配置,尽可能使用SSD
- Elasticsearch最大的瓶颈往往是磁盘读写性能,尤其是随机读取性能。使用SSD通常比机械硬盘查询速度快5~10倍,写入性能提升不明显 ?
- 对于文档检索类查询性能要求较高的场景,建议考虑SSD作为存储,同时按照1:10的比例配置内存和硬盘。
- 对于日志分析类查询并发要求较低的场景,可以考虑采用机械硬盘作为存储,同时按照1:50的比例配置内存和硬盘。
- 单节点存储数据建议在2TB以内,最大不要超过5TB,避免查询速度慢、系统不稳定。
2.给JVM配置机器一半的内存,但是不建议超过32G
- 修改conf/jvm.options配置,-Xms和-Xmx设置为相同的值,推荐设置为机器内存的一半左右,剩余一半留给操作系统缓存使用。
- jvm内存建议不要低于2G,否则有可能因为内存不足导致ES无法正常启动或内存溢出,jvm建议不要超过32G,否则jvm会禁用内存对象指针压缩技术,造成内存浪费。
- 机器内存大于64G内存时,推荐配置-Xms30g -Xmx30g 。
3.规模较大的集群配置专有主节点,避免脑裂问题
- Elasticsearch主节点(master节点)负责集群元信息管理、index的增删操作、节点的加入剔除,定期将最新的集群状态广播至各个节点。在集群规模较大时,建议配置专有主节点只负责集群管理,不存储数据,不承担数据读写压力。
4.Linux操作系统调优
- 关闭交换分区,防止内存置换降低性能。
- 单用户可以打开的最大文件数量,可以设置为官方推荐的65536或更大些
- 单用户线程数调大
- 单进程可以使用的最大map内存区域数量
二. 索引性能调优建议
1.设置合理的索引分片数和副本数
- 索引分片数建议设置为集群节点的整数倍,初始数据导入时副本数设置为0,生产环境副本数建议设置为1(设置1个副本,集群任意1个节点宕机数据不会丢失;设置更多副本会占用更多存储空间,操作系统缓存命中率会下降,检索性能不一定提升)。单节点索引分片数建议不要超过3个,每个索引分片推荐10-40GB大小。索引分片数设置后不可以修改,副本数设置后可以修改。Elasticsearch6.X及之前的版本默认索引分片数为5、副本数为1,从Elasticsearch7.0开始调整为默认索引分片数为1、副本数为1。
2.使用批量请求
- 使用批量请求将产生比单文档索引请求好得多的性能。写入数据时调用批量提交接口,推荐每批量提交5~15MB数据。例如单条记录1KB大小,每批次提交10000条左右记录写入性能较优;单条记录5KB大小,每批次提交2000条左右记录写入性能较优。
3.通过多进程/线程发送数据
- 单线程批量写入数据往往不能充分利用服务器CPU资源,可以尝试调整写入线程数或者在多个客户端上同时向Elasticsearch服务器提交写入请求。与批量调整大小请求类似,只有测试才能确定最佳的worker数量。 可以通过逐渐增加工作任务数量来测试,直到集群上的I / O或CPU饱和。
4.调大refresh interval
- 在 Elasticsearch 中,写入和打开一个新段的轻量的过程叫做 refresh 。 默认情况下每个分片会每秒自动刷新一次。这就是为什么我们说 Elasticsearch 是 近 实时搜索: 文档的变化并不是立即对搜索可见,但会在一秒之内变为可见。并不是所有的情况都需要每秒刷新。可能你正在使用 Elasticsearch 索引大量的日志文件,你可能想优化索引速度而不是近实时搜索,可以通过设置 refresh_interval,降低每个索引的刷新频率。
5.设计mapping配置合适的字段类型
- Elasticsearch在写入文档时,如果请求中指定的索引名不存在,会自动创建新索引,并根据文档内容猜测可能的字段类型。但这往往不是最高效的,我们可以根据应用场景来设计合理的字段类型。
三. 查询性能调优建议
1.使用过滤器缓存和分片查询缓存
- 默认情况下,Elasticsearch的查询会计算返回的每条数据与查询语句的相关度,但对于非全文索引的使用场景,用户并不关心查询结果与查询条件的相关度,只是想精确的查找目标数据。此时,可以通过filter来让Elasticsearch不计算评分,并且尽可能的缓存filter的结果集,供后续包含相同filter的查询使用,提高查询效率。
2.使用路由routing
- Elasticsearch写入文档时,文档会通过一个公式路由到一个索引中的一个分片上。默认的公式如下:shard_num = hash(_routing) % num_primary_shards
- _routing字段的取值,默认是_id字段,可以根据业务场景设置经常查询的字段作为路由字段。例如可以考虑将用户id、地区作为路由字段,查询时可以过滤不必要的分片,加快查询速度。
- 查询时不指定路由,需要查询所有分片:
3.强制合并只读索引,关闭历史数据索引
- 只读的索引可以从合并成一个单独的大segment中收益,减少索引碎片,减少JVM堆常驻内存。历史数据索引如果业务上不再支持查询请求,可以考虑关闭索引,减少JVM内存占用。
4.配置查询聚合节点
- 查询聚合节点可以发送粒子查询请求到其他节点,收集和合并结果,以及响应发出查询的客户端。通过给查询聚合节点配置更高规格的CPU和内存,可以加快查询运算速度、提升缓存命中率。
- 某客户使用25台8核CPU32G内存节点ELasticsearch集群,查询QPS在4000左右。增加6台16核CPU32G内存节点作为查询聚合节点,观察服务器CPU、JVM堆内存使用情况,并调整缓存、分片、副本参数,查询QPS达到12000。
5.设置查询读取记录条数和字段
- 默认的查询请求通常返回排序后的前10条记录,最多一次读取10000条记录,通过from和size参数控制读取记录范围,避免一次读取过多的记录。通过_source参数可以控制返回字段信息,尽量避免读取大字段。
6.避免前缀模糊匹配
- Elasticsearch默认支持通过*?正则表达式来做模糊匹配,如果在一个数据量超过10亿条的索引上执行模糊匹配,尤其是前缀模糊匹配,通常耗时会比较长,甚至可能导致内存溢出。尽量避免在高并发查询请求的生产环境执行这类操作。
- 某客户需要对车牌号进行模糊查询,通过查询请求"车牌号:*A8848*"查询时,往往导致整个集群负载较高。通过对数据预处理,增加冗余字段"车牌号.keyword",并事先将所有车牌号按照1元、2元、3元...7元分词后存储至该字段,字段存储内容示例:沪,A,8,4,沪A,A8,88,84,48,沪A8...沪A88488。通过查询"车牌号.keyword:A8848"即可解决原来的性能问题。
7.避免索引稀疏
- Elasticsearch6.X之前的版本默认允许在一个index下面创建多个type,Elasticsearch6.X及之后的版本只允许创建一个type。在一个type下面创建多个字段不一样的type,或者将几百个字段不一样的索引合并到一个索引中,会导致索引稀疏问题。
- 建议每个索引下只创建一个type,字段不一样的数据分别独立创建index,不要合并成一个大索引。每个查询请求根据需要去读取相应的索引,避免查询大索引扫描全部记录,加快查询速度。
Flag
1、Elasticsearch5.3中发布了跨集群搜索(cross-cluster search)功能,供用户跨多个集群进行查询,如本地协调节点去访问多个不同机房的ES集群查询日志信息等。Elasticsearch 7.0中引入 ccs_minimize_roundtrips 执行模式可以减少一次请求来回的网络开销
Re: https://www.elastic.co/guide/en/elasticsearch/reference/7.x/modules-cross-cluster-search.html
2、7.X JVM引入了新的circuit breaker(熔断)机制,当查询或聚合的数据量超出单机处理的最大内存限制时会被截断,并抛出异常?
Re: https://www.elastic.co/guide/en/elasticsearch/reference/current/circuit-breaker.html
3、跨集群复制(CCR)在 Elasticsearch 6.5中作为beta功能引入,6.7、7.X中GA,可以用在跨机房、跨地区情况下的集群数据同步。在这个版本中加入了一些监控的特性,解决了一些例如主从同步异常的问题。
Re: https://www.elastic.co/guide/en/elasticsearch/reference/7.6/ccr-getting-started.html
4、ILM:引生命周期管理(Index Lifecycle Management)作为一个beta特性在6.6发布,在7.0GA。索引生命周期管理现在可以管理frozen indices,他作为其cold阶段的一部分;也可以对其管理的索引使用CCR功能。
Re: https://www.elastic.co/guide/en/elasticsearch/reference/7.0/frozen-indices.html
https://www.elastic.co/guide/en/elasticsearch/reference/7.0/index-lifecycle-management.html
5、Elasticsearch SQL:Elasticsearch SQL可以让用户能够使用SQL进行交互查询Elasticsearch中索引数据。该功能在Elasticsearch 6.3中作为alpha版本引入,目前在Elasticsearch 6.7和7.0中也能够生产使用。
通过Elasticsearch REST endpoints、Elasticsearch SQL command line interface、 JDBC driver、ODBC driver可以使用es sql。
Re: https://www.elastic.co/guide/en/elasticsearch/reference/7.0/xpack-sql.html
6、Transforms: ElasticSearch 7.2.0中引入,7.7.0 GA。Transforms and Transform APIs提供给我们一个能力,即指定索引中不同字段进行聚合,并将聚合结果索引入一个新建索引中
Re: https://www.elastic.co/guide/en/elasticsearch/reference/7.x/transforms.html
小结与规划:
- 经历过类似的阶段:初始混杂 -> 物理隔离 -> 主备 --> ILM
- 引入ILM管理
- Routing 机制
- ILM 与 自研的治理
- ES使用ChubaoFS实现存储分离
- 跨集群搜索与复制
- 专用主节点、协处理节点
- 禁用动态mapping
- 冷节点 forcemerge
参考资料