资讯详情

资讯详情

Hologres实时数据大屏秒级响应架构设计与全链路调优实践

每年大促前的那段时间业务方总是盯着我这边问大屏能支撑多少并发实时性到底能拉到多快说实话实时数据大屏在架构里的定位很特殊它不像离线报表那样能容忍延迟也不像后台交易系统那样只追求强一致。它要的是既要、又要——既要海量实时数据持续写入又要毫秒级查询返回还得扛住大促瞬间的高并发流量。我在某旅游平台做过一期大促实时数据大屏项目核心指标就一个秒级响应。最终落地的方案是用Hologres作为大屏查询层配合上游实时计算链路的整体调优硬是把大屏从最初的三五秒刷新一次压到了刷新即出数峰值查询P99稳定在800毫秒以内。这篇文章就把整个项目从痛点拆解、方案选型、表模型设计到大促前的容量评估和压测预案完整复盘一遍给正在做实时数仓、数据大屏或者OLAP查询优化的朋友一个可以直接落地的参考。1. 先拆解大屏场景的真实痛点再谈方案选型1.1 大屏查询并不是查个表那么简单很多刚接触实时大屏的开发者会觉得大屏不就是定时跑几个SQL把结果推给前端嘛。真到了业务侧需求完全不是这样。我在这个项目里接到的第一版需求列出来就让我意识到这事不简单。大屏上要同时展示总成交金额、实时订单量、热门目的地Top榜、用户实时分布、各业务线的趋势曲线等接近二十个指标。每个指标背后还带维度下钻比如点击某条曲线要能按小时、按分钟看趋势点击某个城市要能看这个城市的详细订单数据。这意味着查询层要同时面对几个层面的压力。第一个是查询并发大屏通常由多块看板组成前端会同时发起大量查询请求而且大屏是循环刷新不是一次性的查询。以5秒刷新周期算下来高峰期单块看板的QPS就可能到几百多块看板叠加就是几千甚至上万。第二个是数据规模大促期间的订单明细表一天新增几亿行很常见两三天累计就是十亿级以上的数据量在这个规模上做高并发点查和聚合不是随便一台数据库就能扛住的。第三个是写入实时性大屏上看到的订单数据必须是最新的上游数据从业务库抽取、加工、传输再到查询层整个链路的时间要控制在秒级。如果沿用传统做法——业务库直接读或者用普通关系型数据库存明细再跑聚合基本撑不过大促第一波流量。业务库不能承受分析查询的冲击普通数据库在十亿级数据量上做多维聚合单次查询就要好几秒。1.2 对比了一圈为什么最终落在Hologres上在做技术选型的时候我认真地对比了几类常见方案。第一类是直接把大屏查询打在业务数据库上这在数据量小的时候没问题但只要数据量上来多指标聚合查询会严重影响在线交易业务大促期间业务库的稳定性优先级最高这个方案第一个被排除。第二类是使用Elasticsearch做聚合查询。ES在日志检索场景的确很强但做多维度实时聚合分析在大数据量下容易遇到两个问题内存消耗大导致GC频繁以及聚合查询性能不够稳定需要很精细地调索引和分片。在时间紧迫的大促项目中这类繁琐调优容易踩坑。第三类是预计算方案效果很好但扩展和维护成本高比如离线预计算结果表业务流程复杂大屏需求一变就得重新跑任务灵活性差。最终我选了Hologres。原因有几条它是为实时分析设计的数仓服务存储上天然融合了行存和列存行存适合点查和维度表关联列存适合大规模聚合分析两种场景都能覆盖。更关键的是它和高频使用的实时计算框架Flink深度打通上游Flink作业写Hologres只需要配置一个连接器数据能毫秒级写入这正好解决大屏链路里面实时性的问题。再加上它在高并发场景下的表现单实例也能扛住数万QPS的点查整个方案在性能和开发效率之间达到了比较合适的平衡。2. 整体链路设计与核心模块拆解2.1 顶层架构从业务库到数据大屏数据怎么流实时大屏的顶层链路拆开来看就是四段数据源采集、消息中间件、实时计算、查询服务。在这个项目中整体链路设计如下。业务数据源主要来自订单库和用户行为日志。订单库的数据通过日志采集或数据同步组件实时捕获变更写入Kafka用户行为日志则直接通过日志采集端发送到Kafka。Kafka作为消息中间件起到削峰填谷和缓冲的作用业务高峰时数据量暴涨Kafka能保证写入不丢失、不阻塞。然后Flink消费Kafka里的数据做实时清洗和计算。一部分明细数据直接写入Hologres明细表供大屏下钻查询使用另一部分按分钟和小时粒度做预聚合写入Hologres的汇总表大屏看板默认查询汇总表保证秒级返回需要看原始明细时再通过行存点查获取。大屏后端服务收到前端请求后根据指标类型路由到不同的查询逻辑命中Hologres查询结果同时在后端加了一层本地缓存相同查询在几秒内直接复用缓存结果。这层缓存设计很关键能把Hologres端的查询压力再降一个量级。链路设计中有个容易忽视的点上游实时计算链路必须保证最终一致性Flink的实时计算要做到精确一次或至少有效一次处理否则大屏上看到的指标会出现毛刺或者偏差。2.2 表模型设计明细、汇总、维度三类表的定位不同表模型是整个实时大屏能否秒级响应的地基我在这个项目里设计了三类表明细表、汇总表、维度表。明细表存储订单流水数据一行为一个订单或一条行为记录用于大屏的下钻查看和异常排查。这类表的特点是写入量巨大、查询并发低基本是单条或几十条维度的点查。明细表采用行存模式或行列混合主键为订单ID或行为ID保证点查只需走一次主键索引定位。汇总表是秒级响应的核心按大屏的展示需求预先在Flink里按多个维度组合做聚合。比如总成交额、订单量、新老客数等按分钟粒度聚合成一行记录。大屏默认查询最近几分钟的汇总数据查询返回时间极短。汇总表采用列存模式高压缩比降低存储成本同时列存对聚合扫描有很好的优化。维度表存储目的地、用户等级、品类、渠道等维度的静态信息数据量不大但查询频繁需要和大屏指标表做关联。维度表同样采用行存模式并开启数据分发时的复制表模式保证所有节点都持有一份完整维度数据避免查询时的跨节点传输。三张表在Hologres实例中各有分工设计时要特别注意主键和分区的选择。明细表按时间分区每条订单落进对应的当天分区查询天然带时间裁剪汇总表按维度组合建主键方便Flink写入时做更新操作。2.3 查询层的能力设计预聚合优先、点查支撑、缓存兜底数据进了Hologres大屏能不能秒级响应还取决于查询层怎么设计和优化。首先明确查询的分类。通常来说大屏查询分两类指标类查询和分析类查询。指标类查询大多返回单值或一小组数据比如截止当前的GMV、今日订单量、当前在线人数分析类查询会返回一组时序数据或Top榜比如最近24小时销售额趋势曲线、热销目的地Top榜。针对指标类查询核心思路是用汇总表。Flink分钟级聚合后大屏查询某个指标只查最近一条或几条记录。比如查询当前GMV汇总表已经有一行当前分钟累计成交额SQL只需按分钟倒序取最新一条查询开销非常小。针对分析类查询汇总表同样发挥作用比如24小时趋势其实查询的是汇总表中最近24小时的数据按小时再聚合成24行返回。在明细下钻场景点查直接走行存主键查询比如点击某个订单号看详情一条SQL在几毫秒内就能返回。大屏后端再加一级缓存查询结果按指标维度缓存5至10秒同一批看板并发刷新的时候实际上大部分请求都被后端缓存拦截掉了。这套设计下来Hologres层实际的查询压力远小于前端看到的并发量这是大屏稳定性的核心保障。3. 秒级响应背后的关键细节与调优实践3.1 预聚合表到底怎么建才真正省算力预聚合表的设计是整个项目里我认为最值得复盘的部分因为预聚合做得好能让硬件成本低一个量级。第一点是聚合粒度的选择。大屏的实时性要求是秒级但数据聚合没必要也做到秒级。在这个项目中预聚合分为两个粒度分钟级是最高频使用的数据占了大屏百分之八十以上的查询小时级用于长周期趋势曲线查询频率低但仍依赖预聚合结果。这样做的好处是分钟级聚合表的数据量是原始明细的千分之一甚至更低查询效率自然高。第二点是聚合维度的设计。预聚合表不可能覆盖所有维度组合如果每个新指标都加新表维护成本不可控。我采用了一种宽表聚合方案把大屏看板上需要展示的维度都固化在一张宽表里比如时间-业务线-品类-目的地-渠道的组合每个组合一行里面存多个指标字段。Flink做一次实时聚合写一行数据多指标一次展示。凡是新增指标但维度组合不变的需求不用新增表只需在Flink作业里多加一个字段开发量小很多。第三点是写入方式的选择。Hologres支持INSERT和UPSERT两种方式聚合场景必须用UPSERT也就是主键冲突时更新已有行。Flink连接器里配置了主键当上游新计算结果到来自动更新对应的汇总行。这里有个关键经验汇总表的主键必须包含聚合的时间粒度字段比如分钟级表主键是业务线ID品类ID目的地ID分钟时间戳这样同一分钟的数据只会保留最新结果不会出现重复行。3.2 分布键和分区键的选择直接影响查询时延Hologres作为分布式数仓数据存储在多个分片上查询时如果数据分布不合理就会出现一个查询把一个分片打热、其余分片空闲的情况。大促期间热点问题尤其明显。分布键Distribution Key决定了数据按哪个字段打散存储。这个项目的汇总表里我选择的分布键是业务线ID因为大屏查询绝大多数都会带上业务线维度按这个字段打散同一业务线的数据落在同一组分片上查询一个业务线的指标时只访问少量分片减少了网络开销和并发竞争。这里有非常值得注意的细节分区键不能和分布键混淆。分区键用于裁剪数据减少扫描量分布键则决定数据物理分布。在实际使用中为了说明为什么选择这张表的结构例如大促订单量按时间分区一分钟一个分区一天的明细表有1440个分区查询某段时间的数据时通过分区裁剪直接跳过无关分区性能提升明显。另外一个容易被忽略的点是小表复制。维度表在设计时开启了复制模式这意味着维度表的数据会在每个分片都存一份副本。这样在关联维度表时不需要跨分片做数据交换大屏看板的关联查询延迟能再降低百分之三十以上。对数据量不大但高频关联的维度表这个优化非常划算。3.3 高并发查询时的连接数、内存和CPU调优实时大屏在高峰期发送大量并发查询时Hologres负载会明显上升。我遇到过这个大促项项目中最难察觉的一个问题连接数管理不当导致查询排队进而拖累整个大屏刷新。Hologres每个实例的连接数是有限的大屏后端服务如果为每个请求都创建新连接很容易把连接池打满。我在大屏后端使用了统一的连接池设置了最大连接数和最小空闲连接数连接池按QPS预估配置而不是无脑设大。连接数太少请求排队等待连接数太多Hologres侧会触发限流。这个平衡点需要在压测中反复调整大屏场景通常把连接池的最大连接数控制在可并发查询量的1.5倍左右比较合适。内存调优方面Hologres的查询内存和存储内存是分开管理的。大屏SQL多为小查询内存压力不大但如果是聚合查询扫全表且没有索引支撑内存消耗会急剧上升。优化方式是给关键指标建好索引控制单次扫描的数据量。CPU调优主要体现在查询并发上Hologres在CPU资源使用较高时会自动排队开启查询队列后大屏查询在高峰期会有可感知的延迟。我在项目里把大屏后端的刷新频率做成了动态调整高峰期非核心指标自动降为15秒刷新一次核心指标保持5秒刷新避免所有查询同时涌进来打满CPU。3.4 大屏SQL的不要清单少用复杂函数、控制扫描范围在大屏查询场景里最简单的SQL往往是最快的。我在代码评审时整理过一个大屏SQL不要清单按这个清单规范了后端查询逻辑排查慢查询的效率高了很多。第一条不要在大屏SQL里用正则表达式、自定义函数之类的复杂表达式。比如过滤订单ID时不要用LIKE或者正则匹配直接按主键等值查询。大屏SQL是高频重复查询引擎对每一条SQL都会解析执行复杂函数会让执行计划变重、CPU消耗变大。第二条不要忘了时间范围裁剪。有段时间某块看板的趋势数据每次查询都要五秒多排查后发现SQL里没带时间过滤条件导致每次查询都扫描全表。加上时间条件之后从五秒多直接降到了两百毫秒。第三条不要在大屏SQL里做多张大表的JOIN。大屏场景最常见的性能杀手就是大表关联尤其是明细表关联明细表。正确做法是把能提前关联好的数据在Flink里join好写入Hologres时就已经是单表宽表查询时不需要再做关联。如果必须关联也优先关联复制模式的维度表避免大表之间的数据打散传递。第四条不要用SELECT *。大屏指标只需返回几个字段手动列出字段名可以减少数据传输量和解析消耗。虽然这条看起来很基础但在高并发场景下能省一点是一点。4. 实操记录容量评估、写入链路打通与压测预案4.1 大促前的容量评估不靠猜靠公式大促前一周左右我在做容量评估时用了这套估算逻辑。先估算QPS。大屏平均每块看板有6个图表前端在5秒刷新周期内会发出6个查询请求单块看板QPS约1.2。这次大屏总共规划了五块看板那就是6QPS。但如果活动页有客户访问量波动导致业务侧希望缩短到3秒刷新一次QPS就会翻倍到12。再加上大屏后端的缓存机制真正打到Hologres的只有其中一部分但评估时仍按最差情况即全部12QPS。再估算写入吞吐。订单明细表大促峰值每秒约新增五万行订单数据Flink预聚合后汇总表每分钟写入约数千行明细表每秒写入五万行。这个数据量对Hologres而言并不算高Hologres的写入吞吐单位是每秒百万行级别压力主要在查询侧。估算内存和存储容量。明细表一天的数据量按行数乘以单行平均大小估算约亿行乘以0.5KB就是几十GB一天大促三天累计约两百GB左右。汇总表因为数据行数少只占几个GB。整体存储和内存配置按了这个估算结果再留出30%余量。最终在压测中验证实例规格和资源组配置刚刚好满足需求。4.2 Flink写入Hologres链路稳定性的控制点Flink实时计算作业写入Hologres是整个链路的实时性保障也是最容易出问题的一环。我在Flink的Hologres Sink配置上踩过几个坑记录一下实际调整过的核心参数。写入方式选择了UPSERT模式append_only虽然快但明细表如果出现主键冲突又没有UPSERT机制数据会重复且覆盖不了旧数据。实时订单明细表虽然没有明确的更新需求但Flink作业重启恢复时可能出现重复数据写入用UPSERT模式能通过主键去重保证了数据的准确性。批量写入大小和写入并发需要搭配着设置。一开始我为了提高写入吞吐把batch_size调得很大结果下游Hologres分片负载不均部分分片写入积压。后来调整为每个分片对应的写入批次自适应触发当批次大小达到阈值或写入等待时间达到阈值时就flush整体吞吐稳定了延迟也维持在毫秒级。还有一个关键细节是写入失败的重试策略。大促期间网络抖动或Hologres端负载升高会导致写入失败Flink连接器的重试如果采用固定间隔大规模写失败时会造成写入放大效应。实际做法是配置指数退避重试策略并设置重试次数上限超过上限后进入failover流程同时大屏后端可以感知到写入延迟自动切换为展示缓存数据避免空白。4.3 压测通过不等于上线稳预案比压测更重要大屏上线前做了一遍压测过程其实不算太复杂。用压测工具模拟了双11峰值的QPS跑了一遍核心查询压测结果P99在600毫秒左右满足秒级响应目标。但真正的大促不是压测能完全模拟的数据特征和流量起伏都会不同。我们在应急预案上花了不少心思。第一准备降级开关大屏后端支持按看板维度一键关闭当Hologres负载超过安全水位时先关闭非核心看板的实时刷新改为展示静态缓存数据第二动态调整刷新频率按CPU水位自动从5秒调整到10秒、15秒避免所有查询集中在同一时刻发出第三前端缓存兜底前端页面本身也缓存了上一次的成功查询结果即使后端查询失败大屏也能展示最近一次的数据不会白屏。这套预案在大促当天真正派上了用场。当天下午流量高峰时Hologres实例CPU短暂冲上了80%自动降级策略随即触发关闭了两块非核心看板的实时刷新核心大屏依旧保持秒级刷新整个过程没有出现一次白屏。5. 上线后踩过的坑和问题排查实录5.1 热点分片某一块看板数据延迟其他看板正常上线第一天就遇到了一个意外情况好几块看板都正常唯独热门目的地Top榜这块看板刷新时有明显延迟有时要两秒多才出数。排查思路从查询计划开始。先看这条SQL的执行计划发现它没有走汇总表而是scan了明细表。进一步查Hologres的监控面板发现明细表部分分片的CPU和记录数明显高于其他分片热点分片出现了。根因有两个一是分布键设置不合理热门目的地表的分布键用了目的地的ID但大促期间某几个大热门目的地的数据量远高于其他分片导致数据严重倾斜二是Top榜查询的是全量排序无法通过分片裁剪减少数据量。解决方案是把Top榜改为从预聚合的汇总表里查汇总表已经按目的地时间做了聚合数据量小了很多同时把分布键调整为目的地ID哈希让数据更均匀地打散到各个分片。因为写入表结构变更需要重建项目期间就直接新建了一张汇总维度更高的大宽表来代替问题很快解决了。这个坑让我意识到大屏的Top榜类查询最怕全量数据大表排序最好提前把排序结果在Flink里算好大屏直接展示终端结果。5.2 连接数超限导致的大屏白屏上线第二天早上业务反馈大屏出现阶段性白屏每次持续一两分钟。从大屏后端日志看到大量获取连接失败的异常Hologres侧监控显示连接数超过了实例上限。排查后发现是连接池配置的问题。大屏后端服务在启动后的初始化阶段会根据配置的最大连接数一次性创建连接但大屏看板的查询会周期性并发高峰期连接不够用新请求只能等待连接释放等待时间一长就超时前端拿到了超时错误大屏就白屏。解决方式分两步。第一步把连接池的最大连接数调大同时给连接池设置更合理的获取连接超时时间保证请求不会因为获取不到连接而直接失败第二步调整大屏后端的查询并发模型把同步查询改成了部分异步化看板加载时只并发请求核心数据非核心指标延后加载把连接占用峰值降了下来。5.3 数据写进去了大屏却看不出变化有一个数据已经写入但大屏却显示旧数据的诡异问题排查了很久。最开始怀疑是写入链路出问题但在Hologres控制台直接查数数据是最新的写入链路正常。然后怀疑大屏后端缓存没失效排查后也确认缓存是通的。最后发现是Hologres的查询模型问题。汇总表开启了行列混合存储但大屏SQL查询的是列存部分而写入的新数据在行存部分里列存与行存之间存在毫秒级或更长的同步延迟同步周期内查询列存就会查到旧数据。解决方式是大屏查询默认查询最新几分钟的数据数据同步延迟隐藏在这个时间窗口内同时把实时性要求最高的指标改用行存为主存储或采用更直接的同步机制。大促场景下大屏通常愿意接受次秒级或秒级延迟这个容忍度给了架构设计一定的缓冲空间但前提是心里清楚延迟发生在哪个环节并保证延迟可控。5.4 SQL慢查询排查的基础方法大促期间Holo侧的一些系统表和监控工具特别有用。我排查慢查询的时候习惯性地先查系统表中的慢查询记录确认慢查询集中在哪张表、哪个SQL模板再针对性优化。异常检测和告警策略建议重点监控三个指标QPS、CPU利用率和延迟。QPS突然下降说明查询链路有问题CPU长时间高说明需要降级策略延迟超过某阈值说明SQL或资源有问题。同时建议开启Hologres的查询审计日志把每个上线的SQL都留底。大促期间如果某个看板突然变慢直接翻日志定位对应的SQL模板比看前端报错信息高效得多。5.5 日常问题速查表问题现象可能原因应对操作大屏部分看板延迟高查询走了明细表全表扫描或热点分片走汇总表调整分布键检查分区裁剪大屏整体白屏连接池打满或Hologres资源不足检查连接数与实例负载触发降级开关数据写入正常但查询旧数据行列存储同步延迟、缓存未失效检查存储模型配置等待延迟窗口或调整查询范围高峰期CPU飙高并发查询过多、SQL不够优化启用查询队列动态降刷新频率关闭非核心看板某个指标与其他报表对不上Flink聚合维度不一致或写入重复对比明细数据检查Flink聚合逻辑和UPSERT配置上游延迟导致大屏数值停滞Kafka消费积压、Flink任务反压查看Kafka消费Lag调整Flink并发或升级资源6. 最后分享几个这个项目沉淀下来的经验复盘这个项目我最大的一个体会是实时大屏架构中查询层只是整个链路的一小部分真正的功夫在表模型设计和上游计算逻辑里。如果你把大屏慢的问题归结为Hologres不够快那大概率是方案设计的问题——预聚合、分布键、时间裁剪这次真用手段优化过SQL执行计划就能看到显著变化。第二点经验是大屏的秒级响应从来不是单靠数据库或者单靠前端就能实现的。它靠的是整套链路Flink预聚合降低查询量、Hologres高并发查询兜底、后端缓存削减瞬时压力、前端降级策略应对突发故障。每一层只承担一部分压力任何一层被打穿都会拖垮整体体验所以要给每一层都留好退路。最后给正在做类似项目的朋友一个最朴素的建议先在非高峰时段把所有大屏查询模板在目标库上跑一遍把执行计划和耗时记录下来当成基线。之后每次调整索引、表结构或SQL都和基线对比用数据说话的优化才是可持续的优化。这样大促真正来了你睡得着觉业务方也不会来砸你门。
觉得有用,分享给同行:

为您的企业打造数字门面

稳重轻奢商务风格,端正雅致视觉,长效耐看不易过时。

立即咨询 →