Files
sanbuphy ef70b1d8e1 feat: add comprehensive backend topics and fix build issues
## 新增内容

### 附录文档扩展
- 扩展前端项目架构文档 (frontend-project-architecture.md)
- 扩展后端项目架构文档 (backend-project-architecture.md)
- 扩展数据治理文档 (data-governance.md)
- 扩展数据可视化文档 (data-visualization.md)
- 扩展分布式系统文档 (distributed-systems.md)
- 扩展高可用文档 (high-availability.md)
- 扩展单体到微服务文档 (monolith-to-microservices.md)
- 扩展系统设计方法论文档 (system-design-methodology.md)
- 扩展 Docker 容器文档 (docker-containers.md)
- 扩展 Kubernetes 文档 (kubernetes.md)
- 扩展 Linux 基础文档 (linux-basics.md)
- 扩展神经网络文档 (neural-networks.md)

### 新增交互式组件
- 数据治理组件: DataQualityDemo, DataGovernanceFrameworkDemo, DataLineageDemo
- 数据可视化组件: ChartTypeSelectorDemo, DashboardLayoutDemo
- 分布式系统组件: CAPTheoremDemo, ConsistencyModelsDemo, DistributedChallengesDemo
- 高可用组件: AvailabilityCalculatorDemo, FailoverStrategyDemo
- 系统设计组件: SystemDesignStepsDemo, CapacityEstimationDemo
- Docker 容器组件: DockerArchitectureDemo, DockerLifecycleDemo
- Kubernetes 组件: K8sArchitectureDemo, K8sWorkloadsDemo
- Linux 基础组件: LinuxFileSystemDemo, LinuxCommandDemo, LinuxPermissionsDemo
- 神经网络组件: NeuronDemo, NetworkLayersDemo, NetworkArchitectureDemo
- 单体到微服务组件: ArchEvolutionDemo
- 项目架构组件: ProjectArchitectureComparisonDemo
- 附录导航组件: AppendixFlowMap

### 英文版重构
- 将 en-us 目录重命名为 en
- 更新相关配置和组件中的语言代码

## Bug 修复
- 修复 index.js 中重复的组件导入语句导致的 build 失败
- 恢复被注释的 InvertedIndexDemo 和 SearchRelevanceDemo 导入
- 修复 HomeFeatures.vue 中 en-us 与 config.mjs 中 en 不一致导致的语言切换问题

## 其他改进
- 添加构建脚本 (scripts/build.mjs)
- 更新依赖版本
2026-02-26 04:35:28 +08:00

