157 lines
4.0 KiB
Markdown
157 lines
4.0 KiB
Markdown
# 负载均衡功能
|
||
|
||
`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()
|
||
``` |