Doris 应用实践之高并发 & 大吞吐,如何选择?


背景

Doris 官方介绍:

Apache Doris 是一个基于 MPP 架构的高性能、实时的分析型数据库,以极速易用的特点被人们所熟知,仅需亚秒级响应时间即可返回海量数据下的查询结果,不仅可以支持高并发的点查询场景,也能支持高吞吐的复杂分析场景。

在查询引擎方面,Doris 采用 MPP 的模型,节点间和节点内都并行执行,也支持多个大表的分布式 Shuffle Join,从而能够更好应对复杂查询。

在这里插入图片描述

基于以上特点,开始考虑引入 Doris 解决业务上的跨库查询问题(JOIN)。

对于 B 端业务,繁琐的关联逻辑,经常会涉及到多张表关联查询,这些表可能分布在不同服务、不同库,查询条件的多样性以及数据的实时性着实让人头疼:

在这里插入图片描述

当然,也确实有过很多优化手段,比如从产品上限制查询条件、从实现上分条件查询、历史数据归档等等。

但是,这过程仍然存在很多问题,比如 数据可能经常要从各个服务拿过来组合,查询条件可变化,并且筛选条件需要不同服务来处理。这就是典型的跨服务条件筛选

在这里插入图片描述

即使分页查询在这种情况下,由于查询条件分散,服务间的查询很难做到单纯的分页处理。然后就伴随着大批请求参数传递,大批 IN 查询等等。

直到引入 Doris,解决了我们以上部分场景。


一、Doris 心法?

武侠小说里常常出现的词,武功秘籍心法 ------ 决定了你能否修炼达到上层境界。Doris 也一样,只有理解了其核心能力,才能绽放其光芒!

在 Doris 官方介绍里,高并发大吞吐 ,同时支持亚秒级响应,似乎是 OLAP 领域完美的解决方案。如果你有所质疑,那应该就是过来人了。

在这里插入图片描述

Doris 引入后,应用的第一个需求便是十几张表关联的大吞吐查询,从实时性和开发量来看确实有很大提升。但是,也存在一个极大的缺陷,业务在高峰期使用时,Doris BE 节点经常宕机。

我们曾一度怀疑 Doris 高并发的虚假性,线上配置 8 台 8 核 16G 的 BE机器,QPS 撑不到 10 。

慢慢地,我们发现,Doris 的 高并发和大吞吐需要分开考虑,也就是说,大吞吐的查询下,很难达到高并发,还得思考一些配套方案。

通过 Doris 实践,我们发现影响查询效率的因素主要有:

  • 扫描的数据量
  • 节点间是否大批数据做 shuffle
  • 聚合查询
  • 排序
  • 开窗函数

大致可以从这些方面尝试提升效率,常见的有 SQL JOIN 优化,感兴趣可以了解下。

当 SQL 层面已经无法优化之后,针对高吞吐和小吞吐的查询需要采用不同的策略。

1. 大吞吐

对于这类查询一般相当耗费集群内存资源,很容易导致 OOM,从而引发机器宕机,因此需要做到:

  • 控制好此类查询的并发度。

  • 同时,也要尽可能提升查询速度,避免长时间查询占用过多集群资源。

2. 高并发

对于小吞吐的点查询,能支持较高的并发。究其原因:

  • 本质还是扫描数据少,单个查询占用极少内存资源。

  • 配置:两台 4 核 8G 的 BE 节点,小吞吐的点查询 QPS 能达到 300+。


小结下:Doris 官方文档已经说的很清楚了,支持高并发的点查询复杂的大吞吐查询。因此,你在评估需求时,要区分好这两类场景。

二、优化之路

再来回顾下我们的需求:数据实时性、涉及 15 张数据表且跨库查询。


1. 选择?

如果数据不需要实时性,我们可以通过大数据组件 Hive 离线跑批,问题就简单了。不巧的是,业务就是要一定的数据实时性。

一般来说,对于这种复杂的大吞吐查询,耗时操作都在数据计算上面,我们从计算的时间点来看看:

  • 提前处理:这种一般可以是监听 binlog 变更进行实时聚合计算 或者高频定时跑批次。查询时相当于直接查结果集,速度很快。
  • 查询时处理:用户请求真正过来了才进行处理,比如 JOIN 等。

两种处理方式各有优缺点:

  • 提前处理:将耗时的操作前置。一般是实时监听 或者 定时预处理,并存储处理结果,查询上基本支持高并发,而坏处是较多的开发量(实时监听)或者 数据有一定的延迟(定时跑批)。
  • 查询时处理:耗时的逻辑后置,用户请求来了才真正开始处理,无法应对高并发、请求不可控容易宕机等。好处是无冗余数据,数据实时性高。

