From 0e8b99e17f1947ae9d64902e94da25c477184e2c Mon Sep 17 00:00:00 2001 From: xfy Date: Wed, 29 Apr 2026 15:47:28 +0800 Subject: [PATCH] =?UTF-8?q?docs:=20=E7=B2=BE=E7=AE=80=E5=B9=B6=E9=87=8D?= =?UTF-8?q?=E6=9E=84=20README=20=E6=96=87=E6=A1=A3=E7=BB=93=E6=9E=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 移除冗余的配置示例、生产清单和常见问题章节,新增核心模块依赖关系、 设计模式和性能优化设计等架构文档,统一 Markdown 表格格式。 💘 Generated with Crush Assisted-by: mimo-v2.5-pro via Crush --- README.md | 718 +++++++++++++----------------------------------------- 1 file changed, 169 insertions(+), 549 deletions(-) diff --git a/README.md b/README.md index 2eaa0c5..057cc69 100644 --- a/README.md +++ b/README.md @@ -28,14 +28,14 @@ ### 负载均衡 -| 算法 | 说明 | -|------|------| -| Round Robin | 轮询,均匀分配 | -| Weighted Round Robin | 加权轮询,按权重分配 | -| Least Connections | 最少连接,选择活跃连接最少的目标 | -| IP Hash | IP 哈希,同一客户端始终路由到同一目标 | -| Consistent Hash | 一致性哈希,支持虚拟节点(默认 150),最小化节点变更影响 | -| Random | Power of Two Choices,随机选择两个后比较,简单高效 | +| 算法 | 说明 | +| -------------------- | -------------------------------------------------------- | +| Round Robin | 轮询,均匀分配 | +| Weighted Round Robin | 加权轮询,按权重分配 | +| Least Connections | 最少连接,选择活跃连接最少的目标 | +| IP Hash | IP 哈希,同一客户端始终路由到同一目标 | +| Consistent Hash | 一致性哈希,支持虚拟节点(默认 150),最小化节点变更影响 | +| Random | Power of Two Choices,随机选择两个后比较,简单高效 | ### 故障转移 @@ -116,7 +116,7 @@ make build-all ./bin/lolly -c /path/to/lolly.yaml # 生成默认配置 -./bin/lolly --generate-config -o lolly.yaml +./bin/lolly -g -o lolly.yaml # 导入 nginx 配置 ./bin/lolly --import /etc/nginx/nginx.conf -o lolly.yaml @@ -138,6 +138,7 @@ lolly 支持将 nginx 配置文件转换为 YAML 格式: ``` 支持的 nginx 指令: + - `server` 块:listen、server_name、ssl_certificate、ssl_certificate_key - `location` 块:proxy_pass、root、alias、index、try_files - `upstream` 块:server(含 weight、max_fails、fail_timeout、backup、down)、least_conn、ip_hash、hash、random @@ -145,392 +146,10 @@ lolly 支持将 nginx 配置文件转换为 YAML 格式: 不支持的指令会在转换时显示警告,需要手动处理。 -## 配置 - -配置文件使用 YAML 格式。以下是完整配置示例: - -```yaml -mode: "auto" # single/vhost/multi_server/auto - -variables: - set: - app_name: "lolly" - version: "1.0.0" - -servers: - - listen: ":8080" - name: "example.com" - default: true # vhost 默认主机 - server_names: ["example.com", "*.example.com"] - read_timeout: 30s - write_timeout: 30s - idle_timeout: 120s - max_conns_per_ip: 100 - max_requests_per_conn: 1000 - concurrency: 262144 # 最大并发连接数 - read_buffer_size: 16384 # 16KB - write_buffer_size: 16384 - client_max_body_size: "10MB" - server_tokens: false # 隐藏版本号 - - static: - - path: "/" - root: "/var/www/html" - index: ["index.html", "index.htm"] - try_files: ["$uri", "$uri/", "/index.html"] - try_files_pass: false - symlink_check: true - location_type: "prefix" - - path: "/assets/" - root: "/var/www/assets" - internal: true # 仅允许内部重定向访问 - - proxy: - - path: "/api" - targets: - - url: "http://backend1:8080" - weight: 2 - max_conns: 100 - max_fails: 3 - fail_timeout: 30s - backup: false - down: false - proxy_uri: "/v1" # 替换请求路径 - - url: "http://backend2:8080" - weight: 1 - load_balance: "weighted_round_robin" - virtual_nodes: 150 # 一致性哈希虚拟节点数 - hash_key: "$uri" # 一致性哈希键 - location_type: "prefix_priority" - internal: false - health_check: - interval: 10s - path: "/health" - timeout: 5s - slow_start: 30s # 慢启动时间 - match: - status: ["200-299"] - body: "ok" - headers: - Content-Type: "application/json" - next_upstream: - tries: 3 - http_codes: [502, 503, 504] - timeout: - connect: 5s - read: 30s - write: 30s - headers: - set_request: - X-Forwarded-For: "$remote_addr" - X-Real-IP: "$remote_addr" - set_response: - X-Proxy-By: "lolly" - remove: ["X-Internal-Header"] - hide_response: ["X-Powered-By"] - pass_response: ["Content-Type", "Content-Length"] - cookie_domain: ".example.com" - cookie_path: "/" - cache: - enabled: true - max_age: 5m - stale_while_revalidate: 1m - stale_if_error: 10m - stale_if_timeout: 5m - cache_lock: true - cache_lock_timeout: 5s - methods: ["GET", "HEAD"] - min_uses: 1 # 缓存阈值 - background_update_disable: false - cache_ignore_headers: ["Set-Cookie"] - revalidate: true # 条件请求 - cache_valid: - ok: 10m # 200-299 - redirect: 1h # 301/302 - not_found: 1m - client_error: 0 - server_error: 0 - buffering: - mode: "default" # default/on/off - buffer_size: 16384 - buffers: "8 16k" # 8 个 16KB 缓冲区 - proxy_ssl: - enabled: true - server_name: "backend.internal" - trusted_ca: "/etc/ssl/ca/upstream-ca.crt" - client_cert: "/etc/ssl/client.crt" - client_key: "/etc/ssl/client.key" - min_version: "TLSv1.2" - insecure_skip_verify: false - redirect_rewrite: - mode: "default" # default/off/custom - rules: - - pattern: "http://backend:8000/" - replacement: "$scheme://$host:$server_port/" - client_max_body_size: "50MB" - balancer_by_lua: - enabled: false - script: "/etc/lolly/scripts/balancer.lua" - timeout: 100ms - fallback: "round_robin" - - ssl: - cert: "/etc/ssl/certs/server.crt" - key: "/etc/ssl/private/server.key" - cert_chain: "/etc/ssl/certs/chain.crt" - protocols: ["TLSv1.2", "TLSv1.3"] - ciphers: ["TLS_AES_128_GCM_SHA256", "TLS_AES_256_GCM_SHA384"] - ocsp_stapling: true - session_tickets: - enabled: true - key_file: "/var/lib/lolly/session_tickets.key" - rotate_interval: 1h - retain_keys: 3 - client_verify: - enabled: false - mode: "require" # none/request/require/optional_no_ca - client_ca: "/etc/ssl/ca/client-ca.crt" - verify_depth: 1 - crl: "/etc/ssl/ca/client-ca.crl" - http2: - enabled: true - max_concurrent_streams: 128 - max_header_list_size: 16384 - idle_timeout: 90s - push_enabled: false - h2c_enabled: false - graceful_shutdown_timeout: 30s - hsts: - max_age: 31536000 - include_sub_domains: true - preload: false - - security: - access: - allow: ["192.168.1.0/24", "10.0.0.0/8"] - deny: [] - default: "deny" - trusted_proxies: ["172.16.0.0/16"] - geoip: - enabled: false - database: "/var/lib/GeoIP/GeoIP2-Country.mmdb" - allow_countries: ["CN", "US"] - deny_countries: [] - default: "deny" - cache_size: 10000 - cache_ttl: 1h - private_ip_behavior: "allow" - rate_limit: - request_rate: 100 - burst: 200 - conn_limit: 50 - algorithm: "token_bucket" # token_bucket/sliding_window - key: "ip" - sliding_window_mode: "approximate" # exact/approximate - sliding_window: 60 - auth: - type: "basic" - require_tls: true - algorithm: "bcrypt" # bcrypt/argon2id - realm: "Secure Area" - min_password_length: 8 - users: - - name: "admin" - password: "$2y$10$N9qo8uLOickgx2ZMRZoMy..." - auth_request: - enabled: false - uri: "/auth" - method: "GET" - auth_timeout: 5s - forward_headers: ["Cookie", "Authorization"] - headers: - X-Original-Uri: "$request_uri" - X-Original-Host: "$host" - headers: - x_frame_options: "DENY" - x_content_type_options: "nosniff" - content_security_policy: "default-src 'self'" - referrer_policy: "strict-origin-when-cross-origin" - permissions_policy: "geolocation=(), microphone=()" - error_page: - pages: - 404: "/var/www/errors/404.html" - 500: "/var/www/errors/500.html" - default: "/var/www/errors/error.html" - response_code: 0 # 覆盖响应状态码 - - rewrite: - - pattern: "^/old/(.*)$" - replacement: "/new/$1" - flag: "permanent" - - pattern: "^/api/v1/(.*)$" - replacement: "/v1/$1" - flag: "last" - - compression: - type: "gzip" # gzip/brotli/both - level: 6 - min_size: 1024 - types: ["text/html", "text/css", "application/javascript", "application/json"] - gzip_static: true - gzip_static_extensions: [".gz", ".br"] - - lua: - enabled: true - scripts: - - path: "/etc/lolly/lua/rewrite.lua" - phase: "rewrite" - timeout: 30s - enabled: true - - path: "/etc/lolly/lua/access.lua" - phase: "access" - timeout: 30s - - path: "/etc/lolly/lua/content.lua" - phase: "content" - timeout: 30s - - path: "/etc/lolly/lua/log.lua" - phase: "log" - timeout: 30s - global_settings: - max_concurrent_coroutines: 1000 - coroutine_timeout: 30s - code_cache_size: 1000 - max_execution_time: 30s - coroutine_stack_size: 64 - coroutine_pool_warmup: 4 - enable_file_watch: true - minimize_stack_memory: true - - limit_rate: - rate: 1048576 # 1MB/s - burst: 524288 # 512KB 突发 - large_file_threshold: 10485760 # 10MB - large_file_strategy: "skip" # skip/coarse - - types: - default_type: "application/octet-stream" - map: - ".html": "text/html" - ".css": "text/css" - ".js": "application/javascript" - ".json": "application/json" - - unix_socket: - mode: 0666 - user: "www-data" - group: "www-data" - - cache_api: - enabled: false - path: "/_cache/purge" - allow: ["127.0.0.1", "10.0.0.0/8"] - auth: - type: "token" - token: "${CACHE_API_TOKEN}" - -http3: - enabled: true - listen: ":443" - max_streams: 1000 - idle_timeout: 30s - enable_0rtt: true - -stream: - - listen: ":3306" - protocol: "tcp" - upstream: - targets: - - addr: "mysql1:3306" - weight: 3 - - addr: "mysql2:3306" - weight: 1 - load_balance: "round_robin" - ssl: - enabled: false - cert: "/etc/ssl/stream.crt" - key: "/etc/ssl/stream.key" - client_ca: "" - protocols: ["TLSv1.2", "TLSv1.3"] - ciphers: [] - verify_depth: 1 - proxy_ssl: - enabled: false - trusted_ca: "/etc/ssl/ca.crt" - server_name: "mysql.internal" - cert: "" - key: "" - protocols: ["TLSv1.2", "TLSv1.3"] - verify: true - session_reuse: true - -resolver: - enabled: false - addresses: - - "8.8.8.8:53" - - "8.8.4.4:53" - valid: 30s # 缓存 TTL - timeout: 5s - ipv4: true - ipv6: false - cache_size: 1024 - -cache_path: - path: "/var/cache/lolly" - levels: "1:2" - max_size: 1073741824 # 1GB - inactive: 60m - purger: true - purger_interval: 1m - l1_max_entries: 10000 - l1_max_size: 67108864 # 64MB - promote_threshold: 3 - -logging: - format: "json" # text/json - access: - path: "/var/log/lolly/access.log" - format: "combined" - error: - path: "/var/log/lolly/error.log" - level: "info" # debug/info/warn/error - -performance: - goroutine_pool: - enabled: true - max_workers: 10000 - min_workers: 100 - idle_timeout: 60s - file_cache: - max_entries: 50000 - max_size: 268435456 # 256MB - inactive: 60s - transport: - idle_conn_timeout: 90s - max_conns_per_host: 500 - -monitoring: - status: - enabled: true - path: "/status" - format: "json" # json/text/html/prometheus - allow: ["127.0.0.1", "10.0.0.0/8"] - pprof: - enabled: false - path: "/debug/pprof" - allow: ["127.0.0.1"] - -shutdown: - graceful_timeout: 30s # SIGQUIT 优雅停止 - fast_timeout: 5s # SIGINT/SIGTERM 快速停止 - -include: - - path: "conf.d/*.yaml" # glob 模式展开 -``` - -完整配置说明请参考 `config.example.yaml` 和源码 `internal/config/config.go`。 - ## 架构 +### 请求处理流程 + ``` +------------------+ | Client | @@ -565,6 +184,84 @@ include: +---------+ +-----------+ +---------+ ``` +### 核心模块依赖关系 + +``` + main.go (CLI 入口) + │ app.Run() + ▼ +┌─────────────────────────────────────────────────────────────────┐ +│ App (app/) │ +│ 生命周期: loadConfig → initServer → Start → handleSignal │ +│ 组合: Server + HTTP3Server + HTTP2Server + StreamServer │ +└─────────────────────────────┬───────────────────────────────────┘ + │ + ┌───────────────────────┼───────────────────────┐ + │ │ │ + ▼ ▼ ▼ +┌───────────┐ ┌──────────────┐ ┌───────────┐ +│ config │ │ server │ │ upgrade │ +│ (YAML) │ │ (HTTP) │ │ (热升级) │ +│ 18 文件 │ │ GoroutinePool│ │ FD 继承 │ +└─────┬─────┘ └─────┬────────┘ └───────────┘ + │ │ + │ ▼ + │ ┌───────────────────────────────────────┐ + │ │ Middleware Chain │ + │ │ AccessLog → Security → Compression │ + │ │ → BodyLimit → Rewrite → Lua │ + │ └─────┬─────────────────────────────────┘ + │ │ + │ ▼ + │ ┌───────────┐ + │ │ matcher │ + │ │ (Location)│ + │ │ Radix Tree│ + │ └─────┬─────┘ + │ │ + │ ┌───────────┴───────────┐ + │ │ │ + │ ▼ ▼ + │ ┌───────────┐ ┌───────────┐ + │ │ handler │ │ proxy │ + │ │ (Static) │ │ (反向代理)│ + │ │ sendfile │ │ HostClient│ + │ └─────┬─────┘ └─────┬─────┘ + │ │ │ + │ ▼ ▼ + │ ┌───────────┐ ┌───────────┐ + │ │ cache │ │loadbalance│ + │ │ FileCache │ │ 7 种算法 │ + │ └───────────┘ └─────┬─────┘ + │ │ + ▼ ▼ +┌───────────┐ ┌───────────┐ +│ logging │ │ resolver │ +│ (zerolog) │ │ (DNS) │ +└───────────┘ └───────────┘ +``` + +### 设计模式应用 + +| 模式 | 应用位置 | 说明 | +| ---------- | ------------------------------------- | -------------------------------------------- | +| 策略模式 | `loadbalance/` | 7 种 LB 算法可插拔切换,实现 `Balancer` 接口 | +| 责任链模式 | `middleware/` | 中间件逆序包装链式调用,洋葱模型 | +| 工厂模式 | `proxy/proxy.go` | `createBalancerByName` 根据名称创建均衡器 | +| 对象池模式 | `proxy/headersPool`, `cache/`, `lua/` | `sync.Pool` 复用高频对象 | +| 观察者模式 | `server/upgrade.go` | 信号监听与处理,优雅升级触发 | + +### 性能优化设计 + +| 优化点 | 实现方式 | 收益 | +| -------------- | -------------------- | ---------------------------- | +| fasthttp | 替代 net/http | 零分配请求处理,10x 性能提升 | +| sendfile | Linux 内核级传输 | 大文件零拷贝,减少 CPU 开销 | +| sync.Pool | headers/buffers 复用 | 减少 GC 压力 | +| Goroutine Pool | worker 池复用 | 避免 goroutine 爆炸 | +| 原子计数器 | `atomic.AddUint64` | 负载均衡无锁选择 | +| LRU 缓存 | GeoIP/FileCache | 减少重复查询/读取 | + ### 目录结构 ``` @@ -702,7 +399,7 @@ internal/ 请求处理流程: ``` -Request → AccessLog → AccessControl → RateLimiter → Auth → AuthRequest → BodyLimit → +Request → AccessLog → AccessControl → RateLimiter → Auth → AuthRequest → BodyLimit → Rewrite → Compression → SecurityHeaders → ErrorIntercept → Handler ``` @@ -729,6 +426,7 @@ type Balancer interface { #### 代理缓存 支持: + - **缓存锁**(cache_lock)- 防止缓存击穿,同一缓存键只允许一个请求访问后端 - **过期复用**(stale-while-revalidate)- 允许在后台刷新时返回过期缓存 - **后台刷新** - 异步更新缓存,不影响请求响应时间 @@ -745,14 +443,14 @@ Lolly 提供基于 gopher-lua 的 Lua 脚本扩展能力,支持 nginx-lua 兼 请求到达 → rewrite → access → content → header_filter → body_filter → log → 响应返回 ``` -| 阶段 | 说明 | 可用操作 | -|------|------|----------| -| rewrite | URL 重写 | ngx.req.set_uri, ngx.req.set_uri_args | -| access | 访问控制 | ngx.exit, ngx.req.get_headers | -| content | 内容生成 | ngx.say, ngx.print, ngx.exit | -| header_filter | 响应头修改 | ngx.header[key] = value | -| body_filter | 响应体修改 | ngx.arg[1] 操作响应体 | -| log | 日志记录 | ngx.log, 记录请求信息 | +| 阶段 | 说明 | 可用操作 | +| ------------- | ---------- | ------------------------------------- | +| rewrite | URL 重写 | ngx.req.set_uri, ngx.req.set_uri_args | +| access | 访问控制 | ngx.exit, ngx.req.get_headers | +| content | 内容生成 | ngx.say, ngx.print, ngx.exit | +| header_filter | 响应头修改 | ngx.header[key] = value | +| body_filter | 响应体修改 | ngx.arg[1] 操作响应体 | +| log | 日志记录 | ngx.log, 记录请求信息 | ### 支持的 API @@ -908,6 +606,7 @@ ngx.exit(200) ### 安全限制 默认沙箱模式禁用以下 Lua 库: + - `os`(除 os.time) - `io` - `file` @@ -953,7 +652,7 @@ docker run -d \ ### Docker Compose ```yaml -version: '3' +version: "3" services: lolly: image: lolly:latest @@ -1028,8 +727,8 @@ sudo systemctl status lolly # 查看状态 { "name": "backend1", "targets": [ - {"url": "http://10.0.0.1:8080", "healthy": true, "latency_ms": 5}, - {"url": "http://10.0.0.2:8080", "healthy": true, "latency_ms": 8} + { "url": "http://10.0.0.1:8080", "healthy": true, "latency_ms": 5 }, + { "url": "http://10.0.0.2:8080", "healthy": true, "latency_ms": 8 } ], "healthy_count": 2, "unhealthy_count": 0, @@ -1078,13 +777,13 @@ sudo systemctl status lolly # 查看状态 ## 信号处理 -| 信号 | 行为 | -|------|------| -| SIGTERM, SIGINT | 快速停止 | -| SIGQUIT | 优雅停止,等待请求完成 | -| SIGHUP | 重载配置 | -| SIGUSR1 | 重新打开日志文件 | -| SIGUSR2 | 热升级 | +| 信号 | 行为 | +| --------------- | ---------------------- | +| SIGTERM, SIGINT | 快速停止 | +| SIGQUIT | 优雅停止,等待请求完成 | +| SIGHUP | 重载配置 | +| SIGUSR1 | 重新打开日志文件 | +| SIGUSR2 | 热升级 | ## 性能 @@ -1100,13 +799,13 @@ sudo systemctl status lolly # 查看状态 在 4 核 8GB 服务器上测试(使用 `internal/benchmark/tools/loadgen`): -| 场景 | RPS | 平均延迟 | P99 延迟 | -|------|-----|----------|----------| -| 静态文件(1KB) | 120,000+ | 0.8ms | 3ms | -| 静态文件(100KB) | 15,000+ | 6ms | 25ms | -| 反向代理(无缓存) | 80,000+ | 1.2ms | 5ms | -| 反向代理(有缓存) | 150,000+ | 0.6ms | 2ms | -| WebSocket 连接 | 50,000 连接 | - | - | +| 场景 | RPS | 平均延迟 | P99 延迟 | +| ------------------ | ----------- | -------- | -------- | +| 静态文件(1KB) | 120,000+ | 0.8ms | 3ms | +| 静态文件(100KB) | 15,000+ | 6ms | 25ms | +| 反向代理(无缓存) | 80,000+ | 1.2ms | 5ms | +| 反向代理(有缓存) | 150,000+ | 0.6ms | 2ms | +| WebSocket 连接 | 50,000 连接 | - | - | ### PGO 优化 @@ -1128,47 +827,49 @@ make build-pgo performance: goroutine_pool: enabled: true - max_workers: 10000 # 根据 CPU 核数调整 + max_workers: 10000 # 根据 CPU 核数调整 min_workers: 100 idle_timeout: 60s file_cache: - max_entries: 50000 # 根据内存调整 - max_size: 268435456 # 256MB + max_entries: 50000 # 根据内存调整 + max_size: 268435456 # 256MB transport: idle_conn_timeout: 90s - max_conns_per_host: 500 # 根据后端容量调整 + max_conns_per_host: 500 # 根据后端容量调整 ``` 容量规划建议: -| 流量级别 | max_workers | file_cache.max_size | max_conns_per_host | -|----------|-------------|---------------------|--------------------| -| 低流量(<10K RPS) | 500 | 64MB | 100 | -| 中流量(10K-100K RPS) | 5000 | 256MB | 300 | -| 高流量(>100K RPS) | 10000 | 512MB | 500 | +| 流量级别 | max_workers | file_cache.max_size | max_conns_per_host | +| ---------------------- | ----------- | ------------------- | ------------------ | +| 低流量(<10K RPS) | 500 | 64MB | 100 | +| 中流量(10K-100K RPS) | 5000 | 256MB | 300 | +| 高流量(>100K RPS) | 10000 | 512MB | 500 | ## 与 NGINX 对比 -| 特性 | Lolly | NGINX | -|------|-------|-------| -| HTTP/3 | 支持(quic-go) | 1.25+ 支持 | -| HTTP/2 | 支持(需 TLS) | 支持 | -| 配置格式 | YAML | 自定义 DSL | -| 热升级 | 支持 | 支持 | -| 扩展方式 | Go 代码/Lua | C 模块/Lua | -| 部署方式 | 单二进制 | 需安装 | -| TCP/UDP Stream | 支持 | 支持 | -| 代理缓存 | 支持(带锁) | 支持 | -| GeoIP | MaxMind GeoIP2 | GeoIP 模块 | -| 一致性哈希 | 支持(内置) | 需第三方模块 | +| 特性 | Lolly | NGINX | +| -------------- | --------------- | ------------ | +| HTTP/3 | 支持(quic-go) | 1.25+ 支持 | +| HTTP/2 | 支持(需 TLS) | 支持 | +| 配置格式 | YAML | 自定义 DSL | +| 热升级 | 支持 | 支持 | +| 扩展方式 | Go 代码/Lua | C 模块/Lua | +| 部署方式 | 单二进制 | 需安装 | +| TCP/UDP Stream | 支持 | 支持 | +| 代理缓存 | 支持(带锁) | 支持 | +| GeoIP | MaxMind GeoIP2 | GeoIP 模块 | +| 一致性哈希 | 支持(内置) | 需第三方模块 | **Lolly 优势**: + - YAML 配置更易读、易于解析和生成 - 单二进制部署,无依赖 - Go 原生扩展,无需 C 编译环境 - 现代 Go 库生态系统 **NGINX 优势**: + - 经过大规模生产验证 - 丰富的第三方模块生态 - 更完整的功能集(邮件代理等) @@ -1177,106 +878,24 @@ performance: 常见配置转换示例: -| NGINX | Lolly | -|-------|-------| -| `listen 80;` | `listen: ":80"` | -| `root /var/www/html;` | `root: "/var/www/html"` | -| `proxy_pass http://backend;` | `url: "http://backend"` | -| `proxy_set_header X-Real-IP $remote_addr;` | `set_request: { X-Real-IP: "$remote_addr" }` | -| `limit_req zone=one burst=10;` | `rate_limit: { request_rate: 100, burst: 10 }` | -| `ssl_certificate /path/cert.pem;` | `cert: "/path/cert.pem"` | +| NGINX | Lolly | +| ------------------------------------------ | ---------------------------------------------- | +| `listen 80;` | `listen: ":80"` | +| `root /var/www/html;` | `root: "/var/www/html"` | +| `proxy_pass http://backend;` | `url: "http://backend"` | +| `proxy_set_header X-Real-IP $remote_addr;` | `set_request: { X-Real-IP: "$remote_addr" }` | +| `limit_req zone=one burst=10;` | `rate_limit: { request_rate: 100, burst: 10 }` | +| `ssl_certificate /path/cert.pem;` | `cert: "/path/cert.pem"` | 迁移注意事项: + 1. 变量系统语法相同($remote_addr 等) 2. try_files 语法兼容 3. Lua API 与 OpenResty 高度兼容 4. 健康检查配置略有差异 -## 生产清单 - -### 安全加固 - -- [ ] 启用 TLS 1.2+,禁用 TLS 1.0/1.1 -- [ ] 配置安全头部(HSTS、X-Frame-Options、CSP) -- [ ] 启用访问控制,限制管理端点访问 -- [ ] 配置速率限制,防止 DDoS -- [ ] 启用请求体大小限制 -- [ ] 配置 GeoIP 过滤(如需地区限制) -- [ ] 定期更新 TLS Session Tickets 密钥 - -### 配置验证 - -- [ ] 检查 `ssl.protocols` 仅包含 TLSv1.2/1.3 -- [ ] 检查 `security.headers` 配置完整 -- [ ] 检查 `monitoring.status.allow` 仅允许可信 IP -- [ ] 检查 `max_conns_per_ip` 合理限制 -- [ ] 检查 `client_max_body_size` 符合业务需求 - -### 性能优化 - -- [ ] 启用 Goroutine 池 -- [ ] 配置文件缓存 -- [ ] 启用代理缓存(如适用) -- [ ] 配置连接池参数 -- [ ] 调整文件缓存大小匹配可用内存 - -### 运维准备 - -- [ ] 配置日志轮转 -- [ ] 测试热升级流程 -- [ ] 测试优雅关闭超时 -- [ ] 配置 systemd 服务 -- [ ] 设置监控告警阈值 - ## 故障排除 -### 常见问题 - -**启动失败:端口被占用** -```bash -# 检查端口占用 -sudo lsof -i :80 -sudo lsof -i :443 - -# 或更改监听端口 -listen: ":8080" -``` - -**TLS 证书加载失败** -```bash -# 检查证书文件权限 -ls -la /etc/ssl/certs/server.crt -ls -la /etc/ssl/private/server.key - -# 确保证书格式正确(PEM) -openssl x509 -in /etc/ssl/certs/server.crt -text -noout -``` - -**代理超时** -```yaml -# 增加超时时间 -timeout: - connect: 10s - read: 60s - write: 60s -``` - -**内存占用过高** -```yaml -# 减少缓存大小 -file_cache: - max_entries: 10000 - max_size: 67108864 # 64MB -``` - -**Lua 脚本超时** -```yaml -# 增加执行超时 -lua: - timeout: 60s - max_concurrent: 500 -``` - ### 调试模式 启用详细日志: @@ -1356,23 +975,23 @@ make lint ## 依赖 -| 库 | 版本 | 用途 | -|------|---------|------| -| [fasthttp](https://github.com/valyala/fasthttp) | v1.70.0 | HTTP 服务器核心 | -| [fasthttp/router](https://github.com/fasthttp/router) | v1.5.4 | HTTP 路由器 | -| [quic-go](https://github.com/quic-go/quic-go) | v0.59.0 | QUIC/HTTP/3 实现 | -| [zerolog](https://github.com/rs/zerolog) | v1.35.0 | 零分配 JSON 日志 | -| [gopher-lua](https://github.com/yuin/gopher-lua) | v1.1.2 | Lua 脚本引擎 | -| [klauspost/compress](https://github.com/klauspost/compress) | v1.18.5 | Gzip/Brotli 压缩 | -| [brotli](https://github.com/andybalholm/brotli) | v1.2.1 | Brotli 压缩编码 | -| [geoip2-golang](https://github.com/oschwald/geoip2-golang) | v1.13.0 | GeoIP 查询 | -| [golang-lru/v2](https://github.com/hashicorp/golang-lru) | v2.0.7 | LRU 缓存 | -| [uuid](https://github.com/google/uuid) | v1.6.0 | UUID 生成 | -| [testcontainers-go](https://github.com/testcontainers/testcontainers-go) | v0.42.0 | 集成测试容器 | -| [testify](https://github.com/stretchr/testify) | v1.11.1 | 测试断言 | -| [golang.org/x/crypto](https://golang.org/x/crypto) | v0.50.0 | 加密工具 | -| [golang.org/x/net](https://golang.org/x/net) | v0.53.0 | 网络扩展 | -| [yaml.v3](https://gopkg.in/yaml.v3) | v3.0.1 | YAML 配置解析 | +| 库 | 版本 | 用途 | +| ------------------------------------------------------------------------ | ------- | ---------------- | +| [fasthttp](https://github.com/valyala/fasthttp) | v1.70.0 | HTTP 服务器核心 | +| [fasthttp/router](https://github.com/fasthttp/router) | v1.5.4 | HTTP 路由器 | +| [quic-go](https://github.com/quic-go/quic-go) | v0.59.0 | QUIC/HTTP/3 实现 | +| [zerolog](https://github.com/rs/zerolog) | v1.35.0 | 零分配 JSON 日志 | +| [gopher-lua](https://github.com/yuin/gopher-lua) | v1.1.2 | Lua 脚本引擎 | +| [klauspost/compress](https://github.com/klauspost/compress) | v1.18.5 | Gzip/Brotli 压缩 | +| [brotli](https://github.com/andybalholm/brotli) | v1.2.1 | Brotli 压缩编码 | +| [geoip2-golang](https://github.com/oschwald/geoip2-golang) | v1.13.0 | GeoIP 查询 | +| [golang-lru/v2](https://github.com/hashicorp/golang-lru) | v2.0.7 | LRU 缓存 | +| [uuid](https://github.com/google/uuid) | v1.6.0 | UUID 生成 | +| [testcontainers-go](https://github.com/testcontainers/testcontainers-go) | v0.42.0 | 集成测试容器 | +| [testify](https://github.com/stretchr/testify) | v1.11.1 | 测试断言 | +| [golang.org/x/crypto](https://golang.org/x/crypto) | v0.50.0 | 加密工具 | +| [golang.org/x/net](https://golang.org/x/net) | v0.53.0 | 网络扩展 | +| [yaml.v3](https://gopkg.in/yaml.v3) | v3.0.1 | YAML 配置解析 | ## 许可证 @@ -1380,4 +999,5 @@ MIT License ## 作者 -xfy \ No newline at end of file +xfy +