P1: 架构加固
- 线程池服务器: 连接级读写超时 + 有界队列(BoundedSemaphore),拒绝慢速/洪水连接 - 镜像代理流式转发(64KB 分块 + 4GB 上限),小响应才内存缓存(16MB 上限) - _serve_cached 支持单段 Range(206);pypi 下载流式化;docker urlopen 补超时
This commit is contained in:
+39
-6
@@ -7,6 +7,7 @@ import os
|
||||
import sys
|
||||
import ssl
|
||||
import signal
|
||||
import socket
|
||||
import mimetypes
|
||||
import threading
|
||||
import socketserver
|
||||
@@ -18,29 +19,59 @@ from .mirror_sync import MirrorSyncManager
|
||||
|
||||
|
||||
class ThreadPoolHTTPServer(socketserver.ThreadingMixIn, socketserver.TCPServer):
|
||||
"""使用线程池的 HTTP 服务器"""
|
||||
"""使用线程池的 HTTP 服务器(有界队列 + 连接超时,防慢速 DoS)"""
|
||||
allow_reuse_address = True
|
||||
daemon_threads = True # 使用守护线程
|
||||
|
||||
def __init__(self, server_address, RequestHandlerClass, max_workers=50):
|
||||
def __init__(self, server_address, RequestHandlerClass, max_workers=50,
|
||||
queue_size=50, socket_timeout=30):
|
||||
self.max_workers = max_workers
|
||||
self.queue_size = queue_size
|
||||
self.socket_timeout = socket_timeout
|
||||
self._executor = ThreadPoolExecutor(
|
||||
max_workers=max_workers,
|
||||
thread_name_prefix="http_handler"
|
||||
)
|
||||
# 有界并发槽位(活跃 + 排队),超过上限直接拒绝新连接,
|
||||
# 防止连接洪水导致任务无限堆积在内存
|
||||
self._slots = threading.BoundedSemaphore(max_workers + queue_size)
|
||||
super().__init__(server_address, RequestHandlerClass)
|
||||
|
||||
def process_request(self, request, client_address):
|
||||
"""使用线程池处理请求"""
|
||||
self._executor.submit(self._handle_request, request, client_address)
|
||||
"""使用线程池处理请求(有界队列)"""
|
||||
if not self._slots.acquire(blocking=False):
|
||||
# 队列已满:拒绝并立即关闭连接
|
||||
try:
|
||||
request.shutdown(socket.SHUT_RDWR)
|
||||
except Exception:
|
||||
pass
|
||||
try:
|
||||
request.close()
|
||||
except Exception:
|
||||
pass
|
||||
return
|
||||
try:
|
||||
self._executor.submit(self._handle_request, request, client_address)
|
||||
except Exception:
|
||||
self._slots.release()
|
||||
try:
|
||||
request.close()
|
||||
except Exception:
|
||||
pass
|
||||
|
||||
def _handle_request(self, request, client_address):
|
||||
"""实际处理请求"""
|
||||
try:
|
||||
# 连接级读写超时,防慢客户端无限占用工作线程
|
||||
try:
|
||||
request.settimeout(self.socket_timeout)
|
||||
except Exception:
|
||||
pass
|
||||
self.finish_request(request, client_address)
|
||||
except Exception:
|
||||
self.handle_error(request, client_address)
|
||||
finally:
|
||||
self._slots.release()
|
||||
self.shutdown_request(request)
|
||||
|
||||
def server_close(self):
|
||||
@@ -118,7 +149,9 @@ class MirrorServer:
|
||||
self.server = ThreadPoolHTTPServer(
|
||||
server_address,
|
||||
MirrorServerHandler,
|
||||
max_workers=max_workers
|
||||
max_workers=max_workers,
|
||||
queue_size=max_workers * 5,
|
||||
socket_timeout=self.config.get('timeout', 30)
|
||||
)
|
||||
|
||||
# 传递配置到处理器
|
||||
@@ -128,7 +161,7 @@ class MirrorServer:
|
||||
# 设置调试模式
|
||||
MirrorServerHandler._setup_debug(self.config)
|
||||
|
||||
# 设置超时
|
||||
# 设置 accept 轮询超时
|
||||
self.server.timeout = self.config.get('timeout', 30)
|
||||
|
||||
# 启用HTTPS
|
||||
|
||||
Reference in New Issue
Block a user