Uber与推特架构演进证实数据流决定系统成败

[Chinese] Chapter 2: System Design Basics — Scott Shi

Scott Shi

系统设计不存在通用最优解,分布式架构的核心在于通过50%负载冗余与混合读写模式守住数据底线,而非盲目堆砌代码与依赖底层数据库。

AI-assisted summary of [Chinese] Chapter 2: System Design Basics — original source. Check the original for full context.

Source published:

Key ideas

  • 工业界与 Uber 等大厂普遍将集群负载红线定为 50% 以下,以确保在机房或可用区发生完全故障转移(Failover)时,存活节点能够瞬间承载双倍流量而不至于引发级联雪崩。 (0:00)
  • 微服务架构严禁跨服务直连底层数据库,跨团队必须通过定义清晰、具备版本控制与 SLA 约束的 API 或原生异步流(Streaming)进行数据交互,以避免绕过应用层校验导致不可逆的数据损坏。 (13:00)
  • 推特通过结合推模式(Fan-out-on-write)与拉模式(Pull)的混合架构解决超级大 V 的写放大瓶颈,普通用户采用预计算推入收件箱,而大 V 推文则在读取主页时应用层动态拉取合并。 (60:00)
  • 在度量系统延迟时需关注高分位数(如亚马逊盯防 P99.9 对应的重度高价值用户),但盲目优化 P99.99 往往是不划算的,因为其长尾受客户端网络抖动和浏览器崩溃等不可控外在因素支配。 (74:48)

Detailed notes

## Background 本视频由作者 Scott Shi 于 2020 年 11 月 5 日发布在 YouTube 平台。视频简介表明,本讲主要探讨系统设计的基础概念、常用核心指标,以及工程师在系统设计实践中经常忽视的关键细节,并配有演示文稿课件供学习参考。

## TL;DR 视频围绕经典著作《数据密集型应用系统设计》(DDIA)第一章展开,深入拆解了高可用、可扩展与可维护三大系统支柱,并结合主讲人在 Uber 和 Salesforce 的工业界实战经验,对比了数据流动、跨服务契约红线及读写一致性的取舍。主讲人通过推特架构演进(从 JOIN 到推模式、再到拉推结合的混合模式)详细剖析了写放大与读热点的真实解法,并探讨了吞吐量、P99.9 延迟长尾与偶然复杂度对工程架构的深远影响。分享后半段还延伸解答了 SLA 与 SLO 的本质区别,并结合宏观经济走势向工程人员提供了职场生存策略与防御性投资建议。

## Atmosphere & style 整场讲座兼具工业界老兵的硬核实操感与真诚犀利的指导风格。主讲人语言平实且极富穿透力,不仅毫不避讳地指责工业界普遍的工程反模式,还穿插了自己早年接盘离职导师半成品架构的辛酸史,以及“9人团队给自己上线功能自嗨大半年”的讽刺幽默。临近结尾时,话题从系统高可用陡然转向大萧条与经济周期的生存法则,气氛瞬间从技术探讨切换为带有警醒意味的冷峻关怀,给听众带来极强的现实代入感与认知冲击。

## Bulletin - [00:00](https://www.youtube.com/watch?v=mosDz3n71gE&t=0s) 工业界与 Uber 等大厂普遍将集群负载红线定为 50% 以下,以确保在机房或可用区发生完全故障转移(Failover)时,存活节点能够瞬间承载双倍流量而不至于引发级联雪崩。 - [13:00](https://www.youtube.com/watch?v=mosDz3n71gE&t=780s) 微服务架构严禁跨服务直连底层数据库,跨团队必须通过定义清晰、具备版本控制与 SLA 约束的 API 或原生异步流(Streaming)进行数据交互,以避免绕过应用层校验导致不可逆的数据损坏。 - [01:00:00](https://www.youtube.com/watch?v=mosDz3n71gE&t=3600s) 推特通过结合推模式(Fan-out-on-write)与拉模式(Pull)的混合架构解决超级大 V 的写放大瓶颈,普通用户采用预计算推入收件箱,而大 V 推文则在读取主页时应用层动态拉取合并。 - [01:14:48](https://www.youtube.com/watch?v=mosDz3n71gE&t=4488s) 在度量系统延迟时需关注高分位数(如亚马逊盯防 P99.9 对应的重度高价值用户),但盲目优化 P99.99 往往是不划算的,因为其长尾受客户端网络抖动和浏览器崩溃等不可控外在因素支配。

## Key takeaways - [00:00](https://www.youtube.com/watch?v=mosDz3n71gE&t=0s) 系统设计的三大核心支柱是高可靠性(Reliable)、高可扩展性(Scalable)与高可维护性(Maintainable)。 - [03:00](https://www.youtube.com/watch?v=mosDz3n71gE&t=180s) 大多数系统停机本质是人为失误(Human Error),需要依靠敏捷规范、沙箱环境及标准流程来杜绝个人单点故障与爆炸半径扩散。 - [10:00](https://www.youtube.com/watch?v=mosDz3n71gE&t=600s) 写入持久化的核心边界是主数据库(Primary DB)落盘后即刻返回成功,邮件推送、全文搜索索引更新与只读缓存失效均应通过 CDC 消息队列异步解耦。 - [17:00](https://www.youtube.com/watch?v=mosDz3n71gE&t=1020s) 代码 Bug 容易修复,但数据损坏(Corrupted Data)难以恢复;资深架构师更关注 Data Flow 与数据假设,严禁跨服务直写数据库破坏业务约束。 - [21:00](https://www.youtube.com/watch?v=mosDz3n71gE&t=1260s) 读写一致性是架构选择而非绝对对错,追求即时读己之写(Read-your-writes)需要牺牲响应延迟,而允许异步最终一致性则能极大提升吞吐表现。 - [31:05](https://www.youtube.com/watch?v=mosDz3n71gE&t=1865s) 可靠性的本质是预期管理,可通过混沌工程(如 Netflix Chaos Monkey、Uber Hailstorm)随机模拟单点崩溃,检验微服务的容错降级与幂等性。 - [33:30](https://www.youtube.com/watch?v=mosDz3n71gE&t=2010s) 受生日悖论影响,超大规模集群中硬件故障是常态,且由于驱动与固件中间件缺陷,固态硬盘(SSD)的故障率实际上显著高于传统机械硬盘。 - [35:20](https://www.youtube.com/watch?v=mosDz3n71gE&t=2120s) Uber Schemaless 通过在常规主库索引写入的同时,向第二主库同步追加写入不可变日志(Append-only Log),以极低开销兼顾了持久性与快速故障降级。 - [37:45](https://www.youtube.com/watch?v=mosDz3n71gE&t=2265s) 与独立的硬件故障不同,软件故障具备高度相关性(如 2012 年 Linux 闰秒缺陷),遇到特定时间或条件触发时会导致全网成片瘫痪。 - [40:40](https://www.youtube.com/watch?v=mosDz3n71gE&t=2440s) 双活机房若日常资源利用率达到 60%,在单机房故障流量全部切入时总负载将达 120%,必然导致存活机房瞬时被打爆并引发全链路级联故障。 - [50:00](https://www.youtube.com/watch?v=mosDz3n71gE&t=3000s) 完善的产品研发生命周期包含技术设计、规范审查、多层级测试(单元/负载/健全性/全活容灾)、监控及上线检查清单(Checklist),缺乏监控易致盲区乌龙。 - [01:14:48](https://www.youtube.com/watch?v=mosDz3n71gE&t=4488s) 单机垂直扩展(Scale Up)因为没有 Share-Nothing 架构中多节点协调与网络通信开销,在很多场景下的性能表现远胜于上百台廉价机器构成的集群。 - [01:17:58](https://www.youtube.com/watch?v=mosDz3n71gE&t=4678s) 针对写放大严重、写远大于读的访问场景,基于 LSM-Tree 顺序追加写(Append-only)的现代数据库相较传统强事务关系型数据库具有巨大性能优势。 - [01:20:00](https://www.youtube.com/watch?v=mosDz3n71gE&t=4800s) 系统必须力求简单性以消除偶然复杂度(Accidental Complexity),避免由于频繁并购、遗留架构割裂与过度本地化演变成难以维护的“大泥球”。 - [01:26:45](https://www.youtube.com/watch?v=mosDz3n71gE&t=5205s) SLA 是对外承诺且具有法律赔偿约束的不可逾越红线,而 SLO 是团队内部设定用以指导架构优化的高难度冲刺目标。 - [01:30:15](https://www.youtube.com/watch?v=mosDz3n71gE&t=5415s) 宏观经济正面临供给与需求双休克,美联储托底资产价格延长了出清周期,求职者应转入生存模式选择现金流充沛的企业,投资上宜采取低 Beta 与黄金的防御策略。

## Detailed walkthrough ### [00:00](https://www.youtube.com/watch?v=mosDz3n71gE&t=0s) 系统设计的核心目标与可靠性、可扩展性要求

