AI 年度盘点与2025发展趋势展望,50+案例解析亮相AICon 了解详情
写点什么

日均 5 亿查询量的京东订单中心,为什么舍 MySQL 用 ES?

  • 2020-05-07
  • 本文字数:4035 字

    阅读完需:约 13 分钟

日均5亿查询量的京东订单中心,为什么舍MySQL用ES?

京东到家订单中心系统业务中,无论是外部商家的订单生产,或是内部上下游系统的依赖,订单查询的调用量都非常大,造成了订单数据读多写少的情况。


我们把订单数据存储在 MySQL 中,但显然只通过 DB 来支撑大量的查询是不可取的。同时对于一些复杂的查询,MySQL 支持得不够友好,所以订单中心系统使用了 Elasticsearch 来承载订单查询的主要压力。



Elasticsearch 作为一款功能强大的分布式搜索引擎,支持近实时的存储、搜索数据,在京东到家订单系统中发挥着巨大作用,目前订单中心 ES 集群存储数据量达到 10 亿个文档,日均查询量达到 5 亿。


随着京东到家近几年业务的快速发展,订单中心 ES 架设方案也不断演进,发展至今 ES 集群架设是一套实时互备方案,很好地保障了 ES 集群读写的稳定性,下面就给大家介绍一下这个历程以及过程中遇到的一些坑。

ES 集群架构演进之路

1、初始阶段


订单中心 ES 初始阶段如一张白纸,架设方案基本没有,很多配置都是保持集群默认配置。整个集群部署在集团的弹性云上,ES 集群的节点以及机器部署都比较混乱。同时按照集群维度来看,一个 ES 集群会有单点问题,显然对于订单中心业务来说也是不被允许的。


2、集群隔离阶段


和很多业务一样,ES 集群采用的混布的方式。但由于订单中心 ES 存储的是线上订单数据,偶尔会发生混布集群抢占系统大量资源,导致整个订单中心 ES 服务异常。


显然任何影响到订单查询稳定性的情况都是无法容忍的,所以针对于这个情况,先是对订单中心 ES 所在的弹性云,迁出那些系统资源抢占很高的集群节点,ES 集群状况稍有好转。但随着集群数据不断增加,弹性云配置已经不太能满足 ES 集群,且为了完全的物理隔离,最终干脆将订单中心 ES 集群部署到高配置的物理机上,ES 集群性能又得到提升。


3、节点副本调优阶段


ES 的性能跟硬件资源有很大关系,当 ES 集群单独部署到物理机器上时,集群内部的节点并不是独占整台物理机资源,在集群运行的时候同一物理机上的节点仍会出现资源抢占的问题。所以在这种情况下,为了让 ES 单个节点能够使用最大程度的机器资源,采用每个 ES 节点部署在单独一台物理机上方式。


但紧接着,问题又来了,如果单个节点出现瓶颈了呢?我们应该怎么再优化呢?


ES 查询的原理,当请求打到某号分片的时候,如果没有指定分片类型(Preference 参数)查询,请求会负载到对应分片号的各个节点上。而集群默认副本配置是一主一副,针对此情况,我们想到了扩容副本的方式,由默认的一主一副变为一主二副,同时增加相应物理机。



订单中心 ES 集群架设示意图


如图,整个架设方式通过 VIP 来负载均衡外部请求:


整个集群有一套主分片,二套副分片(一主二副),从网关节点转发过来的请求,会在打到数据节点之前通过轮询的方式进行均衡。集群增加一套副本并扩容机器的方式,增加了集群吞吐量,从而提升了整个集群查询性能。


下图为订单中心 ES 集群各阶段性能示意图,直观地展示了各阶段优化后 ES 集群性能的显著提升:



当然分片数量和分片副本数量并不是越多越好,在此阶段,我们对选择适当的分片数量做了进一步探索。分片数可以理解为 MySQL 中的分库分表,而当前订单中心 ES 查询主要分为两类:单 ID 查询以及分页查询。


分片数越大,集群横向扩容规模也更大,根据分片路由的单 ID 查询吞吐量也能大大提升,但聚合的分页查询性能则将降低;分片数越小,集群横向扩容规模也更小,单 ID 的查询性能也会下降,但分页查询的性能将会提升。


所以如何均衡分片数量和现有查询业务,我们做了很多次调整压测,最终选择了集群性能较好的分片数。


4、主从集群调整阶段


