Skip to content

Instantly share code, notes, and snippets.

Show Gist options
  • Select an option

  • Save zavakid/a58c635006786cc35ee212f66f8dcadc to your computer and use it in GitHub Desktop.

Select an option

Save zavakid/a58c635006786cc35ee212f66f8dcadc to your computer and use it in GitHub Desktop.
The video Think Distributed Systems with Dominik Tornow provides deep insights into the architecture of reliable systems. from https://www.youtube.com/watch?v=FBKDHpkdrGk
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Think Distributed Systems - 视频学习助手</title>
<!-- React & ReactDOM -->
<script src="https://unpkg.com/react@18/umd/react.development.js" crossorigin></script>
<script src="https://unpkg.com/react-dom@18/umd/react-dom.development.js" crossorigin></script>
<!-- Babel for JSX -->
<script src="https://unpkg.com/@babel/standalone/babel.min.js"></script>
<!-- Tailwind CSS -->
<script src="https://cdn.tailwindcss.com"></script>
<!-- Phosphor Icons -->
<script src="https://unpkg.com/@phosphor-icons/web"></script>
<style>
/* Custom scrollbar for better aesthetics */
::-webkit-scrollbar {
width: 8px;
}
::-webkit-scrollbar-track {
background: #f1f1f1;
}
::-webkit-scrollbar-thumb {
background: #cbd5e1;
border-radius: 4px;
}
::-webkit-scrollbar-thumb:hover {
background: #94a3b8;
}
.active-tab {
border-bottom: 2px solid #2563eb;
color: #2563eb;
font-weight: 600;
}
.transcript-item:hover {
background-color: #f8fafc;
}
</style>
</head>
<body class="bg-gray-50 h-screen overflow-hidden text-slate-800">
<div id="root" class="h-full"></div>
<script type="text/babel">
const { useState, useEffect, useRef } = React;
// --- Data: Transcript, Summary, Resources ---
const VIDEO_ID = "FBKDHpkdrGk";
const summaryData = [
{
title: "视频简介",
content: "本期 'Flying High with Flutter' 节目邀请到了《Think Distributed Systems》一书的作者 Dominik Tornow。 Dominik 在节目中深入浅出地探讨了分布式系统的核心概念,不仅仅是针对后端工程师,对于所有现代软件开发者(包括移动端)都至关重要。"
},
{
title: "核心类比:办公楼模型 (The Office Building Analogy)",
content: "Dominik 提出了一个非常形象的 '办公楼' 类比来解释分布式系统:\n1. 每个进程就像办公楼里的一个房间,房间里只有一个人。\n2. 人与人之间不能直接说话(没有共享内存),只能通过 '气动管' (Pneumatic Tubes) 互相发送信件(消息传递)。\n3. 这个模型完美对应了分布式系统的两个核心挑战:并发 (Concurrency) 和 分布 (Distribution/Partial Failure)。"
},
{
title: "CAP 定理的误区与真相",
content: "Dominik 对 CAP 定理提出了批评。他区分了 'CAP 猜想' (实用但非定理) 和 'CAP 定理' (形式化证明但不实用)。他指出 CAP 定理中的 '可用性' 要求所有节点在任何时候都必须响应,这在现实中是不切实际的。相比之下,分布式共识算法(如 Raft, Paxos)通过 Quorum (法定人数) 机制,使得系统即使在部分节点故障时也能保持一致性和可用性,这实际上比 CAP 定理描述的更具指导意义。"
},
{
title: "Safety (安全性) vs Liveness (活性)",
content: "引用 Leslie Lamport 的理论:\n- **Safety**: 保证 '坏事永远不会发生' (Something bad never happens)。例如:银行转账不能凭空消失钱。\n- **Liveness**: 保证 '好事最终会发生' (Something good eventually happens)。例如:转账最终会到账。\n在分布式系统中,我们经常需要在故障发生时,在 Safety 和 Liveness 之间做权衡。"
},
{
title: "消息传递与幂等性 (Idempotency)",
content: "在不可靠的网络中(如移动端),我们无法实现 '恰好一次' (Exactly-once) 的消息传递。我们通常能做到的是 '至少一次' (At-least-once) 加上 **幂等性** (Idempotency)。\n- **策略**:客户端生成一个唯一的 ID (Idempotency Key),服务器收到消息后记录这个 ID。如果客户端重试发送相同的消息,服务器看到 ID 已存在,就不再重复处理,从而实现逻辑上的 '恰好一次'。"
}
];
const resourcesData = [
{
title: "书籍推荐",
items: [
{ label: "Think Distributed Systems (Manning Publications)", link: "https://www.manning.com/books/think-distributed-systems", desc: "Dominik Tornow 所著,通过生动的插图和心智模型来解释分布式系统。" }
]
},
{
title: "核心概念",
items: [
{ label: "CAP 定理", desc: "Consistency (一致性), Availability (可用性), Partition Tolerance (分区容错性)。分布式系统中的经典权衡理论。" },
{ label: "TLA+ (Leslie Lamport)", desc: "一种用于建模并发和分布式系统的形式化规范语言。Dominik 提到的 Safety 和 Liveness 概念深受其影响。" },
{ label: "Actor 模型", desc: "一种并发计算模型,强调通过消息传递进行通信,Erlang, Elixir 和 Dart (Flutter) 都受此影响。" }
]
},
{
title: "人物",
items: [
{ label: "Dominik Tornow", link: "https://twitter.com/DominikTornow", desc: "分布式系统专家,作者,Resonate HQ 创始人。" }
]
}
];
// Processed transcript with manual translation mapping
// Due to length, I've segmented and translated the key parts provided.
const transcriptData = [
{ time: "00:00:10", en: "Hello, welcome to another episode of Flying High with Flutter. I'm your host Alan Wima.", zh: "你好,欢迎收看新一期的《Flying High with Flutter》,我是主持人 Alan Wima。" },
{ time: "00:00:16", en: "Today we have a very interesting, amazing guest Dominik Tornow.", zh: "今天我们要请到一位非常有趣、了不起的嘉宾 Dominik Tornow。" },
{ time: "00:00:23", en: "He wrote a very interesting book that resonates a lot with me called Think Distributed Systems.", zh: "他写了一本非常有趣的书,让我产生了很多共鸣,书名叫做《Think Distributed Systems》(分布式系统思考)。" },
{ time: "00:00:39", en: "People are actually working with distributed systems more than they think.", zh: "人们实际使用分布式系统的情况比他们想象的要多。" },
{ time: "00:00:48", en: "If you have an app, an API server, and a database, you already have a distributed system.", zh: "如果你有一个 App,一个 API 服务器和一个数据库,你就已经拥有一个分布式系统了。" },
{ time: "00:00:58", en: "All modern systems today are distributed systems. It's only a question to what degree.", zh: "当今所有的现代系统都是分布式系统。问题只在于分布式的程度如何。" },
{ time: "00:01:40", en: "I came to the United States for an internship in 2006... that was the year the cloud was born.", zh: "我于 2006 年来到美国实习……那一年正是云计算诞生的一年。" },
{ time: "00:02:25", en: "AWS released S3 and EC2... basically the birth year of the cloud.", zh: "AWS 发布了 S3 和 EC2……基本上那是云计算的诞生之年。" },
{ time: "00:03:04", en: "I was fascinated by the problems that were presented by distributed systems.", zh: "我被分布式系统所带来的问题深深吸引了。" },
{ time: "00:04:54", en: "I like to break large concepts down into fundamental building blocks, thinking from first principles.", zh: "我喜欢将大概念分解为基本的构建块,从第一性原理进行思考。" },
{ time: "00:05:22", en: "There are two forces at play: Concurrency and Distribution.", zh: "这里有两种力量在起作用:并发 (Concurrency) 和 分布 (Distribution)。" },
{ time: "00:05:35", en: "Concurrency is defined by nondeterministic partial order. You don't know what happens next.", zh: "并发的定义是不确定的偏序。你不知道接下来会发生什么。" },
{ time: "00:05:48", en: "Distribution is defined by nondeterministic partial failure. You don't know what fails next.", zh: "分布的定义是不确定的部分故障。你不知道接下来什么会坏掉。" },
{ time: "00:06:30", en: "I settled on the office building analogy. Every room is occupied by one person.", zh: "我选定了办公楼这个类比。每个房间里只有一个人。" },
{ time: "00:06:42", en: "That person cannot communicate by yelling, they have to send letters via pneumatic tubes.", zh: "那个人不能通过喊话交流,他们必须通过气动管发送信件。" },
{ time: "00:07:39", en: "A distributed system is a collection of concurrent components with exclusive access to their own state.", zh: "分布式系统是一组并发组件的集合,它们对自己拥有的状态享有独占访问权。" },
{ time: "00:07:49", en: "They share no state and communicate by exchanging messages over the network.", zh: "它们不共享状态,而是通过网络交换消息进行通信。" },
{ time: "00:09:55", en: "If we have Bob the mail room attendant who is a little disorganized, sometimes he forgets messages.", zh: "如果我们有一个收发室管理员 Bob,他有点乱,有时会忘记发送消息。" },
{ time: "00:10:35", en: "That's what we call an asynchronous system model in the presence of failure.", zh: "这就是我们所说的在存在故障情况下的异步系统模型。" },
{ time: "00:13:08", en: "Shift in perspective: In the office, there is only you and the rest of the world.", zh: "视角的转变:在办公室里,只有你和“世界的其余部分”。" },
{ time: "00:14:25", en: "We often look at distributed systems from a God-like perspective, but no single component has that view.", zh: "我们通常以上帝视角看待分布式系统,但没有任何单一组件拥有那种视角。" },
{ time: "00:17:09", en: "CAP Theorem. I have very strong feelings about the CAP theorem.", zh: "CAP 定理。我对 CAP 定理有非常强烈的看法。" },
{ time: "00:17:55", en: "There is the CAP Conjecture (tangible but not a theorem) and the CAP Theorem (proven but impractical).", zh: "有 CAP 猜想(具体但不算定理)和 CAP 定理(已证明但不切实际)。" },
{ time: "00:18:34", en: "CAP is often misunderstood as 'two out of three'. Partitioning is not a choice, it's a reality.", zh: "CAP 常被误解为“三选二”。分区 (Partitioning) 不是一种选择,它是现实常态。" },
{ time: "00:20:09", en: "In the CAP Theorem, Consistency is defined as linearizability.", zh: "在 CAP 定理中,一致性 (Consistency) 被定义为线性一致性。" },
{ time: "00:21:25", en: "The requirement that ANY server must be able to respond is impractical.", zh: "要求“任何”服务器都必须能够响应,这是不切实际的。" },
{ time: "00:24:06", en: "Distributed consensus (like Paxos/Raft) allows us to make progress as long as a quorum exists.", zh: "分布式共识(如 Paxos/Raft)允许我们只要存在法定人数 (Quorum) 就能继续运行。" },
{ time: "00:24:37", en: "That is the true breakthrough, not CAP.", zh: "这才是真正的突破,而不是 CAP。" },
{ time: "00:28:44", en: "Any property of a system is a combination of Safety properties and Liveness properties.", zh: "系统的任何属性都是安全性 (Safety) 属性和活性 (Liveness) 属性的结合。" },
{ time: "00:28:52", en: "Safety: Nothing bad is ever going to happen.", zh: "安全性:坏事永远不会发生。" },
{ time: "00:29:00", en: "Liveness: Something good is eventually going to happen.", zh: "活性:好事最终会发生。" },
{ time: "00:33:03", en: "Message delivery: At most once, at least once, and exactly once.", zh: "消息传递:至多一次,至少一次,以及恰好一次。" },
{ time: "00:34:11", en: "Nobody can guarantee exactly-once delivery and processing generally.", zh: "通常没有人能保证“恰好一次”的传递和处理。" },
{ time: "00:36:46", en: "At most once: Either it happened or it didn't, I won't worry about it.", zh: "至多一次:要么发生了要么没发生,我不再操心了。" },
{ time: "00:37:53", en: "At least once: If I don't get a receipt, I send the request again.", zh: "至少一次:如果我没收到回执,我就再次发送请求。" },
{ time: "00:39:14", en: "We combine 'at least once' delivery with Idempotency.", zh: "我们将“至少一次”传递与“幂等性”结合起来。" },
{ time: "00:39:23", en: "I put an invoice number on my letter. If Bob sees it twice, he knows he already paid it.", zh: "我在信上写上发票编号。如果 Bob 看到两次,他就知道他已经付过款了。" },
{ time: "00:43:17", en: "Think in terms of message passing, not TCP connections.", zh: "要用消息传递的思维来思考,而不是 TCP 连接。" },
{ time: "00:45:02", en: "Start with the client adding IDs that can be used as idempotent keys.", zh: "从客户端添加可以用作幂等键 (Idempotent Keys) 的 ID 开始。" },
{ time: "00:49:40", en: "I was booking a flight, the app was glitchy, and I got charged multiple times.", zh: "我在订机票,APP 出故障了,结果我被扣了好几次款。" },
{ time: "00:50:38", en: "Eventually the system reconciled, ensuring safety, but the user experience was terrible.", zh: "最终系统对账了,保证了安全性,但用户体验非常糟糕。" },
{ time: "00:52:41", en: "The concept of a Holarchy (not hierarchy) helps reasoning about complex systems.", zh: "Holarchy(全子与整体,非层级结构)的概念有助于推理复杂的系统。" },
{ time: "00:53:16", en: "A Holon is a whole in and of itself, but also part of something bigger.", zh: "全子 (Holon) 本身是一个整体,同时也是更大整体的一部分。" }
];
// --- Components ---
function App() {
const [activeTab, setActiveTab] = useState('transcript');
const playerRef = useRef(null);
// Load YouTube API
useEffect(() => {
if (!window.YT) {
const tag = document.createElement('script');
tag.src = "https://www.youtube.com/iframe_api";
const firstScriptTag = document.getElementsByTagName('script')[0];
firstScriptTag.parentNode.insertBefore(tag, firstScriptTag);
window.onYouTubeIframeAPIReady = () => {
playerRef.current = new window.YT.Player('player', {
videoId: VIDEO_ID,
events: {
'onReady': onPlayerReady,
}
});
};
} else {
playerRef.current = new window.YT.Player('player', {
videoId: VIDEO_ID,
events: {
'onReady': onPlayerReady,
}
});
}
}, []);
const onPlayerReady = (event) => {
// Player is ready
};
const seekTo = (timeStr) => {
if (playerRef.current && playerRef.current.seekTo) {
// Convert "00:01:40" to seconds
const parts = timeStr.split(':');
const seconds = parseInt(parts[0]) * 3600 + parseInt(parts[1]) * 60 + parseInt(parts[2]);
playerRef.current.seekTo(seconds, true);
playerRef.current.playVideo();
}
};
return (
<div className="flex flex-col md:flex-row h-screen">
{/* Left: Video Panel */}
<div className="w-full md:w-1/2 bg-black flex items-center justify-center relative">
<div id="player" className="w-full h-full absolute inset-0"></div>
{/* Fallback/Placeholder if JS loads slowly */}
<div className="text-white z-0">Loading Video...</div>
</div>
{/* Right: Info Panel */}
<div className="w-full md:w-1/2 flex flex-col bg-white h-1/2 md:h-full overflow-hidden">
{/* Tabs Header */}
<div className="flex border-b border-slate-200 bg-white">
<button
onClick={() => setActiveTab('transcript')}
className={`flex-1 py-4 text-center text-sm font-medium transition-colors ${activeTab === 'transcript' ? 'active-tab bg-blue-50' : 'text-slate-500 hover:text-slate-700'}`}
>
全文字幕
</button>
<button
onClick={() => setActiveTab('summary')}
className={`flex-1 py-4 text-center text-sm font-medium transition-colors ${activeTab === 'summary' ? 'active-tab bg-blue-50' : 'text-slate-500 hover:text-slate-700'}`}
>
核心总结
</button>
<button
onClick={() => setActiveTab('resources')}
className={`flex-1 py-4 text-center text-sm font-medium transition-colors ${activeTab === 'resources' ? 'active-tab bg-blue-50' : 'text-slate-500 hover:text-slate-700'}`}
>
相关资料
</button>
</div>
{/* Tab Content Area */}
<div className="flex-1 overflow-y-auto p-6 scroll-smooth">
{/* Transcript Tab */}
{activeTab === 'transcript' && (
<div className="space-y-6">
<div className="text-xs text-slate-400 mb-4 flex items-center gap-1">
<i className="ph ph-info"></i> 点击文字可跳转视频进度
</div>
{transcriptData.map((item, index) => (
<div
key={index}
onClick={() => seekTo(item.time)}
className="group cursor-pointer p-3 rounded-lg hover:bg-blue-50 transition-all border border-transparent hover:border-blue-100"
>
<div className="flex items-center gap-2 mb-1">
<span className="text-xs font-mono bg-slate-100 text-slate-500 px-1.5 py-0.5 rounded group-hover:bg-blue-200 group-hover:text-blue-700 transition-colors">
[{item.time}]
</span>
</div>
<p className="text-base text-slate-800 leading-relaxed font-medium mb-1">
{item.zh}
</p>
<p className="text-sm text-slate-500 leading-relaxed group-hover:text-slate-600">
{item.en}
</p>
</div>
))}
</div>
)}
{/* Summary Tab */}
{activeTab === 'summary' && (
<div className="space-y-8 animate-fade-in">
{summaryData.map((section, index) => (
<div key={index} className="bg-white border border-slate-100 rounded-xl p-5 shadow-sm">
<h3 className="text-lg font-bold text-slate-800 mb-3 flex items-center gap-2">
<div className="w-1 h-5 bg-blue-500 rounded-full"></div>
{section.title}
</h3>
<p className="text-slate-600 leading-7 whitespace-pre-line">
{section.content}
</p>
</div>
))}
</div>
)}
{/* Resources Tab */}
{activeTab === 'resources' && (
<div className="space-y-8">
{resourcesData.map((category, index) => (
<div key={index}>
<h3 className="text-sm uppercase tracking-wider text-slate-400 font-bold mb-4 border-b border-slate-100 pb-2">
{category.title}
</h3>
<ul className="space-y-4">
{category.items.map((item, idx) => (
<li key={idx} className="bg-white p-4 rounded-lg border border-slate-200 hover:border-blue-300 transition-colors shadow-sm">
<div className="flex justify-between items-start">
<div>
<h4 className="font-semibold text-slate-800 text-base mb-1">
{item.link ? (
<a href={item.link} target="_blank" className="hover:text-blue-600 hover:underline flex items-center gap-1">
{item.label}
<i className="ph ph-arrow-square-out text-xs"></i>
</a>
) : (
item.label
)}
</h4>
<p className="text-sm text-slate-500 leading-relaxed mt-1">
{item.desc}
</p>
</div>
</div>
</li>
))}
</ul>
</div>
))}
</div>
)}
</div>
</div>
</div>
);
}
const root = ReactDOM.createRoot(document.getElementById('root'));
root.render(<App />);
</script>
</body>
</html>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment