把单体拆成两个服务
目标
将订单和库存置于同一进程中的单体应用,在先固定契约后拆分为两个独立服务,并自动验证拆分前后的响应是否一致。
为什么重要
拆分服务时,真正困难的并不是移动代码,而是确认迁移后仍会得到相同答案,以及数据所有权是否也一并完成了迁移。实践中最常见的失败是“服务拆开了,数据表却仍然共享”。这样一来,部署虽然能够独立进行,但变更模式仍然需要两个团队协商,因为耦合存在于数据而不是代码中。因此,本实验要求在移动代码之前,先将契约(contract)固定在文件中,最后再检查源代码,确认数据访问是否真正断开。在绞杀者模式中,如果无法确信门面背后的两个实现会给出相同答案,就不能切换流量。
步骤
- 在 127.0.0.1:8101 启动
/opt/fixtures/msa/monolith.py,使GET /health返回 200。 - 检查单体应用的路由,在
/root/msa/seams.txt中按每行一项的方式,以경로 도메인格式记录。必须同时出现orders和inventory两个领域,并且至少有 4 行。 - 创建
/root/msa/contract.json。顶层键只有orders和inventory两个,每个键都包含port(整数)和paths(字符串数组)。orders 为 8103,inventory 为 8102。 - 创建
/root/msa/inventory_svc.py并在 127.0.0.1:8102 启动。GET /stock/SKU-1应返回{"sku":"SKU-1","qty":<정수>}。 - 创建
/root/msa/orders_svc.py并在 127.0.0.1:8103 启动。POST /orders接收{"sku":"SKU-1","qty":2},查询库存服务后,库存充足时返回 201 和order_id,不足时返回 409。 orders_svc.py源代码中不得出现/opt/fixtures/msa/inventory.json之类的库存数据路径,而应调用 8102。- 创建
/root/msa/parity.sh。向单体应用(8101)和新的订单服务(8103)发送相同请求,当状态码和判定一致时输出PARITY OK。将执行结果保存到/root/msa/parity.out。 - 在
/root/msa/decision.md中加入## 쪼갠 이유和## 쪼개지 말았어야 할 이유两个标题,并在每个标题下至少写 30 个字符。
参考
- 后台启动:
nohup python3 파일.py > /root/msa/파일.log 2>&1 & - 检查端口:
ss -ltnp | grep 810 - 常见错误 1:新服务仍然直接打开并读取库存 JSON 文件——这并不是真正的拆分。
- 常见错误 2:擅自更改响应 JSON 的键名——这正是需要先写下契约的原因。
启动单体应用并建立基线
在 127.0.0.1:8101 启动 /opt/fixtures/msa/monolith.py,使 GET /health 返回 200。
使用 python3 运行 /opt/fixtures/msa/monolith.py 后,它会在 8101 端口启动。不要忘记后台运行(&)和日志重定向。
列出接缝(seam)
检查单体应用的路由,在 /root/msa/seams.txt 中按每行一项的方式,以 경로 도메인 格式记录。必须同时出现 orders 和 inventory 两个领域,并且至少有 4 行。
拆分前先写出候选边界。使用 grep 检查单体应用的路由定义,逐行记录路径及其所属领域。
固定两个服务的契约
创建 /root/msa/contract.json。顶层键只有 orders 和 inventory 两个,每个键都包含 port(整数)和 paths(字符串数组)。orders 为 8103,inventory 为 8102。
契约先于代码。使用 JSON 记录服务名、端口和公开路径。关键在于库存服务承诺提供什么。
拆分库存服务
创建 /root/msa/inventory_svc.py 并在 127.0.0.1:8102 启动。GET /stock/SKU-1 应返回 {"sku":"SKU-1","qty":<정수>}。
只将库存相关逻辑移到新文件,并在 8102 端口启动。响应必须是包含 sku 和 qty 的 JSON。
拆分订单服务
创建 /root/msa/orders_svc.py 并在 127.0.0.1:8103 启动。POST /orders 接收 {"sku":"SKU-1","qty":2},查询库存服务后,库存充足时返回 201 和 order_id,不足时返回 409。
订单服务不直接读取库存,而是通过 HTTP 查询。库存不足时返回 409 是契约的一部分。
证明数据所有权已拆分
orders_svc.py 源代码中不得出现 /opt/fixtures/msa/inventory.json 之类的库存数据路径,而应调用 8102。
如果订单服务源代码中仍保留库存数据文件路径,说明它们依然耦合。请检查源代码。
比较单体应用与新服务的响应等价性
创建 /root/msa/parity.sh。向单体应用(8101)和新的订单服务(8103)发送相同请求,当状态码和判定一致时输出 PARITY OK。将执行结果保存到 /root/msa/parity.out。
编写一个脚本,将相同输入发送到两条路径并比较结果。两个响应相同时,让它输出 PARITY OK。
记录拆分决策
在 /root/msa/decision.md 中加入 ## 쪼갠 이유 和 ## 쪼개지 말았어야 할 이유 两个标题,并在每个标题下至少写 30 个字符。
分别写明应该拆分和本不应该拆分的理由。必须准确使用指定的两个 Markdown 标题,才能通过评分。