| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752 |
- 'use client';
- import { type MouseEvent, type ReactNode } from 'react';
- import { ArrowRight, BookOpen, Route, Workflow } from 'lucide-react';
- import { courseHref } from './course-navigation';
- import { modules } from './module-catalog';
- import './course-home.css';
- type Navigate = (module: string, lesson?: string) => void;
- const moduleDetails = [
- {
- slug: 'api',
- position: '请求入口:浏览器与业务逻辑之间',
- responsibility:
- '把一个 Python 函数变成别人能调用的 HTTP 接口,约定输入、返回值、错误和通信方式。',
- importance:
- '接口是前后端的共同约定。边界不清,调用方就不知道请求是否成功、如何处理失败。',
- problem:
- '参数乱传、错误信息不一致、慢调用卡住服务,以及结果需要逐步展示时怎样通信。',
- example:
- '商家创建商品、修改名称和价格、切换上架状态;用这些操作练 CRUD,再用商品咨询演示 SSE 与 WebSocket。',
- question: '用户的一个操作,怎样成为服务端的一次可靠调用?',
- },
- {
- slug: 'database',
- position: '持久数据层:任务与业务记录的真源',
- responsibility:
- '通过表、约束、索引和事务保存数据;“真源”就是冲突时系统最终以这里的记录为准。',
- importance:
- '进程会重启、请求会并发。数据库既要让数据留下来,也要守住“哪些状态允许存在”的规则。',
- problem:
- '数据丢失、重复记录、并发覆盖、慢查询、锁等待,以及备份能否真正恢复。',
- example:
- '在 shop_lab 从商品与分类需求推导表结构,解释价格为什么按分存、分类为什么拆表,再练事务、索引与恢复。',
- question: '服务重启后,哪些事实必须还在?',
- },
- {
- slug: 'api-database',
- position: 'API 与 MySQL 的连接处:会话和事务边界',
- responsibility:
- '把接口接入数据库,安排连接的借用与归还,明确何时提交、何时回滚,以及如何升级表结构。',
- importance:
- '接口返回“成功”应对应已经提交的事实;重复请求和并发修改不能悄悄破坏业务规则。',
- problem:
- '连接泄漏、事务跨请求、重复提交、并发更新冲突,以及“记录写了、任务没发出去”的双写窗口。',
- example:
- '长任务受理时,把任务记录和 outbox 待投递事件写入同一事务;课程用持久化商品服务理解这些边界。',
- question: '一次接口成功,到底承诺了哪些数据已经写入?',
- },
- {
- slug: 'tasks',
- position: '执行层:任务投递器、队列与独立 worker',
- responsibility:
- '先区分协程、线程和进程,再把长任务交给独立执行进程;管理状态、并发、重试与取消。',
- importance:
- '“接口先返回”不会自动带来可靠性。任务能否跨进程退出恢复,要依靠持久记录、投递和确认机制。',
- problem:
- '请求超时、事件循环阻塞、任务丢失、重复执行、积压,以及 worker 做到一半退出。',
- example:
- '商家导出商品清单,API 先返回任务 ID,worker 读取商品快照并生成文件;用这条链路练并发、重试和恢复。',
- question: '用户不用一直等的工作,之后由谁保证继续执行?',
- },
- {
- slug: 'redis',
- position: '加速层:API 旁的可重建缓存',
- responsibility:
- '把高频读取的结果临时放到 Redis;定义缓存键、有效期、更新失效、容量和故障降级。',
- importance:
- '缓存让重复读取更快,但可能短暂落后于数据库。先说清可接受的旧数据窗口,才知道怎样使用它。',
- problem:
- '数据库重复承压、热点同时过期、缓存穿透、内存耗尽,以及缓存不可用时请求雪崩。',
- example:
- '商品详情被反复读取时使用 Redis 缓存;商家修改商品后处理失效,并以 MySQL 为真源。',
- question: '哪些数据可以临时读副本,丢了也能重新构建?',
- },
- {
- slug: 'docker',
- position: '运行包装层:API、worker 和依赖服务的容器',
- responsibility:
- '把代码与依赖构建成镜像,用 Compose 组织服务网络、配置、健康检查、持久卷与资源限制。',
- importance:
- '同一份代码需要在不同机器上按可重复的方式启动;容器删掉时,数据库数据仍应有独立的保存位置。',
- problem:
- '本地能跑而部署失败、服务互相找不到、容器重建丢数据、资源争抢,以及升级无法回滚。',
- example:
- '把 API、worker、MySQL、Redis 作为职责不同的服务运行;课程搭建 shop-service 容器环境。',
- question: '怎样把几个进程及其依赖装成可重复运行的一套环境?',
- },
- {
- slug: 'linux',
- position: '主机与网络入口:承载进程,对外提供服务',
- responsibility:
- '管理运行账户、目录权限、端口、systemd、Nginx、TLS、发布回滚和备份恢复流程。',
- importance:
- '程序能启动只是起点。它还要能被安全访问、在故障后恢复,并且在升级时有明确的退路。',
- problem:
- '端口不通、权限错误、进程退出、流式响应被代理缓冲、证书配置错误和发布中断。',
- example:
- '为商品服务的 HTTP 与流式入口配置反向代理,把 shop-service 部署到独立 Linux 练习机。',
- question: '从自己的电脑到别人能访问的服务,中间还有哪些工作?',
- },
- {
- slug: 'troubleshooting',
- position: '横跨各层:日志、指标、追踪与恢复手册',
- responsibility:
- '用请求 ID 和任务 ID 串起现场;指标看整体变化,日志看具体事件,追踪看跨组件耗时。',
- importance:
- '“很慢”只是症状。先找证据和影响范围,才能决定该限流、回滚,还是修复某个依赖。',
- problem:
- '不知道请求卡在哪、CPU 与连接耗尽、慢 SQL、缓存失效、任务积压,以及修好后无法证明恢复。',
- example:
- '同一个任务 ID 贯穿 API、投递和 worker,区分“排队久”和“执行慢”;课程进行隔离故障演练。',
- question: '用户说任务一直转圈,怎样沿着证据找到卡住的那一段?',
- },
- {
- slug: 'distributed',
- position: '设计视角:所有跨进程、跨机器的连接处',
- responsibility:
- '用架构图与故障推演理解扩容、一致性、复制、分片、消息可靠性和服务治理;练习说明设计取舍。',
- importance:
- '组件各自正常,不等于协作一定正确。网络超时只能说明没及时收到答复,不能证明对方没执行。',
- problem:
- '部分失败、重复消息、数据不一致、流量突增、热点、级联故障,以及系统设计题只会堆组件。',
- example:
- '讨论“任务已完成但响应丢失”“数据库成功但投递失败”等场景;12 节课以理论和面试推演为主。',
- question: '多个组件没有同时成功时,系统该如何继续工作?',
- },
- {
- slug: 'review',
- position: '课程收尾:逐一检查九个技术模块',
- responsibility:
- '用理解问题、情境推演和成果证据检验掌握程度,把薄弱点对应到原课时。',
- importance:
- '能跟着做出结果之后,还需要独立解释原因,并在条件变化时作出有依据的判断。',
- problem:
- '看答案觉得都懂,合上课件却讲不清、做不出,或不知道还需要补哪一课。',
- example:
- '继续用商品查询、编辑和清单导出,闭卷回答问题,核对要点,并记录需要回学的部分。',
- question: '学完之后,拿什么证明自己已经掌握?',
- },
- ];
- function HomeLink({
- module,
- navigate,
- children,
- className,
- }: {
- module: string;
- navigate: Navigate;
- children: ReactNode;
- className?: string;
- }) {
- return (
- <a
- href={courseHref(module)}
- className={className}
- onClick={(event: MouseEvent<HTMLAnchorElement>) => {
- if (
- event.button !== 0 ||
- event.metaKey ||
- event.ctrlKey ||
- event.shiftKey ||
- event.altKey
- )
- return;
- event.preventDefault();
- navigate(module);
- }}
- >
- {children}
- </a>
- );
- }
- function ArchitectureNode({
- title,
- lines,
- module,
- kind = 'service',
- }: {
- title: string;
- lines: string[];
- module?: string;
- kind?: 'service' | 'context' | 'queue' | 'storage' | 'runtime';
- }) {
- const className = `home-architecture-node home-node-${kind}`;
- const content = (
- <>
- <strong>{title}</strong>
- {lines.map((line) => (
- <span key={line}>{line}</span>
- ))}
- </>
- );
- return module ? (
- <a
- className={className}
- href={`#home-module-${module}`}
- aria-label={`查看${title}的课程定位`}
- >
- {content}
- </a>
- ) : (
- <div className={className}>{content}</div>
- );
- }
- function ArchitectureLayer({
- name,
- responsibility,
- kind,
- children,
- note,
- }: {
- name: string;
- responsibility: string;
- kind: string;
- children: ReactNode;
- note?: string;
- }) {
- return (
- <div className={`home-architecture-layer home-layer-${kind}`}>
- <div className="home-layer-heading">
- <h3>{name}</h3>
- <p>{responsibility}</p>
- </div>
- <div className="home-layer-content">
- <div className="home-layer-nodes">{children}</div>
- {note && <p className="home-layer-note">{note}</p>}
- </div>
- </div>
- );
- }
- function ArchitectureDiagram() {
- return (
- <div className="home-layered-architecture">
- <div className="home-architecture-stack">
- <ArchitectureLayer
- name="客户端层"
- responsibility="发起操作 · 接收结果"
- kind="client"
- >
- <ArchitectureNode
- title="客户端"
- lines={[
- '浏览器 / API 调用方',
- '提交请求、查询任务状态、订阅执行进度',
- ]}
- kind="context"
- />
- </ArchitectureLayer>
- <ArchitectureLayer
- name="接入层"
- responsibility="对外入口 · 流量转发"
- kind="access"
- >
- <ArchitectureNode
- title="07 入口网关 · Nginx / TLS"
- lines={['接收 HTTPS 请求,通过路由与反向代理转发到 API']}
- module="linux"
- />
- </ArchitectureLayer>
- <ArchitectureLayer
- name="业务服务层"
- responsibility="处理请求 · 组织业务"
- kind="business"
- note="短请求由 API 调用业务并返回;长任务在同一事务中保存任务与 outbox,提交后返回任务 ID。"
- >
- <ArchitectureNode
- title="01 API 服务"
- lines={['业务鉴权、参数校验', '同步响应 / 受理长任务']}
- module="api"
- />
- <ArchitectureNode
- title="Agent 编排*"
- lines={['规划步骤、管理上下文', '由 API 或 worker 调用']}
- kind="context"
- />
- <ArchitectureNode
- title="模型 / 工具*"
- lines={['由 Agent 编排调用', '生成、检索或执行动作']}
- kind="context"
- />
- </ArchitectureLayer>
- <ArchitectureLayer
- name="异步执行层"
- responsibility="交接任务 · 独立执行"
- kind="tasks"
- note="投递器读取已提交的 outbox;worker 幂等处理、写回 MySQL 后再确认消息,投递与执行均需考虑重试。"
- >
- <ArchitectureNode
- title="04 任务投递器"
- lines={['读取 outbox 并发送消息', '发送后更新投递状态']}
- module="tasks"
- kind="queue"
- />
- <ArrowRight
- className="home-task-arrow"
- size={18}
- aria-hidden="true"
- />
- <ArchitectureNode
- title="04 消息队列"
- lines={['Broker 暂存任务消息', '等待 worker 领取']}
- module="tasks"
- kind="queue"
- />
- <ArrowRight
- className="home-task-arrow"
- size={18}
- aria-hidden="true"
- />
- <ArchitectureNode
- title="04 Worker"
- lines={['执行工作 / 调用编排', '幂等处理、写回结果']}
- module="tasks"
- kind="queue"
- />
- </ArchitectureLayer>
- <ArchitectureLayer
- name="数据层"
- responsibility="访问数据 · 保存事实"
- kind="data"
- note="API 与 worker 按需访问;缓存未命中时读取 MySQL 真源。Redis 缓存与消息队列承担不同职责。"
- >
- <ArchitectureNode
- title="03 API + 数据库"
- lines={['管理会话与事务边界', '任务 + outbox 同事务提交']}
- module="api-database"
- kind="storage"
- />
- <ArchitectureNode
- title="02 MySQL"
- lines={['业务数据的持久真源', '商品、任务状态与结果']}
- module="database"
- kind="storage"
- />
- <ArchitectureNode
- title="05 Redis 缓存"
- lines={['保存可重建的查询结果', 'TTL 到期 / 更新时失效']}
- module="redis"
- kind="storage"
- />
- </ArchitectureLayer>
- <ArchitectureLayer
- name="运行基础层"
- responsibility="承载服务 · 部署恢复"
- kind="runtime"
- note="承载本地服务及依赖;外部模型与工具服务运行在各自系统中。"
- >
- <ArchitectureNode
- title="06 Docker"
- lines={['封装 API、worker 与本地依赖', '镜像、容器、网络与持久卷']}
- module="docker"
- kind="runtime"
- />
- <ArchitectureNode
- title="07 Linux"
- lines={['承载进程与容器', '权限、网络、发布与恢复']}
- module="linux"
- kind="runtime"
- />
- </ArchitectureLayer>
- </div>
- <aside className="home-crosscutting" aria-label="贯穿各层的能力">
- <div className="home-crosscutting-heading">
- <span>贯穿各层</span>
- <p>从请求入口到运行底座</p>
- </div>
- <a
- href="#home-module-troubleshooting"
- className="home-crosscutting-card"
- >
- <span className="home-crosscutting-number">08</span>
- <h3>观测与排障</h3>
- <p>用请求 ID / 任务 ID 串联各层证据。</p>
- <dl>
- <div>
- <dt>日志</dt>
- <dd>发生了什么</dd>
- </div>
- <div>
- <dt>指标</dt>
- <dd>整体运行怎样</dd>
- </div>
- <div>
- <dt>追踪</dt>
- <dd>慢在哪一段</dd>
- </div>
- </dl>
- </a>
- <a href="#home-module-distributed" className="home-crosscutting-card">
- <span className="home-crosscutting-number">09</span>
- <h3>分布式设计</h3>
- <p>审视跨进程、跨机器协作中的失败与取舍。</p>
- <ul>
- <li>超时与部分失败</li>
- <li>重复消息与幂等</li>
- <li>一致性与恢复</li>
- </ul>
- <span className="home-crosscutting-tag">设计视角 · 理论模块</span>
- </a>
- </aside>
- </div>
- );
- }
- const timeline = [
- [
- '提交请求',
- '商家点击“导出商品清单”。API 校验请求并确定商品快照;这时尚未承诺文件已经生成。',
- '当前请求',
- ],
- [
- '记录已提交',
- '在一个数据库事务里写入任务和待投递事件。事务提交后,API 返回 202 与任务 ID。',
- '受理 ≠ 完成',
- ],
- [
- '任务交接',
- '投递器读取事件并发送到队列。此时浏览器的原请求已经结束,投递失败可以稍后重试。',
- '异步开始',
- ],
- [
- '独立执行',
- 'worker 领取任务,把固定的商品快照写入导出文件;完成后保存结果引用,再确认消息。重复消息需要幂等处理。',
- '可能重试',
- ],
- [
- '读取结果',
- '客户端拿任务 ID 查询 API,或订阅进度。API 从任务记录判断等待、执行、成功或失败。',
- '看持久状态',
- ],
- ];
- export function CourseHome({ navigate }: { navigate: Navigate }) {
- const totalLessons = modules.reduce((sum, module) => sum + module.count, 0);
- return (
- <article className="course-home" id="course-home">
- <header className="home-hero">
- <div className="eyebrow">
- <span /> AGENT BACKEND · COURSE GUIDE
- </div>
- <h1 tabIndex={-1}>
- 先看见整个系统,
- <br />
- 再学会每一个模块<span className="title-dot">.</span>
- </h1>
- <p className="home-lead">
- 从一个容易理解的电商商品服务出发,逐步学会接住请求、保存商品、导出清单,并在失败时恢复。这些后端能力也构成服务端
- Agent 的基础。
- </p>
- <div className="home-actions">
- <HomeLink
- module="api"
- navigate={navigate}
- className="home-primary-link"
- >
- 从 API 第一模块开始 <ArrowRight size={17} />
- </HomeLink>
- <a href="#architecture" className="home-secondary-link">
- 先看系统全貌 <Workflow size={17} />
- </a>
- </div>
- <dl className="home-course-facts">
- <div>
- <dt>{String(modules.length).padStart(2, '0')}</dt>
- <dd>学习模块</dd>
- </div>
- <div>
- <dt>{totalLessons}</dt>
- <dd>课时与自测单元</dd>
- </div>
- <div>
- <dt>8 + 1 + 1</dt>
- <dd>后端实践 + 架构理论 + 复盘自测</dd>
- </div>
- </dl>
- </header>
- <aside className="home-scope-note" aria-label="课程范围">
- <BookOpen size={21} />
- <div>
- <strong>用简单的电商商品服务,走通整个后端链路。</strong>
- <p>
- 实战聚焦商品管理、分类、评价和清单导出;价格按分存储,上下架用布尔值表示。前
- 8 个模块依次补齐接口、存储、任务、缓存、部署和排障,第 9
- 个模块讲分布式设计理论,第 10
- 个模块逐一复盘并自测掌握程度。下图同时标出 Agent 的扩展位置;Agent
- 编排、模型与工具、完整业务鉴权用于说明所在位置,不属于本课已实现的完整
- Agent / RAG 项目。
- </p>
- </div>
- </aside>
- <section id="architecture" aria-labelledby="home-architecture-heading">
- <div className="home-section-heading">
- <span>01 / SYSTEM MAP</span>
- <h2 id="home-architecture-heading">把课程放进一张分层架构图</h2>
- <p>
- 从客户端到运行底座,按职责逐层理解系统;观测与设计能力贯穿各层。节点编号对应下方课程模块,点击可查看定位。
- </p>
- </div>
- <figure className="home-architecture-figure">
- <div className="home-diagram-legend">
- <span>
- <i className="home-legend-module" /> 课程覆盖模块
- </span>
- <span>
- <i className="home-legend-task" /> 异步任务交接
- </span>
- <span>
- <i className="home-legend-context" /> * Agent 扩展上下文
- </span>
- </div>
- <ArchitectureDiagram />
- <figcaption>
- 分层表示职责与支撑关系,请求按需访问相关组件,并非逐层依次执行。橙色箭头表示异步任务交接;API
- 负责业务鉴权,Nginx 负责入口代理。带 * 的 Agent
- 编排、模型与工具用于说明扩展位置,不属于本课已实现的完整系统。
- </figcaption>
- </figure>
- <div className="home-reading-paths">
- <article>
- <span className="home-reading-number">A</span>
- <h3>短请求:当场取回结果</h3>
- <p>
- 客户端 → 网关 → API → 数据库、缓存或业务调用 →
- 原路返回。用户等待的是这一次请求完成;慢依赖仍会占用请求的时间预算。
- </p>
- </article>
- <article>
- <span className="home-reading-number">B</span>
- <h3>长任务:先受理,再执行</h3>
- <p>
- API 写入任务和 outbox → 返回任务 ID。投递器 → 队列 → worker →
- 写回结果。用户之后再查询进度,接收成功并不等于执行成功。
- </p>
- </article>
- <article>
- <span className="home-reading-number">C</span>
- <h3>运行与可靠性:贯穿整张图</h3>
- <p>
- Docker 管运行单元,Linux
- 管主机与入口,观测帮助找故障。分布式设计关注它们之间的网络、重复、超时与不一致。
- </p>
- </article>
- </div>
- <p className="home-term-note">
- <strong>两个容易混淆的词:</strong>队列像“待办传送带”,worker
- 是实际做事的进程;Redis 可以用来缓存,也可以承担某些队列的 broker
- 角色,但两种用途的丢失容忍度、持久化和内存策略不同,不能因产品名相同就视为同一种数据。
- </p>
- </section>
- <section id="modules" aria-labelledby="home-modules-heading">
- <div className="home-section-heading">
- <span>02 / MODULE GUIDE</span>
- <h2 id="home-modules-heading">每个模块,补上哪一种能力</h2>
- <p>
- 前九个模块对应上图中的技术位置,最后一个模块用于复盘自测,检查这些能力能否独立运用。
- </p>
- </div>
- <div className="home-module-grid">
- {moduleDetails.map((detail, index) => {
- const catalogEntry = modules.find(
- (candidate) => candidate.slug === detail.slug,
- );
- if (!catalogEntry) return null;
- return (
- <article
- key={detail.slug}
- className="home-module-card"
- id={`home-module-${detail.slug}`}
- >
- <div className="home-module-card-top">
- <span className="home-module-number">
- {String(index + 1).padStart(2, '0')}
- </span>
- <span>
- {catalogEntry.count}{' '}
- {detail.slug === 'review' ? '自测单元' : '课时'} ·{' '}
- {detail.slug === 'distributed'
- ? '理论与面试'
- : catalogEntry.kicker}
- </span>
- <catalogEntry.icon size={19} />
- </div>
- <h3>{catalogEntry.name}</h3>
- <p className="home-module-question">{detail.question}</p>
- <dl>
- <div>
- <dt>所在位置</dt>
- <dd>{detail.position}</dd>
- </div>
- <div>
- <dt>负责什么</dt>
- <dd>{detail.responsibility}</dd>
- </div>
- <div>
- <dt>为何重要</dt>
- <dd>{detail.importance}</dd>
- </div>
- <div>
- <dt>解决问题</dt>
- <dd>{detail.problem}</dd>
- </div>
- <div>
- <dt>放进实例</dt>
- <dd>{detail.example}</dd>
- </div>
- </dl>
- <HomeLink
- module={detail.slug}
- navigate={navigate}
- className="home-module-entry"
- >
- 进入{catalogEntry.name}
- <ArrowRight size={16} />
- </HomeLink>
- </article>
- );
- })}
- </div>
- </section>
- <section id="journey" aria-labelledby="home-task-story-heading">
- <div className="home-section-heading">
- <span>03 / ONE LONG TASK</span>
- <h2 id="home-task-story-heading">把“导出一份商品清单”走一遍</h2>
- <p>
- 这是把多个模块连起来的设计示例:关键不在“后台”两个字,而在每个阶段承诺了什么、失败后由谁接手。
- </p>
- </div>
- <ol className="home-task-timeline">
- {timeline.map(([title, description, state], index) => (
- <li key={title}>
- <span className="home-timeline-index">{index + 1}</span>
- <div>
- <div className="home-timeline-title">
- <h3>{title}</h3>
- <span>{state}</span>
- </div>
- <p>{description}</p>
- </div>
- </li>
- ))}
- </ol>
- <div className="home-failure-note">
- <strong>如果 worker 刚写完结果就退出了?</strong>
- <p>
- 消息可能尚未确认,随后会被再次投递。所以“至少一次投递”仍需业务幂等:同一个任务
- ID
- 再次到达时,要识别已经提交的结果。若任务会向外部系统产生副作用,还需要对方支持幂等键或配套的核对与补偿流程。
- </p>
- <HomeLink module="distributed" navigate={navigate}>
- 去分布式模块推演更多失败场景 <ArrowRight size={15} />
- </HomeLink>
- </div>
- </section>
- <section id="learning-path" aria-labelledby="home-learning-path-heading">
- <div className="home-section-heading">
- <span>04 / LEARNING ROUTE</span>
- <h2 id="home-learning-path-heading">没有后端经验,就按这条路走</h2>
- <p>
- 会基础
- Python、能执行终端命令即可从第一模块开始。数据库、Docker、Linux
- 环境在对应模块准备,每一步都带着上一阶段的问题进入下一阶段。
- </p>
- </div>
- <ol className="home-learning-route">
- <li>
- <Route size={20} />
- <div>
- <h3>先让请求有入口,数据能保存</h3>
- <p>
- 01 API → 02 数据库 → 03 API +
- 数据库。先完成一个能正确提交、查询与修改数据的服务。
- </p>
- </div>
- <HomeLink module="api" navigate={navigate}>
- 开始 <ArrowRight size={16} />
- </HomeLink>
- </li>
- <li>
- <Workflow size={20} />
- <div>
- <h3>再处理等待、并发与重复读取</h3>
- <p>
- 04 异步任务 + 05 Redis。两者都建立在持久化 API
- 之上;任务模块进入队列部分前,先准备 Redis 基础环境。
- </p>
- </div>
- <HomeLink module="tasks" navigate={navigate}>
- 进入 <ArrowRight size={16} />
- </HomeLink>
- </li>
- <li>
- <BookOpen size={20} />
- <div>
- <h3>让服务运行起来,也能查清故障</h3>
- <p>
- 06 Docker → 07 Linux → 08
- 排障。用部署、停止、升级和恢复检验前面实现的边界。
- </p>
- </div>
- <HomeLink module="docker" navigate={navigate}>
- 进入 <ArrowRight size={16} />
- </HomeLink>
- </li>
- <li>
- <Workflow size={20} />
- <div>
- <h3>把组件连起来,解释架构为什么这样设计</h3>
- <p>
- 09
- 分布式系统设计。用已有组件经验讨论容量、数据与失败;围绕理论和面试场景展开,不安排实战代码。
- </p>
- </div>
- <HomeLink module="distributed" navigate={navigate}>
- 进入 <ArrowRight size={16} />
- </HomeLink>
- </li>
- <li>
- <BookOpen size={20} />
- <div>
- <h3>最后,检验每个模块是否真的掌握</h3>
- <p>
- 10
- 复盘与自测。每个技术模块对应一个自测单元:独立回答问题、推演变化、核对掌握证据,再按缺口回学。
- </p>
- </div>
- <HomeLink module="review" navigate={navigate}>
- 开始自测 <ArrowRight size={16} />
- </HomeLink>
- </li>
- </ol>
- </section>
- </article>
- );
- }
|