ARTICLE DETAIL

资讯详情

深耕网站视觉设计与运营推广的一线实战洞察。

广电大数据可视化:机顶盒采集、Flink实时数仓与ECharts大屏

广电大数据可视化:机顶盒采集、Flink实时数仓与ECharts大屏 1. 广电大数据到底特殊在哪先把场景拆明白广电这块的数据跟我们平时在互联网公司看到的那套用户行为数据骨子里是两回事。互联网讲的是点击、曝光、转化广电讲的是开机、换台、停留、回看。听起来差不多但数据的产生方式、粒度、时效要求完全不一样。机顶盒是一台台部署在家庭里的终端设备它没有浏览器没有App那种灵活的埋点能力很多行为数据是靠固件里的回传模块定时上报的。这就决定了广电大数据的第一特性数据来源被设备能力卡死你能采到什么很大程度取决于机顶盒型号和固件版本。省级网络公司动辄几百万到上千万台终端横跨十年以上的设备代际新旧机器的回传能力天差地别这是做广电数据可视化首先要接受的现实。第二个特性是时效分层极端明显。直播收视这种数据运营部门要求你分钟级甚至秒级看到频道份额的变化晚八点黄金档一个节目崩了得马上知道。但用户画像、留存分析这类数据T1 跑完全够了。一个平台里同时存在准实时和离线两条完全不同的链路这跟纯互联网数仓的架构思路是有分歧的。你要是拿一套纯离线调度去硬扛直播看板铁定翻车反过来把画像也塞进实时链路成本又高得离谱。第三个特性是指标口径的行业惯性。收视率、到达率、人均收视时长、频道份额这些词广电行业内部有约定俗成的算法甚至跟传统抽样调查时代的定义有历史延续性。你新做一套大数据口径如果跟老口径差太远业务方第一时间就不信任你。所以做广电数据可视化先把口径对齐再谈技术实现这个顺序不能反。我接触到的大多数广电大数据项目需求方其实就是几拨人频道编排的想优化节目单广告经营的想证明投放价值网络运维的想盯住终端在线率和故障分布领导层想在大屏上一眼看到全省态势。这四拨人的诉求完全不同共同点只有一个——都要看图不看表。这就是为什么数据可视化在这个领域不是锦上添花而是刚需。你给他们一堆 CSV没人看你给他们一块能自动刷新的可视化大屏会议室的讨论效率立刻不一样。2. 整体架构设计从机顶盒到大屏的完整链路2.1 五层架构的选型逻辑广电大数据的链路我一般拆成五层采集层、接入层、存储计算层、服务层、可视化层。这个分层不是为了好看而是为了让每一层的故障能隔离。采集层出问题最多是数据延迟不至于把大屏拖垮可视化层崩了底层的数据资产还在。采集层就是机顶盒上的回传模块。说实话这一层你能动的东西最少因为改固件要走灰度、要走审批周期极长。所以常规做法是在上报网关上做尽可能多的加工和补全把设备端当哑终端对待。网关通常用 Nginx 做接入后面挂一个 Java 或者 Go 写的上报服务负责协议解析、字段清洗、服务端打时间戳。这里有个关键设计——时间戳一定要用服务端时间后面我会专门讲为什么。接入层选型上Kafka 基本是标配。它的价值在于削峰填谷。广电的数据有个很典型的潮汐特征凌晨两点到早上六点几乎没量晚上七点到十一点是洪峰两个时段能差十几倍。如果采集端直接写数据库晚高峰直接把库打爆。Kafka 把洪峰缓冲下来下游按自己的节奏消费这是最朴素也最有效的解耦。存储计算层分两条线。实时线用 Flink 消费 Kafka做窗口聚合结果写进 ClickHouse 或者 Apache Doris 这类 OLAP 引擎供大屏秒级查询。离线线走 HDFS Hive用 Spark 跑 T1 的全量指标结果回写到同一套 OLAP 里或者单独建离线结果表。你可能会问为什么实时和离线不合并成一套答案是成本。全量历史明细放 ClickHouse存储成本会让人肉疼而放 Hive 便宜十倍不止。分工明确各干各擅长的事。服务层就是一层薄薄的 API 网关加缓存。大屏的查询接口统一从这里出去热点数据用 Redis 挡一道。这里必须强调一点可视化层的接口一定要做聚合绝不能把明细透传给前端。我见过太多项目前端直接查 500 万行明细再在前端做聚合大屏一刷新浏览器就转圈这种设计一律推倒重来。可视化层现在的主流是 ECharts 配 Vue 或 React大屏场景会额外用到 ECharts GL 做三维地球和飞线效果。企业级数据可视化平台也有现成的商业方案但对于广电这种指标口径特殊的行业我倾向于自研或者基于开源二次开发把口径牢牢攥在自己手里。2.2 集群部署策略与容量估算广电大数据的集群部署策略核心矛盾是成本和数据保留周期。原始明细数据保留多久我的经验是原始日志保留 90 天足够聚合后的分钟级指标保留 1 年天级指标和画像保留 3 年。为什么要这么切因为运维排障一般看最近一个月业务复盘看最近一年用户画像看长期趋势。按这个梯度设计存储能省下一大笔。容量估算得拿真实数字说话。假设一个省级平台有1000 万台终端每台机器每天产生约150 条有效事件开机、心跳、换台、点播、关机那就是15 亿条/天。每条原始事件压缩前大约 200 字节压缩后按 1/4 算日增原始数据约75GB加上副本系数 3HDFS 实际占用约225GB/天。保留 90 天大概20TB。这个规模用十来台普通配置的服务器就能撑住不需要盲目堆机器。Kafka 的容量要按峰值算不能按均值。还是 1000 万终端晚八点黄金档假设有25%的终端同时在线也就是 250 万台每台每分钟回传 1 条事件折算下来约4.2 万 TPS。这个数字必须留冗余我一般按峰值再乘以3 倍来配也就是目标吞吐12 万 TPS。单个 Kafka 分区的写入吞吐在普通机械盘上大约 1 万 TPS 量级那么分区数至少12 到 16 个实际我会开24 个给未来增长和突发留空间。分区数不是越多越好太多会增加元数据管理和重平衡的开销这个度要拿捏。Flink 的并行度跟 Kafka 分区对齐是最省心的24 个分区配 24 个并行度上下游天然对齐不会出现某个算子空转。如果开了窗口聚合记得把 watermark 的延迟设成能容忍乱序的程度广电设备时钟漂移严重乱序数据很常见watermark 设 30 秒到 1 分钟都算正常。这里就有个坑watermark 设太大实时性变差设太小窗口外的迟到数据被丢弃指标就会偏低。我的做法是允许迟到并输出到侧输出流把迟到数据单独存一份人工核对时能看到丢了什么而不是无声无息地消失。3. 数据采集与数仓建模的实操要点3.1 采集层的埋点与回传设计机顶盒埋点这件事最大的难点不是技术是设备多样性。同一批机顶盒可能来自五六个厂商固件版本几十种上报字段的名字、编码、单位都可能不一样。你可以这样理解这就像收集几十个方言区的人写的日记格式各异你得先统一成普通话。我的处理原则是在接入层做标准化映射而不是在设备端改。具体做法是维护一张字段映射表按厂商 固件版本维度匹配把各家报上来的原始字段名翻译成统一字段。举个例子有的机器把频道号叫channel_id有的叫ch_no有的叫service_id映射表里全部归一成channel_id。这样设备端不用动网关侧加一张配置表就能解决大部分脏活。-- 字段标准化映射表结构示例 CREATE TABLE dim_device_field_mapping ( vendor_code VARCHAR(32), -- 厂商编码 firmware_ver VARCHAR(32), -- 固件版本 src_field_name VARCHAR(64), -- 原始字段名 std_field_name VARCHAR(64), -- 标准字段名 transform_rule VARCHAR(256), -- 转换规则如单位换算 valid_from DATE -- 生效日期 );回传频率也要设计。开机、关机这种状态变更类事件实时上报心跳类的五分钟一次足够换台这种高频事件如果每次都实时上报量会爆炸通常做法是本地缓存 30 秒合并后上报。这里有个现实取舍合并上报能大幅省流量省压力代价是你会丢失 30 秒内的精确换台次数只能得到看过哪些频道。如果你的指标需要精确换台频次这部分数据就得牺牲存储和带宽去换。提示机顶盒本地时钟普遍不准偏差几分钟甚至几小时都常见。所以事件里的event_time只能作为参考真正的分区时间一律用服务端接收时间。我吃过这个亏——某天一批机器固件时钟跳变按设备时间分区数据全塞进了一个错误的小时分区里排查了半天。3.2 数仓分层与核心指标口径广电数仓我一般按ODS → DWD → DWS → ADS四层来建。ODS 层就是原始回传落地的落地表除了标准化字段尽量别加工。DWD 层做清洗、去重、会话切割。会话切割是关键什么是一次收视会话我的定义是同一终端、同一频道、连续观看中间切换间隔不超过 30 秒算一次会话。超过 30 秒就断成两次。这个 30 秒不是拍脑袋是因为机顶盒回传合并窗口就是 30 秒跟你自己采集的节奏对齐才不会自相矛盾。DWS 层做轻度聚合比如按天 频道 区域汇总收视时长。ADS 层就是给大屏用的结果表直接对应一个图表。这样分层的好处是口径逻辑都压在 DWD 和 DWS 里ADS 只是搬运改口径不用动前端。核心指标的口径我用表格给你列清楚这些是广电业务里最容易扯皮的地方指标名称计算口径常见坑开机率当日有开机行为的终端数 / 总有效终端数分母要把长期离网但未销户的终端剔除否则分母虚高频道份额某频道收视时长 / 所有频道收视时长分母是否含回看和时移行业内有争议必须写清楚到达率看过该频道至少 1 分钟的终端数 / 总终端数1 分钟这个门槛各家不同要对齐人均收视时长总收视时长 / 有收视行为的终端数分母到底是全部终端还是活跃终端差一倍点播转化率点播成功次数 / 进入点播页次数页面进入事件如果没埋这个指标就废了这张表看着简单实际项目中每一条都能引发一场会议争论。我的建议是每个指标在维表里配一段口径说明跟代码一起版本管理谁改了口径都要留痕。业务方问起来能直接甩出定义和历史变更记录省得反复解释。3.3 用户画像标签的落地广电的用户画像跟互联网电商的画像逻辑不太一样。电商画像冲着转化去广电画像更多冲着收视偏好和生命周期管理去。标签体系我通常分成三类基础属性标签区域、终端型号、入网时长、行为标签偏好频道类型、观看时段偏好、点播活跃度、状态标签活跃、沉默、流失预警。行为标签的生成核心是权重衰减。一个人三个月前爱看体育最近天天看电视剧那他的偏好标签应该以近期为主。我一般用时间衰减公式近期行为权重按e^(-λt)衰减t 是天数差λ 取 0.02 到 0.05 之间。取 0.02 的话30 天前的行为权重还有约 0.55取 0.05 的话只剩 0.22。具体取多少取决于你希望画像反映多久的偏好——想反映近期趋势就取大一点想反映稳定偏好就取小一点。这个参数没有标准答案得拿业务反馈来调。标签算出来之后别急着上大屏。先做小范围验证挑几个已知特征的区域做对照看看标签跟实际是否吻合。我见过团队直接全量上线结果高价值用户标签圈出来一堆只开机不看的僵尸终端就是因为权重没处理把历史行为算得太重了。4. 核心指标计算与可视化实现4.1 收视率与活跃度的计算逻辑收视率的实时计算是广电大数据的皇冠明珠也是技术难点最集中的地方。先说离线版思路简单粗暴把 DWD 层的收视会话表按频道 时间片聚合算出每个时间片每个频道的观看终端数再除以总终端数。这个用 Hive 或 Spark SQL 一把梭就能出来。-- 离线频道分钟级收视份额计算示例 INSERT INTO ads_channel_minute_share PARTITION (dt${dt}) SELECT channel_id, time_slice, -- 分钟级时间片 COUNT(DISTINCT terminal_id) AS view_cnt, -- 该分钟观看终端数 ROUND( COUNT(DISTINCT terminal_id) * 1.0 / SUM(COUNT(DISTINCT terminal_id)) OVER (), -- 全场总观看数作分母 4 ) AS share_ratio FROM dwd_view_session WHERE dt ${dt} AND duration_sec 60 -- 过滤掉误触发的短会话 GROUP BY channel_id, time_slice;实时版就得靠 Flink 了。这里有个绕不开的问题去重。收视份额的分母是所有频道观看终端数之和但同一台终端在同一分钟理论上只能看一个频道跨频道去重不能简单相加。所以实时链路里我通常用滚动窗口 终端维度最新状态来做窗口内按terminal_id去重只保留每个终端在该窗口内的最后一个频道状态。Flink 里可以用KeyedProcessFunction维护一个终端状态表窗口触发时把所有终端的最新频道状态拿出来统计。这个状态如果太大千万级终端得配好 RockDB 状态后端和 TTL不然内存扛不住。活跃度指标相对好算。DAU 就是当日有任一有效事件的去重终端数MAU 同理。但这里有个细节周活跃和月活跃的口径要对齐别一个算自然周一个算滚动 30 天。我之前接手的一个项目两块报表一个用滚动 7 天一个用自然周数字永远对不上业务方天天来问最后发现是口径问题代码本身没错。这种坑纯属沟通问题但代价极大。4.2 ECharts 大屏的关键图表落地大屏这块门面工程做得好不好直接决定项目在领导心里的印象分。广电大屏的经典布局是中间一个三维地图或者雷达态势两侧对称摆放趋势折线、排行条形、实时滚动列表。KPI 数字用大字号卡片顶部放时间实时刷新。ECharts 的配置有几个实战要点。第一数据更新的方式。大屏要定时刷新但绝对不能用chart.setOption(option)反复整体刷新那样会有内存泄漏和动画抖动。正确做法是用setOption的增量更新只传变化的部分// 增量更新折线图数据保留图表实例 function updateTrend(chart, newData) { chart.setOption({ series: [{ data: newData }] }, { notMerge: false, // 关键增量合并不重建 lazyUpdate: true // 延迟渲染避免频繁重绘 }); }第二数据刷新频率和接口响应的匹配。实时看板 5 秒刷一次是常见的但前提是你的接口能在 200 毫秒内返回。如果接口要 2 秒你设 5 秒刷新就会不停堆积请求浏览器用着用着就卡死。我的经验是刷新间隔至少是接口平均响应时间的 10 倍接口 200 毫秒就 5 秒刷接口慢到 1 秒就退到 15 秒或 30 秒刷。第三WebSocket 还是轮询。实时性要求高的用 WebSocket 推送但推送频率要控制。别一有数据变化就推那样前端渲染压力大。通常做法是服务端按固定节拍比如 3 秒批量推一次前端拿到后合并渲染。我见过后端每条数据都推一次结果高峰期一秒钟推几百条浏览器直接卡崩。注意大屏上如果放了地图千万别用在线地图底图。会议室网络环境复杂一旦底图加载失败整块大屏就是一片空白非常尴尬。正确做法是把 GeoJSON 底图数据打包进项目本地彻底摆脱网络依赖。4.3 可视化平台的后台配置化设计一个能长期活下去的广电数据可视化平台一定要配置化不能每加一个图表就改一次前端代码。我的做法是把大屏拆成组件 数据源两块。每个图表是一个组件实例绑定一个数据源 ID数据源里配置 SQL 或 API 地址、刷新间隔、参数。运营想换一个图表改配置就行不用发版。这套设计的关键在于接口协议的统一。所有可视化数据源返回的 JSON 结构必须是同一个骨架前端只认这个骨架具体数值放在data数组里。这样前端图表组件才能通用。统一协议的好处在后期的运维上体现得淋漓尽致——新增图表零代码调整布局拖拖拽拽就完成项目能稳稳跑好几年而不是做完就烂尾。配置表的设计我一般这么搞配置项说明示例screen_id大屏唯一标识gd_overview_01component_type组件类型line/bar/map/kpidata_source_id绑定的数据源ds_channel_sharerefresh_sec刷新间隔秒5position位置和尺寸 JSON{x:100,y:200,w:400,h:300}params传入参数 JSON{region:全省}有了这张表整个大屏的布局和数据绑定全部落库前端启动时拉一次配置动态渲染。想改布局改库。想换数据改库。这套东西一旦搭起来团队维护成本能降一大截。5. 常见问题排查与性能优化实录5.1 大屏卡顿与数据延迟的排查思路大屏卡顿和数据延迟是运维中最常见的两类故障我把它们整理成一张速查表按现象 → 可能原因 → 排查动作 → 解法来组织出了事照着走就行现象可能原因排查动作解法大屏整体转圈接口慢或超时看接口 P99 耗时加缓存、加预聚合单个图表空白数据为空或报错查数据源日志修 SQL、补数据数字长时间不动刷新失败或推送断看 WebSocket 心跳重连、降级为轮询数据延迟 1 小时以上Kafka 积压看消费 lag扩分区、加消费并行度指标突然暴涨暴跌迟到数据或重复上报查当日数据条数加去重、修 watermark凌晨数据缺失跨天分区错误查分区时间字段统一用服务端时间这张表里的每一条我都亲身踩过。就说 Kafka 积压这条最常见的原因是下游消费能力跟不上上游生产。表面看是积压实际可能是 Flink 算子反压而反压的根子往往是某个聚合算子状态太大GC 频繁。这时候光扩分区没用得去看 Flink 的反压监控找到瓶颈算子。排查顺序我一般这么走先看大屏接口耗时排除前端问题再看 OLAP 查询耗时排除查询问题然后看 Kafka lag排除消费问题最后看上游生产量排除数据洪峰。逐层往上别一上来就改代码先定位再动手。5.2 实操心得与避坑清单做了几个广电大数据可视化项目下来有几条经验是普通文档里不会写、但实际特别管用的。第一条把口径写到维表里跟代码一起管理。听起来很土但救过我好几次。业务方问你这个份额怎么算的我能直接翻出维表里的定义和变更历史而不是去翻半年前的代码。省下来的时间全是可以用来干正事的。第二条大屏的刷新频率宁慢勿快。新手总想让大屏越实时越好五秒一刷甚至一秒一刷。实际用下来除了直播监控这种特殊场景大部分业务看板 30 秒到 1 分钟刷一次完全够用。刷太快服务器压力大浏览器也累还容易在会议室网络不好时翻车。稳定性比实时性重要一百倍。第三条所有对外展示的数字都必须能追溯到明细。大屏上的数字一旦被质疑你得能在几分钟内给出它的来源明细。我的做法是每个指标结果表都保留一份明细抽样随机抽 100 条明细可以随时展示。这样业务方质疑时你能当场演示这个数是怎么来的信任感一下子就建立起来了。第四条永远给实时链路准备降级方案。实时计算链路复杂出故障的频率比离线高得多。我的方案是实时链路挂掉时大屏自动切到最近一次成功离线结果 标记数据延迟时间而不是直接报错白屏。用户看到数据更新至 20:15比看到一个红叉舒服多了也更能容忍几分钟的延迟。第五条别迷信大集群。广电的数据量看着吓人15 亿条一天但真正算下来需要的算力并没有想象中那么夸张。我见过团队上来就申请几十台服务器结果一半在空转。先用小集群扛住等真扛不住了再加这个策略在广电场景里屡试不爽。数据量的增长是渐进的架构的扩展能力比一次性堆硬件更重要。第六条文档和监控一起做。大屏上线那天不是项目的终点是起点。上线前必须配好监控接口成功率、数据新鲜度、Kafka lag、任务运行状态。我见过太多项目上线当天风风光光三个月后没人敢动因为不知道哪里会崩。监控配上报警规则定好才能睡得安稳。最后分享一个我最近在用的小技巧。大屏上的数字刷新如果太频繁会让人眼花其实可以在前端做平滑过渡动画数字从旧值滚动到新值看着很舒服也能掩盖刷新时的视觉跳变。ECharts 的数字卡片配合animationDuration稍微调长一点效果就出来了。这种小细节业务方未必说得出来但用起来就是觉得高级这就是可视化的价值——让数据看起来可信、看起来舒服数据才真正被人用起来。
返回列表