feat: 优化配置
This commit is contained in:
@@ -50,8 +50,8 @@ ENABLE_KEEP_ALIVE=true
|
|||||||
# 禁用压缩(减少CPU开销)
|
# 禁用压缩(减少CPU开销)
|
||||||
DISABLE_COMPRESSION=true
|
DISABLE_COMPRESSION=true
|
||||||
|
|
||||||
# 缓冲区大小(字节)
|
# 缓冲区大小(字节,建议流式响应使用64KB或更大)
|
||||||
BUFFER_SIZE=32768
|
BUFFER_SIZE=65536
|
||||||
|
|
||||||
# ===========================================
|
# ===========================================
|
||||||
# 日志配置
|
# 日志配置
|
||||||
|
@@ -1,9 +1,9 @@
|
|||||||
version: '3.8'
|
version: "3.8"
|
||||||
|
|
||||||
services:
|
services:
|
||||||
openai-proxy:
|
gpt-load:
|
||||||
build: .
|
build: .
|
||||||
container_name: openai-proxy-go
|
container_name: gpt-load
|
||||||
ports:
|
ports:
|
||||||
- "3000:3000"
|
- "3000:3000"
|
||||||
volumes:
|
volumes:
|
||||||
@@ -21,32 +21,5 @@ services:
|
|||||||
retries: 3
|
retries: 3
|
||||||
start_period: 40s
|
start_period: 40s
|
||||||
|
|
||||||
# 环境变量
|
env_file:
|
||||||
environment:
|
- .env
|
||||||
- GO_ENV=production
|
|
||||||
|
|
||||||
# 日志配置
|
|
||||||
logging:
|
|
||||||
driver: "json-file"
|
|
||||||
options:
|
|
||||||
max-size: "10m"
|
|
||||||
max-file: "3"
|
|
||||||
|
|
||||||
# 资源限制
|
|
||||||
deploy:
|
|
||||||
resources:
|
|
||||||
limits:
|
|
||||||
memory: 512M
|
|
||||||
cpus: '1.0'
|
|
||||||
reservations:
|
|
||||||
memory: 128M
|
|
||||||
cpus: '0.25'
|
|
||||||
|
|
||||||
# 网络配置
|
|
||||||
networks:
|
|
||||||
- proxy-network
|
|
||||||
|
|
||||||
# 网络定义
|
|
||||||
networks:
|
|
||||||
proxy-network:
|
|
||||||
driver: bridge
|
|
||||||
|
@@ -309,8 +309,15 @@ func (ps *ProxyServer) handleProxy(c *gin.Context) {
|
|||||||
// 增加请求计数
|
// 增加请求计数
|
||||||
atomic.AddInt64(&ps.requestCount, 1)
|
atomic.AddInt64(&ps.requestCount, 1)
|
||||||
|
|
||||||
// 读取请求体用于重试
|
// 检查是否为流式请求
|
||||||
|
isStreamRequest := strings.Contains(c.GetHeader("Accept"), "text/event-stream") ||
|
||||||
|
strings.Contains(c.Request.URL.RawQuery, "stream=true") ||
|
||||||
|
strings.Contains(c.Request.Header.Get("Content-Type"), "text/event-stream")
|
||||||
|
|
||||||
var bodyBytes []byte
|
var bodyBytes []byte
|
||||||
|
var requestBody io.Reader = c.Request.Body
|
||||||
|
|
||||||
|
// 为了支持重试,需要缓存请求体(包括流式请求)
|
||||||
if c.Request.Body != nil {
|
if c.Request.Body != nil {
|
||||||
var err error
|
var err error
|
||||||
bodyBytes, err = io.ReadAll(c.Request.Body)
|
bodyBytes, err = io.ReadAll(c.Request.Body)
|
||||||
@@ -326,14 +333,15 @@ func (ps *ProxyServer) handleProxy(c *gin.Context) {
|
|||||||
})
|
})
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
requestBody = strings.NewReader(string(bodyBytes))
|
||||||
}
|
}
|
||||||
|
|
||||||
// 执行带重试的请求
|
// 执行带重试的请求
|
||||||
ps.executeRequestWithRetry(c, startTime, bodyBytes, 0)
|
ps.executeRequestWithRetry(c, startTime, bodyBytes, requestBody, isStreamRequest, 0)
|
||||||
}
|
}
|
||||||
|
|
||||||
// executeRequestWithRetry 执行带重试的请求
|
// executeRequestWithRetry 执行带重试的请求
|
||||||
func (ps *ProxyServer) executeRequestWithRetry(c *gin.Context, startTime time.Time, bodyBytes []byte, retryCount int) {
|
func (ps *ProxyServer) executeRequestWithRetry(c *gin.Context, startTime time.Time, bodyBytes []byte, requestBody io.Reader, isStreamRequest bool, retryCount int) {
|
||||||
// 获取密钥信息
|
// 获取密钥信息
|
||||||
keyInfo, err := ps.keyManager.GetNextKey()
|
keyInfo, err := ps.keyManager.GetNextKey()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -358,10 +366,10 @@ func (ps *ProxyServer) executeRequestWithRetry(c *gin.Context, startTime time.Ti
|
|||||||
c.Set("retryCount", retryCount)
|
c.Set("retryCount", retryCount)
|
||||||
}
|
}
|
||||||
|
|
||||||
// 使用缓存的请求体
|
// 准备请求体和内容长度
|
||||||
var requestBody io.Reader
|
|
||||||
var contentLength int64
|
var contentLength int64
|
||||||
if len(bodyBytes) > 0 {
|
if len(bodyBytes) > 0 {
|
||||||
|
// 使用缓存的请求体(支持重试)
|
||||||
requestBody = strings.NewReader(string(bodyBytes))
|
requestBody = strings.NewReader(string(bodyBytes))
|
||||||
contentLength = int64(len(bodyBytes))
|
contentLength = int64(len(bodyBytes))
|
||||||
}
|
}
|
||||||
@@ -429,7 +437,7 @@ func (ps *ProxyServer) executeRequestWithRetry(c *gin.Context, startTime time.Ti
|
|||||||
// 检查是否可以重试
|
// 检查是否可以重试
|
||||||
if retryCount < config.AppConfig.Keys.MaxRetries {
|
if retryCount < config.AppConfig.Keys.MaxRetries {
|
||||||
logrus.Infof("准备重试请求 (第 %d/%d 次)", retryCount+1, config.AppConfig.Keys.MaxRetries)
|
logrus.Infof("准备重试请求 (第 %d/%d 次)", retryCount+1, config.AppConfig.Keys.MaxRetries)
|
||||||
ps.executeRequestWithRetry(c, startTime, bodyBytes, retryCount+1)
|
ps.executeRequestWithRetry(c, startTime, bodyBytes, nil, isStreamRequest, retryCount+1)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -465,7 +473,7 @@ func (ps *ProxyServer) executeRequestWithRetry(c *gin.Context, startTime time.Ti
|
|||||||
resp.Body.Close()
|
resp.Body.Close()
|
||||||
|
|
||||||
logrus.Infof("准备重试请求 (第 %d/%d 次)", retryCount+1, config.AppConfig.Keys.MaxRetries)
|
logrus.Infof("准备重试请求 (第 %d/%d 次)", retryCount+1, config.AppConfig.Keys.MaxRetries)
|
||||||
ps.executeRequestWithRetry(c, startTime, bodyBytes, retryCount+1)
|
ps.executeRequestWithRetry(c, startTime, bodyBytes, nil, isStreamRequest, retryCount+1)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -488,12 +496,44 @@ func (ps *ProxyServer) executeRequestWithRetry(c *gin.Context, startTime time.Ti
|
|||||||
// 设置状态码
|
// 设置状态码
|
||||||
c.Status(resp.StatusCode)
|
c.Status(resp.StatusCode)
|
||||||
|
|
||||||
// 流式复制响应体(零拷贝)
|
// 优化流式响应传输
|
||||||
|
if isStreamRequest {
|
||||||
|
// 流式响应:启用实时刷新
|
||||||
|
if flusher, ok := c.Writer.(http.Flusher); ok {
|
||||||
|
// 使用优化的缓冲区进行流式复制
|
||||||
|
buf := make([]byte, config.AppConfig.Performance.BufferSize)
|
||||||
|
for {
|
||||||
|
n, err := resp.Body.Read(buf)
|
||||||
|
if n > 0 {
|
||||||
|
_, writeErr := c.Writer.Write(buf[:n])
|
||||||
|
if writeErr != nil {
|
||||||
|
logrus.Errorf("写入流式响应失败: %v", writeErr)
|
||||||
|
break
|
||||||
|
}
|
||||||
|
flusher.Flush() // 立即刷新到客户端
|
||||||
|
}
|
||||||
|
if err != nil {
|
||||||
|
if err != io.EOF {
|
||||||
|
logrus.Errorf("读取流式响应失败: %v", err)
|
||||||
|
}
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// 降级到标准复制
|
||||||
|
_, err = io.Copy(c.Writer, resp.Body)
|
||||||
|
if err != nil {
|
||||||
|
logrus.Errorf("复制流式响应失败: %v", err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// 非流式响应:使用标准零拷贝
|
||||||
_, err = io.Copy(c.Writer, resp.Body)
|
_, err = io.Copy(c.Writer, resp.Body)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
logrus.Errorf("复制响应体失败: %v (响应时间: %v)", err, responseTime)
|
logrus.Errorf("复制响应体失败: %v (响应时间: %v)", err, responseTime)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Close 关闭代理服务器
|
// Close 关闭代理服务器
|
||||||
func (ps *ProxyServer) Close() {
|
func (ps *ProxyServer) Close() {
|
||||||
|
Reference in New Issue
Block a user