Files
starlette-dial/pkg/dial/LOAD_BALANCING.md
2025-06-28 19:03:29 +08:00

157 lines
4.0 KiB
Markdown
Raw 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.

# 负载均衡功能
`ModifiableRequest` 类现在支持 round-robin 负载均衡功能,可以自动在多个后端服务器之间分发请求。
## 功能特性
- 🔄 **Round-Robin 轮询**: 按顺序在多个主机之间分发请求
- 🛡️ **线程安全**: 使用锁机制确保并发安全
- 🔧 **灵活配置**: 支持带协议和不带协议的主机配置
- 🎯 **智能路由**: 自动判断是否需要负载均衡
## 使用方法
### 1. 基本负载均衡
```python
from pkg.dial import client
from pkg.dial.req import ModifiableRequest
def request_handler(request: ModifiableRequest):
# 只指定路径,让负载均衡器自动选择主机
request.rewrite_uri("/api/users")
return request.build()
# 创建代理,支持多个后端服务器
proxy_handler = client.proxy(
hosts=["server1.com", "server2.com", "server3.com"],
req_fn=request_handler
)
```
### 2. 带协议的主机配置
```python
# 支持混合协议配置
hosts = [
"http://server1.com",
"https://server2.com",
"server3.com" # 自动添加 http:// 前缀
]
proxy_handler = client.proxy(hosts, request_handler)
```
### 3. 绕过负载均衡
```python
def request_handler_fixed(request: ModifiableRequest):
# 指定完整 URL绕过负载均衡
request.rewrite_uri("https://specific-server.com/api/users")
return request.build()
# 即使配置了多个主机,也会使用指定的 URL
proxy_handler = client.proxy(
hosts=["server1.com", "server2.com"],
req_fn=request_handler_fixed
)
```
## 工作原理
### URL 解析逻辑
1. **检查 URL 是否包含主机**:
- 如果 URL 包含主机(如 `https://example.com/api/users`),直接使用该 URL
- 如果 URL 只有路径(如 `/api/users`),从主机列表中选择一个
2. **Round-Robin 选择**:
- 使用线程安全的计数器
- 按顺序循环选择主机
- 自动处理主机数量变化
3. **URL 构建**:
- 自动添加协议前缀(如果缺失)
- 确保路径格式正确
- 合并查询参数
### 示例请求分发
假设配置了 3 个主机:`["server1.com", "server2.com", "server3.com"]`
```
请求 1: http://server1.com/api/users
请求 2: http://server2.com/api/users
请求 3: http://server3.com/api/users
请求 4: http://server1.com/api/users # 重新开始轮询
请求 5: http://server2.com/api/users
...
```
## 配置示例
### Starlette 应用中的使用
```python
from starlette.applications import Starlette
from starlette.routing import Route
from pkg.dial import client
def api_handler(request: ModifiableRequest):
request.rewrite_uri("/api/v1/data")
return request.build()
app = Starlette(routes=[
Route(
"/api/data",
client.proxy(
hosts=[
"http://backend1:8080",
"http://backend2:8080",
"http://backend3:8080"
],
req_fn=api_handler
)
)
])
```
### 健康检查集成
```python
def health_check_handler(request: ModifiableRequest):
request.rewrite_uri("/health")
return request.build()
# 健康检查路由
health_proxy = client.proxy(
hosts=["server1.com", "server2.com"],
req_fn=health_check_handler
)
```
## 注意事项
1. **主机格式**: 建议使用完整的主机名或 IP 地址
2. **协议处理**: 如果不指定协议,默认使用 `http://`
3. **并发安全**: 使用线程锁确保多线程环境下的安全性
4. **错误处理**: 如果主机列表为空,会抛出 `ValueError` 异常
5. **性能考虑**: 负载均衡器本身开销很小,适合高并发场景
## 故障排除
### 常见问题
1. **主机无法访问**: 确保所有配置的主机都是可访问的
2. **协议错误**: 检查主机配置中的协议是否正确
3. **路径问题**: 确保路径格式正确(以 `/` 开头)
### 调试技巧
```python
def debug_handler(request: ModifiableRequest):
# 添加调试信息
request.add_header("X-Debug", "true")
request.rewrite_uri("/api/debug")
return request.build()
```