项目:3台 AWS EC2 服务器 + Route 53 健康检查 + Python 负载均衡器
之前用 python3 -c "..." 直接运行代码,进程是临时的,断了就没了。
用 systemd 注册成系统服务后:开机自动启动,崩溃自动重启。
sudo tee /opt/server.py > /dev/null << 'PYEOF'
...代码...
PYEOFsudo— 用管理员权限执行(普通用户没权限写/opt/目录)tee— 把内容写入文件/opt/server.py—/opt/是 Linux 约定放"额外安装软件"的地方> /dev/null— 把屏幕输出扔掉<< 'PYEOF'— heredoc 语法,从这里到 PYEOF 之间的内容全部作为输入
[Unit]
Description=Web Server
After=network.target
[Service]
ExecStart=/usr/bin/python3 /opt/server.py
Restart=always
RestartSec=3
[Install]
WantedBy=multi-user.target[Unit] — 描述服务
Description— 服务名字,方便人看After=network.target— 等网络启动完再启动,因为服务器需要网络
[Service] — 如何运行
ExecStart— 启动命令,必须写完整路径Restart=always— 进程崩溃自动重启(守护进程的核心)RestartSec=3— 崩溃后等3秒再重启,防止反复崩溃
[Install] — 何时启动
WantedBy=multi-user.target— 正常开机时启动,Linux 固定写法
sudo systemctl daemon-reload # 重新读取所有 .service 文件
sudo systemctl enable webserver # 注册为开机自启
sudo systemctl restart webserver # 立刻启动
sudo systemctl is-active webserver # 检查是否在跑(返回 active 表示正常)注意:每次修改 .service 文件后都要先跑 daemon-reload,否则 systemd 读的是旧版本。
from http.server import HTTPServer, BaseHTTPRequestHandler
import json
class Handler(BaseHTTPRequestHandler):
def do_GET(self):
if self.path == '/health':
self.send_response(200)
self.send_header('Content-type', 'application/json')
self.end_headers()
self.wfile.write(json.dumps({'status': 'healthy', 'server': 'us-east'}).encode())
else:
self.send_response(200)
self.send_header('Content-type', 'application/json')
self.end_headers()
self.wfile.write(json.dumps({'message': 'Hello from US East (Virginia)!', 'server': 'us-east'}).encode())
def log_message(self, f, *a): pass
HTTPServer(('0.0.0.0', 80), Handler).serve_forever()http.server— Python 内置,提供写 HTTP 服务器需要的工具HTTPServer— 负责监听端口、接受连接BaseHTTPRequestHandler— 负责处理每一个请求,我们继承它写自己的逻辑json— 把 Python 字典转成 JSON 字符串
BaseHTTPRequestHandler 已经帮你处理了 HTTP 协议的底层细节(解析请求头、建立连接等)。
我们只需要告诉它"收到请求后做什么"。
就像继承了父母的基因,但有自己的性格——Handler 继承了底层网络能力,但自定义了响应逻辑。
HTTP 有多种请求类型:GET(获取)、POST(提交)、PUT(更新)、DELETE(删除)。
收到 GET 请求自动调用 do_GET,收到 POST 自动调用 do_POST,以此类推。
if self.path == '/health':self.path 是请求的路径:
- 访问
http://3.236.124.247/health→self.path是/health - 访问
http://3.236.124.247/→self.path是/
我们设计了两个接口:
/health— 给健康检查用,返回{"status": "healthy"}- 其他所有路径 — 返回问候消息
self.send_response(200) # 1. 状态码
self.send_header('Content-type', 'application/json') # 2. 响应头
self.end_headers() # 3. 头部结束
self.wfile.write(json.dumps({...}).encode()) # 4. 响应正文常见状态码:200(成功)、404(找不到)、500(服务器错误)
.encode() 的作用:网络传输需要字节,不能直接传字符串,所以要转换。
def log_message(self, f, *a): pass覆盖父类的 log_message 方法,让它什么都不做(pass),关掉默认的请求日志打印。
HTTPServer(('0.0.0.0', 80), Handler).serve_forever()'0.0.0.0'— 监听所有网卡,让外部可以访问('127.0.0.1'只有本机能访问)80— HTTP 默认端口,访问时不用写端口号serve_forever()— 永远运行,不停接受新请求
import urllib.request
import json
import time
import itertools
SERVERS = [
{"name": "US East (Virginia)", "ip": "3.236.124.247"},
{"name": "US West (Oregon)", "ip": "100.23.127.116"},
{"name": "EU West (Ireland)", "ip": "34.245.154.170"},
]urllib.request— Python 内置,用来发 HTTP 请求json— 解析 JSON 响应time— 提供time.sleep(),让程序暂停itertools— 提供itertools.cycle(),实现轮询的核心
def check_health(server):
try:
url = f"http://{server['ip']}/health"
with urllib.request.urlopen(url, timeout=3) as resp:
data = json.loads(resp.read())
return data.get("status") == "healthy"
except Exception:
return Falsetimeout=3— 3秒没响应就放弃,网络操作不能无限等with ... as resp— 用完自动关闭连接,防止资源泄漏except Exception: return False— 任何错误(超时、连接拒绝)都返回 False,防御性编程
def get_healthy_servers():
return [s for s in SERVERS if check_health(s)]等价于:
result = []
for s in SERVERS:
if check_health(s):
result.append(s)
return result普通列表有尽头:[A, B, C] → A, B, C, 然后结束
cycle 无限循环:cycle([A, B, C]) → A, B, C, A, B, C, A, B, C ... 永远
每次调用 next(server_cycle) 取下一台服务器,这就是 Round Robin(轮询) 算法。
if request_count % 10 == 0:
healthy = get_healthy_servers()
if healthy != last_healthy:
server_cycle = itertools.cycle(healthy)
last_healthy = healthy% 10 == 0— 取余运算,每10个请求做一次健康检查(不需要每次都查,太浪费)if healthy != last_healthy— 只有列表变化时才重置轮询,否则每次检查都重置会造成不均匀
你的电脑(负载均衡器)
↓ 每10个请求做一次健康检查
├── US East ✅/❌
├── US West ✅/❌
└── EU West ✅/❌
↓ Round Robin 轮询(只发给健康的服务器)
├── 请求#1 → US East
├── 请求#2 → US West
└── 请求#3 → EU West
正常:cycle([US-East, US-West, EU-West])
→ 每台各收 1/3 流量
US-East 挂了:
→ 健康检查发现
→ 重建 cycle([US-West, EU-West])
→ US-East 不再收到任何请求
US-East 恢复:
→ 健康检查发现
→ 重建 cycle([US-East, US-West, EU-West])
→ 自动重新加入轮询
| 组件 | 技术 |
|---|---|
| 3 台服务器 | AWS EC2,分布在 us-east-1、us-west-2、eu-west-1 |
| Web 服务 | Python HTTP Server,systemd 守护进程 |
| 健康监控 | AWS Route 53 Health Checks,8个地区同时检测 |
| 负载均衡 | Python Round Robin 算法 |
| 故障转移 | 自动检测 + 自动剔除 + 自动恢复 |
简历描述:
Built a highly available distributed system across 3 AWS regions (us-east-1, us-west-2, eu-west-1) with automatic health monitoring via Route 53, Round Robin load balancing, and zero-downtime failover.