简介:《火山引擎智能数据洞察平台v2.0》PPT配套PDF面向企业数据分析师、BI产品经理及数据平台建设者,系统梳理火山引擎eABI平台的产品定位、能力矩阵与落地场景,可用于BI选型、方案汇报和团队内部培训。压缩包内为1个PDF文件,大小约21.54MB,便于直接查阅与归档。内容围绕报表制作、探索分析、数据洞察三大能力栈展开,并覆盖平台从2014年内部启用到2020年对外服务的成长路径、字节跳动内部用户规模与查询量等实践数据,同时详解跨源异构融合、可视化建模、秒级查询、AI建模、嵌入式分析及开放API等模块。已有789人学习,适合需要快速建立智能数据洞察平台整体认知、了解企业级数据分析产品架构与功能细节的读者参考。
1. 智能数据洞察平台要解决的,是三拨人抢同一份数
业务方在群里丢一句「上周这个渠道的转化怎么掉了」,数据同学往往要开三个窗口:Hive 客户端查明细、BI 工具拖图表、Excel 里再对一遍口径。这份 v2.0 方案讲的智能数据洞察平台,目标就是把这三件事收进同一个入口——报表制作、探索分析、数据洞察三条能力栈并排,底下压着一套统一的数据模型和权限体系。
方案里给了一组挺能说明问题的数字:内部跑了六年,覆盖八成以上用户、五百多个业务职能,三万一千多个数据模型、总量七十多 PB,每天一百五十万次查询、三万四千份报表每天十万人次在看。适合两类人读:一类是做数据平台、指标中台、报表系统,正在被「口径对不上」折磨的开发和架构;另一类是接到需求要把 BI 嵌进自家系统的团队,想看看别人是怎么把嵌入、OpenAPI、权限这几件事一次性想清楚的。
2. 产品架构拆解:一条查询从数据源到仪表盘经过哪几层
把这份方案里的架构图摊平,纵向是六层,横向是三条能力栈。六层从下往上分别是数据源层、接入同步层、存储计算层、平台服务层、分析引擎层、展现层。这套分层不是画着好看的,它的价值在于——出问题时你能快速判断该去查哪一层,而不是把整条链路当黑匣子瞎猜。
2.1 六层架构里每一层到底干什么
最底下是数据源层,方案列得比较全:关系型数据库、RESTful API、HDFS/Hive/Impala 这类离线大数据栈、常见公有云对象存储、Kafka 流式数据,外加其他外部数据源。注意这里有个隐含设计:平台不要求你把数据先搬进来才能分析,跨源直查是产品卖点之一。
往上是接入同步层,四条路并行:批量同步(T+1 或小时级)、流式同步(Kafka 常驻消费)、API 集成(拉三方接口)、文件上传(Excel/CSV 的地推数据、活动数据)。这四类之上还有一个编排与调度模块,负责依赖关系、失败重试、数据回溯。实操里最容易翻车的就是这一层——调度没配好依赖,下游模型读到半截数据,图表立刻给你看一条断崖。
第三层是存储计算层:数仓 Hive 承担明细和大宽表,OLAP 引擎承担点查和聚合,Redis 做结果缓存,Kafka 做流式中转,Spark/Flink 承担重计算任务。方案里特别强调了这个 OLAP 引擎是基于社区版列式引擎做了大量改造的自研版本,后面第 4 章会单独拆。
第四层是平台服务层,也就是很多 BI 产品讲不清楚的地方:元数据系统、权限与项目中心、监控。元数据系统管的是「这个模型从哪来、字段什么含义、被谁引用过」;权限与项目中心管的是「谁能看哪张表、哪个字段、哪一行」。这两个子系统做得糙,前面所有分析能力都会被安全部门一票否决。
第五层是分析引擎层:数据建模系统、查询分析系统、增强分析引擎(归因服务、聚类、文本问答)、订阅服务、查询服务、指标监控、下载服务、数据接口。方案里把 AI 能力放在这一层而不是最上面,说明它是服务化的、可被其他模块调用的,不是单独一个「AI 页面」。
最上面是展现层:可视化系统、数据问答、可视化探索、仪表盘、Notebook、SQL 查询、数字大屏、移动驾驶舱、嵌入分析、OpenAPI 网关。
提示:排查线上问题时,先确认坏在哪一层。图表能打开但数字不对,多半在建模层;图表转圈,先看 OLAP 和缓存;页面 401,去权限与项目中心。
2.2 数据接入:四条同步链路怎么选、怎么配
方案里数据接入的入口只有一个,但后端走了四种机制。选型的判断标准其实很朴素:数据源支不支持增量、延迟要求多高、有没有网络隔离。
- 业务库、订单库,走批量同步,按时间戳或自增 ID 拉增量,落 Hive 分区表。
- 埋点、推荐引擎这类持续输出的事件流,走 Kafka 流式接入,落到实时表或直接进 OLAP。
- 三方渠道(电商后台、投放平台)没有库权限的,走 API 集成,配置请求模板和分页规则,由调度器定时拉。
- 活动地推、人工收集的表格,走文件上传,配合字段映射和清洗规则做落地。
我一般会把批量同步任务的配置写成声明式文件,交给调度器解析,这样任务能进 Git 做版本管理,改口径有据可查:
# batch_order_sync.yaml —— 订单库增量同步到数仓分区表 source: type: mysql # 源类型:关系库 connection: biz_order_prod # 连接名,凭据托管在项目中心,不写明文 extract: mode: incremental # 增量抽取 cursor_field: updated_at # 增量游标字段 split_pk: order_id # 分片主键,避免单线程拉全表 target: type: hive table: dwd_order_detail partition: field: dt # 按天分区 value: "${bizdate}" # 调度变量,回溯时直接改 bizdate write_mode: overwrite_partition schedule: cron: "0 30 2 * * ?" # 每天 02:30 触发 depends_on: [dim_user_snapshot] # 显式声明上游依赖 quality: row_count_check: {min: 100000} # 行数下限校验,低于阈值直接告警这段配置有几个点值得说。cursor_field决定增量边界,选updated_at还是自增 ID 要看业务库有没有物理删除;有删除就得额外配一张删除日志表,否则下游永远是「活着的旧数据」。split_pk是并发切分的依据,配了它,千万级表的抽取能从几十分钟压到几分钟。depends_on是血泪经验——不显式声明依赖,调度器就按时间先后跑,上游晚十分钟,下游就吃到昨天的快照,报出来的数字对不上还找不到原因。
注意:
write_mode用overwrite_partition而不是overwrite_table。前者只重写当天分区,回溯时不会把历史数据一起干掉。
2.3 元数据与权限项目中心:模型能不能被找到、被谁看见
这一层在方案里只占一页,但实际开发量不小。元数据系统干三件事:采集(从 Hive Metastore、OLAP、外部 API 自动同步表结构和字段类型)、补全(业务同学填中文名、口径说明、负责人)、血缘(这个模型被哪些报表引用、改它会影响谁)。
血缘这东西平时感觉不出来,改字段的时候就是后悔药。你打算把order_amount从含运费改成不含运费,先跑一遍血缘,发现下游挂了四十多张报表,就会老老实实新建一个字段而不是原地改。
权限与项目中心的模型我建议按三层设计:项目(业务域,比如交易、增长、供应链)→ 数据集(模型级)→ 行列权限(字段级、行级)。方案里提到的「认证数据集」是个很实用的机制:数据集一旦认证,普通用户只能用它,不能自己改 SQL 直连底层表,从源头堵住口径分裂。这套机制落地时最容易被业务吐槽「不灵活」,通常的做法是开放「申请—审批」通道,而不是直接放开。
3. 数据建模与指标口径:跨源数据集和 FIXED 表达式怎么写
方案里数据分析部分花了很大篇幅讲「简化 Excel 的操作,直追 Excel 的灵活」,这句话背后其实是建模层的功劳。用户在前端拖一个维度、拖一个指标,中间要经过数据集解析、指标表达式求值、SQL 生成、下推到引擎这一串动作。
3.1 跨源建模:五张异构表拼成一个数据集
方案里举的例子很典型:天猫订单数据(API)、APP 订单数据(Oracle)、订单汇总数据(Hive)、用户收藏记录(Hive)、用户下单转化(OLAP)、活动地推数据(CSV),在融合层里被统一成「订单数据集」和「用户信息数据集」。前端分析时只看到「金额」「地域」这些维度指标,完全不用关心它落在哪个库。
融合层的关键是逻辑数据类型统一和下推策略。不同源的decimal、timestamp、string语义不一样,时间字段尤其麻烦——有的带时区有的不带,有的精确到秒有的到毫秒。常见的做法是在融合层做一次标准化映射:
{ "dataset": "order_unified", "sources": [ {"alias": "tmall", "type": "api", "physical": "tmall_order"}, {"alias": "app", "type": "oracle","physical": "app_order"}, {"alias": "hive", "type": "hive", "physical": "dwd_order_sum"} ], "fields": [ {"name": "order_id", "type": "string", "expr": "COALESCE(tmall.order_id, app.order_id)"}, {"name": "amount", "type": "decimal(18,2)", "expr": "SUM(tmall.pay_amt + app.pay_amt)"}, {"name": "pay_time", "type": "timestamp", "expr": "TO_TIMESTAMP(app.pay_time, 'yyyy-MM-dd HH:mm:ss')"}, {"name": "region", "type": "string", "dimension": true} ], "pushdown": {"join_engine": "olap", "max_scan_rows": 50000000} }COALESCE那段处理的是「同一张逻辑表在多个源里都有记录」的去重合并问题;pay_time显式做了格式转换,避免下游按天聚合时把跨时区的数据算到错误的日期;pushdown指定 join 下推到 OLAP,同时给了一个扫描行数上限——这个是保护措施,防止有人不小心把两张十亿级表做笛卡尔积,把整个集群拖垮。
方案里还有一层叫「融合层 OLAP 引擎」,意思是不管上游几个源,最终由 OLAP 层统一承接计算。这个设计的好处是查询优化器只需要对付一种执行引擎,坏处是跨源 join 的数据要先搬到 OLAP,数据量大的时候得靠预聚合兜底。
3.2 FIXED 表达式:同一个指标两种写法,结果必须一样
方案里有一页专门讲「用户购买次数分布」,用 BI 表达式和 SQL 各写了一遍,这是全篇最值得抄的一段。
需求是:先算出每个用户下了多少单,再统计「下了 N 单的用户有多少人」。这在前端就是一个维度{fixed[用户id]: uniq(订单id)}:
-- 等价 SQL:先按用户聚合,再按次数聚合 SELECT times, COUNT(DISTINCT user_id) AS user_cnt FROM ( SELECT user_id, COUNT(DISTINCT order_id) AS times FROM order_detail WHERE status = 'succeed' GROUP BY user_id ) t GROUP BY times ORDER BY times DESC;{fixed[用户id]: uniq(订单id)}的语义是:在指定的维度上做聚合,不受当前视图里其他维度影响。这和普通聚合有本质区别——视图里如果还放了「支付方式」这个维度,普通uniq(订单id)会被拆成按支付方式分组的订单数,而 FIXED 版本仍然是「这个用户总共下了几单」,支付方式只影响最后的展示分组。
这个语义在 SQL 里对应COUNT(DISTINCT ...) OVER (PARTITION BY user_id)或子查询,具体走哪种由优化器决定。落地时踩过的坑是:FIXED 里的维度字段必须写清楚,写{fixed[用户id]}和{fixed[会员id]}在关联表里可能是两套值,尤其是用户表和会员表做了多次合并之后。
方案里还提到 LOD 表达式、同环比、上卷下钻、参考线、条件格式这些控件。同环比在实现上不要每个图表单独算,常见做法是在数据集里预置「同比日期」「环比日期」两个隐藏维度,前端切换时改的是过滤条件,而不是重新写一遍表达式。
3.3 AI+BI 一体化:清洗算子和模型算子串成流水线
方案里把数据准备分成两段:BI 侧的清洗(筛选、连接、聚合、合并、过滤、转置、自定义 SQL、内置函数),和 AI 侧的建模(判别、预测、分类、聚类、回归)。这两段不是割裂的两个页面,而是一条流水线——清洗完的输出直接作为模型输入,模型输出的预测标签又能回写成数据集字段,供报表使用。
-- 场景:对高价值流失用户做聚类,输出人群标签回写数据集 CREATE TABLE ads_user_cluster AS SELECT user_id, cluster_id, -- 用消费频次和客单价两个特征做分群 CASE cluster_id WHEN 0 THEN '高频高客单' WHEN 1 THEN '高频低客单' WHEN 2 THEN '低频高客单' ELSE '沉默用户' END AS cluster_label FROM ( SELECT user_id, -- 聚类函数由增强分析引擎提供,底层是向量化计算 cluster(vec_norm(recency, frequency, monetary), 4) AS cluster_id FROM dws_user_rfm WHERE dt = '${bizdate}' ) t;这段里cluster()是伪代码,实际调用方式各家不一样,有的是 SQL 函数,有的是 Notebook 里调 Python 再回写。关键是最后那一步回写:模型的输出必须变回数据集里的一个维度字段,业务同学才能在仪表盘上按人群筛选。方案里说「让非专业群体也能体验模型算法带来的深度挖掘价值」,落地难点不在算法,而在这条回写通路——很多平台的 AI 模块和 BI 模块是两套权限两套存储,结果就是「模型跑完了,报表看不到」。
提示:聚类类模型一定要做人工复核。给簇自动起名那一步很容易起错,最后报表上的「高价值用户」标签贴到了羊毛党身上,这种事故比模型不准更伤信任。
4. 查询性能与工程落地:73.5PB 上怎么做到明细秒查
三万一千个模型、七十三点五 PB、每天一百五十万次查询——这个量级下,用户对速度的预期是点一下出结果。方案里给出的答案是自研 OLAP 加三层缓存,再加上建模侧的若干调优开关。
4.1 自研 OLAP 的取舍:为什么在社区列式引擎上改
方案写得很直白:基于社区版做了大量开发和优化,方向有四个——高可用、实时性、数据安全、集群运维。这四个方向恰好对应开源版本在企业场景最容易被诟病的四点。
高可用方面,开源版本常见的痛点是单副本或副本切换慢,一个节点挂掉,查询直接报错。改造思路一般是查询层做副本路由,查询失败自动重试到其他副本,前端感知不到。实时性方面,社区版对高频小批量写入不友好,数据要攒够一批才合并,导致「刚刚写入的数据查不到」。常见做法是加一层 Kafka 中转,写入先进缓冲,查询层对最新分区走单独的内存表或增量表。
数据安全这块,方案里提到认证数据集和行列过滤。这类能力如果只做在应用层,一条直连 SQL 就能绕过。所以改造点通常在引擎侧做行级过滤注入——用户提交的 SQL 在解析后自动加上WHERE region IN (...)这类条件,而不是靠前端不显示。
集群运维则是把副本调度、分区合并、慢查询采集这些手工活做成平台里的按钮和看板。
方案里有个「处理速度至少提高 100 倍」的表述,这个数字是产品口径,对比的是常规 OLAP 在同类查询下的表现。真实项目里别拿这个数字去承诺,不同数据分布、不同查询模式差异很大,上线前一定按自己的场景压测。
4.2 三层缓存:结果缓存、Redis、物化预聚合
真实世界的 BI 查询有个特点——百分之八十的请求集中在少数几个仪表盘上,而且往往是同一批维度组合反复刷。所以缓存设计比引擎优化见效更快。
第一层是结果缓存,按「SQL 指纹 + 数据版本号」做 key。这里有个关键点:数据更新后必须让缓存失效,常见做法是分区写入成功后发一条版本变更消息,缓存层把这批 key 全部清掉。如果只按 SQL 做 key 不做版本,就会出现「改了数据,报表还是旧的」这类经典投诉。
第二层是Redis,承接仪表盘的首屏渲染。一个仪表盘有十来个图表,如果每个都实时查 OLAP,首屏就要等十几秒。做法是仪表盘保存时预跑一遍所有图表,把结果塞进 Redis,用户打开时直接读。注意要设置合理的过期时间,并且对「今天」这种实时性要求高的看板做特殊处理,跳过预跑。
第三层是物化预聚合,针对大盘趋势、地域分布这类固定粒度的查询,提前把聚合结果落成表:
-- 预聚合表:按天 + 地域 + 品类汇总 GMV CREATE TABLE ads_gmv_agg_d AS SELECT dt, region, category, COUNT(DISTINCT order_id) AS order_cnt, SUM(pay_amount) AS gmv, SUM(pay_amount) / COUNT(DISTINCT order_id) AS aov -- 客单价 FROM dwd_order_detail WHERE status = 'succeed' GROUP BY dt, region, category; -- 查询侧命中预聚合:粒度更细的查询才回退到明细表 -- 优化器判断条件:WHERE 的维度是 region/category 的子集,且时间跨度 > 7 天这张表的字段设计和查询改写是配套的。aov(客单价)在这里提前算好,但如果用户临时想看「按支付方式拆分的客单价」,预聚合表里没有这个维度,就得回退到明细表。所以预聚合的粒度选择要基于真实的查询日志,而不是拍脑袋——常见做法是跑一个月的慢查询日志,统计高频的维度组合,取 Top 20 做预聚合。
4.3 建模侧的调优开关:过滤器下推、自动 DDL、数据回溯
方案的产品能力矩阵里列了一串看起来不起眼但很实用的开关,实际用起来比调引擎参数更见效:
| 开关 | 作用 | 用错会怎样 |
|---|---|---|
| 行列过滤 | 把 WHERE 条件下推到源端,减少扫描量 | 下推条件用了函数包裹字段,索引失效,全表扫 |
| 自动 DDL | 数据源结构变化时自动同步表结构 | 源端删字段后自动同步,下游模型静默丢列 |
| 智能重命名 | 模型字段改名时自动同步到引用它的报表 | 改了别名但没改血缘,报表报字段不存在 |
| 同步数据依赖 | 显式声明上下游,调度按依赖跑 | 只按时间跑,上游延迟导致数据错位 |
| 数据回溯 | 指定日期重跑指定分区 | 回溯范围配错,历史数据被覆盖 |
| 性能调优 | 模型级缓存、并发度、超时配置 | 并发度调太高,单条查询快但集群被打满 |
「行列过滤」这条我要多说一句。很多项目里性能问题的根因不在引擎,而在 SQL。比如写WHERE DATE_FORMAT(pay_time,'%Y-%m-%d') = '2025-01-01',字段被函数包住,分区裁剪直接失效,七十三 PB 的表扫全量。改成WHERE pay_time >= '2025-01-01' AND pay_time < '2025-01-02',扫描量能差好几个数量级。产品层面能做的,是在表达式编辑时识别这种写法并给出提示。
「自动 DDL」和「智能重命名」是一对。自动 DDL 是双刃剑:源端加字段,自动同步很省事;源端删字段或改类型,自动同步就会让下游静默出错。我的建议是加字段自动同步,删字段和改类型走审批,宁可让人手动点一下。
「数据回溯」是运维必备,但也是事故高发区。回溯任务一定要带预览——先算出影响的分区数和行数,让人确认后再执行。方案里没写这一层,但实际交付时客户一定会提。
5. 避坑与常见问题排查:五条真实踩过的坑
这一章单独拎出来,是因为这套架构的每一层都有一批「看起来正常、结果不对」的故障。下面五条按「现象 → 原因 → 解决」写,基本覆盖了上线后前三个月的投诉类型。
5.1 接入与建模类问题
现象:跨源数据集刷新超时,前端转圈两分钟后报「查询失败」。
原因:融合层把 API 源和 Hive 大表做 join,API 侧是逐页拉取,Hive 侧是千万级扫描,两边都慢,最后超时。也有一部分情况是 join 没有下推,数据被拉到查询进程的内存里做关联,直接 OOM。
解决:先把跨源 join 拆成两步——API 数据每天定时同步到 Hive 落地表,再在 Hive 内部做 join;如果必须实时关联,就把小表(API 侧)广播到内存,大表走分区裁剪。同时给数据集配置max_scan_rows上限和超时时间,宁可快速失败也不要拖垮整个查询队列。
现象:图表上的数字和手写 SQL 跑出来的对不上,差个百分之几。
原因:九成是口径问题,一成是时区问题。口径上常见的是去重方式不同——BI 里uniq默认是精确去重还是估算去重,得看底层的实现;报表用COUNT(DISTINCT),手写 SQL 用了COUNT(*),数字当然不一样。时区上,源数据存的是 UTC,平台按东八区展示,跨天边界的数据就会跑到另一天。
解决:先在 BI 里把生成的 SQL 导出来,和手写 SQL 逐段对比,重点看 WHERE 条件和聚合函数。时区问题统一在数据集层做转换,不要在每张报表里单独处理。另外建议把「认证数据集」的口径说明写清楚,注明去重方式、统计周期、是否含退款,这比事后对账省事得多。
5.2 查询与展示类问题
现象:数字大屏刷新时整个集群变慢,其他报表全部超时。
原因:大屏配了实时刷新,几秒钟一次,每次刷新触发十几个图表的全量查询,这些查询没有走缓存(实时看板通常会跳过预跑缓存),直接打到 OLAP。几块大屏叠加,等于对集群做持续压测。
解决:大屏的刷新频率分级——核心指标 30 秒,趋势图 5 分钟,明细表不自动刷。查询侧给大屏单独配置资源组和并发上限,别和交互式查询抢同一个队列。另外,实时看板的时间范围要限制,别让用户能选「近一年」还开自动刷新。
现象:仪表盘嵌入到第三方系统后,打开是空白或者一直跳登录页。
原因:跨域场景下 Cookie 的SameSite和Secure属性不匹配,浏览器直接不带上会话;或者第三方系统用的是 iframe,而平台侧配了X-Frame-Options: DENY。还有一种情况是嵌入的 token 有效期太短,页面停留久了就失效,但页面没有做续期。
解决:嵌入场景改用 token 鉴权而不是 Cookie 会话,token 放在 URL 参数或 postMessage 里传递,有效期覆盖一个工作日的使用时长,快过期时前端静默续期。服务端把允许嵌入的域名做成白名单,按域名下发Content-Security-Policy的frame-ancestors,而不是简单地放开。
现象:数据回溯跑完了,报表上的数字还是旧的。
原因:回溯只重写了数仓分区,但没触发下游模型的刷新,也没清缓存。链路是「源表分区 → 数据集 → 缓存 → 图表」,只改了第一环。
解决:把回溯做成一个编排任务,重跑分区后自动触发依赖它的数据集刷新,再按数据集发缓存失效消息。这里依赖的就是第 2 章说的元数据血缘——没有血缘,你根本不知道要清哪些缓存。上线初期我是靠人工列清单的,漏了两次之后就老实把血缘接进回溯流程了。
6. 二次开发:嵌入方式怎么选、接口怎么接、改完怎么验证
真正接手这个平台做二次开发的团队,需求通常集中在三件事:把看板嵌进自家业务系统、通过接口拿数据、按自家组织架构改权限。这三件事的技术路径完全不同,选错了后面很难回头。
6.1 嵌入方式的选型:Iframe、SDK、OpenAPI 各自的边界
| 方式 | 适用场景 | 代价 |
|---|---|---|
| Iframe 嵌入 | 快速把整张仪表盘塞进现有系统,改动最小 | 交互受限于平台提供的能力,样式难以深度定制 |
| SDK 集成 | 需要在自己的页面里控制筛选器、联动、跳转 | 要引入前端包,版本升级需要跟着改 |
| OpenAPI | 只要数据,不要图表,自己渲染 | 图表、交互全部自己实现,工作量大 |
大部分项目实际用的是混合方案:整体页面用 Iframe,关键的筛选联动用 postMessage 通信,个别核心指标走 OpenAPI 自己渲染。Iframe 的传参要注意 URL 长度限制,复杂筛选条件不要全塞 query string:
// 父页面 -> 嵌入看板:传递筛选条件并接收渲染完成事件 const frame = document.getElementById('bi-frame'); frame.src = 'https://bi.example.internal/dashboard/1024?token=' + encodeURIComponent(token); // 复杂条件走 postMessage,避免 URL 过长 frame.onload = () => { frame.contentWindow.postMessage({ type: 'SET_FILTER', payload: { region: ['east', 'south'], dateRange: { start: '2025-01-01', end: '2025-01-31' }, // 隐藏平台的默认头部,让嵌入更贴合宿主页面 hideHeader: true } }, 'https://bi.example.internal'); // 必须指定目标 origin,不要用 '*' }; // 接收看板侧的回调:图表点击、渲染完成、鉴权失效 window.addEventListener('message', (e) => { if (e.origin !== 'https://bi.example.internal') return; // 校验来源 if (e.data.type === 'AUTH_EXPIRED') refreshToken(); // token 续期 });postMessage的第二个参数一定要写明确的目标 origin,写'*'等于把消息广播给任何页面,一旦宿主页面里嵌了第三方广告或统计脚本,筛选条件和 token 就泄露了。接收侧同样要校验e.origin,这两个方向都要做,只做一边等于没做。
6.2 权限改造:跟着组织架构走的最小改动
平台的权限模型是「项目 → 数据集 → 行列权限」,而大部分公司的组织架构在 HR 系统或 AD 里。最小改动的做法不是把组织架构搬进平台,而是在登录时做一次映射:用户登录 → 查 HR 接口拿到部门和岗位 → 映射成平台的项目角色 → 写进 token 的 claim 里。
这样组织调整时只改映射表,不动平台里的权限配置。要注意的是映射表本身要有版本和生效时间,否则人员调岗后历史报表的访问记录会对不上。
6.3 改完怎么验证:三步对账法
改造完最怕的是「页面能打开、数字悄悄错了」。我现在的习惯是走三步对账:
第一步,抽样对账。挑三个业务方最关心的指标,用原生 SQL 直连底层表算一遍,和平台出的数逐日对比,差异超过千分之一就停下来查。
第二步,缓存穿透验证。改完数据后立刻刷新报表,确认看到的是新数——这一步专门抓缓存失效没做对的问题。
第三步,权限回归。用低权限账号登录,确认该看不到的字段和行确实看不到,而不是前端隐藏了、接口还能返回。这一步用接口直接请求最有效,别只点页面。
从那以后我每次接这类 BI 平台的二次开发,都会先把「血缘、缓存失效、权限校验」这三条链路各画一遍,画出断点再动手,比上来就写代码少返工很多。希望帮到你。
本文还有配套的精品资源,点击获取