1. 先理解"单体"与"微服务"
想象一家全能餐厅:
- 一个厨房做所有菜(炒菜、蒸菜、凉菜、甜点、结账、洗碗......)
- 所有员工在一个大空间里工作
- 如果某个环节出问题(比如洗碗机坏了),整个餐厅可能都要暂停
这就是单体架构:一个程序(一个代码库、一个进程)包含了所有功能。
现在想象美食广场:
- 每个档口独立:拉面档口、披萨档口、奶茶档口、收银台独立
- 拉面档口有自己的厨房、食材、员工
- 一个档口坏了,不影响隔壁档口继续卖
这就是微服务架构 :把一个大型应用拆成多个小型独立服务,每个服务专注做一件事,各自运行、各自部署。
2. 微服务的核心特点(极简版)
- 单一职责:每个服务只做一件明确的事(比如"用户服务"只管理用户注册、登录;"订单服务"只处理订单)。
- 独立部署:修改订单服务,不需要重新发布用户服务。
- 独立数据:每个服务有自己的数据库(可以不同种类:MySQL、Redis、MongoDB)。
- 轻量级通信:服务之间通过 HTTP/HTTPS、gRPC 或消息队列互相调用。
3. FastAPI 在微服务中的角色
FastAPI 是构建微服务的绝佳工具,因为它:
- 快:性能接近 Node.js 和 Go,适合高并发。
- 自带异步 :
async/await方便调用其他服务(不会阻塞)。 - 自动生成 API 文档 :每个微服务都自动有
/docs,调试和协作方便。 - 数据校验和序列化:Pydantic 帮你保证服务之间传递的数据格式正确。
- 依赖注入:轻松复用认证、数据库会话等逻辑。
简单说:你用 FastAPI 写一个"用户服务",再写一个"订单服务",它们各自独立运行,互相通过 HTTP 请求调用。
4. 一个具体的例子:电商微服务
假设我们拆成三个服务:
| 服务名称 | 职责 | FastAPI 入口 |
|---|---|---|
| 用户服务 | 注册、登录、查询用户信息 | http://user-service:8000 |
| 商品服务 | 商品增删改查、库存管理 | http://product-service:8001 |
| 订单服务 | 创建订单、查询订单 | http://order-service:8002 |
4.1 用户服务(简化版)
python
# user_service/main.py
from fastapi import FastAPI
app = FastAPI()
users_db = {"1": {"name": "张三", "email": "zhang@example.com"}}
@app.get("/users/{user_id}")
async def get_user(user_id: str):
return users_db.get(user_id, {"error": "user not found"})
@app.post("/users")
async def create_user(name: str, email: str):
user_id = str(len(users_db) + 1)
users_db[user_id] = {"name": name, "email": email}
return {"user_id": user_id}
4.2 订单服务(需要调用用户服务)
python
# order_service/main.py
from fastapi import FastAPI, HTTPException
import httpx
app = FastAPI()
orders = []
@app.post("/orders")
async def create_order(user_id: str, product: str):
# 调用用户服务,检查用户是否存在
async with httpx.AsyncClient() as client:
resp = await client.get(f"http://user-service:8000/users/{user_id}")
if resp.status_code != 200:
raise HTTPException(400, "用户不存在")
order_id = len(orders) + 1
orders.append({"order_id": order_id, "user_id": user_id, "product": product})
return {"order_id": order_id, "status": "created"}
关键点 :订单服务不直接查数据库,而是通过 HTTP 请求询问用户服务。两个服务完全独立。
5. 服务之间怎么互相找到?(服务发现)
在小例子中,我们写死了地址 http://user-service:8000。但在真实生产环境中,服务可能随时迁移 IP、增减实例。这时候就需要服务发现 工具(如 Consul、etcd、Nacos)或简单的反向代理(如 Nginx、Traefik)。不过作为小白,你先记住:微服务之间通过网络通信,你需要一种方式知道"用户服务现在在哪里"。
6. 微服务带来的挑战(只提一下,不展开)
- 分布式事务:下单需要扣库存、创建订单、扣钱,跨服务很难保证原子性。
- 调试困难:一个请求可能经过 5 个服务,排查问题需要链路追踪(如 Jaeger)。
- 部署复杂:需要容器编排(Kubernetes)来管理几十个服务。
- 数据一致性:每个服务有自己的数据库,数据同步需要最终一致性。
但是不要怕:对于很多中小项目,先写成一个 FastAPI 单体,等真正遇到瓶颈再拆微服务。不要为了"微服务"而微服务。
7. 总结:FastAPI + 微服务的正确姿势
- 前期:用 FastAPI 写一个完整单体应用,快速验证业务。
- 中期:把相对独立的模块(如用户、支付、通知)抽成独立的 FastAPI 服务。
- 通信 :使用
httpx异步请求、或 gRPC。 - 部署:每个服务打成一个 Docker 镜像,用 Docker Compose 或 Kubernetes 管理。
FastAPI 的优秀设计(异步、类型提示、OpenAPI 自动生成)让你在拆分微服务时依然保持高效开发。
8. "走通感觉"的迷你实验
在你自己的电脑上,开两个终端。
终端1 -- 用户服务 (保存为 user.py):
python
from fastapi import FastAPI
app = FastAPI()
@app.get("/me")
async def me():
return {"name": "Alice", "id": 1}
运行:uvicorn user:app --port 8000
终端2 -- 订单服务 (保存为 order.py):
python
from fastapi import FastAPI
import httpx
app = FastAPI()
@app.get("/order")
async def create_order():
async with httpx.AsyncClient() as client:
user = await client.get("http://localhost:8000/me")
return {"user": user.json(), "item": "book"}
运行:uvicorn order:app --port 8001
访问 http://localhost:8001/order,你会看到订单服务成功调用了用户服务。
9.Uvicorn 和微服务架构
- Uvicorn 是什么?
- 类型:ASGI 服务器(异步网关服务器接口)。
- 作用:接收网络请求(比如来自浏览器的 HTTP 请求),然后把请求交给你的 FastAPI 应用处理,最后把响应返回给客户端。
- 类比:Uvicorn 就像餐厅的"服务员"------负责接收顾客点单、传给厨房、再把菜端给顾客。它不决定餐厅是做大厨全包的"单体餐厅"还是"美食广场"(微服务)。
- 微服务架构是什么?
- 类型:一种设计模式,指导你如何构建软件系统。
- 核心思想:把一个大型应用拆成多个独立运行、独立部署、拥有独立数据库的小服务。
- 类比:把餐厅改成美食广场,每个档口独立经营、互相通过传菜窗(网络调用)协作。这个"美食广场"的设计蓝图就是微服务架构。
微服务架构:设计/架构层,"我们系统采用微服务架构,有用户服务、订单服务、商品服务"。
Uvicorn:实现/运行层, "每个微服务独立运行,用 Uvicorn 启动 FastAPI 实例"。
你可以用 Uvicorn 运行一个单体 FastAPI 应用,也可以用 Uvicorn 分别运行多个微服务。Uvicorn 只是工具,不决定架构。
uvicorn 就是让 FastAPI 能够"听到网络上的敲门声"------也就是监听 HTTP 端口。
Uvicorn 负责:监听端口(比如 8000)、接收 HTTP 请求、解析请求、调用 FastAPI 应用、返回响应。
FastAPI 本身:定义了"当收到什么请求时,执行什么代码",但它不会自己监听端口。