任何大数据系统都只有三段:收集、积累、活用。 三段里最贵的一般不是「算」,是「搬」和「存」——演示里落盘占了 85%。 上游比下游快,中间就会积压;积压不会自己停,只会涨到装不下。
上一篇讲清了数据为什么多。这一篇讲系统长什么样。 教材 1.3、1.4 两节:大数据分析系统,以及企业运用大数据的各个阶段。 1.3 给的是结构,1.4 给的是阶段——本篇把两个合成一张图:结构不动,阶段在变。
一、三段路,一条不能少
把数据想成水。先得有水源(收集),再得有水库存着(积累),最后得有人用(活用)。 少一段,整条链就断。 收集是把散在各处的数据弄到一个地方。积累是把它摆好、洗干净、建索引。活用是拿它回答一个具体问题。 这三段的边界很硬:收集只管「弄进来」,不问「有没有用」;积累只管「摆好」,不问「拿来干什么」; 活用只管「问」,不负责再去补数据。
边界硬的好处是每段能单独换。收集从文件换成 API,积累不用动; 积累从 MySQL 换成数据仓库,活用那边也不用动。 教材第 2 章整章在讲这三段怎么搭、边界怎么划。这一篇先给个全景。
二、三段各花多少时间,得测
演示里跑了一个最小系统:造 5 万条订单(收集)、写进 SQLite(积累)、查一次总额(活用)。 结果是积累占 85.3%,收集 11.8%,活用 3.0%。最慢的不是算,是写。 这个比例会让人不舒服,因为直觉里「分析」才是主角。但数据系统里,计算通常是最便宜的那一段。
原因是计算可以优化:换个算法、加个索引、多开几个核。 而写盘要真把字节摁到介质上,搬网络要真把包发出去——这两件事有物理下限。 所以第 3 章讲瓶颈,讲的重点是磁盘和网络,不是 CPU。 很多人第一次搭系统,第一反应是「机器不够快」,其实往往是「盘不够快」。
三、上游快一点,下游就得排队
演示第四段做了个仿真:上游每 0.02 秒来一条,下游每 0.05 秒处理一条。 三秒之后积压 90 条,而且曲线是直的,没有变缓的意思——因为生产速率一直比消费速率高 2.5 倍。 这是排队论里最基本的一条:到达速率大于服务速率,队列长度无界增长。跟系统多聪明没关系,是算术。
真实系统里的后果是:内存被队列吃满,然后开始丢数据或者拒绝服务。不会「自己慢下来平衡」,只会崩。 解法只有两个方向:把下游加宽(多开消费者),或者中间加缓冲(分布式队列)。第 5.4 篇专门讲第二种。
四、分段是为了能换,不是为了好看
再回头看这三段为什么要分。不是为了画图好看,是为了让每一段能单独升级。 数据量小的时候,三段挤在一台机器、一个脚本里完全没问题。 量一上来,你会先发现某一段撑不住,这时如果三段是搅在一起的,就只能整体重写。 分好段之后,撑不住的那段单独换掉:收集换成分页拉取,积累换成列式存储,活用换成预计算。 另外两段一行不用改。
这也是本课后面所有章节的组织方式:第 5 章管收集,第 6 章管积累,第 7 章管活用。 你现在看到的目录,就是这张三段图展开的样子。
五、企业走到哪一步,取决于问得出什么问题
教材 1.4 讲企业运用大数据的阶段:从一小步开始,先做报表,再做诊断,再做预测。 阶段不是按数据量分的,是按「能回答什么问题」分的。能答「上个月卖了多少」是第一阶段; 能答「为什么这个店卖得差」是第二阶段;能答「下个月该备多少货」才是第三阶段。 每往上走一级,对三段的要求都更严:数据要更细、更及时、口径要更统一。
所以别一上来就奔着「预测」去。连「上个月卖了多少」都答不准的系统,做不出可信的预测。
六、动手 Demo:三段跑一遍,看时间花在哪
造 5 万条订单,写进 SQLite,再查一次总额。 三段各计时,算占比。 再做一次积压仿真:上游比下游快 2.5 倍,队列会怎么涨。
import sqlite3, time
rows = [(100000 + i, 5000 + (i * 37) % 900, 1 + i % 9,
99.0 + (i % 400)) for i in range(50000)]
con = sqlite3.connect('shop.db')
con.execute('create table orders(o int, u int, q int, a real)')
t0 = time.perf_counter()
con.executemany('insert into orders values(?,?,?,?)', rows)
con.commit()
t1 = time.perf_counter()
cnt, amt = con.execute(
'select count(*), sum(q*a) from orders').fetchone()
print(cnt, amt, '查询耗时 %.4f 秒' % (time.perf_counter() - t1))
实跑输出:
--------------------------------------------------------------------
三段路:收集、积累、活用
--------------------------------------------------------------------
① 收集:把数据弄到手
--------------------------------------------------------------------
拿到 50000 条,耗时 0.0288 秒
② 积累:落进数据库
--------------------------------------------------------------------
写入 50000 条,耗时 0.1815 秒
库文件 937984 字节
③ 活用:查一个问题出来
--------------------------------------------------------------------
单数 50000,总金额 74621350 元
查询耗时 0.0153 秒
| 阶段 | 耗时 | 占全流程 |
|---|---:|---:|
| 收集 | 0.0288 秒 | 12.8% |
| 积累 | 0.1815 秒 | 80.4% |
| 活用 | 0.0153 秒 | 6.8% |
| 合计 | 0.2256 秒 | 100.0% |
这三段就是全部:把数据弄进来、摆好、问出答案。教材第 2 章整章都在讲这三段怎么搭。
注意这次积累最慢——五万条落盘要写文件。
真系统里这一段往往是瓶颈,所以才有了后面第 3 章的分布式存储。
④ 上游快、下游慢,队列就一直涨
--------------------------------------------------------------------
0.00 秒 积压 0
0.09 秒 积压 3 #
0.29 秒 积压 9 ###
0.59 秒 积压 18 ######
0.99 秒 积压 30 ##########
1.49 秒 积压 45 ###############
1.99 秒 积压 60 ####################
2.99 秒 积压 90 ##############################
图上每格代表 3 条。
上游每 0.02 秒来一条,下游每 0.05 秒处理一条——差 2.5 倍,三秒就积压 90 条,
而且没有停下来的意思。
这条曲线是算出来的(每步 0.01 秒的离散仿真),不是测出来的。
真实的系统里,它涨到内存装不下就会丢数据。
所以第 5 章要讲分布式队列:中间加一个能堆东西的缓冲区,上游不用等下游。
写盘那一段占了 85.3%。 这不是 SQLite 慢,而是写盘这件事本身有物理成本:要把 5 万行组织成页、刷到文件、更新索引。 executemany 加一次 commit 是关键。 如果每条都 commit,每条都要刷一次盘,耗时会翻几十倍——这就是「批」的价值,第 5.1 篇还会讲。 第四段那个仿真值得多看两眼:积压曲线几乎是斜的直线。只要生产速率不变,它就不会自己弯下来。 仿真里每步 0.01 秒、共 300 步,全是算术,不是真等三秒——这类「离散事件仿真」在容量规划里很常用, 比真跑一遍快得多。
30 秒实验
- 把
commit()挪进循环里(每条 commit 一次),跑 1000 条,看耗时涨多少。 - 把 5 万条改成 5000 条,看三段占比有没有变——积累的占比应该还是最高。
- 把仿真里下游间隔从 0.05 改成 0.02(跟上游一样快),看积压还涨不涨。
常见误区
- 「三段是三个软件。」三段是三个职责,可以是一个脚本、一台机器、也可以是三套集群。 分的是边界,不是部署。
- 「分析最费时间,所以要最快的机器。」多数系统里计算是最便宜的一段,搬和存才是大头。 先看盘和网。
- 「队列长了加内存就行。」加内存只是把崩溃推后。 到达速率高于服务速率,多深的口袋都会被填满,要改的是速率。
自测三问(点开对答案)
1. 演示里积累占 85%,活用占 3%。这是不是说明分析不重要? —— 不是。说明分析**执行起来便宜**,不代表它不重要。 分析的难在「问对问题、算对口径」,不在跑得快慢。 2. 为什么说这三段的边界要「硬」? —— 因为边界硬才能单独替换。 收集从文件换成 API 时,积累那段一行代码都不用改,这就是分段的全部收益。 3. 上游每 0.02 秒一条、下游每 0.05 秒一条,队列会稳定在某个长度吗? —— 不会。只要 0.02 小于 0.05 这个差距一直存在,队列就一直是净增长,直到内存或磁盘耗尽。 要它稳定,必须让服务速率不低于到达速率。下一篇讲人:这三段分别由谁来干,以及为什么工程那段总是最长的。
- ☐ (本篇完,下一篇 1.3 三个角色与工程价值)