216 lines
8.2 KiB
Vue
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<!--
DistributedChallengesDemo.vue
分布式系统常见挑战交互演示
-->
<template>
<div class="challenges-demo">
<div class="header">
<div class="title">分布式系统八大挑战</div>
<div class="subtitle">点击查看每个挑战的详情和应对策略</div>
</div>
<div class="challenge-grid">
<div
v-for="c in challenges"
:key="c.key"
:class="['challenge-card', { active: activeChallenge === c.key }]"
@click="activeChallenge = activeChallenge === c.key ? null : c.key"
>
<div class="challenge-icon">{{ c.icon }}</div>
<div class="challenge-name">{{ c.name }}</div>
</div>
</div>
<div v-if="current" class="detail-panel">
<div class="detail-title">{{ current.icon }} {{ current.name }}</div>
<div class="detail-desc">{{ current.desc }}</div>
<div class="detail-scenario">
<span class="label">场景举例</span>{{ current.scenario }}
</div>
<div class="detail-solution">
<span class="label">应对策略</span>
<ul class="solution-list">
<li v-for="(s, i) in current.solutions" :key="i">{{ s }}</li>
</ul>
</div>
</div>
</div>
</template>
<script setup>
import { ref, computed } from 'vue'
const activeChallenge = ref('network')
const challenges = [
{
key: 'network',
name: '网络不可靠',
icon: '🔌',
desc: '分布式系统的节点通过网络通信,而网络随时可能丢包、延迟、断开。这是分布式系统最根本的挑战——你永远不能假设网络是可靠的。',
scenario: '服务 A 调用服务 B,请求发出后 3 秒没收到响应。是 B 没收到?还是 B 处理了但响应丢了?A 无法区分。',
solutions: [
'超时 + 重试:设置合理超时,失败后重试(需保证幂等性)',
'心跳检测:定期发送心跳包检测连接是否存活',
'断路器模式:连续失败后暂停调用,避免雪崩'
]
},
{
key: 'clock',
name: '时钟不同步',
icon: '⏰',
desc: '每台机器的物理时钟都有微小偏差(时钟漂移),即使用 NTP 同步也只能精确到毫秒级。在分布式系统中,你不能依赖物理时钟来判断事件的先后顺序。',
scenario: '节点 A 在 10:00:00.001 写入数据,节点 B 在 10:00:00.002 写入数据。但 B 的时钟快了 5ms,实际上 B 先写的。',
solutions: [
'逻辑时钟(Lamport Clock):用递增计数器代替物理时钟',
'向量时钟(Vector Clock):每个节点维护一个向量,追踪因果关系',
'TrueTimeGoogle Spanner):用 GPS + 原子钟提供有界误差的时间'
]
},
{
key: 'partition',
name: '网络分区',
icon: '✂️',
desc: '网络分区是指部分节点之间无法通信,但各自仍在运行。这时系统必须在一致性和可用性之间做选择(CAP 定理)。',
scenario: '数据中心 A 和 B 之间的光纤被挖断,两边的服务各自运行,但数据开始分叉。',
solutions: [
'CP 策略:分区时拒绝写入,保证一致性(如 ZooKeeper',
'AP 策略:分区时允许写入,事后合并冲突(如 DynamoDB',
'多数派写入:只要多数节点确认就算成功'
]
},
{
key: 'consistency',
name: '数据一致性',
icon: '🔄',
desc: '多个副本之间如何保持数据一致?强一致性性能差,最终一致性可能读到旧数据。没有银弹,只有权衡。',
scenario: '用户在节点 A 修改了头像,但刷新页面时请求被路由到节点 B,看到的还是旧头像。',
solutions: [
'读写同一节点:写入后的读请求路由到同一节点',
'读修复(Read Repair):读取时检测不一致并修复',
'反熵协议:后台定期比对副本,修复差异'
]
},
{
key: 'failure',
name: '部分失败',
icon: '💥',
desc: '分布式系统中,部分节点可能失败而其他节点正常运行。系统需要在部分失败的情况下继续提供服务。',
scenario: '5 个节点的集群中有 2 个节点宕机,系统需要判断:是继续服务还是停止?剩余节点的数据是否完整?',
solutions: [
'冗余副本:数据存多份,单点故障不影响可用性',
'故障检测:通过心跳和超时机制快速发现故障节点',
'自动故障转移:检测到主节点故障后自动切换到备节点'
]
},
{
key: 'split-brain',
name: '脑裂问题',
icon: '🧠',
desc: '当网络分区导致集群分成两部分时,两边都认为自己是"主",各自接受写入,导致数据冲突。这就是脑裂。',
scenario: '主从架构中,主节点和从节点之间网络断开,从节点以为主节点挂了,自己升级为主。现在有两个主节点同时写入。',
solutions: [
'多数派选举:只有获得多数票的节点才能成为主节点',
'Fencing Token:旧主节点的写入请求会被存储层拒绝',
'仲裁节点:引入第三方节点来裁决谁是真正的主'
]
},
{
key: 'ordering',
name: '事件排序',
icon: '📋',
desc: '在分布式系统中,不同节点上发生的事件没有全局统一的顺序。如何确定"谁先谁后"是一个根本性难题。',
scenario: '两个用户同时编辑同一个文档,节点 A 收到"删除第 3 行",节点 B 收到"修改第 3 行"。最终结果取决于执行顺序。',
solutions: [
'全序广播(Total Order Broadcast):所有节点以相同顺序处理消息',
'CRDT(无冲突复制数据类型):数据结构本身保证合并无冲突',
'OT(操作转换):Google Docs 使用的协作编辑算法'
]
},
{
key: 'transaction',
name: '分布式事务',
icon: '🔐',
desc: '跨多个节点的操作如何保证原子性?要么全部成功,要么全部回滚。这比单机事务复杂得多。',
scenario: '电商下单:扣库存在服务 A,扣余额在服务 B,创建订单在服务 C。如果扣余额失败,库存需要回滚。',
solutions: [
'2PC(两阶段提交):协调者先问所有参与者能否提交,再统一提交',
'Saga 模式:每个步骤有对应的补偿操作,失败时逐步回滚',
'TCCTry-Confirm-Cancel):预留资源 → 确认 → 取消'
]
}
]
const current = computed(() =>
challenges.find(c => c.key === activeChallenge.value)
)
</script>
<style scoped>
.challenges-demo {
border: 1px solid var(--vp-c-divider);
background: var(--vp-c-bg-soft);
border-radius: 12px;
padding: 1.5rem;
margin: 1.5rem 0;
}
.header { margin-bottom: 1rem; }
.title { font-weight: 700; font-size: 1.1rem; }
.subtitle { color: var(--vp-c-text-2); font-size: 0.9rem; }
.challenge-grid {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(100px, 1fr));
gap: 0.5rem;
margin-bottom: 1rem;
}
.challenge-card {
display: flex;
flex-direction: column;
align-items: center;
gap: 0.2rem;
padding: 0.6rem 0.4rem;
border-radius: 8px;
cursor: pointer;
background: var(--vp-c-bg);
border: 1px solid var(--vp-c-divider);
transition: all 0.2s;
}
.challenge-card:hover { border-color: var(--vp-c-brand); }
.challenge-card.active {
border-color: var(--vp-c-brand);
background: rgba(var(--vp-c-brand-rgb), 0.05);
}
.challenge-icon { font-size: 1.3rem; }
.challenge-name { font-size: 0.75rem; font-weight: 600; text-align: center; }
.detail-panel {
background: var(--vp-c-bg);
border-radius: 8px;
padding: 1rem;
border: 1px solid var(--vp-c-divider);
}
.detail-title { font-weight: 700; font-size: 0.95rem; margin-bottom: 0.4rem; }
.detail-desc {
font-size: 0.82rem;
color: var(--vp-c-text-2);
margin-bottom: 0.5rem;
}
.detail-scenario {
font-size: 0.82rem;
margin-bottom: 0.5rem;
padding: 0.5rem;
background: rgba(245, 158, 11, 0.06);
border-radius: 6px;
}
.detail-solution { font-size: 0.82rem; }
.solution-list {
margin: 0.3rem 0 0 1.2rem;
padding: 0;
}
.solution-list li {
margin-bottom: 0.2rem;
font-size: 0.8rem;
color: var(--vp-c-text-2);
}
.label { font-weight: 600; color: var(--vp-c-text-2); }
</style>