到此,订单中心的 ES 集群已经初具规模,但由于订单中心业务时效性要求高,对 ES 查询稳定性要求也高,如果集群中有节点发生异常,查询服务会受到影响,从而影响到整个订单生产流程。很明显这种异常情况是致命的,所以为了应对这种情况,我们初步设想是增加一个备用集群,当主集群发生异常时,可以实时的将查询流量降级到备用集群。


那备用集群应该怎么来搭?主备之间数据如何同步?备用集群应该存储什么样的数据?


考虑到 ES 集群暂时没有很好的主备方案,同时为了更好地控制 ES 数据写入,我们采用业务双写的方式来搭设主备集群。每次业务操作需要写入 ES 数据时,同步写入主集群数据,然后异步写入备集群数据。同时由于大部分 ES 查询的流量都来源于近几天的订单,且订单中心数据库数据已有一套归档机制,将指定天数之前已经关闭的订单转移到历史订单库。


所以归档机制中增加删除备集群文档的逻辑,让新搭建的备集群存储的订单数据与订单中心线上数据库中的数据量保持一致。同时使用 ZK 在查询服务中做了流量控制开关,保证查询流量能够实时降级到备集群。在此,订单中心主从集群完成,ES 查询服务稳定性大大提升。



5、现今:实时互备双集群阶段


期间由于主集群 ES 版本是较低的 1.7,而现今 ES 稳定版本都已经迭代到 6.x,新版本的 ES 不仅性能方面优化很大,更提供了一些新的好用的功能,所以我们对主集群进行了一次版本升级,直接从原来的 1.7 升级到 6.x 版本。


集群升级的过程繁琐而漫长,不但需要保证线上业务无任何影响,平滑无感知升级,同时由于 ES 集群暂不支持从 1.7 到 6.x 跨越多个版本的数据迁移,所以需要通过重建索引的方式来升级主集群,具体升级过程就不在此赘述了。


主集群升级的时候必不可免地会发生不可用的情况,但对于订单中心 ES 查询服务,这种情况是不允许的。所以在升级的阶段中,备集群暂时顶上充当主集群,来支撑所有的线上 ES 查询,保证升级过程不影响正常线上服务。同时针对于线上业务,我们对两个集群做了重新的规划定义,承担的线上查询流量也做了重新的划分。


备集群存储的是线上近几天的热点数据,数据规模远小于主集群,大约是主集群文档数的十分之一。集群数据量小,在相同的集群部署规模下,备集群的性能要优于主集群。


然而在线上真实场景中,线上大部分查询流量也来源于热点数据,所以用备集群来承载这些热点数据的查询,而备集群也慢慢演变成一个热数据集群。之前的主集群存储的是全量数据,用该集群来支撑剩余较小部分的查询流量,这部分查询主要是需要搜索全量订单的特殊场景查询以及订单中心系统内部查询等,而主集群也慢慢演变成一个冷数据集群。


同时备集群增加一键降级到主集群的功能,两个集群地位同等重要,但都可以各自降级到另一个集群。双写策略也优化为:假设有 AB 集群,正常同步方式写主(A 集群)异步方式写备(B 集群)。A 集群发生异常时,同步写 B 集群(主),异步写 A 集群(备)。


ES 订单数据的同步方案

MySQL 数据同步到 ES 中,大致总结可以分为两种方案:


  • 方案 1:监听 MySQL 的 Binlog,分析 Binlog 将数据同步到 ES 集群中。

  • 方案 2:直接通过 ES API 将数据写入到 ES 集群中。


考虑到订单系统 ES 服务的业务特殊性,对于订单数据的实时性较高,显然监听 Binlog 的方式相当于异步同步,有可能会产生较大的延时性。且方案 1 实质上跟方案 2 类似,但又引入了新的系统,维护成本也增高。所以订单中心 ES 采用了直接通过 ES API 写入订单数据的方式,该方式简洁灵活,能够很好的满足订单中心数据同步到 ES 的需求。


由于 ES 订单数据的同步采用的是在业务中写入的方式,当新建或更新文档发生异常时,如果重试势必会影响业务正常操作的响应时间。


所以每次业务操作只更新一次 ES,如果发生错误或者异常,在数据库中插入一条补救任务,有 Worker 任务会实时地扫这些数据,以数据库订单数据为基准来再次更新 ES 数据。通过此种补偿机制,来保证 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 起为默认设置。

总结

架构的快速迭代源于业务的快速发展,正是由于近几年到家业务的高速发展,订单中心的架构也不断优化升级。而架构方案没有最好的,只有最合适的,相信再过几年,订单中心的架构又将是另一个面貌,但吞吐量更大,性能更好,稳定性更强,将是订单中心系统永远的追求。


本文转载自技术锁话公众号。


原文链接:https://mp.weixin.qq.com/s/QQ0M6C5G2LwIKhBdEmnnXA


2020-05-07 17:352252

评论

发布
暂无评论
发现更多内容

真香!阿里最新产出分布式进阶实战手册,涵盖分布式架构所有操作

Java你猿哥

Java 架构 Spring Cloud Spring Boot ssm

SpringBoot异步线程,父子线程数据传递的5种姿势

Java你猿哥

Java Spring Boot 线程 ssm 异步

【Python金融-001】如何快速计算股票的收益?1行代码,高效做T

程序员晚枫

Python 金融 股票

阿里内部总结的微服务笔记,从入门到精通小白也能学的会

Java你猿哥

分布式 微服务 微服务架构 Spring Cloud ssm

大神在民间!碰巧在Github发现一个Java面试高分Guide,已跳槽涨20K

做梦都在改BUG

Java java面试 Java八股文 Java面试题 Java面试八股文

2023-06-02:给定一个二进制数组 nums 和一个整数 k, k位翻转 就是从 nums 中选择一个长度为 k 的 子数组, 同时把子数组中的每一个 0 都改成 1 ,把子数组中的每一个 1

福大大架构师每日一题

golang 算法 rust 福大大

以技术实践赋能开源安全|2023开放原子全球开源峰会开源安全技术与实践分论坛即将启幕

开放原子开源基金会

开源 开源软件供应链 开源安全技术

原来user.dir竟然会影响classpath的值

Java你猿哥

Java tomcat classpath ssm

来自大佬的洗礼!全网独家的SpringCloud Alibaba学习笔记,太全了

做梦都在改BUG

Java 架构 微服务 Spring Cloud

Django笔记四十一之Django中使用es

Hunter熊

Python django elasticsearch

推进开源法律知识普及|2023开放原子全球开源峰会开源法律与合规分论坛即将启幕

开放原子开源基金会

开源 法律与合规

Nautilus Chain:我们将支持EIP6969

BlockChain先知

Generative AI 新世界 | 大型语言模型(LLMs)概述

亚马逊云科技 (Amazon Web Services)

机器学习 tensorflow 开源 PyTorch Amazon SageMaker

北美 2023 被裁员的感悟

HoneyMoose

Spring Boot 开发离不开这些注解,快来学习啦!

Java你猿哥

spring Spring Boot ssm spring aop java框架

Nautilus Chain:我们将支持EIP6969

西柚子

全网首推!头条大佬手码的164页Elasticsearch核心学习手册,我服了

做梦都在改BUG

Java 搜索引擎 elasticsearch ES

文心一言 VS 讯飞星火 VS chatgpt (29)-- 算法导论5.2 1题

福大大架构师每日一题

ChatGPT 文心一言

深度学习入门系列(一):一文看懂 MNIST

U2647

神经网络 机器学习 深度学习 keras

2023金三银四Java开发岗热门面试题总结

小小怪下士

Java 程序员 面试 金三银四

不愧是牛客网爆火的1658 页《Java 面试突击核心讲》,面面俱到太全了

采菊东篱下

Java 程序员 面试

专业笔记工具:Keep It 激活版

真大的脸盆

Mac Mac 软件 笔记工具

JavaScript深度剖析之变量、函数提升:从表面到本质

Immerse

Nautilus Chain:我们将支持EIP6969

大瞿科技

Nautilus Chain:我们将支持EIP6969

股市老人

2023年互联网Java工程师高级面试八股文汇总(1260道题目附解析)

架构师之道

Java 面试

C语言编程-共用体

梦笔生花

6 月 优质更文活动

以后我准备告别String.format()了,因为它不够香!

Java你猿哥

Java 编程 string 格式化 format

简化Mybatis分页操作,让我们来聊聊 PageHelper 及实现原理

Java你猿哥

Java mybatis ssm PageHelper

日均5亿查询量的京东订单中心,为什么舍MySQL用ES?_行业深度_技术琐话_InfoQ精选文章