本次讲解主要围绕《Designing Data-Intensive Applications》(DDIA)第一章展开,介绍系统设计的基础概念。主讲人结合了自身在 Uber 工作中的经验,以及之前团队经历伦敦 Group Audit 审计时的规范流程,分享了符合工业界先进标准的系统设计思路。上一讲侧重于探讨“什么做法是不奏效的(what doesn't work)”,而本次的主题则是构建一个“行得通(what works)”的系统,其核心目标是设计出具备高可靠性(Reliable)、高可扩展性(Scalable)和高可维护性(Maintainable)的系统。

在谈到可扩展性(Scalability)时,主讲人指出通常需要衡量系统的吞吐性能与延迟(Latency),工业界最常见的两种扩展维度分别是应对 QPS 的扩展和应对数据容量(Data Size)的扩展。若进一步拆解可用性(Availability)与容灾边界,系统架构的设计必须满足:除非整个物理世界发生极端灾难(例如同一时间段内所有数据中心所在 Region 均遭遇大地震彻底瘫痪),否则在任何单点故障场景下服务都必须保持可用。具体的容灾梯度包括:允许机房里整排机器的单机架(Rack)宕机、允许数据中心内的单个可用区(Zone)挂掉,甚至允许整个数据中心地域(Data Center Region)完全离线,而对外暴露的服务依然不受影响。为了在极端灾难下承载流量切换,工业界(包括 Uber 内部的设计文档)普遍遵循一条关键准则:日常运行中单台机器或集群的负载通常不能超过 50%(不超过一半)。因为一旦另一半的机房或可用区宕机,存活系统需要瞬间接管全部流量;宁可承担冗余机器的硬件成本,也绝不能让服务停摆,核心逻辑始终是 "business first"。

- **高可靠、可扩展、可维护(Reliable, Scalable, Maintainable)**:数据密集型系统设计的三大支柱。 - **两类常见扩展需求**:应对瞬时高频请求的 QPS 扩展,以及应对海量存储的 Data Size 扩展。 - **逐级容灾能力**:容忍 Rack 级别、Zone 级别直至整个 Region 级别的完全宕机。 - **50% 负载红线(Load ≤ 50%)**:留足一半冗余应对故障转移(Failover),避免雪崩。

---

[03:00](https://www.youtube.com/watch?v=mosDz3n71gE&t=180s) 可维护性与人为故障:制度与流程的作用

可维护性(Maintainability)看似琐碎,却是保障系统稳定的核心。根据工业界统计,绝大部分的系统停机故障(System Downtime)本质上都是人为失误(Human Error),例如运维操作失误(Operation Error)或程序员代码引入的缺陷(Software Error)。主讲人举例提到,去年亚马逊 AWS S3 曾发生过一次严重的全局宕机事件。S3 对外承诺的持久性与可用性高达 12 个 9(99.9999999999%),这几乎相当于保证永远不会宕机。然而由于当时 SRE 在执行一大堆脚本时出现操作失误,导致整个服务中断了数小时,直接使实际可用性暴跌至 6 个 9 甚至 7 个 9,场面“非常 embarrassing”。由于违反了 SLA(服务等级协议),AWS 面临数以亿计(数百个 million)的高额商业赔偿。

为了最大程度规避人为错误,团队往往需要依赖严密的管理流程而非单纯依靠代码。例如广泛使用的敏捷开发(Agile),虽然在一些团队中并未普及,但确实是一种有效降低混乱的发明。另一个维度是系统的演进能力(Evolvability)。在许多工程团队中容易形成“寡头政治”:团队即使有十几个人,真正的架构决策和核心设计往往只掌握在两到三个人手里。如果这两三个人出现变动,系统就会面临断层。因此,如何进行知识传递(Knowledge Transfer)、消除个人维度的单点故障(Single Point of Failure),是工程管理与系统可维护性中必须解决的课题。

---

[05:00](https://www.youtube.com/watch?v=mosDz3n71gE&t=300s) 系统组件的“积木”理念与典型架构全景

分布式系统设计的整体哲学与 Linux 的设计哲学高度相似:系统由各种各样职责分明的基本组件(“积木”)构成,每个组件各司其职,架构师的任务就是根据产品或甲方需求将这些积木搭在一起。常见的基础积木类型包括: 1. **数据库(Database)**:负责基础的数据持久化、存入与调取。 2. **缓存(Cache)**:用来加速后续的二次读取(Secondary read after),极大降低读取延迟。 3. **搜索索引(Search Index / Inverted Index)**:允许用户基于关键词对数据进行全文检索。 4. **流处理与消息队列(Stream Processing / Message Queue,如 Kafka)**:负责跨进程发送消息并进行异步解耦处理。 5. **批处理(Batch Processing)**:定期处理海量累积数据,用于离线分析。主讲人结合自身背景指出,批处理常用于构建 Analytics 仪表盘,帮助公司管理层(如 CEO)监控业务表现(例如拉丁美洲市场的增长数据),配合 A/B Test 验证广告策略与收入变现,实现 "generate knowledge, derive insight"。

主讲人以一个简化的基础系统设计(以类似 LinkedIn 的职场社交网络为例)展示了各组件的协作关系:用户登录系统后,普通的读取操作直接走内存缓存(In-memory Cache);如果用户发生了写入行为,例如更新工作状态(从 Uber 跳槽至新公司,或是晋升为 Staff 级别),写入请求必须首先写入主数据库(Primary Database)。随后,通过数据库的变更数据捕获技术(CDC,Capture Data Change / Change Data Capture,如 DynamoDB Streams、Cassandra CDC 或 Oracle Golden Gate),变更会被作为流事件发送至消息队列(如 Kafka),异步触发下游消费者更新全文搜索索引、清理或更新只读缓存,以及向粉丝异步发送职位变动的 Email 或推送通知(Notification)。

```mermaid flowchart TD accTitle: User Profile Update Architecture accDescr: High-level overview of synchronous writes and asynchronous downstream propagation.

User["User Client"] App["Application Server"] DB[("Primary Database")] MQ["Message Queue / Kafka (CDC)"]

subgraph SyncWrite ["Synchronous Write Flow"] User -->|"1. Update job title"| App App -->|"2. Write row"| DB App -.->|"3. Return success"| User end

subgraph AsyncFanout ["Asynchronous Downstream Fanout"] DB -->|"4. Stream change event"| MQ MQ --> CacheWorker["Worker: Invalidate / Update Cache"] MQ --> IndexWorker["Worker: Update Search Index"] MQ --> EmailWorker["Worker: Send Notifications"] end ```

- **异步解耦识别**:在系统设计中,一旦遇到发送邮件(Email sending)或通知推送(Notification),都应当无脑选择异步机制(Message Queue / Streaming)。

---

[10:00](https://www.youtube.com/watch?v=mosDz3n71gE&t=600s) 写入持久化边界与缓存恢复策略

在这个架构模型中,主讲人向在场学员抛出了一个关键问题:当用户在 LinkedIn 上更新职位信息时,系统应该在哪个时间节点向前端返回“更新成功”?学员与主讲人达成共识:**必须在主数据库(Primary Database)成功落盘写入之后立即返回**。因为此时数据已经安全、可靠地持久化了。至于后续的缓存更新、搜索索引同步、发送邮件等,都交由异步链路完成。

紧接着讨论转向缓存容灾:如果用于加速读取的内存缓存(In-memory Cache)突然发生单点宕机并重启清空,系统该如何恢复? 1. **直接回源主库**:通过 Primary Database 读取数据并重新懒加载进缓存;或者先以冷启动的空缓存提供服务。 2. **预热缓存(Warm-up Seed Cache)**:在工业界及学术论文中,更标准的做法是维护一个指定的预热数据集(可以存储在外部独立介质或以固定配置加载),当缓存节点重启崩溃恢复时,自动拉取种子数据进行固定预热。

针对学员提出的“缓存失效重启是否会导致后端可用性下降并触发限流(Rate Limit)”的疑问,主讲人澄清了常见误区: - 数据库层通常不做限流(Database 不会主动做 Throttling)。 - 限流(Throttling / Rate Limiting)的核心作用通常发生在对外 API 入口层,主要服务于两个目的:一是**防御恶意攻击(Malicious Users)**;二是**保证多租户公平性(Guarantee Fairness)**,防止某个接入方占用全部资源导致其余租户饿死。

---

[13:00](https://www.youtube.com/watch?v=mosDz3n71gE&t=780s) 团队间的契约防线:严禁跨服务直连数据库

主讲人重点强调了微服务设计中的一条红线规则:**任何团队都绝对不应该跨服务直接读取或修改另一个团队的底层数据库**。他引用了亚马逊创始人杰夫·贝佐斯(Jeff Bezos)著名的“API 宣言”:团队之间唯一的合作方式就是通过对外暴露的 API,严禁直接访问底层 DB。这并非单纯的技术限制,更是一种组织与管理维度的刚性约束。

| 交互维度 | 直接读取/修改对方数据库(Bad Practice) | 通过定义好的 API 交互(Best Practice) | |:--- |:--- |:--- | | **版本与契约兼容性** | 数据库 Schema、字段更名、表归档均无保证,极易直接破坏调用方。 | API 具备明确的版本控制(Versioning)与向前兼容性承诺。 | | **底层维护与路由透明性** | 依赖具体的 Database Driver(如 JDBC 依赖),主从切换、分库分表运维对调用方直接暴露。 | 底层做主备切换、读写分离或迁移维护时,对调用方完全透明无感。 | | **SLA 保障** | 数据库无法针对特定业务调用方设置明确的性能边界。 | API 明确承诺 QPS 与延迟边界,受服务等级协议(SLA)保护。 | | **业务逻辑与完整性约束** | 调用方直写容易绕过外键、唯一性检验等应用层约束,造成数据永久损坏。 | 由所属团队的 Application Logic 统一校验业务假设与安全保证。 |

在小团队(比如 10 个人以内)中,如果彼此沟通密切,直连数据库的问题可能暂时不明显;但在 Uber、Amazon 这类大规模工程体系下,跨服务直连数据库会引发灾难性的维护噩梦。

针对学员提问的“缓存失效(Invalidate Cache)是否必须通过消息队列进行”,主讲人明确表示:不一定非要走异步队列,应用层直接同步调用删除往往更为高效。由于缓存通常部署在内存中(如 Redis、Memcached),单次读写延迟通常在 1 毫秒以下(部分低至纳秒或百微秒级别),吞吐可达 $10^5$ 量级,相较于数据库有 10 倍甚至百倍的速度优势,同步调用带来的延迟开销完全可以忽略不计。

---

[17:00](https://www.youtube.com/watch?v=mosDz3n71gE&t=1020s) 数据第一:应用逻辑校验与不可逆的数据损坏

为什么尤其严禁外部服务直接“写入”底层数据库?主讲人指出,读数据库可能只是破坏封装,而写数据库则会彻底打破应用层的数据假设(Assumption / Safety Guarantee)。现代很多系统(特别是 NoSQL 或分库分表体系)并不依赖底层数据库提供外键约束(Foreign Key)或强全局唯一性,而是将这些校验放在应用层代码(Application Logic Level)中执行。例如:必须两条记录同时插入成功才算有效,否则执行回滚补偿。如果外部服务直接写入底层 DB,绕过了这些业务逻辑限制,产生脏数据,这些安全假设一旦被打破往往是“永远无法恢复的”。

代码中的 Bug 容易修复,但数据一旦损坏(Corrupted Data),修复代价极高。主讲人分享了切身经历: - 修复脏数据往往需要额外开发一次性脚本(如 Scraper/Cleaner)清洗非法数据,甚至在后续的生产业务代码中打上各种“防御性过滤补丁”,导致代码结构急剧劣化。 - 丧失对数据的信任,会导致“单一真实源(Source of Truth)”失效。 - 资深工程师在 Code Review 时往往“不看 Code Flow,只看 Data Flow”:他们聚焦于数据如何流转、系统基于何种数据假设、如何从机制上保障这些假设不被打破。“Data is always first”构成了分布式系统设计的绝对基石。

主讲人回忆了自己作为应届生(New Grad)刚入职 Salesforce 时的往事(大约在 2015 年,当时 Apache Airflow 尚未普及): - 主讲人的导师设计了一套类似 Airflow 的 DAG 工作流调度引擎原型,但导师刚实现了约 20% 就离职了,剩下的重担落到了这位刚毕业一年的职场新人身上。 - 该系统非常复杂,需要处理调度锁(Locking)、并发竞争、任务调度,以及将传入的 JSON 请求解析为有向无环图(DAG)。 - 当主讲人向一位资深工程专家汇报系统代码、API 设计和实现进度时,对方直接打断并表示完全不关心 API 和业务代码怎么写,只严厉追问:**数据怎么处理?数据库中的数据流动是怎样的?旧系统数据如何平滑迁移?如何设计 Shadow Test 保证迁移数据 100% 正确以替换老系统?** - 这一经历对主讲人产生了极大震撼,也印证了后端开发的终极复杂度永远沉淀在数据本身。主讲人指出,这在机器学习领域同样适用:无论算法模型(无论是决策树还是深度学习)多么花哨,工程上的关键分水岭始终在于是否具备经过清洗的高质量数据(Pruned, High-Quality Data)。

---

[21:00](https://www.youtube.com/watch?v=mosDz3n71gE&t=1260s) 读写一致性假设与设计权衡(Design Choice)

在讨论的最后,主讲人深入剖析了前面提到的异步落盘架构所带来的**一致性权衡(Design Choice)**。

虽然在主库(Primary Database)写完后立刻返回能保障写入低延迟,但由于缓存失效和搜索索引同步是异步触发的,这会立刻打破系统的读写一致性假设(Read-your-writes Inconsistency): 1. **读自己的写冲突(Read-Your-Writes Inconsistency)**:用户 Scott 刚刚更新了职位并提交,页面刷新重新发起读请求。由于更新缓存是后台异步进行的,此时缓存中仍然驻留着老数据,用户读取缓存后赫然发现自己的职位依然是旧头衔,打破了“用户应当能立刻读到自己刚写入的内容”的假设。 2. **全文搜索索引滞后**:Scott 兴奋地告知同事祥靖:“我的职位变动更新了,你去搜索看看!”然而祥靖在客户端搜索 Scott 和新公司时却一无所获。原因在于后台工作进程尚未完成全文索引(Inverted Index)的构建与刷新。

这两种现象并非程序 Bug,而是典型的设计取舍(Design Choice)。对于发帖、改资料等社交网络场景,用户通常能够容忍“别人需要等待片刻才能搜索到我的更新”。但如果业务对强一致性有严苛诉求,系统也可以选择另一种极端: - 写入请求进入后,必须依次完成主数据库写入、更新同步至内存缓存、全文索引构建完毕,全部就绪后才向前端返回成功。 - 在这种强一致模式下,数据能时刻保持单调一致(Monotonic),各存储介质间不存在时间差裂隙。 - 代价则是极度牺牲写请求的响应时间,用户的接口响应可能需要原地等待 10 秒、20 秒甚至 1 分钟(因为构建 Full-text Index 开销巨大)。架构师必须根据具体的业务场景在延迟与一致性之间做出权衡。

[25:00](https://www.youtube.com/watch?v=mosDz3n71gE&t=1500s) 读写一致性权衡与缓存演进:从 Redis 到 Facebook 的 HHVM

在系统架构中,缓存与数据库的读写顺序完全取决于具体的业务场景。如果业务不强求“读己之写”(Read-your-writes)的一致性,系统可以在写入底层主库(Primary DB)后再异步更新或读取;但如果业务严格要求用户写完后必须立刻能读到最新数据,往往需要直接同步写缓存或更新主库后再同步写入缓存。还有一些极其追求吞吐而对持久化(Durability)要求不高的场景,甚至可以直接写入内存缓存后立即向客户端返回成功,再通过异步方式慢慢刷入主数据库。这种做法的致命缺陷在于:一旦数据刚刚写入内存(如 Redis),而在异步刷入数据库前机器发生故障,就会导致数据丢失(Data Loss),但这完全取决于业务容忍度。

聊到内存缓存选型时,Redis 和 Memcached 是两个核心代表。Redis 提供了丰富复杂的底层数据结构(如 List、Set、Sorted Set 等),而 Memcached 则是最纯粹的 Key-Value 存储。早期的 Facebook 深度依赖经典的 LAMP 架构,即 PHP 加 Memcached 的组合。然而纯解释执行的 PHP 在面对极大规模的并发流量时遭遇了严重的性能瓶颈。为了让 PHP 能够水平扩展(Scale),Facebook 内部曾诞生了一个非常著名且技术难度极高的项目——HipHop(即后来的 HHVM,HipHop Virtual Machine)。

工程师们将弱类型的 PHP 代码定义为带有类型注解的强类型语言(后演化为 Hack 语言),并通过编译器直接将其编译为高性能的 C++ 机器码在生产环境运行。虽然这对不熟悉编译器原理的人来说颇具黑魔法色彩,但 HHVM 确实延缓了 PHP 在 Facebook 的退役进程。不过在当下的 Facebook 内部,几乎已经没有人会去写原生 PHP 了,它已经被视作恐龙时代的技术遗产。这再次印证了一个事实:系统设计没有绝对的最优解,只有取舍(Trade-off)。

- **Read-your-writes(读己之写)权衡**:优先写缓存即刻返回能带来极高吞吐,但面临异步持久化失败导致丢数据的风险;写主库再失效/更新缓存能保证持久性,但写延迟更高。 - **HHVM 的技术本质**:将 PHP 加上强类型约束,通过自研编译器编译成高效的 C++ 二进制执行,是 Facebook 在基础设施层面为榨干语言性能而做的极致工程妥协。

---

[28:30](https://www.youtube.com/watch?v=mosDz3n71gE&t=1710s) 系统设计三大支柱:Reliability、Scalability 与人员流动率的隐喻

系统设计的核心原则可以高度提炼为三个维度:可靠性(Reliability)、可扩展性(Scalability)和可维护性(Maintainability)。可靠性意味着即便在软硬件故障或人为误操作发生时,系统依然能够稳定且正确地履行其既定功能;可扩展性要求系统能够伴随数据量(Data Volume)、流量(Traffic/QPS)以及业务复杂度的增长而平滑扩容;至于可维护性,由于大型软件系统总在不断迭代演进,如何保证知识(Knowledge)在团队内部长效沉淀并易于维护至关重要。

提到团队维护,人员流动率(Turnover Rate)是一个非常生动的反照镜。软件工程领域的人员流动极其频繁,例如 Uber 的平均任期一度只有 11 个月左右,Facebook 也差不多是一到两年。这种高频换血虽然带来了知识传承的挑战,但从产业健康度来看却是一种积极信号。

如果对比一些所谓的夕阳产业,比如传统的半导体芯片设计行业,人员流动率极低,一个人往往能在一家公司干上三十年。这种“新人进不来、老人出不去”的封闭环境,反倒证明行业缺乏剧烈的技术演进与创新活力。若有朝一日穿越到未来 20 年,想要一眼判断哪个行业最具发展前景,看哪个行业的人力流动率更高往往是个有趣的指标。

- **Reliability(可靠性)**:系统在面对硬件故障、软件 Bug 以及人类误操作时,依然维持预期表现与正确性。 - **Scalability(可扩展性)**:系统在 QPS 飙升、数据膨胀或算法复杂度变差(如变更为 $O(N^2)$ 时)能通过水平增加 CPU、内存、磁盘和网络资源来承接负载。 - **Maintainability(可维护性)**:在人员高频交替的环境下,系统依然能保持清晰的代码抽象、完备的文档与低心智负担的运维流程。

---

[31:05](https://www.youtube.com/watch?v=mosDz3n71gE&t=1865s) 可靠性(Reliability)的核心:预期管理与混沌工程(Chaos Monkey)

所谓的可靠性,核心本质就是“预期管理(It's all about expectation)”——确保系统在用户做出预期外行为甚至出现误操作时,依然能正确运转。在接口与系统设计中,工程师必须建立明确的假设(Assumptions):传入的一大堆字段里,哪些字段可以为 `null`,哪些绝对不能为 `null`;一旦调用方违背了假设传错了参数,系统应该如何优雅容错与拦截,而不是直接白屏崩溃。

除了功能维度的预期,可靠性还深度涵盖了性能(Performance)与安全性。自动驾驶的决策模块(Decision Making)必须在严格限定的毫秒级时限内给出计算结果;打开 Uber App 或发起打车请求,网络调用必须在固定阈值内返回;面对外部恶意攻击或突发流量时,系统必须配置限流(Throttle)机制来保障公平性(Fairness)和防滥用。

为了在分布式微服务架构中检验系统的容错能力,业界诞生了混沌工程(Chaos Engineering)。Uber 内部有一个名为 Hailstorm 的测试机制,其思想正是师承 Netflix 的 Chaos Monkey:故意在生产或测试环境中随机干掉个别服务进程,制造混乱,以检验上下游系统能否和平、优雅地降级处理(Handle peacefully)。对于强一致性的支付交易系统而言尤为如此,设计者必须假设支付进程随时可能在运行到任意一行代码时崩溃,在这种极端断电或宕机情况下,系统依然必须杜绝诸如“双重支付(Double Spending)”等致命问题。

```mermaid flowchart LR accTitle: 混沌工程进程测试流程 accDescr: 展示 Chaos Monkey / Hailstorm 如何随机中断微服务进程并验证系统容错能力的流向图。

subgraph ChaosInjection["故障注入系统"] CM["Chaos Monkey / Hailstorm"] -- 随机终止进程 --> Svc["核心支付服务 (Process)"] end

subgraph FaultTolerance["下游容错验证"] Svc -. 进程突然崩溃.-> Downstream["下游 / 补偿机制"] Downstream -- 校验状态幂等性 --> SafeCheck{"是否发生 Double Spending?"} SafeCheck -- 否 --> Pass["系统具备高容错性"] SafeCheck -- 是 --> Fail["存在致命数据漏洞"] end ```

---

[33:30](https://www.youtube.com/watch?v=mosDz3n71gE&t=2010s) 硬件故障与生日悖论:SSD 为何比机械硬盘故障率更高?

硬件故障(Hardware Faults)是可靠性最大的天敌。从单块硬件来看,制造商宣称的平均寿命往往长达 8 到 10 年,单机出故障的概率似乎极低。然而,系统规模一旦扩大到成千上万台机器,经典的“生日悖论”(Birthday Paradox)就会起效——在一个机器池中,几乎每一天都会有设备毫无征兆地突然倒下。作为大规模廉价商用机集群的先驱,Google 早在十几年前就不得不直面硬件故障常态化的问题。

更为反直觉的是,随着技术的发展,硬件故障不仅没有递减,反而呈现递增态势。固态硬盘(SSD)的故障率实际上远远高于传统的机械硬盘(HDD)。SSD 不仅硬件单元本身容易损坏,其中间层的 SSD 驱动(Driver)与固件中间件也频繁暴露出各种底层缺陷。

为了在不可靠的硬件之上构建可靠的系统,工程师必须在运维策略上推行滚动升级(Rolling Upgrades),并采用异构采购模式: - **分散机型与批次**:坚决避免全量采购同一型号、同一批次的硬件;一旦某型号存在先天性设计缺陷,不至于引发整个数据中心的大规模同时宕机(Massive Failure)。 - **坏盘即抛(Discard corrupted nodes)**:硬件一旦损坏或数据损坏,立刻下线剔除,依赖无共享架构(Share-Nothing Architecture)中的数据副本来实现恢复。

---

[35:20](https://www.youtube.com/watch?v=mosDz3n71gE&t=2120s) 数据库副本机制的妥协:Uber Schemaless 的双写日志解法

为了避免单点故障(Single Point of Failure),主数据库(Primary DB)绝不能只有单台,必须依赖多副本复制(Replication)。在同步复制(Synchronous)和异步复制(Asynchronous)之间,架构师面临着严苛的延迟与可靠性权衡:

- **同步复制(3 副本)**:主库加两台从库全部写入落盘才返回客户端成功。这种策略虽然能防止丢数据,但响应时间(Response Time)会成倍飙升,原先 100 毫秒的请求可能直接延长到 200 毫秒以上。 - **异步复制**:主库写完立刻返回 `true`,后台异步将数据推送到 Replica。大部分互联网公司都采用该方案,但存在致命窗口期:一旦主库刚刚给客户端返回成功就瞬间挂掉,而数据还未同步到副本,系统选拔新主库后,客户端以为写入成功的数据便凭空蒸发了。

```mermaid flowchart TD accTitle: Uber Schemaless 双写妥协架构 accDescr: 客户端写入主库的同时向第二主库写只追加日志,两处落盘成功后返回客户端。

Client["客户端 Client"] --> WriteReq["发起写请求"]

subgraph UberSchemaless["Uber Schemaless 写入折中策略"] WriteReq --> Primary["主数据库 (Primary DB)<br/>常规 B-Tree 索引写入"] WriteReq --> SecondPrimary["第二主数据库 (Second Primary)<br/>仅追加 Log (Append-only)"] end

Primary & SecondPrimary --> Await["两处操作均完成"] Await --> ReturnAck["向客户端返回 True"] Primary -. 突发宕机 Crash.-> Failover["从 Second Primary 读取 Log 恢复<br/>降级为只读模式 (Read-Only)"] ```

Uber 自研的 Schemaless 存储系统为此做出了非常精妙的工程折中。它在写入主库的同时,向另一台次级主库(Second Primary Database)同步写入一条不可变日志(Log)。由于日志采用只追加(Append-only)的写模式,不需要维护复杂的 B-Tree 索引结构,写入极快。只有当主库与这处日志同时写完后,才向调用方返回成功。一旦主库崩溃,系统可以立即从第二主库中读取 Log,将节点置于只读模式(Read-only mode)继续对外服务,从而在极低延迟损耗下提供了额外的持久性与可靠性保证。

---

[37:45](https://www.youtube.com/watch?v=mosDz3n71gE&t=2265s) 软件故障的高相关性:闰秒 Bug 与比尔·盖茨的 DOS 时钟黑客算法

与随机散落、彼此独立的硬件故障不同,软件故障(Software Faults)往往具有极强的一致性和高度相关性(High Correlations)。它们如潜伏的定时炸弹,在特定条件未被触发前完全察觉不到,一旦触发就会引发全球范围内的同时崩溃。

关于时钟(Clock),计算机历史上有着诸多戏剧性的经典故事: 1. **比尔·盖茨的 DOS 时钟近似算法**:早期微软在开发 DOS 系统时,为了极度节省那几个字节(Bytes)的宝贵内存,盖茨在时钟计算上采用了一套近似算法,虽然节约了内存资源,却导致底层时钟始终存在系统级的精度偏差。 2. **闰秒(Leap Second)与平摊算法**:为了让天文观测与原子钟时间保持同步,有些年份会在特定日期人为增加一秒。然而操作系统的时钟结构根本无法将 `23:59:59` 之后的一秒显示为 `60` 秒。为了抹平这多出来的一秒,工程师往往采用近似平摊算法(Leap Smearing),将这一秒平均拆分到当天的 86,400 秒中,使得当天的每一秒都比平时慢了八万六千四百分之一。

这种底层的时序 Hack 很容易埋下系统隐患。2012 年 6 月 30 日,Linux 内核因为闰秒处理逻辑的缺陷爆出严重 Bug。当时全球超过 95% 乃至 98% 的服务器操作系统都运行在 Linux 内核之上。由于时间条件不到 2012 年 6 月 30 日根本不会被触发,该缺陷在研发和日常测试中从未暴露;而当这一天到来时,全世界范围内调用底层时钟的应用程序瞬间成片崩溃,造成了破坏力极大的高相关性灾难。

---

[40:40](https://www.youtube.com/watch?v=mosDz3n71gE&t=2440s) 级联故障与双活容灾陷阱:机房 60% 水位线的惨痛教训

软件故障还往往表现为资源的过度霸占(CPU、内存、磁盘 I/O 或网络带宽耗尽),或是依赖的服务出现延迟突增、接口超时、返回畸变数据(Corrupted Response),进而诱发全链路雪崩,演变成级联故障(Cascading Failure)。

这种级联雪崩在多机房容灾切换(Data Center Failover)场景中屡见不鲜: - 很多公司建设了两个数据中心互为灾备,监控显示平时两个数据中心的资源利用率(Capacity Utilization)均在 60% 左右,运维人员误以为系统非常健康。 - 然而,一旦其中一个机房意外断电或宕机,所有流量被瞬间切入(Reroute)到另一个存活的数据中心。 - 此时存活机房原先已占用 60% 的资源,根本无法承载另外 60% 的激增流量(总需求高达 120%),结果活着的机房在瞬间被打爆、瘫痪,导致整个业务全面陷入级联溃败。

这种由于容量规划不足而导致的容灾变全灭,在非纯工程驱动决策的公司里几乎反复上演。“如果这个公司不是由工程师掌舵、不是工程师做技术决策,它一定会被这种级联故障狠狠咬上一次,付出惨痛代价之后才会学乖做容量优化。”

---

[42:50](https://www.youtube.com/watch?v=mosDz3n71gE&t=2570s) 避免人为错误(Human Error):从 Six Sigma 管理哲学到 Uber Flipper 与沙箱环境

在所有系统故障的诱因中,人为错误(Human Error)永远占据着最大的比重。著名的 AWS S3 重大宕机事故就是典型的人为配置失误(Configuration Error):工程师在调试运维时的一条错误配置指令,直接将亚马逊承诺高达“12 个 9”的高可用性,瞬间下拉到甚至不足“6 个 9”,造成了全网震动的尴尬灾难。

为了从根源上将人为犯错的概率降至最低,软件系统必须借助优秀的抽象和接口约束,做到“防呆设计”: - **管理层面的六西格玛(Six Sigma)哲学**:2000 年前后由通用电气(GE)前 CEO 杰克·韦尔奇极力推崇的六西格玛理论,其核心在于通过严密且标准化的管理流程,从机制上杜绝人类犯错的可能性。 - **解耦操作入口与生产环境**:绝不能让用户或工程师在最容易犯错的地方直接触及产生致命破坏的爆炸半径。Uber 的全球配置管理系统 Flipper 即是鲜明样本。在 Flipper 上,工程师可以频繁调整业务开关与 A/B 测试配置,如果不加以隔离,一次误改就会迅速波及全球生产节点。

防范人为变更灾难最理想的屏障是构建真正意义上的沙箱环境(Sandbox Environment)。理想的沙箱环境必须与生产环境(Production Environment)保持 100% 绝对一致——包括运行代码、底层依赖以及由生产集群源源不断实时镜像同步过来的真实业务数据;同时,沙箱中的任何误操作、数据修改或实验配置,又绝对不能对真实的终端用户造成丝毫干扰。尽管构建这种完全镜像且安全隔离的沙箱环境极其困难,甚至在 Uber 当时也未能完全落地,但它代表了防御人为误操作最高阶的技术演进方向。

[45:00](https://www.youtube.com/watch?v=mosDz3n71gE&t=2700s) 部署环境与发布流程:Salesforce 与 Uber 的对比及波音 737 MAX 的管理教训

谈到代码的集成和部署环境,讲师比较了 Uber 和 Salesforce 的实践。他认为在部署成熟度上,Salesforce 明显优于 Uber。Salesforce 最大的优势之一是拥有完善的个人开发环境(Personal Environment),所有核心代码都可以在单台工作站(Workstation)上本地运行。工程师在个人机器上验证代码没有破坏任何功能后,代码会按每三个月的周期合并推送到 Sandbox 环境。Sandbox 中的数据与生产环境(Production Data)保持严格一致,并配备专业测试人员进行全面验证。

通过 Sandbox 阶段后,新功能会优先部署给 Salesforce 内部员工(Dogfooding)。内部验证稳定后,系统开始进入 A/B 测试并向外部客户分阶段发布(Phased Rollout)。Rollout 的节奏极其谨慎:先从小企业客户开始试水,逐步扩展到中大型客户,最后才推进至核心大客户。每个 Phase 之间通常留出两周观察期。虽然这套流程走完一次完整的总发布需要近三个月,发布频率并不高,但它极度安全,几乎绝无可能发生软件故障导致大规模数据丢失的灾难。讲师提到 Uber 内部正在推进类似 Sandbox 的项目(如 Bits 工具),但他认为这种基础设施 Uber 早在该做,直言从软件开发标准和整体工程水平来看,Uber 并不像外界想象的那样顶尖。

```mermaid flowchart LR accTitle: Salesforce Deployment Pipeline accDescr: A phased rollout pipeline from personal workstation to external customers. subgraph Dev["开发与测试"] A["个人工作站 (Local Workstation)"] --> B["Sandbox 环境 (Prod 数据/测试人员)"] end subgraph Internal["内部与灰度验证"] B --> C["内部员工试用 (Dogfooding)"] --> D["A/B 测试与灰度验证"] end subgraph Prod["分阶段外部发布"] D --> E["小客户 (Small Customers)"] E -- "每阶段间隔 2 周" --> F["大客户与核心大客户"] end ```

在敏捷发布与快速恢复(Quick Recovery)方面,除了依赖完善的单元测试和集成测试,监控系统也是前置防线。在渐进式发布过程中,如果监控指标(Metrics)出现异常毛刺或错误率上升,就可以作为早期预警信号(Early Warning Sign)及早止血修复。讲师特别强调了“工程主导权(Engineering Ownership)”的重要性。缺乏技术理解的管理者强行用政治意志干预工程决策,往往会酿成巨祸。他以波音 737 MAX 坠机事故为例(《华尔街日报》或《纽约时报》曾刊登长文深度调查):当时负责的传感器工程师强烈反对将整个控制依赖于单点故障(Single Point of Failure)的探测器,但管理层为了赶工上线强行压制技术异议并强推交付,最终直接导致了惨烈的空难悲剧,涉事工程师也愤而离职。这证明良好的工程管理流程是不可逾越的底线。

---

[50:00](https://www.youtube.com/watch?v=mosDz3n71gE&t=3000s) 产品研发五阶段体系与九人隔离的线上黑色幽默

讲师结合所在团队的实践,梳理了产品研发生命周期(Product Development Life Cycle)的各个防御层级: 1. **技术设计(Technical Design)**:包括 Database Design、API Design、ERD(Engineering Review Document)、安全与隐私评估(Security & Privacy Assessment)。在没有写一行代码前发现缺陷,修复成本最低。 2. **代码规范与审查(Code Standard & Code Review)**:确保代码风格统一并遵守最佳实践,把潜在破坏限制在极小范围。 3. **分层测试体系(Testing Tier)**: - **单元测试(Unit Test)**:验证最小功能单元的正确性。 - **负载测试(Load Testing)**:验证系统高并发与极限容量下的可扩展性。 - **健全性测试(Sanity Test)**:验证关键路径与灾难隔离,比如某个微服务挂掉时,不至于引发全局灾难性瘫痪(Catastrophe)。 - **依赖前置测试(Counter-testing / Dependency Sanity Test)**:在跑重型测试之前快速验证所依赖的上游 Service 1/2/3/4 是否健康。 - **全活容灾测试(All Active Test)**:验证多数据中心故障切换(Data Center Failover)。例如旧金山(San Francisco)区域机房宕机时,流量是否能够无缝切流(Roll Over)到洛杉矶(Los Angeles)机房。 - **回归测试(Regression Test)**:从业务逻辑和端到端功能验证改动未破坏旧有链路。 - **团队 Bug Bash**:新功能上线前,团队聚在一起备上啤酒,全员以探索性测试挖掘边角 Bug,同时提升团队内部对新 Feature 的认知度。 4. **系统监控与分析(System Monitoring & Analytics)**: - 追踪系统指标、异常堆栈(Exception)、服务可用性协议(SLA,例如必须 500ms 内返回响应)。 - 移动端与产品数据分析(Mobile & Product Analytics):在注重 KPI 的现代敏捷开发体系下(如 Facebook 的增长模式),数据被深度用来衡量用户停留时间。扎克伯格曾公开表示,任何时刻线上都跑着上万个不同版本的 Facebook,全天候通过 A/B 测试驱动指标迭代。 - 讲师指出不同业务的 KPI 往往存在天然冲突:例如安全团队(Safety Team)的 KPI 是提升系统安全性,这势必会打击恶意或高风险行为,导致短期的用户活跃度(User Activeness)下降,工程团队必须在指标拉扯间寻找平衡。 5. **发布检查清单与事后复盘(Safety Checklist & Post-Mortem Review)**:发布前必须逐项核对 Checklist,发生故障后必须召开复盘会。

讲师分享了一个真实发生过的极具讽刺意味的 Post-Mortem 案例:公司另一个团队在当年 2 月份宣布上线了一个新功能,并撰写总结报告宣布该功能“已 100% 成功全量发布”。直到 11 月份召开故障复盘时,大家才震惊地发现,由于发布系统的分组配置严重失误,该功能实际上仅被开放给了对照组(Control Group)——在整整九个月的时间里,全网真正能看到并使用该功能的“用户”,只有负责该项目的 9 位开发人员自己。讲师指出,这一乌龙暴露出严重的工程短板:发布时缺少严格核验的 Safety Checklist、测试版本分配流程失控,更致命的是线上移动数据监控(Mobile Analytics)形同虚设,连该功能长达大半年全网零外部调用的事实都未曾察觉。在行为面试(Behavioral Interview)中,这套从设计、多层测试到监控的严密流程,正是回答“如何保证软件交付质量”的标准答案。

---

[55:00](https://www.youtube.com/watch?v=mosDz3n71gE&t=3300s) Twitter 架构演进:从 3 表 JOIN 到推模式(Fan-out-on-write)与写放大

以设计 Twitter 为例,讲师用 2012 年的真实业务指标展开系统架构推演: - 发推请求(Post Tweet):平均 4.6k RPS,峰值约 12k RPS。 - 刷新主页(Read Timeline):读请求高达 300k RPS。

在早期的 **Twitter 1.0 架构**中,系统采用了传统的关系型数据库范式化设计(Normalized Data),将数据拆分成三个表: 1. `Tweets Table`(推文数据) 2. `Users Table`(用户数据) 3. `Follows Table`(关注关系)

```mermaid flowchart LR accTitle: Twitter 1.0 Relational Join Bottleneck accDescr: The normalized 3-table join architecture that bottlenecks on timeline read. subgraph ReadPath["读链路性能瓶颈: 300k RPS"] U["当前用户 Scott"] --> F["Follows Table\n(查找关注了谁)"] F --> J["三表 Join 匹配推文"] T["Tweets Table\n(按关注列表拉取推文)"] --> J J --> R["聚合展示 Timeline 页面"] end ```

这种方案在写入时性能极佳,4.6k 到 12k RPS 甚至单台高配数据库机器就能撑住;但读路径在 300k RPS 的海量并发下全面溃败。因为每次读取主页,系统都要去查当前用户关注了哪些人,再拿着整个关注列表去推文表里做关联扫描(Join)。如果一个大 V(例如特朗普)发了一条推特,有数百万甚至数千万人关注他,无数用户在刷新时就必须反复对大 V 的推文记录做高频全表扫描,数据库性能会迅速崩塌,系统完全不具备横向扩展能力(Not Scalable)。

为了解决读性能问题,Twitter 进化到了**反范式化(Denormalized)的 Fan-out(写扩散/推模式)架构**。系统引入了消息队列(Message Queue): - 用户发推时,推文先进入 Outbox 消息队列。 - 后台任务根据发推人的关注者列表(Followers),将该推文直接写入每一个粉丝的个人主页收件箱(Recipient / Home Timeline Table)。 - 这种预计算策略将读操作极度简化:用户读 Timeline 时,无需进行任何 Join,只需直接单点查询自己的 Home Timeline 缓存表即可。

但这种方案带来了新的代价——**写放大(Write Amplification)**。根据 2012 年的数据,系统将发推的 4.6k RPS 经过 Fan-out 扇出后,后端写吞吐激增到了 340k RPS。写放大倍数达到了近 80 倍:

$$\text{Write Amplification} = \frac{\text{扇出后写入吞吐 (340k/s)}}{\text{原始发推写入吞吐 (4.6k/s)}} \approx 74 \sim 80 \text{ 倍}$$

这直观地反映出当时 Twitter 用户的平均关注数(Average Followers)约为 80 人。虽然当用户关注新博主时,系统需要异步把新博主的历史推文追加(Append)到粉丝的 Timeline 中,但由于关注操作的频率远低于常规读写,这在平均场景下是可行的。然而,写扩散机制很快撞上了致命瓶颈——超级大 V。

---

[01:00:00](https://www.youtube.com/watch?v=mosDz3n71gE&t=3600s) 破局大 V 热点:混合模式(Hybrid Architecture)与答疑

推模式在面对超级影响力用户(Influencer)时存在致命缺陷。以当时拥有 3100 万粉丝的特朗普(Donald Trump)为例:平均写放大虽然是 80 倍,但极端情况下的写放大倍率等于单人的粉丝总量。大 V 发一条推特,消息队列和后台 Worker 就必须瞬间在数据库中复制并写入 3100 万次。随着大 V 粉丝持续增长,系统开销不仅巨大而且不可持续。

为此,Twitter 演化出了第三种方案——**拉推结合的混合模式(Hybrid / Mix Mode)**: - **普通用户(非网红)**:维持 **Fan-out 写扩散(推模式)**。发推直接推送到所有粉丝的收件箱,因为其粉丝量少,写放大几乎可忽略。 - **大 V / 网红(Influencer,如特朗普、奥巴马)**:取消写扩散,采用 **Pull 读拉取(拉模式)**。大 V 发推只写入自己的个人推文流(Key-Value 存储),不向几千万粉丝扇出。 - **用户读取主页时**:系统在应用层进行聚合——发起 1 次查询拉取属于该用户的反范式化普通好友 Timeline,同时并行发起 N 个轻量 API 分别拉取其所关注的各路大 V 的最新推文流,最终在内存中将数据合并排序后返回给前端。这种方案在读写性能与资源消耗之间取得了极佳的工程平衡。

```mermaid flowchart TD accTitle: Twitter Hybrid Timeline Architecture accDescr: Diagram illustrating hybrid fan-out for normal users and pull for influencers. subgraph WritePath["写入路径 (Write Path)"] UserA["普通用户发推"] -->|Fan-out 扇出| Inbox["用户个人 Timeline (收件箱)"] Celeb["大 V / 网红发推 (如 Trump)"] -->|单次写入| KV["大 V 独立推文表 (Key-Value)"] end subgraph ReadPath["读取路径 (Read Path: 混合拉取)"] Inbox -->|读普通好友推文| Merge["聚合与排序引擎 (Merge & Sort)"] KV -->|读关注的大 V 推文| Merge Merge --> Output["最终返回用户 Home Timeline"] end ```

在随后的互动答疑中,学员围绕测试方案与系统细节展开了深入探讨: - **测试执行环节与工具链**:除了 Unit Test、Integration Test 和 End-to-End Test 直接嵌入工程师的代码仓库外,大型公司(如 Uber)通常有专门的基础设施团队(Infra Team)自研全套压测工具,通过标准 API 提供自动化压测平台;小公司则多基于开源工具做二次封装二次集成。讲师指出,现存许多老旧行业(如传统自动驾驶车端研发)并非标准 Cloud 环境,开发流程宛如单机软件,CICD 自动化往往滞后。 - **Timeline 存储与数据留存(Retention)**:针对学员提问的 Global Table 与 Feed/Face Table 概念,讲师澄清底层不会有所谓集中式的全局大表,一定是水平切分(Sharded)的。粉丝看到的主页 Timeline 与被访问博主自己的个人推文页(User Profile)读取的是两张完全解耦的表。对于主页 Feed 是否需要丢弃历史旧数据,讲师指出这取决于产品策略:若支持无限滚动(Infinite Scroll),短期内可以不 Drop;或者采取类似 Google News 的策略,仅预存最近数百或一千条 Feed,更早的历史数据直接丢弃或走冷读取。此外,由于主页 Timeline 数据是预生成的,可能引发数据一致性差异——博主发推后若进行编辑修改,用户主页刷到的缓存可能是旧版本,只有点进该博主的个人主页时才能看到最新的修改内容。

[01:10:00](https://www.youtube.com/watch?v=mosDz3n71gE&t=4200s) Feed 流持久化权衡与推特超大读热点优化

围绕推特 Feed 流的设计,现场探讨了数据保留与持久化的核心取舍。当用户关注的人发布大量新推文时,个人时间线(Feed 表)中过期的旧数据会被逐步丢弃或只截取保留最新的 100 到 1000 条,因为这种截断策略足以覆盖绝大多数用户的刷新场景;如果用户真要翻看几年前的历史推文,系统完全可以直接回源到对应博主的用户主页推文表(User Tweets Table)中拉取。关于 Feed 表究竟应该只存在于内存缓存(如 Redis)还是沉淀在物理数据库中,这也是典型的架构抉择。如果仅存放在 Redis 中,一旦机器挂掉,必须通过大量重度关联查询(Heavy Joins)来重建数据,海量请求瞬间涌入极易引发雪崩把底层服务器打垮。因此,更稳妥的做法是建立专门的物理 Feed 表作为后备底座,再配合内存缓存进行加速。

从业务容忍度的视角来看,读写故障的影响截然不同。用户发布一条推文后,后台若耗费 10 秒钟才异步分发到所有粉丝的 Feed 流中,用户基本感知不到,对业务几乎没有实质伤害;但如果用户打开推特 App 尝试刷新主页 Timeline 时直接报错白屏,这就是灾难性的重特大故障("This is a very big outage")。架构师在评估系统选型时必须优先考虑最坏情况(Worst Case)。

面对像特朗普(Trump)这样拥有数千万甚至上亿关注者的超级大 V,所有人几乎在同一时刻读取其最新推文,会形成极端的读热点(Read Hotspot)。一种行之有效的工程解法是通过后缀打散读负载:在存储系统中将特朗普的时间线复制成 100 份副本,Key 名后附加分片编号(例如 `Trump_00` 到 `Trump_99`)。当海量粉丝发起读取时,负载均衡随机落到不同副本上。这种方案的代价在于写入时必须扇出写入 100 个副本,且副本间同步存在微小的网络时差,系统只能保证最终一致性(Eventual Consistency),在极端短暂的窗口期内,不同用户刷到的推文可能会有毫秒级的先后差异。

```mermaid flowchart TD accTitle: 读热点副本分流架构 accDescr: 超级大V发布推文时扇出写入多个副本以支撑百万级并发读取

subgraph WritePath["写入链路"] V["大V发布推文"] --> Fanout["扇出写入多副本"] end

subgraph Replicas["打散副本集 (Trump_00 ~ 99)"] R0["副本 Trump_00"] R1["副本 Trump_01"] RN["副本 Trump_99"] end

subgraph ReadPath["海量粉丝读取"] Fanout --> R0 Fanout --> R1 Fanout --> RN F1["粉丝群体 A"] -->|随机路由| R0 F2["粉丝群体 B"] -->|随机路由| R1 F3["粉丝群体 C"] -->|随机路由| RN end ```

[01:14:48](https://www.youtube.com/watch?v=mosDz3n71gE&t=4488s) 性能指标全景:吞吐量、响应时间分位数与 Scale Up/Out

评估一个系统的性能极限,本质上是在排查硬件资源的木桶短板。任何设备上的关键资源都可能成为单点瓶颈,包括 CPU、内存、网络带宽以及磁盘 IO,没有任何一项可以被忽视。批处理系统(如 Hadoop)的设计首要目标是最大化吞吐量(Throughput),而实时交互系统则全力追求更低的响应时间(Latency / Response Time)。在度量响应时间时,业界普遍关注分位数指标:平均值(Mean/Average)、中位数(P50)、P95、P99 以及 P99.9。

针对长尾延迟(High Tail),部分核心业务必须严格盯防 P99.9 这一极端指标。以亚马逊(Amazon)的购物车结算系统为例,之所以要花巨大代价去优化 P99.9,是因为落在这一长尾区间的请求往往携带极大的数据复杂度,背后对应着购买成百上千件商品的超级高价值重度用户(Heavy User)。保障这部分用户的体验直接关乎公司的核心营收。然而,系统通常不会盲目去优化“4 个 9”(P99.99),因为到了这个阶段,网络抖动或客户端 App/浏览器本地崩溃等系统无法掌控的外在环境干扰,都会被计入该长尾延迟,强行优化只会打破投入产出的平衡。

在系统扩容策略上,存在 Scale Up(垂直扩展)与 Scale Out(水平扩展)之分。学术界与工业界多篇论文均证实,在很多场景下,一台配置极其强悍的高性能单机表现力往往强于 100 台廉价机器组成的集群。这是因为分布式系统的 Share-Nothing 架构中,节点间的网络开销、数据并行同步与协调调度存在大量额外损耗(Overhead)。虽然互联网企业由于数据规模限制普遍采用 Scale Out,但单机垂直扩展的高效性仍然不容忽视。

- **串行与并行延迟特性**:多服务串行调用时,任何一个节点的响应延迟都会逐级累加;多服务并行发起调用时,整体耗时取决于耗时最长的那个慢节点(Straggler)。 - **优化边界原则**:追求极致响应时间必须识别可控与不可控因素,超出服务端控制范围的网络丢包或终端崩溃不应成为服务端指标内耗的根源。

[01:17:58](https://www.youtube.com/watch?v=mosDz3n71gE&t=4678s) 没有银弹:写放大、访问模式与 LSM-Tree 存储革新

系统设计领域从来没有“放之四海皆准”的通用解法("There is no one size fits all solution")。系统究竟需要支持“读己所写”(Read-your-writes)、单调读(Monotonic Read),还是优先保障极致的写入响应,完全取决于业务的具体约束。当系统遇到瓶颈时,可能是请求吞吐量过大、单次传输的数据体量过大、数据结构过于复杂,或是被特殊的读写访问模式(Access Pattern)所拖垮,每一类问题都需要针对性的解法甚至催生新的存储组件。

写放大(Write Amplification)是颠覆系统读写比认知的典型现象。在推特等社交场景中,单纯看用户行为,读操作可能是写操作的 100 倍;然而推文一旦经过推模式的扇出扩散(Fanout),写操作被放大成千上万倍,导致底层存储承受的实际写吞吐量反而远远压倒了读吞吐量。面对这种写远大于读的严苛工况,诸如 DynamoDB、Apache Cassandra 以及基于 LSM-Tree(Log-Structured Merge-tree)架构的现代数据库应运而生。这类数据库不再死守关系型数据库严格的强事务一致性,而是专注于成为 Best-Effort Database,通过顺序追加写(Append-only log)与后台异步合并来换取极高的写入性能。

``` 【不同访问模式下的吞吐量等价对比】 场景 A:100,000 requests/second × 1 KB/request = 100 MB/s 数据吞吐量(高并发、极小包) 场景 B:3 requests/minute × 2 GB/request = 100 MB/s 数据吞吐量(极低频、超大包) 结论:两者的总数据吞吐量完全一致,但系统的并发模型、缓冲策略与架构选型天差地别。 ```

[01:20:00](https://www.youtube.com/watch?v=mosDz3n71gE&t=4800s) 系统可维护性与菲亚特汽车的“大泥球”灾难史

根据经典著作《数据密集型应用系统设计》(DDIA)第一章的论述,优秀系统的三大基石是可靠性(Reliability)、可伸缩性(Scalability)与可维护性(Maintainability)。其中可维护性本质上是关于“人”的问题,主要拆解为三个维度: 1. **可操作性(Operability)**:确保运维与线上系统正常运转,Google 开创的 SRE 理论著作与 Uber 欧洲工程团队的 SRE 实践均提供了深厚的行业参考。 2. **简单性(Simplicity)**:系统架构必须清晰易懂,使新工程师能够迅速上手熟悉(Ramp up),避免系统退化为难以理解的黑盒。 3. **可演化性(Evolvability)**:系统应具备高扩展性,保证未来的功能迭代、代码拓展、知识沉淀、文档更新以及事后复盘(Post-mortem)能够顺利推进,设计上要力求“最小化意外”(Minimum surprise)。

如果工程项目缺乏简单性,任由业务逻辑与技术债无底线交织,系统就会沦为软件工程中臭名昭著的“大泥球”(Big Ball of Mud)。曾有一位工程师撰写了长达十余页的匿名长文,披露了一家大型传统汽车联盟(推测为包含菲亚特、克莱斯勒、Jeep 等品牌的菲亚特克莱斯勒汽车集团 FCA)内部极其灾难性的数据库整合项目。由于该集团是几十年来资本频繁并购的产物,各个子品牌都拥有一套自建的独立 SQL 数据库与专用 API。

雪上加霜的是,在 1990 至 2000 年代前后,软件架构狂热推崇“本地化部署”(Localization),导致仅 Jeep 单一品牌在北美、欧洲和亚洲各区域就搭建了彼此隔离且版本迥异的数据库系统。整个联盟内部盘踞着上百个异构数据库。当管理层企图通过一个宏大的项目将所有底层数据库封装合并为一个统一的 API 时,项目遭遇了惨烈无比的大溃败("miserable fail")。这些系统甚至在数据库模式变更(Schema Update)机制上存在底层死结——例如某些遗留的 Oracle 数据库由于预写日志(WAL)与元数据锁定机制的限制,修改 Schema 时必须整体停机停服维护。当几百个彼此不兼容且维护窗口各异的数据库纠缠在一起时,整个项目从立项之初就注定了彻底失败的命运。保障系统设计的简单性与依赖项的精简清晰,是规避此类架构灾难的根本底线。

[01:25:00](https://www.youtube.com/watch?v=mosDz3n71gE&t=5100s) 消除偶然复杂度与敏捷工程实践

在系统设计的架构与演进中,必须严肃对待“偶然复杂度”(Accidental Complexity)。所谓偶然复杂度,是指系统面临的复杂性并非源自软件要解决的业务问题本身,也不是暴露给用户的外部 API 接口有多复杂,而是因为工程师在底层具体实现、历史包袱与流程推进中人为制造出来的泥潭。讲者举例提到,之前聊过的数据库版本割裂、大泥球架构(Big Ball of Mud)以及传统企业里僵化的流程体系,都是偶然复杂度的典型代表。与此相对,现代工程界极力推崇敏捷开发模式(Agile)与测试驱动开发(TDD),以此来规范交付流程、控制代码质量。

讲者探讨了硅谷科技大厂如 Facebook 和 Uber 推崇的入职文化——让工程师在入职第一天(Day 1)就直接写代码并推送到生产环境部署上线。讲者坦言,自己一直认为“入职第一个月就推代码是有很大风险的”,因为新人在不熟悉整体系统架构与边界的情况下盲目提交代码容易埋雷;但这些顶尖科技公司极度以代码产出为导向(code-oriented),视 Day 1 部署为软件工程师专业素养的试金石。对于不熟悉敏捷和 TDD 的同学,讲者强烈建议去阅读相关资料,特别是某些传统行业和企业对敏捷流程极其看重,行业内甚至诞生了大量的敏捷教练(Agile Master / Scrum Master)培训与资质认证。

- **偶然复杂度(Accidental Complexity)**:并非软件业务本身带来的必要复杂度,而是实现细节、架构异化或工程流程缺陷带来的额外累赘,用户感知不到但团队深陷其中。 - **大厂 Day 1 部署文化**:Facebook、Uber 等公司要求新人入职首日即完成代码部署上线,主张极度以编码和交付为导向,但也存在对系统理解不透彻带来的隐性风险。

---

[01:26:45](https://www.youtube.com/watch?v=mosDz3n71gE&t=5205s) 问答互动:SLA 与 SLO 的区别及服务间数据传递方式

在问答环节,有听众提问关于系统设计中常出现的 SLA 与 SLO 究竟该如何区分。讲者以亚马逊 AWS S3 的服务保障为例进行了清晰的对比:SLA(Service Level Agreement,服务等级协议)是一份具有法律与财务约束力的“底线合同”。比如云厂商承诺可用性达到多少个 9,一年内故障停机如果超过允许的时间阈值(例如超过 0.5 秒),就构成了违约,平台必须按照协议向客户真金白银地赔钱;而 SLO(Service Level Objective,服务等级目标)则是团队内部为了追求卓越而设定的进取型目标,比如当前 SLA 承诺几个 9,但团队的 SLO 目标是做到更高标准的指标。简而言之,“SLA 是不可打破的底线(not break-end),而 SLO 则是内部全力冲刺的高难度目标(hard-end to achieve)”。

随后有听众询问关于服务与服务之间的进程隔离(Process Isolation)以及跨服务传递数据的方式。讲者指出,服务间传递数据通常有三种途径:通过数据库(Database)、通过 API 接口,以及通过流处理(Streaming)。在大中型企业中,跨服务直接读写同一个数据库是被严格禁止的,因为这会彻底摧毁进程隔离与模块封装,“除非是五个人想怎么搞就怎么搞的小微团队,稍微大一点的公司基本不可能通过共享数据库来传递数据”。至于 API 与 Streaming,两者各有千秋:API 交互普遍是同步模式(Synchronous,虽然也可封装成异步),而 Streaming 天然就是事件驱动的原生异步世界(Native Asynchronous)。

```mermaid flowchart TD accTitle: Service Data Communication Approaches accDescr: Comparison of three data exchange approaches between services showing their isolation level and synchronous nature.

subgraph AntiPattern["反模式:共享存储(破坏进程隔离)"] S1["服务 A"] --> DB[("共享数据库 Database")] S2["服务 B"] --> DB end

subgraph Recommended["推荐模式:保持进程隔离与边界"] direction LR S3["服务 A"] -- "同步/请求响应 (Sync API)" --> S4["服务 B"] S5["生产者服务"] -- "异步事件流 (Native Async Streaming)" --> S6["消费者服务"] end ```

- **SLA(服务等级协议)**:对外承诺的最低红线,一旦被打破将触发商业或财务惩罚(赔偿客户损失)。 - **SLO(服务等级目标)**:对内设定的更高标准与追求方向,未达到不会赔钱,但指导架构优化。 - **数据流传递三种方式**: - **Database**:直接查库共享数据,大公司严禁以此跨服务交互,极易破坏进程隔离。 - **API**:标准微服务交互,以同步阻塞/请求响应模型为主。 - **Streaming**:消息队列/事件流传递,具备原生的异步解耦能力。

---

[01:30:15](https://www.youtube.com/watch?v=mosDz3n71gE&t=5415s) 宏观经济与危机反思:疫情冲击远超 2008 年金融危机

由于系统设计基础内容已基本讲完,时间来到晚上 7 点,讲者将视线转向宏观经济。结合自己对 2007–2008 年次贷危机的复盘与最新数据研究,讲者希望给正在找工作或面对裁员的同学树立一个合理的心理预期("ready expectation")。讲者犀利指出,在当前环境下“现在失业不一定是坏事”,因为宏观经济将持续变坏,未来必然会出现更大规模的裁员浪潮;如果此时能敏锐意识到危机,尽快进入“生存模式”(survive mode),主动寻找一家现金流极其强劲(cash flow very strong)的避风港企业,反而能在后续更残酷的衰退中存活下来。从地域来看,讲者判断中国在此次危机中的韧性与复苏表现将远好于美国,因此“回国发展其实是一个非常不错的选择”。

讲者强调,大众普遍被表象所蒙蔽,以为疫情在几个月内平息后一切就会重回正轨。然而从经济学(Economic)视角来看,最糟糕的时刻("the worst")还远远没有到来。本次危机与以往截然不同,它是全球产业链遭遇的供给侧与需求侧双重休克(双休克),并伴随着高通胀和法币严重贬值的巨大风险。更致命的是,美联储(Fed)在此次危机中采取了大规模托底资产价格的做法,这虽然避免了瞬间崩盘的硬着陆(hard hit),但人为扭曲出清周期的代价是极大地延长大萧条与经济停滞的时间("prolong economic depression")。讲者预估这次衰退周期很可能会长于 3 年,甚至到 2023 年都未必能够恢复,所有人切勿被股票市场的虚假反弹假象所迷惑。

- **危机认知**:疫情可能在数月内缓和,但实体经济的最糟时刻远未见底,面临供给与需求的“双休克”。 - **美联储(Fed)救市的代价**:极力托底资产价格虽然避开了短期硬着陆,但延长了大萧条周期,恢复期可能长达三年以上。 - **职业建议**:迅速切换至生存模式(survive mode),优先选择现金流充沛、抗周期能力强的企业;对海外华人而言,回国也是抵御美国长期经济波动的合理选项。

---

[01:33:45](https://www.youtube.com/watch?v=mosDz3n71gE&t=5625s) 散户疯狂炒股 vs 聪明钱防守:如何做防御性投资

讲者揭示了当前资本市场中一个极其危险的结构性背离现象。在美国政府向中低收入群体发放巨额疫情补贴支票后,最普遍的社会现象竟然是底层民众拿着这笔救济金涌入 Robinhood 等免佣金券商炒股。Robinhood 后台数据显示,最近一个月的散户买盘与卖盘极度失衡,买入量达到了卖出量的 10 倍以上,整个市场处于非理性的狂热状态。然而,真正的“聪明钱”(Smart Money)——例如美国银行私人客户部门(Bank of America Private Client)所代表的高净值与超级富豪资金,自 3 月 20 日美股暴跌反弹以来,却在持续不断地大规模净减持、抛售股票资产,转而大量增持避险黄金。

对于资金体量达到数十上百亿美元的巨富阶层而言,核心逻辑在于降低风险(Reduce Risk),只要资产维持 10% 的稳健收益就能产生数亿美元的回报,因此绝不可能在非理性泡沫中裸奔。基于此,讲者建议普通人应停止跟风投机,立即着手布局“防御性投资”(Defensive Investment): 1. 降低资产组合的波动率,挑选贝塔系数较低(Low Beta)的标的,避免持有随大盘剧烈震荡的高风险资产; 2. 适度增持黄金等抗通胀、抗系统性危机的硬通货。

讲者最后回忆起自己在 2008 年上大学、2012 年毕业时极为艰难的求职经历:华尔街早在 2007 年 10 月就已感知到危机,但雷曼兄弟直到 2008 年 9 月才正式引爆,股市在 2009 年 3 月见底,而整个社会就业和实体经济的真正复苏整整拖到了 2013 年。经济是一个高度混沌的复杂系统,美联储在 2008 年的干预力度相比今天简直是“小儿科”。今年的宏观干预规模之大前所未有,其引发的滞后阵痛和修复周期将更加痛苦而漫长。讲者呼吁大家建立清晰客观的预期("right expectation"),做好打持久战的准备,并承诺后续如果有空会专门留出时间,为大家详细拆解这套宏观分析背后的数据与研究笔记。

## Notable quotes > [00:00](https://www.youtube.com/watch?v=mosDz3n71gE&t=0s) business first — Scott Shi

> [05:00](https://www.youtube.com/watch?v=mosDz3n71gE&t=300s) generate knowledge, derive insight — Scott Shi

> [17:00](https://www.youtube.com/watch?v=mosDz3n71gE&t=1020s) Data is always first — Scott Shi

> [31:05](https://www.youtube.com/watch?v=mosDz3n71gE&t=1865s) It's all about expectation — Scott Shi

> [40:40](https://www.youtube.com/watch?v=mosDz3n71gE&t=2440s) 如果这个公司不是由工程师掌舵、不是工程师做技术决策,它一定会被这种级联故障狠狠咬上一次,付出惨痛代价之后才会学乖做容量优化。 — Scott Shi

> [01:10:00](https://www.youtube.com/watch?v=mosDz3n71gE&t=4200s) This is a very big outage — Scott Shi

> [01:17:58](https://www.youtube.com/watch?v=mosDz3n71gE&t=4678s) There is no one size fits all solution — Scott Shi

> [01:20:00](https://www.youtube.com/watch?v=mosDz3n71gE&t=4800s) miserable fail — Scott Shi

> [01:25:00](https://www.youtube.com/watch?v=mosDz3n71gE&t=5100s) 入职第一个月就推代码是有很大风险的 — Scott Shi

> [01:26:45](https://www.youtube.com/watch?v=mosDz3n71gE&t=5205s) SLA 是不可打破的底线(not break-end),而 SLO 则是内部全力冲刺的高难度目标(hard-end to achieve) — Scott Shi

> [01:30:15](https://www.youtube.com/watch?v=mosDz3n71gE&t=5415s) 现在失业不一定是坏事 — Scott Shi

> [01:30:15](https://www.youtube.com/watch?v=mosDz3n71gE&t=5415s) 回国发展其实是一个非常不错的选择 — Scott Shi

> [01:30:15](https://www.youtube.com/watch?v=mosDz3n71gE&t=5415s) the worst — Scott Shi

## Mentioned Designing Data-Intensive Applications, DDIA, Scott Shi, Uber, Amazon, AWS S3, LinkedIn, Kafka, DynamoDB, Cassandra, Oracle Golden Gate, Jeff Bezos, Salesforce, Apache Airflow, Redis, Memcached, HHVM, Facebook, Hack, Netflix, Chaos Monkey, Hailstorm, Google, Schemaless, Bill Gates, MS-DOS, Linux, Six Sigma, Jack Welch, GE, Flipper, Bits, Boeing 737 MAX, The Wall Street Journal, The New York Times, Mark Zuckerberg, Twitter, Donald Trump, Barack Obama, Google News, Hadoop, LSM-Tree, FCA, Fiat, Chrysler, Jeep, Oracle, Robinhood, Bank of America, Federal Reserve, Lehman Brothers

## Video description In this video, we talked about the system design basics, what metrics we are using and what are the point we usually overlooked in the system design,

doc: https://docs.google.com/presentation/d/1XLYvFKO_cK6fis9wuwm7bwZcrwodXbohSnP80jRhsVQ/edit?usp=sharing

[Source](https://www.youtube.com/watch?v=mosDz3n71gE)

中文简报

Uber与推特架构演进证实数据流决定系统成败 系统设计不存在通用最优解,分布式架构的核心在于通过50%负载冗余与混合读写模式守住数据底线,而非盲目堆砌代码与依赖底层数据库。 视频围绕经典著作《数据密集型应用系统设计》(DDIA)第一章展开,深入拆解了高可用、可扩展与可维护三大系统支柱,并结合主讲人在 Uber 和 Salesforce 的工业界实战经验,对比了数据流动、跨服务契约红线及读写一致性的取舍。主讲人通过推特架构演进(从 JOIN 到推模式、再到拉推结合的混合模式)详细剖析了写放大与读热点的真实解法,并探讨了吞吐量、P99.9 延迟长尾与偶然复杂度对工程架构的深远影响。分享后半段还延伸解答了 SLA 与 SLO 的本质区别,并结合宏观经济走势向工程人员提供了职场生存策略与防御性投资建议。 工业界与 Uber 等大厂普遍将集群负载红线定为 50% 以下,以确保在机房或可用区发生完全故障转移(Failover)时,存活节点能够瞬间承载双倍流量而不至于引发级联雪崩。 (0:00) 微服务架构严禁跨服务直连底层数据库,跨团队必须通过定义清晰、具备版本控制与 SLA 约束的 API 或原生异步流(Streaming)进行数据交互,以避免绕过应用层校验导致不可逆的数据损坏。 (13:00) 推特通过结合推模式(Fan-out-on-write)与拉模式(Pull)的混合架构解决超级大 V 的写放大瓶颈,普通用户采用预计算推入收件箱,而大 V 推文则在读取主页时应用层动态拉取合并。 (60:00) 在度量系统延迟时需关注高分位数(如亚马逊盯防 P99.9 对应的重度高价值用户),但盲目优化 P99.99 往往是不划算的,因为其长尾受客户端网络抖动和浏览器崩溃等不可控外在因素支配。 (74:48)

Reading summary

主讲人结合工业界实践阐述,构建高可用系统的核心在于恪守“数据优先”与防范人为失误,架构设计不存在绝对最优解,本质是在一致性、延迟与可用性之间进行业务权衡;同时在尾声提示对宏观长期衰退保持防御预期。 容灾冗余底线与级联故障防范 (0:00) 系统设计三大支柱为可靠性、可扩展性与可维护性。主讲人指出,高可用架构必须实现机架、可用区乃至全地域离线的逐级容灾。为防流量切换诱发雪崩,日常单机或集群负载不能突破 50% 红线。双机房各跑 60% 负载看似健康,但单机房故障切流时总需求达 120%,将导致存活机房瞬时瘫痪并引发级联溃败。此外,“生日悖论”导致大规模硬件池故障常态化,固态硬盘(SSD)故障率亦显著高于机械硬盘,需推行滚动升级与无共享架构提高容错。 数据优先准则与服务边界隔离 (13:00) 后端架构的终极复杂度沉淀在数据本身,主讲人强调“数据永远第一”,代码缺陷易修复,但绕过业务校验产生的脏数据破坏往往无法逆转。因此,微服务设计严禁跨服务直连底层数据库,必须通过具备版本控制与 SLA 承诺的 API 交互,以维持进程隔离并确保应用层校验生效。在数据通信上,服务间应严格区分同步 API 与原生异步流(如 CDC、消息队列),对于邮件推送等非关键路径必须无脑异步解耦。 读写一致性取舍与热点演进 (55:00) 架构演进取决于读写访问模式。以 Twitter 为例,早期关系型数据库三表 Join 在 300k RPS 读并发下崩溃;转向反范式写扩散(Fan-out)虽优化了读延迟,却带来近 80 倍写放大并在千万粉丝大 V 面前失效。系统最终演化为普通用户写扩散推模式、大 V 读拉取的混合架构。主讲人指出,优先写主库保障持久性但牺牲响应,优先写缓存能提升吞吐却有宕机丢数据风险,读热点则需通过打散副本等最终一致性策略做出工程折中。 防呆设计与全生命周期交付防御 (42:50) 多数系统停机本质上是人为失误,如 AWS S3 曾因运维脚本错误导致可用性暴跌并面临高额赔偿。为防范人员流动风险与操作失误,系统需通过防呆设计消除偶然复杂度。主讲人对比 Salesforce 与 Uber 实践,指出镜像沙箱、内部试用(Dogfooding)与渐进式灰度发布能极大杜绝故障;而忽视工程师反对、强推交付导致的波音 737 MAX 空难,则证明良好的工程管理流程是不可逾越的底线。 宏观经济双休克与防御性应对 (90:15) 在课程尾声,主讲人预测宏观经济将面临供给侧与需求侧双休克的长期衰退,美联储托底资产价格虽避免了硬着陆,却可能拉长萧条周期至 3 年以上。面对散户持补贴支票涌入炒股、而巨富阶层持续净减持股票并增持黄金的极端背离,主讲人建议求职者进入生存模式,优先加入现金流充沛的企业,投资上降低资产组合波动率并适度配置黄金以防范系统性风险。 主讲人总结指出,分布式架构设计的本质是在业务约束下识别核心瓶颈并做精细取舍,而非盲目套用模式;在工程系统与个人职业规划中,建立合理的预期管理与防御思维都是化解不确定性的核心底线。

Source quotes

[0:00] Scott Shi: business first [5:00] Scott Shi: generate knowledge, derive insight [17:00] Scott Shi: Data is always first [31:05] Scott Shi: It's all about expectation [40:40] Scott Shi: 如果这个公司不是由工程师掌舵、不是工程师做技术决策,它一定会被这种级联故障狠狠咬上一次,付出惨痛代价之后才会学乖做容量优化。 [70:00] Scott Shi: This is a very big outage [77:58] Scott Shi: There is no one size fits all solution [80:00] Scott Shi: miserable fail [85:00] Scott Shi: 入职第一个月就推代码是有很大风险的 [86:45] Scott Shi: SLA 是不可打破的底线(not break-end),而 SLO 则是内部全力冲刺的高难度目标(hard-end to achieve) [90:15] Scott Shi: 现在失业不一定是坏事 [90:15] Scott Shi: 回国发展其实是一个非常不错的选择 [90:15] Scott Shi: the worst

Original transcript

[0:00] 好 我现在开始录了今天主要讲的就是非常非常入门的叫Introduction to System Design然后这个是DDIA的第一章然后其中我也加入一些我自己的理解,还有一些Uber里面就是我们组在使用的,因为大部分都是Uber同事,我们组在使用的,我觉得有一些地方是非常值得借鉴的使用的一部分也是也是被group audit 就是那个London之前有一个audit,然后我们就使用了这个就是看我们这个process是不是符合规范的什么的,我觉得这个上面其实有很多地方,就我们这里面有一些process其实是还是非常先进的我觉得。准确来说,Design Data Intensive Application呢,你设计的目标,像我们之前上周六讲的是什么不work,这周开始讲什么work,那这个目标呢是要设计一个reliable, scalable, maintainable的一个system。谢谢大家Scalable呢你就需要 measure 它的 performance, latency,保证你可以 scale,像我们之前谈过 skill 的话其实主要是两种 skill一种skill是你这个QPS需要Skill 是吧,那另一种Skill,常见Skill是DataSize需要Skill,需要Skill这个DataSize,但是你其实如果breakdown了更细节的话,你就是应该保证,就是在任何情况下,除非你整个所有的DataCenter在同一时间段都遭去地震了,然后整个DataCenter已经就是在DataCenter不同的region data center全部挂掉了,那在任何情况下,你是应该可以允许比如说整个一个一个rack,就是一个rack就是DataCenter里面那种rack,就是说,一排一排的机器,整个rack就go down,或者是整个zone,Datacenter region里面有很多zone,整个zone go down,或者是整个data center,整个data center region就go down,但是你的service依旧是available的,就是一个scalability这个概念,就是availability这个概念,但是这个availability因为有这个要求,所以就一般来说是要求你的skill的时候,你的机器的负担,是不超过一半的,因为你很有可能要接受另一半的那个另一半漏的,这个不是Hard的要求,因为这个也是我看到一个最新的,不是最新的,就是去年读到一篇Uber内部的一个一个Design doc写到的,但是这个其实我觉得是工业界的基本需求,就是你的load是不会超过一半的,你需要prepare for the worst cases,毕竟机器来说,这个Cost比Service Donut Cost要大很多一切都是 business first然后最后一点的话就是maintainability,maintainability相对比较繁琐一点,但是其实是非常重要的一部分,因为基本上大部分的 error 就是大部分的 system done 都是 human error那Human Error可能是多种情况找到Human Error,比如说你就是传统的Operation Error,比如说前段时间Amazon S3 down掉了,也不是前段时间,去年的时候Amazon S3 down掉了,Amazon S3可是它要求可是12个9就是12个9,那它基本上是guarantee no downtime的,然后它down掉了,当时down掉了几个小时以后,它整个就这个12个9就reduce到可能是7个9还是6个9,就非常embarrassing。那为什么说这个它down掉呢?说当时是因为有个human error,它在操作的时候,它有一大堆sre有一大堆script,然后操作的时候导致了一个非常大的error。然后整个AMLONS就当掉了对他们那个business造成损失我觉得可能是以几百个million来算的因为他这个很多公司的对他的那个,他要对不停的其他的公司进行赔偿,因为他violet他那个SLA了。OK,然后Maintainable的话,最大的Error是,我们现在说System Design中最大的Error是HumanError,就是operator 的 error 或者是 programmer 的 error software error 也是 programmer 的 error 最大的 error 是 human error 但是我们能不能测计一个 process 来最大程度减少 human error 然后增加 system reliability这个 process 有时候不是一个 software process 它更多是一个管理的 process 比如说我们知道有那种我们都用agile,但是不是所有公司都用agile的。如果你跟你的主员谈的话,也不是所有人都知道什么是agile的。这个是很有趣的一点,agile其实是非常非常不错的一个process的发明。我个人觉得是不错的process发明。那还有Evolvability,比如说你们组很多时候这个我觉得这个组里面的研发都是寡头政治就是你真正的研发决定设计都就是虽然有个组里面有十几个人但是真的研发决定设计都可能只掌握在其中两个人到三个人手里面这两个人到三个人是做决定性的判断的那么怎么样把这个knowledge transfer一点怎么样做到没有single point failure作为一个就是比如说你去个 [5:00] Group Manager 你怎样做到没有 Single-Priate Failure, 怎样能把这个 Knowledge Transfer 过来, 这个 Process 也是非常重要, 这也是 Maintainability 总的一部分。谢谢大家那我们看到这个System Design呢,我们看到了就是它整体的philosophy还是和那个Linux System Design的那个philosophy很一样很相似的就是你有很多component你有很多积木你每个积木做得非常好能meet不同的needs那么你实际上做这个distribute system design就是把不同的积木放在一起满足甲方的需求满足你的那个就是你的那个whoever request的需求这个不管是product需求还是甲方的需求就满足这个需求就是从大类来分有什么积木呢?比如说可以是一个存储Data,Database就是存Data和除Data,存Data和取Data就是DataBase的功能。你可能是一个Cache,是为了speedup secondary read after,是吧?就是第二个read同一个东西的时候你可以speedup一点,然后之后的read都可以speedup一点,就是Cache。你可能是就是就是Allow user to search,不管这个data是keywords还是什么,所以你需要search indexinverted index,你有可能是从一个就是sign a message for another progress,然后 handle asynchronously就是Stream Processing或者Message Queue做相似的功能message a queueStream, Kafka都是作为相似的功能,然后你有可能是Priorically Crunch Large Month or Accumulate Data,这个的话就比如说你Generate Analytics,因为我过去经验在Analytics,所以我在Batch Processing工作的时间稍微多一点。这个其实不是Customer Facing的,比如说这个的话很多时候就是说,你生成一个Dashboard,给你们公司的,比如CEO,给你们CEO说,我们现在这个区域在拉丁美洲有增长,那么是不是我们可以在拉丁美洲增长,然后做很多A/B test说,我们打广告以后这样的收入,这个收入增长怎么样,我们做这些high level的通过data,然后generate knowledge,然后通过knowledge, derive insight,然后做这种high level的帮助business的一个decision,谢谢大家所以这块的话我们看到一个非常简单的一个system design呢,就是这块list就是一个starter,我觉得就是非常simple的一个starter system design,但是它虽然是starter,但它其实有很多很多值得考虑的地方,比如说这个system design呢可以非常简单就是,你就是比如说假设这是一个linkedin website好了LinkedIn website我login了,ininkin了,然后如果我是RAID的话,我可以去读cash是吧,我可能就很快的读cash。如果是RAID的话,比如说我更新我的job status,我说我突然换工作了,从Uber换到一个ABC公司。很好我就可能是要一个write 因为它这个write的话一定是go to primary database的所以我说我换公司了或者是我换职层了 我升职了 我突然升到staff了 我升职了那么我去更新,那我更新的时候这个Primary Database呢有的是支持Capture Change Data的,Capture CDC,叫Capture Data Change,有叫Capture Change Data,这个是在Dentmo里面。是支持的,有一些Cassandra也是支持的,Cassandra也是支持的CDC的。有一些 Oracle 的 database,比如 Golden Gate,是专门做这个 CDC,说白了什么呢?说白了是你在data里面change一个东西,然后比如说你modify,像我这种case,我modify title了,我升职了,升职这种stuff了,那么这个就变成了一个Row 就是Scout 升至上staff 是吧那么这个CTC会变成一个Streaming 然后这个Streaming 可以通过另一个handler 这个Streaming 可能是Message Queue 可能是Kafka然后trigger另一个application called Asynchronizedly然后做什么呢?你可以update这个search index 是吧?那这样的话别人search的时候就search上scout的最新的title 是吧?然后或者是呢invalued已有的cache 是吧 就是这个inmemory开始 然后update成新的那你在读的时候,你就可以读到最新的了。然后同时,有的那个linking,比如说你做职位change的时候,你也可以trigger那个email,是吧,这send说你的follower email,那这个可以是asynchronize,当你更新完的时候,当你在primary database更新完的时候,那我就触发一个email send,基本上大家想到一些非常fundamental的一些东西,就是有一些fundamental的一些option,你当你看到这个option的时候,你一定要想到是asynchronize做的,比如email send的,比如notification,这都是asynchronize做的,你看到这个email send的,就是asynchronize,然后看到notification就是asynchronize [10:00] Asynchronized一般来说可以Message Queue, Streaming, Kafka,在本质上是可以相互交换的那你就Sign Email,Sign Email说这个Scot有职位变动是吧然后这里面其实有很多有趣的地方首先我们在什么时候 return 给我,比如说我在link in,更新了就是computer里面任何一个地方component都可以fill掉那么我在什么时候告诉LinkedIn这个website,假设整个是LinkedIn这个website,Ninkin在什么时候告诉我我的那个这个job title update 成功了有人想说一下吗有人想就是讨论一下吗?LinkedIn应该在什么时候告诉我我的Job Title Update 成功了?我觉得应该在更新完primary database应该就返回了吧对,那我为什么要在更新完Primary Database以后就返回这个Job更新成功了?因为这样的话就是这个更新就已经持久化了所以谢谢大家所以就是数据经验就是已经已经安全了所以这时候就可以返回返回这个成功的那个信息非常好,这个数据就已经安全了,这个安全是reliable存储下来了,对吧?那么如果是这样子的话,我们讨论一下,如果这个in-memory cache挂掉了以后,那么这个数据是被保存下来了吗怎么样recover,这个in-memory cache,突然这个系统崩掉了,这个机器崩掉了,那我们怎么样recover?好开始崩掉的话应该是不是可不可以通过这个primary database吧email cache 里的数据在录的进去对这个可以是吧,或者我们直接,反正它是个cache嘛,那就上来假设你就有个Empty Cache也可以。然后常见的做法呢,包括paper里面常见做法,工业的做法呢就是,你有一个Warm-up Seed Cache,就是这个Warm-up Seed Cache一般是,就是存在一个另一个地方,或者是Hard-Code也可以,就是你指定这些是Warm-up Cache也可以。有多种方法,就是指定它是Warmup Cache也行,如果它这个Cache崩了以后,你就直接新建一个,然后从这个Warmup Cache这也是一种常见的做法,就是相当于把你这个开始固定 warm up 一点。好,这个问题很好。我想问一下,这间的availability会不会降低,就是比如说你做warm up 的时候,你要做一个rate limit 之类的会发生?rate limit和cash不相同的。就是那个你不是现在cash里面是清空的吗?假如你一下子恢复的时候有很多client request的话,会不会要做收头一下?我觉得大家这块理解了,理解错了,SOTO和Rate Limiting都是对于External Customer或者是internal customer,但是你是为了一些sanity test,你要做那个什么的。但是一般来说,如果比如说你的request是来自另一个service,这个service是internal customer,你只要做非常basic的throughton,你行吗?database是不throughton的。意思就是说从API那边那个levelsertle?对,所以说external,sertle的目的是什么?是防止malicious user主要是两个目的吧一个目的是防止 malicious user其次要guarantee fairness 你不能一个user再用太多资源对吧,如果你比如说你系统你是个 service,你是个 base service,你提供 service 去十个其他的 other team,如果你不搜索头的话,一个 team 可能把所有的资源都占用了,那剩下九个 team 对你的那个影响就非常差。是guaranteed fairness,所以Sroto是这个目的的,但是database没有这个需求,database对它来说,它不是一个,它没有这种business需求,那你也不会直接,你作为一个team来说,你也不会直接把你的database expose给其他team,这是fundamentally run的,那你可以参考一下这个amazon的这个设计,amazon的这个设计,amazon的这个设计,说我两个team之间,这是他们CEO Jeff Barrows说的,发的邮件说两个team之间他们唯一能合作的就是API只能通过API来合作,你不能直接一个team读另一个team的database,就是这个意思你永远不能两个team之间你不应该是直接读另一个team的database,你应该是通过它的service来读的,因为service的话有不同的sla,sla是service level agreement,比如说你committed的你能支持多少的qps,lentense有多少之内的,所以你不能任何一个design来说你是不能直接读另一个team的database的,如果这个有的话这个其实 [15:00] 会有很多很多麻烦这个不是technical的麻烦这个是个管理上的麻烦就是一个organized的麻烦或者能说数据库的那个schema,人家组织有那个API是有promising我的version,我compatible,但是我DB可以改,可以做maintainance,你的路由啊什么的都不是很确定是吧?我不是很清楚这个表达的观点是能几个字吗? -哦,就是说不读因为我直接读你另外一个部门的数据库嘛如果你的表的更改了或者你现在那我通过API的话我那个煮备份的话那个当了的话我API肯定才去读那个备份的那个我直接读你的话我是不是直接就访问你database的instance了就GDPC dependI was sorry,不一定是GDPC,有这个Database is your driver多谢观看也不支持这些东西,在一个人家的表改个字段的名字之类的或者是我把这个表照不掉了,archive,我们说的这个没有任何是技术方面的,更多是管理方面的,就是特别你到一个稍微大一点的,比如说Amazon这种level,或者是Uber这种level,小team的话,其实你直接读database,10个人的team,一个stab,10个人结束Databets,你如果两人之间的agrements一致的话有时候也没有那么严重的问题,但是你到一定大的程度的话,你是不想直接读DTW,这更像一个manager process的一个方面。然后 包括 继续 不好意思啊这个有不好意思另外一个问题可能有点偏提但是就是说当我们invalidate开始的时候一般在工业界的成功做法是通过一个消息对立是吗Invalid cache,您可以直接Invalid,没必要消息对立,您可以做那个消息对立,就是message queue,但是您可以直接Invalid,因为所有的cache的操作基本都是database的10倍以上。开始可以很快很快的相当于从 application code 直接tog to开始 然后把它invided掉对开始可以很快开始没必要asynchronize做 因为你开始breedits可以serve 10的5次方lentens基本上在1毫秒以下MAM开始更快可能不到100纳秒的样子一毫秒下面更下那个什么,反正小于一毫秒,我基本觉得基本Lintency可以无视了,很小的。好的好的所以很多时候系统面试的时候,它不是面试技术层面,这种就是业界大家公认的就是你talk的时候你不应该通过直接modify另一个组的database这也是非常重要的就是你需要有这种agreement 和 understanding 的理解然后不 modify database 有另一种可能就是谢谢读可能还相对好一点,但写一定是不能自己直接写的,因为写的话它可能有一些在application logic level,inforce的东西,你直接写的话就broke这个 assumption了。比如说现在的如果你不用MySQL的话,有很多就有ForeignKey这种relationship,你是不可以通过database来inforce的。那你会在application的角度来inforce。什么叫application角度inforce呢?就是说我在写的时候,这两个肉是一起insert进去的。如果一个insert坏的话,我另一个会有about,是吧,就是application,就是相当于是你用application和code实践的一些restriction,比如说uniqueness 比如说Foreign Key如果你直接写的话 你可能就无视这个restriction 那你就broke了它的assumption了这个assumption 或者叫Sifted Guarantee 一旦broke了以后是永远没法recover的那整个他们这个系统可能就不能用了所以说,code就是如果你写code写错了,introduce 这个 bug 是比较好修的,但如果你在database 里面,在 data 里面crafted,这个维修起来是非常非常非常困难的,你可能需要有设计不同的,比如说你可能需要一个,我之前就靠Slipper去说,我找见所有不符合Assumption Data,然后Clean掉,这是一种常见的做法,那种做法说,我可能我可能遇见invalued data,我就直接filter掉什么的这种,这已经属于非常非常bite的情况了,因为加了很多很多很多东西,就把你code变得很乱。因为你现在不trust你的data,那你怎么样在application level再handle呢?然后如果你有conflict data,你其实是souce or truth data,你变得非常糟糕。所以很多时候你如果问就是非常senior的,他就不看你code。它看你怎么handle data它不看你的code flow 它看你的data flow 你data怎么flow过去 你怎么样handle data 你data assumption 什么 你怎么样guarantee assumption这个是非常重要的,就是data永远是在这个distribute system是核心中的核心。我记得我做一个new grad加入的时候,我当时我的mentor走了, [20:00] 也是聊一些闲事,我第一个project是写一个像Airflow的东西我们当时那是15年,所以那会没有没有airflow 还没有那么popular然后Southforce要研究一个像Irflow的一个东西那我mentor设计了一个类似于Airflow的东西,然后就走了,它只时间了大概20%设计完了以后,我就开始写,那我那会儿的话开始就是就是写Rflow这个东西是吧就是你也知道Airflow还是相对比较复杂的,你有一大堆scheduler,你要有很多做locking,然后你有concurrency怎么处理啊,然后你怎么样handle customer code,Airflow是application code,是python,我当时写的那个application code其实是json,就是我post这个json request,然后把它变成一个daj,然后变成一个daj,那么因为我当时,你想,new grads只有一年的经验,肯定解决不了,那就过来一个非常senior的engineer,所以他过来过去,我解释的时候,我跟他解释说这个写到哪里了,我写了哪些部分,然后mentor走之前写到哪些部分,designer怎么那样子的,他说我不care这个,我只care data,你data怎么处理的,database的data怎么处理的那你application code,API 什么,他不看,就看Data。这就是我当时就我觉得就蛮震撼的一点是吧,因为你在研究生不管是NeoGraph研究生的话,你想的是这个API怎么样,他不看那个就看这个Data怎么处理,也有Data怎么处理的之后的data怎么处理,因为我当时写的是replace existing system,它要做data migration,那我data migration 的时候怎么样guarantee这个data也是valid的我怎么样把Data migrate了以后,怎么样做Shadow test,那我怎么样能保证它Completely replace your system就是说是这个整个这个流程其实非常复杂的,所以所有的backhand code复杂点 运在data always first这个是在machine learning中也是一样的你可以就是我觉得也是 Machine Learning Engineer 的一个共识你有两种可能,一种是你有一个非常fancy的各种的那种这种tool是吧,你可以选择decision training,你可以选择deep learning,各种的东西,另一种是你有一大堆其次,algorithm什么的,其实performance differentiator不是那么大,最重要的是data,data一定要是high quality的,prone过的data。好,我们再说这个,刚刚同学回答的非常对啊,就是你在写的时候,在什么时候返回于success呢?那你在primary databasesave 好的时候,你就要返回success,说你这个scout的title change成功了。但是会有问题,什么问题呢?因为你的这个invalidate和update cache是商户台做的如果我refresh一下Pager我可能看到我还是旧的title这个问题叫 read or write,你是不consistent的,因为当我read的时候,那我会看,哎,我这个read request 有没有scout,scout确实在in-memory cache里面,所以你read happen 在这个primary database update 之前,所以你这个就violate了 radio-righted assumption对吧,那你也可以说,那我也可以说,我在这个update primary database 的时候,我先把 cache 更新了,那你就没有 valid read outRead or Write assumption还有可能存在另一个问题是什么呢?我刚更新了我的title,非常开心啊,我跟我跟祥靖说,祥靖你看我太多更新了,你search一下吧,然后祥靖另一个优子在这 search,search Scott,然后新的公司,然后没有涉及到,为什么呢?因为他这个application的那个search index还没有update到这个full index,full index index上,所以你search的时候还是search不到,那这个的话就broke了另一种assumption,这个可能相对还好一点是吧?就是你毕竟大家都有这种理解就是你更新了自己的post别人不能第一时间看到,这个也是一种assumption,这是一种user对于你这个complete assumption,就是你更新了post你可能需要一点时间来看到我想说这些都是design choice,什么叫design choice呢?我可以说我把这个update request变得很糟我只有告你这个user你update成功,只有当前紧张什么时候发生的时候我update的primary database成功了然后我update in memory cache成功了 我index好了 然后告诉你这个user你的 update 成功了这个是有可能,这纯粹是另一种,就是Design Choice,这种情况下的话,你可能这个Request要等10秒钟,10秒钟,20秒钟,剩1分钟,Full index,Full index,这个相对时间比较长。但是你update成功以后,你说的data都叫monotonic的,就是说你的data都是consistent的这几个 database 之间就是这几个 in-memory cache, primary database, full text index, data consistent [25:00] Did I try? What are you choosing? It's based on your business use case. There are people who don't care about radio rights. After writing it, You can read it and read it and then you can update the primary. There are people care about the original right. Then just write in memory cache. Then write in the update database and then write in memory cache. And the most famous thing is that What is the use of a situation? I don't care about durability, there are times you don't care about transactional data, but I don't care about durability. I just want to write in memory cache, I will return to the end. and then in memory cache Asynchronously, we can write primary database. This will be more difficult for you to write database. It will be more difficult for you to write. This problem is The problem is that if you wrote in memory cache, but you wrote in memory cache, and you wrote in redis, when you wrote in database, failed, then you will have data loss. But some business can tolerate data loss. is also able to accept. I saw some questions. I see there's a problem. Redis is in memory cache, there are redis and memcache. Redis is a very complex data structure, such as list, set, and Memcache is a key value. Memcache is the main value of Facebook. Facebook is now using PHP and Memcache. Facebook was in PHP and MAMP. But it didn't scale PHP. There was a very famous Chinese project. HHVM. By PHP code. Compile from C++, application programmer in Facebook is Application Program in Facebook is PHP, but they are defined as strong type of PHP. And they will put strong type of PHP, So it's a production run, it's a C++. It's a compiler. It's a compiler. It's a compiler. It's a very interesting topic. But you don't know compiler is totally fine. I'm very curious. This one is called HPHP. I guess it's called HHVM. Yes, this project is also very difficult. It is also because of performance. Because PHP is too much. Now, from Facebook, there is no one uses PHP. It is a very dinosaur. I'll see you later. My personal opinion. I'll go to the next page. Do you have any questions? There are some questions in the slide. Actually, I want to draw a very simple example. If you think about system design, this is a very simple example. This is to discuss different trade-offs. For example, you should be able to do radial right, or should you guarantee reliability, or should you guarantee monotonic. But from this one-year, just show this, it's a system that's a trade-off. It's totally dependent on your case. Okay, let's talk about the system design principle. It's mainly three points: reliability, scalability, maintainability. Reliability is that the system should continue to work correctly. You have some assumptions, you have some assumptions, you have some assumptions, and you can tolerate some faults. hardware fault, software fault, human error. Scalability says this system can continually grow, whether it's data volume or data volume. traffic volume, and complexity. Complicity, this actually will be... because you have QPS has increased, but you suddenly change the algorithm, and you become N squared. Then you need more of a machine. This is also another one. But it maps to the底层, you can definitely use CPU, memory, disk, network. So you need to increase. And the last thing is maintenance. You will work on different systems, especially the software. The software's movement is very large. I saw Uber is the software's movement in the company. Like Uber's movement is very large. Turnover rate is 11 months, Facebook is very high, 2 months. Turnover rate is very high. You are constantly driving, and you are constantly driving. How do you keep your knowledge of your knowledge? This is very important. From the beginning, turn over is a very healthy experience. So I think that I do not understand the whole thing. [30:00] 没有找到任何一个行业比较更好前途你会看到西洋产业的话,比如说一些西洋产业,比如说半导体设计,其实也不算是西洋产业了但是这些产业的话,它那个turnover rate非常低,一个人在一个公司能工作30年,那这样的话其实也不是一个非常health的一个行业,就是你新人进不来然后老人出不去这个不是一个很housie的行业,所以我觉得这个是,如果你判断,比如说你突然时间穿越了20年,然后判断最新的时候哪一个是最popular的行业,看哪个turnover rate最高的话一般来说是比较popular的行业。但是也难说,因为有些服务员这个turnover rate也很高,这个也是跟情况来看。OK, Reliability 什么呢?就是你这个 application 需要 perform the function user expected你可以允许user make mistake 或者是允许suffer in unexpected way 然后呢说白了一次, it's all about expectation.那我有一些assumption,就是你怎么样使用我的系统,我有一些assumption,比如说你passing了一大堆field,那哪些fields可以是now 哪些fields不可以是now那如果你 make mistake 以后,这个 field 本来不能是 nod 然后你便 pass 一个 nod 过来,那我应该怎么样 handle 它,然后就是Assumption,然后Handling,还有的话,它就reliability包含Performance,那比如说你要做自动驾驶的这个,假如说做自动驾驶的这个Decision Making,那你必须在保证你在多少之前返回,那比如说request一个Uber,你必须在多少之前返回,你打开Uber App,你必须在多少毫秒之内打开,这都是一些Performance相关的,然后最后的话是防止这个Authorize Access Abuse,去保证你自己的系统加一些shortle,保证你的系统不被外部的malicious user,或者是Guarantee Fairness就不被其他的那个Service 啊 再用更多好OK谁说很多时候,Uber有一个叫Hillstomp,就是直接把你这个service关停,就是你比如说你这个service关停,然后看上下游能不能handle peacefully这个其实好像是Netflix的Chaos Monkey作为这个先驱的说白了就是说,为了保证你这个系统是fault tolerant的,就是你这个micro service在整个大的系统里面是fault tolerant的,那么我就intentionally increase 这个系统的出问题的可能性比如说突然就random的kill一个individual process,没有任何问题,然后看一下你这个系统能不能handle peacefully。这个是对于有一些payment系统是非常重要的,比如说你的payment设计,你要考虑在任何一个program run的时候,任何一个process都可能直接crush掉。那后面能不能处理正确,有没有double spending,有没有double spending的情况,有没有这种各种各样的情况,主要是double spending。谢谢如果我们来看reliable的反面就是fault的话,主要就是一些hardware faults,比如说这个现在已有的Hardware Faults是Hardware是好多都是guarantee就是你可以run10年左右10年 8年 10年 就是它那个 average 其实那个 life span 很长但是我们上一次讲过一个叫做 birthday paradox那当你有很多在能 run 10 年左右的机器的话那你有非常大的可能性,今天就有个机器突然倒掉了,就是BIRTHDAY PARADOX。其实在现实生活中,Hardware Faults happen all the time,特别在Google这块。Google也是Hardware Faults最早云云处理的先驱。并且现有的科技的话,越先进的科技可能我们有更多的Fox,SSD的Fox是远远大于Disk的,SSD的不仅是HardwareFox很多,它的Middleware,它那个SSD driver也经常抱出各种各样的问题所以它虽然更快了,但是它的Fault其实更多的,就是说Hardware Fault不是递减的,它是递增的,所以我们必须要想办法去处理它,那怎么样处理呢?我们可以rolling upgrades,就是一个一个upgrade,比如说你这个Hardware的时候,你就所有的机器不采用同一个机型,分批少量采购,如果其中一部分挂了的话,另一部分还能用。比如说它设计的这个型号有问题,你还可以用其他型号来代替。它这个型号出问题的时候,你也不会massive failure,这是一种。谢谢大家这个说要减少风险的话就是 [35:00] 我们接下来讲那个这个我会讲一下那个08年金融危机啊我跳的有点多那个也是所有的风险到一个篮子里面了然后导致这个风险暴掉了啊今天我会讲一下那个我也觉得非常有趣,就是有一些相连性的然后这个hardware还有常见的话就是,如果你这个hardware出现false的话,你需要把cropted1给discard掉,然后这是 hardware 处理,然后其次的话现在的share nothing architecture 还讲究replicate你比如说这个 hardware 如果出问题的话,你确定它出问题了,你不能 recover 了,那你去一下它的备份里面,replicate 的备份里面去看。说起来 replicate 的话,其实我们刚才这个问题上有一个 fundamental 问题,就是 primary database 它不能是一个,它必须是多个因为你如果是一个的话,就是Single-Port failure,如果你这个Primary Database down的话,你整个Data就Loss了。那如果你这个Primary Database是多个的话,那多个之间要做Replicate,那你这个Replicate是Synchronized,Asynchronized也是有讲究的。这个是非常有趣点就是你synchronize还是asynchronize如果你是synchronize的话就是说你这个database你在写的时候你写进去假设你synchronize常见的是synchronize备份两份嘛就是加上primary是三份嘛如果你是要求是三份全部写完的话那你的那个response time可能是要可能是要除个二甚至要更多的比如说之前100毫秒你可能要200毫秒了如果是asynchronized的所以大部分公司现在都是asynchronized的你可能会有潜在的问题是你这块返回处了,但是你replicate的时候出问题了,就是你这个primary database已经返回处了,你的replicate出问题了,在你replicate到其他database的时候,你这个primary database down掉了。所以你的replica是没有新写的data的,然后这种情况下的话,你的server会coordinate说我需要把一个replica变成primary,那你这种情况下,你returned customer是true,但是你这块lossed data了。Uber那个scheme-less做了一个compromise,如果大家看的话Uber Scheme-less做了compromise是什么呢?它写了primary database直接写的,在另一个secondary database里面不是replica,是在Second primary database 里面是写了一个log的这个log是,因为它只写一个log,就是append过去一个log一样,它就像它写的快,它会不像Btree一样,Btree写起来比较慢,它直接写在log上写的比较快。所以它是这两个都完成了以后,然后会返回处。如果你的primary倒掉以后,你可以去secondary里面,second primary database里面,读log 变成一个止读的模式啊不能变成写变成一个止读的模式然后这样的话是就是 add extra data reliability, durability guarantee.你会看到它这个复杂度其实你看到一个system design的问题你把这个问题搞清楚了你就可以解决很多很多问题很多问题都是相似的好,我们接着看,所以Hardware faults是非常Random的,所以如果出现Hardware faults,你就解决就行了,反正就换掉就可以了,你只要有Systems足够的replicate的话,你就可以解决这个问题,但是Software faults是比较有一致性的,比如它之间有非常强的high correlations,比如说在2012年的时候有一次Linux Kernel有一个leap secant,很多application就crash掉了,这是出现了一个问题,然后说到这个也是跟clock相关,另一个clock有很有趣的问题是有些时候有两个Clark的故事很有趣第一个Clark的故事是就是早些时候微软的那个盖茨,Bill Gates写那个system的时候,他通过了一个近似算法来算他的那个时间。他会写一个近似算法算时间,因为他如果不采用近似算法的话,他会额外再用几个byte的memory,所以用那个近似算法来算这个时间,导致他那个memory使用量更小一点。就是来计算他那个最早的那个operating system,好像是,就是一个DOS系统,它是用近似算法来算时间的,所以它会有一个不准确性在它那个Sys Hub 下。然后,另一个故事呢,不是故事,另一个Story是一个比较新的一点。谢谢很多时候有一种leap second,就是在某天的话有个leap second,它是为了保证它那个时间和那个固定的节点一致。那如果有这一天多了一秒的话,它没办法把那个second的时间从60变成61,就是你的那个operating system没办法把60变成61。那它怎么做呢?它在这一分钟的时候,它把这一秒,均匀的分到这一天上所以你在这一天的时钟实际上是86400秒,那你这一天的这个时钟呢,每一秒都比 [40:00] 其下的一天的时钟慢86,400分之一就是把这一秒平摊到这一天上了也是一个近似的算法,也是算这个leap second的,所以你可以看到这个因为你做了很多这种hackage的处理,所以很有可能会造成Error。当你出现Error,特别是在Linux Kernel的话,有这么多,世界上95%以上的,现在的话可能稍微低了一点,因为Windows Cloud还是挺popular的,但是之前的话世界95%甚至98%以上的那个,server都是Linux kernel,如果Linux有一个问题,它不到这个时间段不trigger,不到这一天,不到June 30,2012不trigger的话那他就永远不可能被发现但是他到这天trigger的时候他整个系统就massively failure你只要run它这个系统,你掉用它的时钟,你就massive failure所以这个subfairware法则是high correlated所以这是非常难以抓到的一点,也是非常damage非常大的一点好然后,这是一点,然后其次的话,你比如说你这个software files可能是在用过多资源,你比如说你在用过多CPU,memory,disk,network,然后你这个software files呢有可能是你depend on system,然后那个system unresponsible,或者是start time非常slow,或者是crofted response。然后你可能会造成Cascade Feeling,比如说一个component的一个small fault,然后trigger了另一个component,然后不断的变成Cascade Feeling这个Cascade Filling和Data Center Fill Over很相关,你比如说你这个Data Center Fill Over有很多这种Cascade Filling,你当你做capacity,就是当你做Data Center这个Monitor的时候,两个Data Center capacity就是那个Resource Utilization都在60%。那你如果一个Data Center跨了,那所有的traffic rewrote到另一个data center里面,那你就变成cascade filling,因为你这个data center已经60%了,你不可能handle另一个data center的60%的resource utilization rate,那你就cascade filling。这个是出现过无处次了,在不同的公司出现过无处次,并且我觉得如果这个公司不是一个engineer run的话,不是engineer做决定的话,他一定会被bite一次死的很惨,然后他会做这个做优化,这个是repeated failure。好然后最后一点的话就是那你怎么样去怎么样去处理它呢 你需要close monitor和analyze the process in system然后你做update的时候需要incremental update然后就剪到Human Error,所有的系统中Human Error是最大的一个Error,所以说我们要怎么样处理这个Human Error呢?常见的解决方式就是我们之前也讲过这个Configuration,那个Amazon S3的Configuration Error,然后导致它直接从12个9,就是它保证Availability是12个9,那就是一年可能只当0.几微妙这种,然后突然就变成了6个9不到,就是非常embarrassing。我的availability guarantee不是太高然后我们这个就是design,你可以是design一个system,就是minimum opportunity,就是比如说你有一个非常好的well-designed abstraction,interface to the right thing,这块呢有一本书写的很好,就是那个,日本有一个叫Just-in-time日本有一个叫Sigma理论它是个管理层的一个理论就是说怎么样设计一套管理的流程,怎么样设计一套管理的系统,它从process 杜绝你那个犯错的可能。我没有读过那本书,但是我读过一些简介,叫Six-Sigma理论。还有很多那种Business Training,叫Six Sigma,然后他是被那个GE的那个总裁推荐了很多次,所以在2000年时候特别火。就从Process的角度来杜绝你这个出错的可能性然后另一种常见的方式就是Decouple the place,比如说 people make most mistake to place they actually can cause a failure,这个 people make most mistake,Uber同学一看就知道Flipper,是吧?Flipper是一个Uber的一个Global Configuration Service,你在上面可以做一大堆Configuration Change,就是比如说你就是突然改了这个A/B test,改了这个Flipper,那如果你把Flipper和这个production deployment 分开的话,比如说你说的 flipper change,你必须有一个,有一个,有一个那个promotion process,必须先去sandbox,然后再去production data,那就做很多。但是unfortunately,Uber没有一个很非常好的sandbox environment。那什么是sandbox environment呢?sandbox environment就是你这个environment其实和production environment是完全一致的,什么都是完全一致的,包括你data也是完全一致的,这点比较难,就是你data是完全一致的,你会完全一致的,你会完全一致的。会不停的从production里面copy data到你的sandbox里面那么但这个sandbox里面是不影响真正user的 [45:00] 这个是在里面可以随便玩是吧可以随便deploy最新的code啊然后可以试一下呃这个这个integration会不会有问题啊这点我觉得Uber是没有Sysforce做的好,Sysforce这块,这个 deployment 做的非常成熟,它首先是有就是它首先是有Personal environment,就是你自己有个人的environment,然后你可以在自己的每个machine上,Selfforce的code有一点非常好一点,就是它所有的code可以在一个single的一个workstation上run起来,所以比如说我deploy最新的Selfforce code,我首先在我自己的机器上测试一下没有broke任何事情,然后呢,在那个每三个月的时候,它会push到这个sandbox environment上,然后在sandbox里面和production data完全一致,你测试一下没有问题,它会有专门tester测试,也没有问题,然后呢,如果这些都没有问题的话,它首先会deploy到Southforce internal customer,就是我们Southforce internally也用自己的Southforce的软件,Clot,那我们internal就是Southforce用户,employee先用下去执行的feature,如果没有问题的话,然后他开始AB test,并且他一般rollout都是一些小公司,他会把它分开,每次的时候不一样,但是rollout一般开始是一些小公司,然后在rollout比较大的customer,然后rollout可能最重要的customer,它是分成几个face rollout的,它每个face之间通常是有两周时间的,所以它rollout非常不是很frequent的,可能要三个月才能本总的rollout一次,但是它非常safe,基本上来说是非常非常safe。不会突然involve一个software failure,导致data全部loss。我看到大家说正在做Bits,有一方面也是Uber的一个sandbox的那个,我一看了一下Bits的dog,也是Uber sandbox的一个effort,但是我觉得这个已经是longed,早应该做的事情。就是好这是不同公司有表,就是我另一点我就说一下我的观点,我个人的观点,我也看了不同的公司,就是不同同学在不同的公司工作,我不觉得我觉得Uber的某些地方是很不错的,但我不觉得Uber的软件开发standard是非常好的,也不觉得Uber的developer是最强的。嗯可能是我个人观点,这个可能扯留点远的,我们接着聊好了好,然后呢,最后的话你可能需要做很多比如说Unit Test,然后Integration Test,各种Test然后能允许你能quickly recover from your error,然后你需要你新的code,要roout的话,要gradulate roout的新code,然后然后你可能需要monitor,比如说看performance matrix和error rate,然后如果出现很多时候你code deploy的时候,你会发现很多early warning sign,比如说这个matrix突然go up,即是early warning sign,可以及早的fix。然后最后一点的话是management非常重要,这个management其实是一个engineering management,就是你engineering是有主导权的,我觉得无数次见过不停的那个engineering的悲剧都是,就是,就是,不懂这个Engineering的Manager强行强加一些政治的决定,然后给Engineering上。比如说这个波音737 MAX,就是他这个,他Wall Street Journal写过一篇文章很长,他就爆料了中间很多的事情,我忘了Wall Street Journal还是New York Times,忘了哪一家了,现在很长就爆料中间问题。他本来是Engineer是强烈反对的,你有个Single-Pied-Fillure,这个Detector强烈反对的,但是就被管理厂强行压下来,然后强行rollout了,然后导致他负责这个Engineer好像快要辞职了,还是已经辞职了,但是这个就是,所以你有个Good management process是非常重要的。谢谢大家这是我们组自己做的一个东西,但是我觉得非常有趣的一点。就是说,如果我们看这个product development life cycle的话,其实是五个阶段。第一个阶段是technical design。你如果在这个阶段能发现问题的话是非常好的。这个包括database design,API design,ERD,Engineer review document,然后security privacy assessment,就是design角度,你还没有写任何code,在这个角度发现很好的。如果不能在这个角度发现的话,如果您在Code standard的里面,比如说你有一些Code standard的没有满足,Code guidance你没有满足,或者Code reviews,如果能在这个角度找见的话,你的damage是最小的,你的damage是远远小于后面的。如果你们能在这个角度找见的话,你可能有Unit test,Test的这个small functionality有没有问题。Load testing,能不能Test的这个scalability,Sanity test,就是这个sand test有的不一样,这块的话,就是说你这个function有没有,就是sand,比如说你这个function突然荡掉了,那其他的会不会造成catastrophe? [50:00] 然后counter-testing 就是说你要test你的那个上面的你的dependent service 有没有functionally correctly这个一般是一个非常快的一个test,就是为做其他的heavy test,做那个非常快的一个就是assumption test,比如说你这个service depends on service1234,那你service1234有没有就是functioning correctlyAll Active Test是什么呢?就是当你有Data Center Fillover的时候,比如说你整个这个Data Center region在这个San Francisco data center region down掉了,那你这个traffic能不能successfully roll over 到Los Angeles,是吧?就是data,就是 all active testing.Regression test 是你从那个business的角度,你从那个functionality角度,你看有没有这个问题。然后最后的话,如果你是新 feature 的话,我们可能还有team backbash,就是我们把新的 feature 列出来,然后找一些啤酒啊,找一些大家列,然后开始测试这个 feature,然后就做,就是一方面是增加feature awareness然后另一方面是看就是找一些尽量在这个feature出问题之间找电探好 然后就是System Monitoring 啊 System Monitoring的话就可能比如说你有Tracking System啊嗯看它那个 matrix 有没有问题啊, error 有没有问题啊,如果有 error 的话,这 error 是什么造成啊,有没有最近所有的 exception 过多啊,SLA 的话就是,比如说你这个 service 要满足其他几个 service,那你有没有满足你自己定的 agreement,比如说你要去 500 毫秒返回,你有没有超过 500 毫秒,然后一些 performance, matrix, product, analytic,就比如说你这个,这个更多也是从 business 角度的,比如说你现在这个 user impression 怎么样啊,你这个Rot feature 有没有达到这个要求啊然后这个Mobile Analytics更多是Track and User Mobile使用率的。比如说现在很多这个Agile Development,包括现在的现代的这个产品开发,就是从Facebook带来这个产品开发,所有都是Focus,最大化KPI,比如说怎么样最大化这个user在Facebook的时间,然后这些,就是Focus上这个的。那么那么他说的都是根据这个优化的,那你这个Mobile Analytics可以用来做一些insights,是吧?比如说这个feature使用量特别低,是不是砍掉这个feature,另一个feature使用量非常高,增加了这个feature。Facebook CEO,Zack Bird有一个采访,我记得是YC Combinator采访的Facebook CEO,他就说Facebook其实不是一个Facebook,但你每个人login的Facebook是不一样的。他每一个时刻有万个version的Facebook在同时run当你说Facebook的时候,它不是同一个version,它其实就是不停的做A/B test,怎么样能增加它的KPI,是吧?并且不同组的KPI有时候是conflict,这个组的KPI是增加safety,比如我们组的KPI就是增加safety,那增加safety,并然要减少user activeness,是吧?有些malicious user一定会减少,那你就做一个right balance,然后还有一些dashboard的oncall alert,就是你出问题的话怎么能第一时间oncall到。然后最后的话就是当你要rollout的时候,你是不是要有一个safety checklist是吧?你要check一下你这个有没有满足这个要求,那你有没有做这个,你有没有做这个。嗯,我就是我在这个这个Safety组有这个Safety组,包括BI组有这个啊叫Post Modem Review,就是你出现 bug 了以后,那个 Post Modem Review,你会发现很多这个 Post Modem Review,它 fundamentally会有一些非常令人哭笑不得的那个问题出现。我就举一个例子吧这是我经历过一个 postmodem review, immobile postmodem review,我们当时是2月份rollout一个feature,2月份rollout的一个feature,不是我诅作的,是另一个诅作的,我2月份rollout的一个feature,他rollout成功了,然后说report非常成功,说已经全部rollout出去了,然后到11月的时候,写了一个postmodel,说这个feature呢,他只在controlgroup release,也就是说,他released的user只有那九个人,只有那九个developer release,他家人都看不到这个feature。这就是他当时control那个release group的时候没有做好,我觉得当时我读的时候比较shock,我觉得这个都没有做好,就是你最后release都已经说release都做好了,然后也没有做好。这个就说明了很多问题,首先你没有一个checklist,是吧,你这个checklist没有弄好,然后你这个administrating test也有问题,是吧,你test administrating,应该把它,不管是重新分配一下,或者release version,这个我觉得也蛮有问题的,然后其次的话,这个mobile analytics也没有做到,是吧,如果真是一个feature,即使很少有人用的feature的话,你怎么知道多少人在用,是吧,结果都没有做到,就release9个月以后发现没有人在用, [55:00] 比如他们那九个developer在用嗯这是一个真实例子,好我们就直接说,就是这个有一套这个流程,development流程其实非常重要的嗯这个的话我觉得就是对,就这样子我觉得你就是很多时候depends on这个你怎么样跟大家解释了这个有时候会在Behaviour question 里面预解,就是Behaviour question 的时候说,你怎么样guarantee你的software是非常好的,比如说你这样的话,你可以在interview的时候说一下我没有这么这么的流程,我觉得这个还是挺不错的。好,我们从Skinability的角度就说点有趣的了,design一个Twitter那 design twitter 的话你可以满足什么呢?你可以 post 一个 twitter比如说你可以发一个新 message然后它这块列了,这是2012年的数据,Post the request is 4.6然后peak的话是12k request peak,然后你可以刷新你的home page就可以看到别人 post a Twitter,比如说这个的话可能有30万的request per second那么如果你design Twitter的话,如果你不考虑这个request的话,最常见的就是建几个table是吧,Normalized data建几个table,所以您可以有Twits Table,当你 post tweet 的时候,你就在Twits Table 上 insert new tweets,非常好用。只要insert一个noter的效率很高4.6k request 12k peak还是很容易handle的基本上一台机器可以handle但是你读的时候就很麻烦,因为你首先你要读,就是作为,比如说我作为Yuja Scott,我要读我follow哪些人,比如说我follow了详敬啊,我follow了Mike啊,我follow了欣扬啊我follow了这个David那我首先要读这些我follow的哪些人我读到follow哪些人以后,我同时得读,他发了哪些twits我得Twitter和Follow的人就得做Join,它其实是三个TableJoin我觉得在这个design里面,System Design里面,当你看到这个三个table join 的时候,这个performance就非常非常糟糕了。基本上是不skill的,除非你这个数量级非常低,那你否则的话这个是不skill的。这是Twitter的1.0,就是它最早实践的时候,它是这么实践的,就是把这个Twits放了一个table,user 放一个table,然后follow relationship 放了一个table,然后他就直接join 就行了,然后不skill,你比如说trump 发一个twitter你有6个million的人follow Trump,那你join的时候,整个这个table就,就是你发现他那个不停的在crowd Trump 的推特,你从data access pattern 来说Trump 发了所有的推辞你不停的在 crawl 不停的在 scan 不停的在 scan 不停的 scan 不停的 scan 的这个效率就非常低No所以他就做了一个denomalized solution 或者finite solution 怎么做呢当你说user post tweets的时候就写到这个新的out tweets message queue,是吧?就是有个queue,然后有twits1,twits2,twits3,twits4,twits5,twits6,是吧?那如果你这个twits1是userA写的,那这个userfollow了userA,那我就把这个写到这个recipient这儿。就起了这块那如果这个推则二呢是没有人follow就不写过去三的话是他们都follow就都写过去所以每个人呢是这个homeline呢这个Home page里面的Timeline其实是被denomalized的所以这个里面比如说你有 popular twits,比如说T8,Twits8,那其实就是写在多个地方就在这个recipient 2和3都有那当你在分析的时候你会发现根据它那个平均数字它一二年算的平均数字它4.6k每秒的write呢,在这翻 out 以后变成34k每秒,340k,34万每秒的write。那这个Writes的数量就增加了,这个比例叫,就是这个Finalt这个Write除以之前的那个Write,这个比例叫WriteAmplification就是RED的增加量增强量这增强量呢就达到了近80倍4.32,80倍,对吧?就是说白了是,你看看出来大概average 可能每一个Twitter user 有80个follower增加了80倍,那这样的话它就,如果把它denomalize在这的话,你读的时候你只读一个就行了,你只要读我自己的user homepage,以及帮我generate的好。我觉得这块常见的问题就是我如果follow new users 怎么样?比如说我这块突然follow了详静了或者我突然follow了麦克了是吧?我follow新 users 怎么样?当我follow的话,那我就会在这个里面把它的trace拿过来,也喷得过去,然后找得好,那就完成这个操作。但是大部分时候,你Follow是一个比较少的操作,你更多的是写Twits,所以写Twits的话不停的分当他说的 follower有问题这个问题并且是个很大的问题是 [60:00] 你非常popular user 比如说川普写了一篇推文他要把这个Twitter分给他31个million的followers就是说,Average的Rate Amplification是80 就是一个写convert成80分这是average 但不是代表是那个peakPick是多少呢?Pick是你的most popular user,是31 million,所以chump写条推文的话,他可能要replicate31 million 次,然后对他每个follow 然后写进去,这个效率是非常非常低的这不是一个好的solution他们是实践了这个solution以后,发现这个solution有更大的问题是什么呢?你的user会越来越popular,对吧?你学的用户越来越多,你的followers会越来越多那你follower越来越多你的write amplification会越来越大这不是一个很好的solution,但他们就这样实践了是吧一二年实践了,然后就发现这个还是不steal那怎么办呢,他们参写了第三种模式呢就是mix模式,什么是mix模式呢就是当你这个user不是一个popular,不是一个influencer,你不是一个网红,那你发了twits看的人比较少,那他就采用这种翻out的模式就是一个一个写到各个user的homeline table里面Home的Timeline Table里面但你如果是一个网红的话你比如说像川普啊奥巴马啊然后那你怎么办呢?你就还是采用这个传统的模式所以他这块呢会有一个这块说,我除了这些不是网红的Twitter以外,Twits以外这个人同时还follow了奥巴马,follow了Trump,那他这个Twitter怎么读呢?他直接去那个奥巴马和Trump的那个Twits读,也是一个denomalize,他会直接读Twits就比如说可以做一个key value,直接读奥巴马的推词,直接读川普的推词。然后把这两个数据结合起来就变成了从一个读变成了两个读,或者是一个读加之前的话这个是一个读嘛,它虽然是一个读,但是它写的amplification特别大。它变成了几个不是很popular的读,就是一个读一些不是influencer,然后再加上N个influencer的单独的组,这个是一个balance hybrid solution,这应该是最好的solution。我不知道为什么Twitter没有第一时间的时间这个solution,我觉得还是比较streetforward的一个观点。大家可以看出来这个System Design其实是大家都在摸索中显示,就是全是摸着石头过河,你可能一开始设计有问题,然后不停的尝试去去improve 然后去摸着石头过锁有什么关系吗这块?谢谢大家谢谢大家大家有什么问题吗或者有什么想说的好哦,之前说有之前一个问题,说除了Unit has all active temp, team backbash,其他在什么地方做?这个的话,像这个Sanity Test, Low Testing,一般来说,公司会有自己的Infra,比如说Uber,有专门做Infra,它会有一个流程,它有一个专门的Infra Team,就专门做Developer Low Test的这个tool,hillsum,他会给你开放一大堆API,你只要follow他的API,然后follow他的那个requirements就写,然后我对,他说白了就有一些low test tool,但是他会有一些,也有一些open source software,但是你一般来说,如果你是在一个非常小公司,你以后加入一个非常小公司,你可能需要自己搞一个,比如说,把一些open source software wrapper成一个tool,然后你说一些requirements。然后就做这个Low Test 但是这里面的话 Regression test 和 unit test 还有一个叫 end to end test还有个integration test,一般是写到自己的code base 里面的,其他的都有一些tool或者是API告诉你怎么做就有的还有个叫blackbox test 还是挺复杂的不需要知道全部的,但是有时候他会问,比如说这种常见说,特别对software engineer manager 这个面识比较多的,就会问你怎么样 guarantee 你这个 code 是没有问题的。这个是常见的一个问题,你可以说我在软件开发的每一个步骤里面,我都有额外的 check,保证我这个软件开发和 rollout 是没有问题的。其实挺喜欢,他们挺喜欢问这种问题的。然后这是一点嗯这个的话有非常早,这个Code integration,CICD,Continuous integration,Continuous deployment,是有很多业界讨论的。这个其实有很多tool的 [65:00] 做的不是特别好,现有的system做的不特别好,有很多可以更改的地方,然后这个其实你看,如果你看你就是这个公司的这个tech,有的公司的tech非常老旧,那它可能可能连integration,continual integration,continual deployment 都不一定有,这个也是看的。所以我可能不太喜欢去AutoMustriving这种地方,因为AutoMustriving的话,你看它其实不是一个cloudautonomous driving不是一个cloth environment,你如果想的话,它不是一个cloth environment,它有点像研发单机版程序所以它这个流程可能有的地方还是挺老旧的Finalt模式中,User写了trades只是进了Q,但是没有GlobalTable。翻案模式中,user写了twit直接进了Q,mere global 推过。这个Global Table不会有Global Table,这个Global Table肯定是share到不同的这个Table上了没有说GlobalTable这个说法,我觉得GlobalTable我很容易直接想到这Duke Caper这种Global Configuration Table。它这个意思就是你写了一个Twits以后,你去根据你这个Twits的Follower,把你的Twits push到你的所有的Follower的Q里面了。好Twitter例子里面是有一个FeedTable吗? Twitter例子里面是有个FeedTable谢谢大家水的 table是Twist推爆吗?还是什么是FIT推爆?谢谢大家谢谢大家Twitter例子不是user table,follows table和twits table我没有很理解什么是费的贴文潘静怡。能解释一下吗嗯看到的那个feet里面吗哦对对对对对是有另外一个table吗对这个是Twist的table是指一个user写的自己的Twits,但是你看别人的,看你HomeFace的时候,那这个是另外一个table吗?对对对,这个是这个是Facetable,就说白了是这个,就比如说,Scott login Twitter,我看到是我自己的Facetable,这个是这个是Facetable,对的。对的这个是他这块没有直接列对还有你刚刚说,Twitter现在是一个Mix的模式,我可能听漏了,是不是那种网红的话,它就用Fan Out的模式,就是用Fan Out,那如果是网红的话,它就Fan In了。视网行是这样子就比如说你follow你其实变成两个嘛比如说我follow了User12345我的friend 我同时follow了Trump和Obama 是吧在这种情况下User12345Twits是直接写到我这个face table里面的或者是这个timeline这个database里面的我直接就能读到,但我同时follow了奥巴马呢,我会有另一个API去靠奥巴马的所有的recently tweets然后同时靠Trump的所有的Resilient推子,然后把这两个相当于是三个API靠嘛,两个去网红的Influencer的,然后另一个去非网红类的,然后把这三个Data结合在一起,然后再再再返回。好的,那你这个Timeline或者是Face的Table,会把他那些比较旧的data给drop掉好问题应该是这个这个就是我觉得是个 decision choice 了就是如果你想让 user infinite scroll 的话可能是短时间不drop你就不停地往下scroll呗但是如果你drop的话你可以比如说例面的层1000个feeds 你可以就是那个什么我不知道推特到底是那个什么但是怎么样做的但是我知道那个Google News是大概就几百个news然后你读完了以后就顺下的就chop掉了我个人觉得刹掉了之后他要再看就是再去Fetch对,再看的话,你有多种思路什么,这还是要Distance needs,但是我想这块point out一点是,你看你的home page的这个data,和你看individual user的这个twits,这应该是去两个不同的table看的。因为你这个home page的这个twits很有可能是pre-generated的。这种情况下你比如说我看就是进行你的data和我在我的timeline里看了这两个trips可能是不同的trips会有个结果是什么呢比如说你发了一个Twits,然后你又更改了你的Twits那我看的可能是旧版本,我去你home page 可能看的是新版本对对你在我里面去某个地方 [70:00] If you look at the user, you should see tweets. It's the user twist table in the user table. But I just asked them if they were going to drop off the new tricks. So timeline or feeds table out of data data will drop down. Out of data feeds, I think it will drop down. Because it will handle majority cases. If you leave a million choices, it will be used to use. It will not be used to do that. It will be 100 or 1000. I think the old ones are still in the face. Because you can use the user table in the face. You can use the user homepage in the face. If you don't want to use the same time. - Okay, thank you. - This is a design choice. If you ask Twitter students, you will have more insight into the answer. This is a design choice. Thank you. Another question is, the face table is not only in cache, or is it in cache? physical database in the physical database. This is a design choice. If I'm in the cache, it might be in the cache. If it failed, you can generate it again. It seems pretty fast. If you start to fill, massive failure is still pretty. This is not very good. I feel like I might still have a fit table. There is a table, and in memory cache is used to be used to be a bit more efficient. Because you have to consider this, if this tweet memory database redis 挂掉的话 Okay. You need to do a heavy joint, the server is down. You can write database better. Because you should be careful, for example, I created a tweet I took 10 seconds to deliver to the user. This actually has no impact. You can't expect that you can only use the first time. I open my Twitter and I load the home timeline. This is a very big outage. So from business perspective, From business perspective, this is to write to the table. You can write this redis down, this phase flow down. From the business impact, this is how to write a table. Because when you write a table, it's a bit slow. But if you're a frequent user, you've already been in the case of warm-up, so it's not so slow. So you should be in the report. So when you think about choice, you should consider the worst case. Thank you. If Trump's 30 million followers are on the same page, they can also read the same Twitter page. Do they have any questions at the same time? They were able to do the same thing. If the users and followers are on the same page, they can be the same person. I think the same person is Trump. This one is a red spot. Red hot spot has different ways to fix it. There are some more difficult ways. What are some more difficult ways? For example, Trump's Twitter is a hotspot. He put Trump's name in the last one. and add a 01001. For example, Trump is... You can divide Trump's Twitter by 100. This is the one I'm using. You can divide it by 100. And you just read it from Trump's account. For example, you can read from 0100 or from... 0.2度, that's okay. That's right. Then you can do the restrew. It's going to be a bit further. Because you have a local read, hotspot, it's going to be further further. What is the problem? Trump has a Twitter. He will write this Twitter in 100 replicas. In the first time, in the second time, in the second time, in the second time, the time is not the same. It will eventually be consistent. For a while, he read the Trump Twitter as well. But in a short time, he read the Trump Twitter as well. Thank you. How to solve the problem of rest flu. How? And then we'll talk about the... All right. I think there are some problems I can do. Performance. Performance has several standards. But the most important thing is that every device can be crashed. So you have to look at CPU, memory, network bandwidth, disk. Disk is a low priority, but you also have to look at. There is no one thing that can be taken away And we talked about [75:00] 不能用的 太高的话 你可能会fill over 或者crush然后在Batch System,比如说Hadoop的话,你可能更讲究的是怎么样optimize throughput那real-time system 可能更加要怎么optimize response time好然后这个Response Time有P95和P99,还有P999,那这个Response Time是非常重要的,因为就是它就是determining user experience, P95, in case you don't know, P95 is the response time rank, and P95 percentile is the response time.然后还有min的话就是p50,还有min的话是算average, 这个命名叫average, 意思算average, 还有median, P50, 什么, 这里面比较重要的是P50, P95, P99, 有些情况下, business case, 你需要optimize, 也很重要的数值, 比如P999, DynamoDB, 就是 Amazon 的那个case, 你要, Amazon 的 shopping cart, 你要optimize P999, 因为它那个, 如果你是 P999, 说明你的request 很大,你的request的 complexity很大,说明你是heavy user,所以一定要guarantee你的user experience 比较好那有人会说为什么不optimate T9就有4个9那如果你optimized那个的话你很多时候当你的那个就是那个Hytel的那个optimization的话,你的response time 可能不是你能control 的了。比如说你这种情况下的话,你可能是比如说你那个Network突然慢了,你的Response Time就增加了你的P999,或者是你这个User看的Crash了也会可能会增加你的P999的Response Time就Client Interactive Request 然后Client Crush了,那也会增加你的P999,所以它会找一个Write Balance,如果你要求所有的Request都返回很快的话,那你有些因素不是你自己能控制了,比如说你的User的那个Network down掉了不是能控制的好,然后其次的话你要optimize response time,需要optimize longest response time,比如说你要parallel的话是找那个最长的,然后如果你是serialized call的话,你可能任何一个response time都是要去优化。谢谢大家然后Skill的话有Skill App和Skill Out,Skill App就是买一个Powerful Machine,就是有时候这个Skill App是一个Skill App我经常看到Paper说是比100个chip machine表现力更强,因为你这个chip machine share nothing architecture,你需要很多overhead的,就是parallel process有很多overhead,所以Skill App其实有时候会更快。好, 谢谢。就是你有多台Machine来处理,那大部分Intel & Complex是用这个的。总体来说,Design的时候是没有one size fits all solution的,所以是你不同的这个request呢,就是你不同的那个需求,像我们之前讨论的那个问题,那你是要read your writes呢,还是你想迅速返回呢,还是希望你的user读的data是consistent的,monautical reading呢,这个其实是有不同的requirement,然后根据不同的requirement来design不同的system,所以是没有one size fits out solution的所以你的问题可能是你的 raise volume 过大或者你Skill的问题可能是Rest Volume过大,或者是你的Volume的Data过大,或者是Complexity的Data过大。或者是response time 过大,或者是跟access pattern 相关的,那每一个这个问题都可以去优化。每个问题可以去优化,每个这个问题甚至可以发明新的轮子去解决你比如说DenimalDB发明DynamoDB里面就是它focuses your focus on write,然后它focuses your focus on best effort database,它不是transactional database,它不能guarantee absolutely no data loss但是它focus on best effort database,因为它发现很多时候database的Write是远远大于read的,比如像刚在那个Twitter的case,你经过Write amplification以后你的写是远远比读大的。之前的话单纯看读和写大概是100倍关系,但是你把Write amplification写进去以后,你的写是远远大于读的。那DenemoDB包括Cassandra是对于Write进行优化的。包括这个log structure,merge trade这种这种database都经营远的进行优化。我们稍微会讲一讲。然后最后一点是,我举了一个,这块有个例子,这个书里面有个例子,写的很好,说,如果你有10万个request per second,那每个request呢,你request data是1kb,那你throughput其实是和三个request per minute,每个request是两个gigabyte size是一样的那你的data size data throughput这两个情况是一样的即使你的request pattern是完全不一样的,一个是100k per second,另一个是三个request per minute这两个request pattern完全不一样,所以你根据不同的request pattern,access pattern,根据不同的Rights/Rights和Rights/Ratual,你可能是要进行不同的优化。这个是第一次 [80:00] 这是基药的 introduction这本书的第一章好,然后这个书的第一章就讲了说我们优化应该优化什么呢?从哪个方向优化?我们应该怎么build一个system呢?应该是个maintainableScalable和就是scalable和那个 sorry, reliable, scalable和maintainable system。最后一点就是maintainability, maintainability是跟人相关的,很多是关于人的。比如说你怎么样能保证你的这个system operated correctly,就是很多SRE的问题。最好的SRE是Google有一篇SRE书写的挺不错的,它也是SRE最早的先取则,至于它那本书写来是挺不错的,你可以搜一下Google的SRE书。然后Uber有几个Engineer在欧洲的Engineer写了几个Block写了也还可以也是还是挺不错的,他列挤了Uber自己的SRE的工作系列还是可以的。其次就是Simplicity,你新的Engineer必须能非常明白,非常容易去Rump up,然后Underzine the system,最后有点Evolvability,你必须能非常容易的去Add codeor add feature you call extendability or modability of what is your plastic is plex那你怎么样保证你的 knowledge transfer book up to date?那你怎么样保证你的 future system? 怎么样去 write post modem? 怎么样去 preserve knowledge?这都是一些关于这个人的管理的一个部分,然后包括你怎么说怎么样,minimum surprise,这个system design 中很多时候你要minimum surprise and trying to foreseen all the predictable behavior.Maintainability的话,simplicity的话是我觉得最重要一点,就是如果你的data就是你的project非常complex的话,它会叫这个,他们叫Big Ball Mark这个有一个非常好玩的reading这块有个非常好玩的reading有一个Anchon Nier 匿名写了一个他那个嗯匿名写了一家他在传统汽车公司工作优化他们汽车公司database的经理,非常常写了大概十几页,有趣的一个译点。他没有指出他那个汽车公司是哪一家,但是我猜是那个菲亚特那个最大的汽车公司,菲亚特有个什么菲亚特什么什么汽车,几家非常大的一个汽车联盟。然后他里面有菲亚特啊,吉普的那个,吉普的那个Brand啊,有些优质之产,还有克莱斯勒,菲亚特克莱斯勒这种,还有一些非常传统的这个,这个,这个。基本上没人买的汽车,我都忘了具体哪些品牌了。它这个是,纯粹是个公司结合的产物。他之前每个公司比如菲亚特有自己的菲亚特管理系统,他有自己的database那会儿都是有买Sycle,就是Sycle database,有自己的Sycle database,有自己的API,然后贝亚特又和比如说吉普结盟了,那就是合并了那它没有自己的database, what makes the worst is 1990 年还是 2000 年的时候,就是三四十年前,二三十年前,那会非常讲究,叫 localization,所以即使是吉普这一家公司,它也在不同的区域有不同的这个database,所以它这个在北美的database和在欧洲的database和在亚洲的database和在哪个地方database都不一样的所以它就有100多个data base,不同的类型的data base,可能是version不一样,然后它的API不一样,把它要融合起来然后他说白了就是想把这个API融合成一个API,然后就是fail,miserablefail,这个就属于常见的 Big Bomber Mart,你不停的通过公司并购,从上一角度并购,然后你每个database之间都相互不兼容,你有这样这样的问题。并且database schema update有问题的,是有问题的,因为根据database的design不一样,比如说 Oracle Database,oracle database在你update schema的时候,你可能会出现schema incompatible,就是跟它那个跟它那个Radiahad Log的模式相关的所以你这个Oracle database如果你要update schema的话你可能需要整个database down掉去maintain然后才能把它update所以这个结合到这么多几百种database,然后在每个region都不一样,整个就是big on one mark,所以这个project,就是destiny to fill,这是很有趣的一个reading啊其次的话,Simplicity 也是要dependency 相对来说比较简明一点然后最重要的一点是 [85:00] remove the accidental complexity What is accidental complexity? It is that your complexity is not in your software solving the problem. So you users can't see this complexity. But your complexity is in implementation. This is accidental complexity. This complexity is not in your API. You can see the API is not the complexity, but in the process of the process, it will be the complexity. Like we talked about the different database versions, Big Ball, Mod, and the traditional companies. This is a problem. This is a problem. The last thing is Agile development mode. TDD and Agile development mode. and let the developer first day deploy code and write code This is Facebook and Uber. This is a way to bring a programmer to the first day. I always think Contribute code first month is very risky, because you don't understand the system, you don't understand the system, but it's a very code oriented. I hope you can go to the first day and write code. This is a software engineer. And I would like to recommend you if you don't know Agile and TDD, you can read it. Some people are very careful about this, especially some traditional companies are very careful about this. TDD and Agile. There are some business news in the industry, and there are people who are doing Agile Master or Agile Master. Trainer has a new product, but it has a place to be able to use it. Thank you. Okay, we've talked about this. Do you have any questions? Thank you. Thank you. There are some questions, I can't see if there are any questions. No problem, I'll talk to the next one. This is what I want to talk about. um - Can I ask you a question? - You can ask. - We mentioned LSA, and when it comes to the system, it will look LSO. How do they divide? - SLO and SLA. - What are the differences between the different from the view? SLA is what? SLA is agreement, for example, I'll give you a example. SLA to the Amazol S3 SLA is 12.9, I was only in a year 0.5 seconds, this is the SLA. If it breaks SLA, Amazon is to pay it customer's money. For example, it was 12.9 seconds, it was 10 seconds. and he will pay the customer's money I pay you how much money every second, according to your company's agreement, how long I pay you, how much money I pay you. I break out SLA agreement. The SLO is what is called? I'm now going to be a 12.9. I'm going to be a 13.9. This is my team of objects. I'm going to be a SLO. So you can think that SLA is a low-end, SLO is a low-end, SLO is a hard-end, SLO is a hard-end to achieve, SLA is not break-end. Thank you. Let's get started. - For example, service and service to the API, you can use the data to replace the data? Process isolation. Oh, yes. This is what I mentioned before. It's not just about data base, right? Yes, but this is the case. There are other things. um, to ensure process isolation? It's a bit of a more often. Oh, often there are three ways to pass data. Database is one, you can just search for database, and pass data. And the other one is API. API is one. There is also a stream. Streaming is a one. You can also use streaming. This is data flow, which is the three of the data flows. Streaming, pass data through streaming, pass data through database, pass data through API. Hmm. Database is a kind of [90:00] 跨叉掉的啊,除非你是很小的公司,就五个人想怎么搞怎么搞这是你稍微大一点的公司,基本上不可能通过database来pass的谢谢大家Streaming 和 API 都可以,但是 Streaming 和 API 又有不同的优缺点吧API的话可能就是基本都是synchronized的就是你也可以把实践成asynchronized, streaming可能就是Native类就是Asynchronized的世界OK好谢谢我这块我可能不讲这个了我可能没时间了 7点了 没时间了不知道有没有人感兴趣啊 有感兴趣我有点想讲谢谢大家谢谢大家谢谢大家我觉得没时间了,我可能不讲了。或者在最后呢你觉得值得讲一讲然后最后愿意留下来的就留下来我这面时间可能自己有点那个什么,我只讲一点好了,就是我最近看了一些经济学的东西,然后然后包含一些我看了一下08年07年的经济危机我看我下载有没有空看大家有没有改进去如果改进去的话我讲08年和这个现在经济危机然后我觉得这个就是我希望这个就是讲这个是什么呢就是说我希望大家就有个ready expectation就是有一个ready expectation什么呢就是嗯现在失业的不一定是坏处,因为我觉得这个经济会持续的变坏就是接下来会有更多事业,肯定的,就更多事业。然后,所以你现在能找到一个很好的工作,非常重要,可能现在失业了,比如说找到一个非常cash flow,非常strong的一个 company,你反而可能之后就不会在后面可以survive下来,所以现在可能是个survive mode比较重要一点。然后,这是一点,然后其次的话,如果找工作的话,我看了一下,我觉得现在这次中国的表现会远好于美国。所以你回国其实可能是一个不错的选择我觉得回国可能是个不错的选择中国的表现会远好于美国这次就是这次这个什么我个人觉得从个人的角度来讲,我觉得回国是个不错的选择。然后其次的话,如果你投资的话,我觉得你现在应该做一些Defensive Investment。嗯我觉得这次是比08年严重的并且严重很多,这次是比08年严重很多,我找了好多数据,我感觉比08年严重很多。所以,并且,我想说的一点,我就几分钟要这样说一点,就是这怎么远远没有结束啊?这个可能从疫情的角度可能几个月,可能底下从下几个月过去,但是从经济的角度来讲,从economic的角度来讲的话,这个就是Worth的远远没有到达,这个Worth是远远没有到达的,这个会非常非常非常糟糕,可能没有人之前会见到这么糟糕,并且它是全球的产业链修可,是供给和需求双修可。然后通货膨胀会很糟糕,就是你的钱的贬值速度很快然后如果这个并且这个Fed 美联储这次是保资产价格,所以它会prolong,就是说它会使这个economic depression 时间会增长。如果它不管的话,会有一个hard hit,就是很糟糕,但是可能很快就恢复了。但是这次这个08年,这个Fed做了很多事,所以这个会延长这个depression的时间,这个depression时间会变得很长,可能会长于三年,可能,我觉得长于三年都可能,到2023年说不定都不一定能恢复,所以我觉得不要被这个股市的假象所迷惑了。然后我想说的是,最后就说简单明了,就是简单明了说几点,这个我做了好多研究,简单明了说几点,就是像最近的话,就看到这个美国穷人拿到补贴金的人最常见的是他拿了补贴金以后开始用来炒股了然后这个是Robinhood data,你看一下最近一个月的data,这个买入量和卖出量是完全不一致的买入量和卖出量是10倍以上的关系大部分人都在买入,这个crazy market竟然在买入但是聪明的钱,就是Bank of America的private client是在不停的销售的尤其可以看到从从4月份以来从3月20号以来从3月份以来全部都是全部在出售的然后他再购入什么呢再购入黄金再购入黄金非常明显但是这个我只能说smart money或者这个这个有钱人的钱呢他在这个其实以另一方面来讲的话 [95:00] 他们在乎减少risk,因为你有20个billion的话,你只要一年10%的收入就是2个billion,他不在乎那个特别高,所以他在乎的是讲究减少risk所以说我这边的话就是还有些其他的,我推荐就是买一些Beta比较低的资产,Beta就是大盘涨的时候涨的更多,就是Beta越高大盘长的时候它长得越少就拜它越低然后你可以增持一些黄金啊什么的然后对于找工作来讲啊 这块有一些就是供给取向分析了 我看别人找了分析了一下 我后来找不到那个图了 就自己画了一遍 这块就不讲了py 就是这个就是接下来会更糟糕,就是现在失业的可能第一时间能早间工作可能是一个很好的,然后我觉得接下来几年会比较Ugly一点,我个人是Twider的,就是这样子好我就说这些了我看到好多人聘我的时候感兴趣好我下次讲吧,因为我今天我可能要自己吃晚饭了什么的,没空了,我下次讲好了,如果感兴趣的话,我可以讲一下细节,因为我这块也是做了一些research,我觉得有很多地方我觉得很多地方就是我读了一些资料然后做了一些research,然后我又读了一些风险啊,收益,有很多很有趣的人写的这个有很多很有趣的人写的notes我就读了一下,然后觉得这个风险收益比不一致啊,我觉得大家如果你有资产的话,可能要做一些defensive investment然后你可以搜一下怎么样做devents,如果大家这次工作受影响的话,我觉得不一定是坏事,你可能会更好的找见一个cashflow很好的一个公司。然后如果这次没有受影响的话我觉得要非常非常非常非常的小心这个这次会比08年,我不知道大家有没有08年,我08年的时候还在上大学。你慢点说还想知道发学的,然后08年09年11年12年我12年早工作的时候还挺困难的因为那会整个经济,你想他07年开始经济危机07年10月份的时候,大家都知道,华尔街都知道发生经济危机了。但是经济危机增重爆调是08年9月份爆调的好08年9月份爆掉的07年10月份华尔街都知道经济未见08年9月份爆掉的什么时候恢复的差不多13年才恢复中间有三四年基本上都没有就是因为就是美联储这个有人很多发那个经济学论文因为经济是个混沌体的宏观经济是个混沌体很难说嘛但是有人发论文就说这个美联储就是是延藏了经济恢复的这个使经济恢复更 painful 然后但是08年的经济恢复其实是非常就是美联储就是跟今年比其实是非常不算什么了就感觉小儿科了今年更严重一点所以这个今年就是它经济恢复会更糟糕一点,就是你想08年,如果从股市来说08年9月就到低点了,你其实从那个从09年3月就到低点了,从08年9月开始,跌了半年以后就到低点了,但是你从以从之后的那个回复来说已经算是非常speed的一个回复了但是这次的话我觉得不会那么快啊并且有很多,我就是分析了很多东西吧,就是分析了很多东西。我希望大家有个right expectation,如果感兴趣的话,我下周稍微多留点时间讲一下吧。反正我觉得现在的话就是,希望大家就是准备好,接下来几年可能都会很糟糕,然后怎么样做一些defensive investment什么的,就我自己的观点。好,我今天就说到这里了,谢谢大家。好谢谢大家感谢观看