环球影城的科学原理
找工作期间去了趟环球影城, 意外发现里边应用不少科学原理, 开篇文章盘(yǘ)点(lè)一下
入园篇: 高并发请求处理
我是 10 点半抵达的环球影城, 门口队伍排的绕了一圈, 用了半小时才走到分流检票口.
一般来说, 当短时间内接收大量超出服务能力的请求, 导致出现请求积压时, 我们称之为高并发场景. 对于环球影城而言, 当新增待检票用户数高于每分钟最多可检票用户数时, 就会出现请求积压现象. 体现为排队队列快速增长. 和普通高并发不一样的是, 在普通高并发场景下, 服务器可以选择直接弃掉部分请求以保证最终指标最优, 但在环球影城场景中, 如果检票人员敢随机宣布部分游客门票作废以试图减少总任务压力的话…肯定会吃官司的侬知道的吧. 所以环球影城面临的不是普通 web 请求, 而是游客提交的必须被处理的任务, 此时的理论抽象结果, 应该是操作系统中常见的: 批处理任务模型.
对于批处理任务系统, 一般有以下衡量指标
而在高并发处理模型中, 比较常见的指标是系统吞吐率
和TP
(top percentile)系列. 系统吞吐量包括QPS
/TPS
/IOPS
指标(每秒平均处理请求数/事务数/io 数), 但这些指标存在误导: 比如 100 万个请求, 100 秒处理完毕, 然后集中在最后一秒给出响应. 这样算下来平均每秒可以处理 1 万个请求, 但用户端每个请求都等待了 100s, 就会出现指标酷炫但实际体验非常糟糕的情况. 所以线上一般更偏向使用TP
指标.
TP(top percentile)指的是百分位数据. TP99 表示大于数据集内 99% 的数据分位点, TP50 表示大于数据集 50%的数据的分位点(中位数). 这个指标非常适合反应系统整体响应时长, 也比较适合衡量环球影城排队的实际情况.
所以, 问题变为: 如何优化系统, 以优化 TP90 的用户排队时间分位值? 我认为可以从这几个方面入手
- 增大缓冲队列确保容纳所有请求
- 由于所有请求都需要处理, 因此增大缓冲区, 避免任务丢失(等待区满员游客排都排不上)是第一要务. 线上服务可以调整请求缓冲区或使用任务队列承载请求, 线下实体可以通过提前修建排队长廊, 设置栅栏支持队伍折叠以在有限空间中增加尽可能多的排队堆栈长度
- 该思路在生物中使用较多: 例如在大脑皮层中通过增加沟回提升表面积, 小肠通过增加绒毛提升表面积, 通过折叠增加小肠实际长度等
- 分流增加处理速度
- 检票作为例常性工作, 只需要
安检
/验票
两个步骤, 是天然的无状态
应用, 因此非常适合进行水平扩容. 一台 X 光机一个检票口两个验票人员就相当于一台服务器, 只要场地允许就可以无限累加, 从而加快验票流程
- 检票作为例常性工作, 只需要
- 人工智能实现实时任务调配
- 虽然通过增加验票口可以对排队人员实现分流, 但是仍可能出现请求分配不均导致个别检票口任务挤压, 影响 TP90 数值的问题. 这时候就需要实现一套分流体系一边合理安排每个服务器(检票口)的工作量.
- 对于线上环境, 可以在以下层面进行分流
- 运营商分流: 移动/联通分配到不同服务器(大区服务器)
- 地区分流: 通过在地域内配置 DNS 把流量分配到不同节点(山东地区对 baidu.com 的解析结果为 1.1.1.1, 山西地区对 baidu.com 的解析结果为 2.2.2.2)
- 服务器内分流: 流量首先进入 Nginx 集群, 根据客户端 ip 进行 hash, 分配到不同服务器
- 确保同一 ip 总被分配到同一服务器
- 为避免新增服务器改动 hash 总数引起任务重分流, 可以使用环形 hash 方案: 先将任务分配到虚拟任务节点中(例如分散到 65535 个虚拟节点上), 然后每个实际服务器承载指定的虚拟节点, 通过新增中间层的方式将用户请求和实际服务进行解耦
- 计算机科学领域的任何问题都可以通过增加一个间接的中间层来解决, via Butler Lampson
- 但就环球影城的实际场景中, 现场实现一个任务分流器显然难度略高, 所以环球影城最终采取了人工智能解决方案
- 在排队的终点和 n 个检票口之间添加空地, 让游客在排完队后可以直接观察到每个检票口的实时队伍长度, 从而可以人工判断那个队伍更快, 进而智能将任务调度到该检票口, 实现 TP 指标的最小化
- 其他思路
- 分流
- 规定门票最早检票入园时间(类似 12306, 分批放票)
- 提升硬件性能
- 配备专业检票人才/使用订制 X 光扫描器自动化发现危险物, 加快单服务器安检任务处理速度
- 自动化探测的话还有假阳性和假阴性问题, 又是另外一块
- 预安检
- 将安检拆分为流水化作业, 由单一安检分为多道工序, 中间划定安全区–次安全区–次次安全区等不同区域, 加快安检流程
- 亚当斯密有言:扣针的制造大约有 18 道工序, 如果未经过专门的训练, 工人们独自分别工作, 每人每天可能 1 枚针也造不出来.而如果 18 道工序分工由专门的工人担任, 即使是只有 10 人的小工厂, 10 个人每天能制造 4.8 万枚针, 就是每人每天制针 4800 枚.
- 分工乃提效之源
- 进阶版的泰罗制在向计算机科学招手
- 预安检 2
- 利用信用分作为安检条件, 信用分 400 分以上免安检, 直接减少工作量
- 相当于利用信用分对任务进行预计算, 使用时直接读取缓存
- 分流
4D 体验篇: 运动的错觉与惯性系
环球影城内的娱乐设施可以分为三类
变形金刚 | 哈利波特 | 侏罗纪公园 | |
---|---|---|---|
拍照打卡类 | 传奇现场 | 奥利凡德魔杖店 | 奇遇迅猛龙 |
过山车 | 霸天虎过山车 | 鹰马飞行 | - |
4D 动感体验 | 火种争夺战 | 禁忌之旅 | 侏罗纪世界大冒险 |
拍照打卡类不必多说, 过山车为什么不会掉下来则是高中物理知识, 这里也不再多讲. 但 4D 动感体验类设施是我第一次在国内看到, 有必要分析下.
4D 体验类最为人称道的, 就是让游客感到自己真的在快速飞行(火种争夺战中的高速赛车/禁忌之旅的魁地奇飞行/侏罗纪大冒险中霸王龙的追逐). 但娱乐设施并不大, 也没有感受到高速移动带来的迎风的感觉, 这是怎么回事?
答案当然是游客并没有动, 但游客感受到了自己在高速移动. 所以问题转化成了: 如何在让游客本身不移动的情况下, 感受到自己在快速移动? 或者换一种问法: 人类为什么会认为自己在移动?
答案是视觉和加速度.
视觉方面, 我们通过周围景物的变化来判断自己是否在移动. 实际生活中当我们坐在火车里, 对面火车开动时就会有"我们这趟火车开动"了的错觉. 如果我们站在沙滩上, 潮水褪去时脚边卷起的沙子也会让我们产生"正在前行"的错觉. 而在 4D 体验中, 这种视觉错觉则是通过球形屏幕实现的. 环球影城首先通过向内凹陷的座位限制我们的可视范围, 然后再让座位对准一个球形荧幕, 在这个荧幕上播放摄像机视角拍摄的场景. 由于拍摄时摄像机在高速移动, 所以坐在座位上以摄像机视角观看电影的我们, 看到了和快速移动的摄像机一样的景象, 也就产生了我们在快速移动的错觉.
值得一提的是, 这种电影错觉只会让我们形成快速移动的感觉, 但不会有立体感. 而为了实现立体感, 需要进一步的模拟----正常情况下, 由于双眼之间有 65mm 的间距, 因此我们双眼正常看到的物体都会有微小的差距, 这种差别被称之为双目视差. 而为实现这种效果, 火种争夺战中使用的是偏振光技术, 通过让观众带偏振光眼镜, 眼镜的两个镜片各只允许一个方向的偏振光进入, 从而实现双眼看到图像不一, 形成立体感. 到了禁忌之旅, 则不需要佩戴眼镜. 这种可能是没有考虑立体效果, 但也可能是通过光屏障/柱状透镜技术, 让双眼看到不同的可视画面, 进而形成立体感.
视觉上的立体运动感搞定后, 下一步就是身体的运动感. 根据伽利略发现的相对性原理: 一切彼此做匀速直线运动的惯性系,对于描写机械运动的力学规律来说是完全等价的。也就是说, 我们并不能通过自身的感觉来判断我们当前所处的位置是静止还是匀速直线运动(这两种状态下我们的感觉都完全一致). 那我们是怎么判断自己是否在运动或者自己在向那个方向运动的呢? 答: 依靠重力加速度的方向, 或者说, 依靠地心引力的方向.
千百万年的进化让我们的生物身体形成了"重力的方向就是下"的先验概念, 借助这个概念, 我们就可以对身体进行 hack: 既然重力方向就是下, 那么如果旋转座椅朝向, 让我们背朝下, 会不会产生我们在"向上"的错觉? 再配合球形荧幕下视觉系统中我们在不断前进的反馈, 就形成了我们在"快速飞升"的错觉. 同样的道理, 通过调整球形荧幕的景像和座位的朝向, 就能让我们产生我们在快速运动的感觉. 这一切是那么完美, 所以设备启动前才会有那句提示: “不要将头部伸出座仓外”…
当发现自己真的在楚门的世界, 眼前城堡只是锅盖面上的投影而锅盖边缘清晰可见…这种感觉可以说是相当出戏了 😂
游园篇: 优速通与时间成本
如果问环球影城中参与人数最多的娱乐项目, 那可能就是排队. 就实际体验看, 除了路边演出和人偶合影不需要排队外, 所有项目入口前都有大大小小的长龙, 连剧场表演也要排队等候入场…队伍等待时间从 15 分钟到 70 分钟不等, 考虑到大多数娱乐项目实际时间只有 3 分钟, 营业时间只有 9 小时, 说游客 70%的时间都在排队并不过分(9 小时玩 8 个项目, 平均每个项目排 57 分钟玩 3 分钟, 剩余 1 小时在路上, 实际娱乐时间占比是(3*8/60)/9=0.04).
但问题来了, 我们掏 600 块钱买票去环球影城, 是为了排队的吗? 理论上不是, 但实际上是: 毕竟 600 块钱玩 24 分钟, 平均每分钟 25 块钱, 一秒钟 4 毛钱, 考虑到 5 毛钱纸币 1 秒内不可能烧完, 环球影城可以说是字面意义的烧钱了. 实际上, 到环球影城的成本并不只是门票: 为了以较好的状态入园需要提前一天在旁边住宿, 为了避开人群需要请假在工作日前往, 园内肚子饿了需要在里边吃饭, 这些都应该归属到游玩的成本项中, 并导致排队行为越看越像亏本买卖----毕竟如果一天内玩不完的话下次还得再来, 再来意味着投入的成本会翻倍.
所以, 从经济学上讲, 如果希望成本最优的完成环球影城体验的话, 那么更有效的方法很可能是: 加钱, 买优速通. 成本分析如下: 环球影城单次门票 638 元, 优速通 1000 元, 总门票成本 1638. 但好处是所有项目均可视为不排队(优速通有单日总量限制, 总量限定下在每个景点最多也就排 10 分钟, 而且全程有空调吹), 一趟即可完成对 13 个核心项目的体验. 假设周边酒店住宿 200 元, 吃饭 100 元的话, 每分钟娱乐成本为 (1638 + 200 + 100)/(13*3) => 49 元/分钟. 如果改为通过玩两次完成全部体验, 则总成本变为(638+200+100)*2/(13*3) = 48 元/分钟, 看起来差距不大(1938 元一天/1876 元两天, 60 块钱), 但实际体验会差很多----相信我, 烈日下排队 1 小时然后玩 3 分钟, 排两个项目就足以让绝大部分人放弃继续排队的念想
或者有人会问: 环球影城这么贵, 为什么还有人会过去呢? 50 块钱一分钟的话, 用 3 分钟的钱去什刹海划划船不好吗? 答案是我也不知道, 可能大部分人都被 638 元的门票的假象骗了, 也可能之前真没见过排这么长队的游乐场. 至少我在去环球影城时, 看到小程序上提示的排队 25 分钟完全是不屑一顾的: 怎么可能有这么多人在排队! 然后等到进场, 才知道小程序的预估时间完全不准: 这么多人 25 分钟哪能轮得上, 至少 40 分钟起! 等再想去买优速通, 才发现有总量限制, 已经全都卖完了. 于是乖乖按项目买的优速通, 更贵.
希望以后能有钱可以随便买优速通吧