从具体方案上来看:

1)提前处理:

  • 我们可以采用后端常规方案,定义大宽表,定时(频次高,比如 30s、60s)从多个微服务拉数据组合并更新大宽表。这种方式,需要控制数据量,否则大批数据传输和更新将成为瓶颈。
  • 采用大数据 Flink 组件,本质是监听 binlog 日志,实时洞察数据变更。这种方式比较通用,但需要写多个监听任务,开发量上去了。

2)查询时处理:

  • 用户请求来一条处理一条,不用考虑数据冗余、数据更新以及大量的开发量,一条 SQL 搞定所有,应该是最理想的方式。

业务上这种场景挺多,我们迫切需要找到一种,直接提供给业务使用的跨库、跨服务查询解决方案。

基于以上原因,我们选择了 Doris,用来应对查询时计算,通过一条大 SQL 解决了这个问题,大概是这样:

在这里插入图片描述

2. 缓存

你也看到了,一条 SQL 而已,快速的上了线。

当我在页面上连续点击多次,问题来了,请求处理不了。查询 Doris 集群监控,发现某节点因 OOM 宕机。

观察用户使用习惯发现,高峰期大部分请求参数都一样,也就是说,返回的结果基本也都一样。嗯,没错,考虑加上缓存避免所有请求全部打到 DB。

业务上要求实时性,缓存时间不能过长,默认加了 30s

3. 并发

缓存上了之后,大部分情况下能正常应对了,但偶尔还是会出现宕机。

问题是这样的:这个大查询总体耗时 2s 左右(单次查询),为了加快查询速度,我们在应用层将 count(总数) 和 select(分页列表)分开并行查询。也就是一次用户请求,就拆分了两次 doris 查询。

前面我们说了,对于这种大吞吐的查询无法支持较高的并发,所以极端情况下,还是会出现 OOM 导致的宕机。

虽然前面已经加了缓存处理,还是有些风险 ----- 同一时间较高的并发请求,可能轻易压垮 doris,必须要在应用层考虑并发限制:

  • 相同查询条件:加锁串行处理,第一个请求会进入 doris 查询,后续直接从缓存查询即可,这也是一种常用手段。
  • 限制并发:控制并发进入 doris 查询的请求数量,这里我们采用 分布式信号量组件Redisson#Semaphore。

这样一层处理后,Doris 集群基本处于绝对安全状态。

4. 批处理

虽然前面我们控制了并发,保障了 doris 集群的安全性,但还是很难大范围推广。

原因之一是大吞吐很难提升 QPS,这往往不满足业务需求;另一个原因是对 Doris 集群资源的不可控,多个类似大吞吐的查询场景,彼此之间相互掣肘,极端情况下很容易导致节点宕机。

所以,对于大吞吐的查询,我们尽量要控制查询频率、查询时长等,避免过多消耗集群资源

上文我们提到,使用缓存来减缓 doris 的查询压力,有了缓存其实也意味着是伪实时查询,说明在业务上往往也能容忍几十秒的延迟。

我们基于此进行优化,进一步通过定时批查询,并存储查询结果,用户请求直接查询结果集便可,效果如下:

在这里插入图片描述

这里本质就是将耗时的计算操作前置,用户请求直接查询结果集,一般是相当快的,高并发的问题基本解决了。

大吞吐量的查询频次由定时任务处理频次决定,完全可控,在这种情况下, 可继续大胆推广使用。

注: 以上查询由 15 张表关联查询,其中有多张 500 万左右的大表,最终的查询结果集在几十万左右。为方便业务层平滑查询,采用双表机制,定时任务轮训全量写入结果集,业务层从最新的结果集读取数据即可。定时查询+插入结果集耗时 2s 左右,业务查询上仅 20ms 左右

总结

随着对 doris 的熟悉,已经逐步应用于多个业务场景下,比如统计分析(PV/UV、用户路径、行为轨迹图)、各种监控大盘等。

Doris 采用了 MPP 架构,在 JOIN 查询方面有显著提升,但同时也限制了其并发能力,无法和机器数量线性增加。

在分析查询时,一般从大吞吐高并发两个方向考虑。其中大吞吐的需要格外注意,要控制好并发和查询时间,可以从缓存、定时批处理的方面考虑。




相关参考:
  • 3
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

柏油

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值