lolly/docs/plan.md
xfy 9d24263918 feat(stream,server,handler): 实现 Phase 6 性能优化和热升级
新增功能:
- stream 模块: 流式传输支持,优化大文件和实时数据传输
- Goroutine 池: 限制并发数量,减少调度开销
- 优雅升级: 零停机热升级,继承父进程监听器
- sendfile: 零拷贝文件传输,大文件直接从内核传输

重构改进:
- App 结构体封装,支持热升级和信号处理
- 配置结构字段对齐和代码清理
- 完善错误处理和日志记录

Co-Authored-By: Claude <noreply@anthropic.com>
2026-04-03 10:39:22 +08:00

1459 lines
37 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.

# Lolly 实现计划
## 概述
**目标**:创建一个类似 nginx 的高性能 HTTP 服务器,纯 Go 实现YAML 配置,单二进制运行。
**核心原则**
- 不是 1:1 复刻 nginx而是更现代、更易用
- 充分利用 Go 特性goroutine、channel、标准库
- 功能完整性优先于极致性能
- 选择"更简单易用"的设计方案
---
## 第一阶段:项目骨架与配置系统
### 目标
搭建项目基础结构,实现配置解析和命令行工具。
### 任务列表
#### 1.1 项目目录结构
```
lolly/
├── main.go # 程序入口
├── internal/
│ ├── config/ # 配置解析模块
│ ├── server/ # HTTP 服务器核心
│ ├── handler/ # 请求处理器
│ ├── middleware/ # 中间件系统(框架)
│ │ ├── security/ # 安全中间件access、ratelimit、auth
│ │ ├── compression/ # 压缩中间件gzip、brotli
│ │ ├── logging/ # 日志中间件
│ │ └── rewrite/ # URL 重写中间件
│ ├── proxy/ # 反向代理模块
│ ├── loadbalance/ # 负载均衡模块
│ ├── ssl/ # SSL/TLS 模块
│ ├── cache/ # 缓存模块
│ ├── stream/ # TCP/UDP Stream 代理
│ └── logging/ # 日志系统核心
├── pkg/
│ └── utils/ # 公共工具函数
├── go.mod
├── go.sum
├── Makefile # 构建脚本
└── README.md
```
**关键文件**
- `main.go` - 入口点,初始化和启动逻辑
- `internal/config/config.go` - 配置结构体定义和解析
- `internal/middleware/middleware.go` - 中间件框架接口定义
#### 1.2 YAML 配置解析
**配置结构体设计**
```go
// internal/config/config.go
// Config 根配置结构
type Config struct {
DefaultServer ServerConfig `yaml:"server"` // 默认服务器配置(单服务器场景)
Servers []ServerConfig `yaml:"servers"` // 多虚拟主机配置(可选)
Logging LoggingConfig `yaml:"logging"`
Performance PerformanceConfig `yaml:"performance"`
}
// 配置字段语义说明:
// - 若只配置 `server` 字段,则作为单一服务器运行
// - 若配置 `servers` 字段,则按虚拟主机模式运行(按 Host 头匹配)
// - 若同时配置两者,`server` 作为默认 fallback 主机,`servers` 按名称匹配
// - 建议使用场景:简单部署用 `server`,多站点部署用 `servers`
// ServerConfig 服务器配置
type ServerConfig struct {
Listen string `yaml:"listen"` // 监听地址 ":8080"
Name string `yaml:"name"` // server_name
Static StaticConfig `yaml:"static"` // 静态文件
Proxy []ProxyConfig `yaml:"proxy"` // 反向代理规则
SSL SSLConfig `yaml:"ssl"` // SSL 配置
}
// StaticConfig 静态文件配置
type StaticConfig struct {
Root string `yaml:"root"` // 根目录
Index []string `yaml:"index"` // 索引文件
}
// ProxyConfig 反向代理配置
type ProxyConfig struct {
Path string `yaml:"path"` // 路径匹配
Target string `yaml:"target"` // 目标地址
LoadBalance string `yaml:"load_balance"` // 负载均衡算法
}
```
**实现要点**
- 使用 `gopkg.in/yaml.v3` 解析 YAML
- 支持配置文件路径命令行参数 `-c/--config`
- 配置验证:必填字段检查、路径有效性
- 默认配置:最小配置即可运行
#### 1.3 命令行工具
**支持的命令**
```bash
lolly # 启动服务器(默认配置)
lolly -c /path/to.yaml # 指定配置文件
lolly -v # 显示版本
```
**实现方式**
- 使用 `flag` 标准库处理参数
- 信号处理:`SIGTERM``SIGINT``SIGHUP`
### 验证方法
```bash
# 构建测试
make build
# 版本显示
./lolly -v
```
---
## 第二阶段HTTP 核心功能
### 目标
实现基础 HTTP 服务器、静态文件服务、请求路由、基础日志系统。
### 技术选型
**HTTP 库**:使用 [fasthttp](https://github.com/valyala/fasthttp) 替代 `net/http`
**选择理由**
- **高性能**:比 net/http 快 6 倍
- **零分配**热点路径无内存分配GC 压力最小
- **原生支持高性能场景**:无需额外优化
**路由库**:使用 [fasthttp/router](https://github.com/fasthttp/router)。
**性能对比**
| 库 | 特点 | 性能 |
|----|------|------|
| fasthttp | 零分配,高性能 | ⭐⭐⭐⭐⭐ |
| net/http | 标准库,通用 | ⭐⭐⭐ |
**关键差异**
| net/http | fasthttp |
|----------|----------|
| `http.Handler` 接口 | `RequestHandler` 函数 |
| `ServeMux` 内置路由 | 无,需 router 库 |
| `http.Request` 对象 | `*fasthttp.RequestCtx` |
| `http.ResponseWriter` | `ctx` 同时处理读写 |
### 任务列表
#### 2.0 中间件框架(前置依赖)
**实现**
```go
// internal/middleware/middleware.go
import "github.com/valyala/fasthttp"
// Middleware 中间件接口
type Middleware interface {
Name() string
Process(next fasthttp.RequestHandler) fasthttp.RequestHandler
}
// Chain 中间件链
type Chain struct {
middlewares []Middleware
}
// Apply 应用中间件链
func (c *Chain) Apply(final fasthttp.RequestHandler) fasthttp.RequestHandler {
handler := final
for i := len(c.middlewares) - 1; i >= 0; i-- {
handler = c.middlewares[i].Process(handler)
}
return handler
}
```
**设计要点**
- 定义统一的中间件接口,所有中间件实现 `RequestHandler` 函数签名
- 支持链式组合,按注册顺序逆序包装(从后往前)
- Phase 2 建立框架,后续阶段填充具体中间件实现
#### 2.1 基础 HTTP 服务器
**核心实现**
```go
// internal/server/server.go
import "github.com/valyala/fasthttp"
// Server HTTP 服务器
type Server struct {
config *config.Config
fastServer *fasthttp.Server
handler fasthttp.RequestHandler
running bool
}
// Start 启动服务器
func (s *Server) Start() error {
s.fastServer = &fasthttp.Server{
Handler: s.handler,
ReadTimeout: s.config.Server.ReadTimeout,
WriteTimeout: s.config.Server.WriteTimeout,
IdleTimeout: s.config.Server.IdleTimeout,
MaxConnsPerIP: s.config.Server.MaxConnsPerIP,
MaxRequestsPerConn: s.config.Server.MaxRequestsPerConn,
}
return s.fastServer.ListenAndServe(s.config.Server.Listen)
}
// Stop 快速停止服务器
func (s *Server) Stop() error {
return s.fastServer.Shutdown()
}
// GracefulStop 优雅停止(等待请求完成)
func (s *Server) GracefulStop(timeout time.Duration) error {
// fasthttp 的 Shutdown 本身就是优雅关闭
return s.fastServer.Shutdown()
}
```
**实现要点**
- 使用 `fasthttp.Server` 配置超时和连接限制
- 优雅关闭:`Shutdown()` 方法自动等待请求完成
- 配置项:`ReadTimeout``WriteTimeout``IdleTimeout``MaxConnsPerIP`
#### 2.2 静态文件服务
**实现**
```go
// internal/handler/static.go
import "github.com/valyala/fasthttp"
// StaticHandler 静态文件处理器
type StaticHandler struct {
root string
index []string
}
// Handle 处理静态文件请求
func (h *StaticHandler) Handle(ctx *fasthttp.RequestCtx) {
path := string(ctx.Path())
// 安全检查:防止目录遍历
if strings.Contains(path, "..") {
ctx.Error("Forbidden", fasthttp.StatusForbidden)
return
}
// 拼接文件路径
filePath := filepath.Join(h.root, path)
// 尝试索引文件
if info, err := os.Stat(filePath); err == nil && info.IsDir() {
for _, idx := range h.index {
idxPath := filepath.Join(filePath, idx)
if fasthttp.ServeFile(ctx, idxPath) == nil {
return
}
}
}
// 直接返回文件
fasthttp.ServeFile(ctx, filePath)
}
```
**功能清单**
- 文件路径安全检查(防止目录遍历)
- MIME 类型自动识别fasthttp 内置)
- 索引文件支持index.html、index.htm
- Range 请求支持fasthttp 内置)
- 文件缓存优化(可选)
#### 2.3 请求路由
**路由库**:使用 [fasthttp/router](https://github.com/fasthttp/router),基于 radix tree 高效匹配。
**实现**
```go
// internal/handler/router.go
import (
"github.com/valyala/fasthttp"
"github.com/fasthttp/router"
)
// Router 请求路由器
type Router struct {
router *router.Router
}
// NewRouter 创建路由器
func NewRouter() *Router {
return &Router{
router: router.New(),
}
}
// Register 注册路由
func (r *Router) Register(path string, handler fasthttp.RequestHandler) {
r.router.GET(path, handler)
r.router.POST(path, handler)
r.router.PUT(path, handler)
r.router.DELETE(path, handler)
}
// Handler 返回路由处理器
func (r *Router) Handler() fasthttp.RequestHandler {
return r.router.Handler
}
```
**fasthttp/router 匹配类型**
| 类型 | 语法 | 示例 |
|------|------|------|
| Named | `{name}` | `/user/{id}` |
| Optional | `{name?}` | `/search/{q?}` |
| Regex | `{name:regex}` | `/user/{id:[0-9]+}` |
| Catch-All | `{filepath:*}` | `/files/{filepath:*}` |
**参数提取**
```go
func handler(ctx *fasthttp.RequestCtx) {
id := ctx.UserValue("id") // 获取路由参数
}
```
#### 2.4 多虚拟主机支持
**实现**
```go
// internal/server/vhost.go
import "github.com/valyala/fasthttp"
// VHostManager 虚拟主机管理器
type VHostManager struct {
hosts map[string]*VirtualHost // 按 server_name 索引
defaultHost *VirtualHost // 默认主机
}
// VirtualHost 虚拟主机
type VirtualHost struct {
name string
handler fasthttp.RequestHandler
}
// Handler 返回虚拟主机选择器
func (v *VHostManager) Handler() fasthttp.RequestHandler {
return func(ctx *fasthttp.RequestCtx) {
host := string(ctx.Host())
if vhost, ok := v.hosts[host]; ok {
vhost.handler(ctx)
} else if v.defaultHost != nil {
v.defaultHost.handler(ctx)
} else {
ctx.Error("Host not found", fasthttp.StatusNotFound)
}
}
}
```
**功能**
-`Host` 头选择虚拟主机
- 默认主机 fallback
- SNI 支持SSLPhase 4
#### 2.5 基础日志系统Phase 2 必需)
**原因**:调试 Phase 2-4 功能需要日志支持,将日志系统基础版本提前实现。
**选型**:使用 [zerolog](https://github.com/rs/zerolog) 作为日志库。
**选择理由**
- **零分配**:高并发场景 GC 压力最小,性能最优
- **JSON 输出**便于日志采集系统ELK、Loki解析
- **API 简洁**:链式调用风格,开发体验好
- **灵活输出**:支持 stdout/stderr/文件,开发模式可选 ConsoleWriter 美化
**性能对比**10 条日志,禁用输出):
| 库 | ns/op | allocs/op |
|----|-------|-----------|
| zerolog | ~40ns | **0** |
| zap (structured) | ~50ns | 0 |
| slog (Go 1.21+) | ~200ns | 5+ |
| logrus | ~2000ns | 23 |
**实现**
```go
// internal/logging/logging.go
import "github.com/rs/zerolog"
// 全局日志实例
var log zerolog.Logger
// Init 初始化日志系统
func Init(level string, pretty bool) {
l := parseLevel(level)
if pretty {
// 开发模式:带颜色和格式化(性能较差,仅开发用)
log = zerolog.New(zerolog.ConsoleWriter{Out: os.Stdout})
} else {
// 生产模式JSON 输出
log = zerolog.New(os.Stdout).Level(l).With().Timestamp().Logger()
}
}
// AccessLogger 访问日志(基础版)
func LogAccess(r *http.Request, status int, size int64, duration time.Duration) {
log.Info().
Str("method", r.Method).
Str("path", r.URL.Path).
Int("status", status).
Int64("size", size).
Dur("duration", duration).
Msg("request")
}
```
**Phase 2 实现范围**
- 基础请求日志:记录请求方法、路径、状态码
- 控制台输出开发阶段便于调试ConsoleWriter 美化)
- Phase 5 将扩展为完整日志系统(文件输出、自定义格式、访问/错误日志分离)
### 验证方法
```bash
# 启动服务器
./lolly -c lolly.yaml
# 静态文件测试
curl http://localhost:8080/index.html
# 路由测试
curl http://localhost:8080/static/test.txt
curl http://localhost:8080/api/health # 应返回 404代理未实现
```
---
## 第三阶段:反向代理与负载均衡
### 目标
实现反向代理功能、多种负载均衡算法、健康检查。
### 任务列表
#### 3.1 反向代理核心
**实现**(基于 fasthttp
```go
// internal/proxy/proxy.go
import "github.com/valyala/fasthttp"
// Proxy 反向代理
type Proxy struct {
targets []*Target
clients map[string]*fasthttp.HostClient // 每个目标一个 HostClient
balancer Balancer
}
// Target 后端目标
type Target struct {
URL string // 目标地址,如 "http://backend1:8080"
Weight int
Healthy bool
Connections int64 // 当前连接数(原子操作)
}
// HostClient fasthttp 客户端(连接池)
// 每个 Target 对应一个 HostClient自动管理连接池
```
**功能清单**
- 请求转发:修改请求头、请求体
- 响应处理:修改响应头
- 超时配置连接超时、响应超时fasthttp.HostClient 配置)
- WebSocket 支持Upgrade 协议检测和转发
- 错误处理:后端不可用时的响应
#### 3.2 负载均衡算法
**实现**
```go
// internal/loadbalance/balancer.go
// Balancer 负载均衡器接口
type Balancer interface {
Select(targets []*Target) *Target
}
// RoundRobin 轮询算法
type RoundRobin struct {
current uint64
}
// WeightedRoundRobin 权重轮询
type WeightedRoundRobin struct {
weights []int
current int
}
// LeastConnections 最少连接
type LeastConnections struct{}
// IPHash IP 哈希
type IPHash struct{}
```
**算法实现**
| 算法 | 说明 |
|------|------|
| round_robin | 简单轮询 |
| weighted_round_robin | 按权重轮询 |
| least_conn | 选择连接数最少的目标 |
| ip_hash | 按客户端 IP 哈希固定目标 |
#### 3.3 健康检查
**实现**
```go
// internal/proxy/health.go
// HealthChecker 健康检查器
type HealthChecker struct {
interval time.Duration
timeout time.Duration
path string // 健康检查路径
targets []*Target
}
// Check 执行健康检查
func (h *HealthChecker) Check()
// Start 后台定期检查
func (h *HealthChecker) Start()
```
**类型**
- **被动检查**:请求失败时标记不健康
- **主动检查**:定期发送探测请求
**配置示例**
```yaml
proxy:
- path: /api
targets:
- url: http://backend1:8080
weight: 3
- url: http://backend2:8080
weight: 1
load_balance: weighted_round_robin
health_check:
interval: 10s
path: /health
timeout: 5s
```
#### 3.4 代理缓存(可选)
**实现**
```go
// internal/cache/proxy_cache.go
// ProxyCache 代理响应缓存
type ProxyCache struct {
storage CacheStorage
rules []CacheRule
}
```
### 验证方法
```bash
# 启动后端服务(用于测试)
# backend1: python3 -m http.server 8001
# backend2: python3 -m http.server 8002
# 配置代理
# lolly.yaml:
# proxy:
# - path: /api
# targets: [http://localhost:8001, http://localhost:8002]
# 测试代理
curl http://localhost:8080/api/test
# 测试负载均衡(多次请求)
for i in {1..10}; do curl http://localhost:8080/api/test; done
```
---
## 第四阶段:安全与 SSL/TLS
### 目标
实现 HTTPS 支持、访问控制、请求限制。
### 任务列表
#### 4.1 SSL/TLS 支持
**实现**
```go
// internal/ssl/ssl.go
// SSLConfig SSL 配置
type SSLConfig struct {
Cert string `yaml:"cert"` // 证书路径
Key string `yaml:"key"` // 私钥路径
CertChain string `yaml:"cert_chain"` // 证书链路径(可选,用于中间证书)
Protocols []string `yaml:"protocols"` // TLS 版本,默认 ["TLSv1.2", "TLSv1.3"]
Ciphers []string `yaml:"ciphers"` // 加密套件(仅 TLS 1.2 有效)
OCSPStapling bool `yaml:"ocsp_stapling"` // OCSP Stapling 支持(默认 false
}
// TLSManager TLS 管理器
type TLSManager struct {
configs map[string]*tls.Config // 按 server_name
}
```
**安全默认配置**
- **TLS 版本**:默认仅允许 TLSv1.2 和 TLSv1.3**强制禁用 TLSv1.0/TLSv1.1**
- **加密套件默认值**TLS 1.2,按优先级排序):
```yaml
# 默认安全加密套件,无需手动配置
ciphers:
- TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256 # 推荐,性能好
- TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384 # 推荐,更安全
- TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305 # 推荐,移动端友好
- TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256 # ECDSA 证书专用
- TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384 # ECDSA 证书专用
- TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305 # ECDSA 证书专用
```
- **TLS 1.3**:自动使用 Go 标准库的安全套件,配置无效
**安全校验**
- 启用 Basic Auth 时,**强制要求 SSL 配置**,否则拒绝启动
- 拒绝配置不安全的加密套件(如 RC4、DES、3DES
**功能清单**
- 证书加载PEM 格式,支持证书链合并
- TLS 版本控制TLSv1.2、TLSv1.3**默认禁用不安全版本**
- 加密套件配置:提供安全默认值,拒绝不安全套件
- SSL 会话缓存减少握手开销LRU 缓存,默认 128 条)
- SNI 支持:多证书,通过 GetCertificate 回调实现
- HTTP/2 自动启用TLS 时自动启用
- OCSP Stapling减少客户端 CA 查询延迟和隐私风险
#### 4.2 IP 访问控制
**实现**
```go
// internal/middleware/security/access.go
// AccessControl IP 访问控制
type AccessControl struct {
allowList []net.IPNet
denyList []net.IPNet
default Action // 默认动作
}
// Check 检查 IP 是否允许
func (a *AccessControl) Check(ip net.IP) bool
```
**性能优化建议**
- 使用 CIDR 树结构radix tree优化大规模 ACL 匹配
- 预编译匹配规则,减少运行时开销
- 支持 IPv4 和 IPv6 双栈匹配
**配置示例**
```yaml
security:
access:
allow: [192.168.1.0/24, 10.0.0.0/8, "2001:db8::/32"] # 支持 IPv6
deny: [192.168.2.100/32]
default: deny
# 可选:使用高性能匹配模式
optimize: true # 启用 CIDR 树优化(适用于 >100 条规则)
```
#### 4.3 请求限制
**实现**
```go
// internal/middleware/security/ratelimit.go
// RateLimiter 速率限制器(令牌桶算法)
type RateLimiter struct {
rate int // 令牌生成速率(请求/秒)
burst int // 桶容量(突发流量上限)
buckets map[string]*TokenBucket
mu sync.RWMutex
}
// TokenBucket 令牌桶
type TokenBucket struct {
tokens float64
lastUpdate time.Time
}
// SlidingWindowLimiter 滑动窗口限流器(可选,解决边界突发问题)
type SlidingWindowLimiter struct {
window time.Duration
limit int
requests map[string][]time.Time
}
// ConnLimiter 连接数限制器
type ConnLimiter struct {
max int
current int
mu sync.Mutex
}
```
**算法选择**
| 算法 | 适用场景 | 特点 |
|------|----------|------|
| 令牌桶 (Token Bucket) | API 请求限流 | 允许突发流量,推荐默认使用 |
| 滑动窗口 (Sliding Window) | 精确限流 | 解决固定窗口边界问题,无突发 |
**功能**
- 请求速率限制(`limit_req`
- 连接数限制(`limit_conn`
- 按 IP 或按 key 限制
- 超限响应429 Too Many Requests
- 支持 `Retry-After` 响应头告知等待时间
#### 4.4 基础认证
**实现**
```go
// internal/middleware/security/auth.go
// BasicAuth 基础认证
type BasicAuth struct {
users map[string]string // username -> hashed_password
algorithm HashAlgorithm // 哈希算法bcrypt默认或 argon2id
realm string
requireTLS bool // 强制 HTTPS默认 true
}
// HashAlgorithm 哈希算法类型
type HashAlgorithm int
const (
HashBcrypt HashAlgorithm = iota // bcrypt默认推荐
HashArgon2id // Argon2id更安全计算密集
)
// Authenticate 验证认证信息
func (b *BasicAuth) Authenticate(r *http.Request) bool
```
**安全要求**
- **强制 HTTPS**:启用 Basic Auth 时必须配置 SSL否则拒绝启动
- **安全哈希**:默认使用 bcrypt成本因子 12可选 Argon2id
- **弃用 apr1**:不再支持不安全的 MD5-based apr1 哈希
- **密码强度**:配置验证,拒绝弱密码
**配置示例**
```yaml
security:
auth:
type: basic
require_tls: true # 强制 HTTPS默认 true
algorithm: bcrypt # bcrypt默认或 argon2id
users:
- name: admin
password: $2b$12$... # bcrypt 哈希(推荐)
- name: api_user
password: $argon2id$... # Argon2id 哈希(可选)
realm: "Restricted Area"
min_password_length: 12 # 密码最小长度
```
#### 4.5 安全头部
**实现**
```go
// internal/middleware/security/headers.go
// SecurityHeaders 安全头部配置
type SecurityHeaders struct {
XFrameOptions string `yaml:"x_frame_options"` // DENY/SAMEORIGIN/ALLOW-FROM
XContentTypeOptions string `yaml:"x_content_type_options"` // nosniff默认
ContentSecurityPolicy string `yaml:"content_security_policy"` // CSP 策略
HSTS HSTSConfig `yaml:"hsts"` // HSTS 配置
ReferrerPolicy string `yaml:"referrer_policy"` // 推荐值
PermissionsPolicy string `yaml:"permissions_policy"` // 权限策略
}
// HSTSConfig HSTS 配置
type HSTSConfig struct {
MaxAge int `yaml:"max_age"` // 过期时间(秒),默认 315360001年
IncludeSubDomains bool `yaml:"include_sub_domains"` // 包含子域名,默认 true
Preload bool `yaml:"preload"` // HSTS 预加载列表,默认 false
}
```
**默认安全头部**
| 头部 | 默认值 | 说明 |
|------|--------|------|
| X-Frame-Options | DENY | 防止点击劫持,可配置为 SAMEORIGIN |
| X-Content-Type-Options | nosniff | 防止 MIME 类型嗅探 |
| Content-Security-Policy | 可配置 | **关键**:防止 XSS 攻击 |
| Strict-Transport-Security | max-age=31536000; includeSubDomains | HSTS强制 HTTPS |
| Referrer-Policy | strict-origin-when-cross-origin | 控制引用信息泄露 |
| Permissions-Policy | 可配置 | 控制浏览器功能权限 |
**注意**`X-XSS-Protection` 已被现代浏览器弃用,不再默认添加,重点依赖 CSP 防护。
**配置示例**
```yaml
security:
headers:
x_frame_options: SAMEORIGIN # 或 DENY默认
content_security_policy: "default-src 'self'; script-src 'self' 'unsafe-inline'; style-src 'self' 'unsafe-inline'"
hsts:
max_age: 31536000 # 1年
include_sub_domains: true # 包含子域名
preload: false # 不加入预加载列表(需用户显式启用)
referrer_policy: strict-origin-when-cross-origin
permissions_policy: "geolocation=(), microphone=(), camera=()"
```
### 验证方法
```bash
# HTTPS 测试
curl -k https://localhost:8443/
# IP 访问控制测试
curl --interface 192.168.1.100 http://localhost:8080/ # 应允许
curl --interface 192.168.2.100 http://localhost:8080/ # 应拒绝
# 速率限制测试
for i in {1..20}; do curl http://localhost:8080/; done # 部分应返回 429
# 基础认证测试
curl -u admin:password http://localhost:8080/protected/
```
---
## 第五阶段:增强功能
### 目标
实现 URL 重写、压缩、缓存、日志系统。
### 任务列表
#### 5.1 URL 重写
**实现**
```go
// internal/rewrite/rewrite.go
// RewriteRule 重写规则
type RewriteRule struct {
Pattern string // 匹配模式
Replacement string // 替换目标
Flag RewriteFlag // last/redirect/break
}
type RewriteFlag int
const (
FlagLast RewriteFlag = iota // 继续匹配其他规则
FlagRedirect // 302 重定向
FlagPermanent // 301 重定向
FlagBreak // 停止匹配
)
```
**配置示例**
```yaml
rewrite:
- pattern: "^/old/(.*)$"
replacement: "/new/$1"
flag: permanent # 301
- pattern: "^/api/v1/(.*)$"
replacement: "/api/v2/$1"
flag: last
```
#### 5.2 Gzip/Brotli 压缩
**实现**
```go
// internal/compression/compression.go
// CompressionHandler 压缩中间件
type CompressionHandler struct {
types []string // 压缩的 MIME 类型
level int // 压缩级别
minSize int // 最小压缩大小
}
```
**配置示例**
```yaml
compression:
type: gzip # gzip/brotli/both
level: 6 # 1-9
min_size: 1024 # 最小 1KB 才压缩
types: [text/html, text/css, application/json]
```
#### 5.3 缓存系统
**静态文件缓存**
```go
// internal/cache/file_cache.go
// FileCache 文件描述符缓存
type FileCache struct {
maxEntries int
maxSize int64 // 内存上限(新增)
inactive time.Duration
entries map[string]*FileEntry
lruList *list.List // LRU 淘汰链表(新增)
}
// FileEntry 缓存条目
type FileEntry struct {
fd *os.File
size int64
modTime time.Time
lastAccess time.Time
}
```
**代理响应缓存**
```go
// internal/cache/proxy_cache.go
// ProxyCache 代理缓存
type ProxyCache struct {
storage Storage // 内存/磁盘存储
rules []CacheRule
maxAge time.Duration
cacheLock bool // 缓存锁开关(默认 true
lock *sync.RWMutex // 缓存锁,防止击穿
pending map[string]*chan struct{} // 正在生成的缓存项
}
// CacheRule 缓存规则
type CacheRule struct {
Path string
Methods []string
Statuses []int // 可缓存的响应状态码
MaxAge time.Duration
}
```
**缓存锁机制(防击穿)**
- 当多个请求同时请求同一个未缓存的资源时,只让一个请求去后端获取
- 其他请求等待第一个请求完成后从缓存读取
- 防止缓存击穿导致后端压力骤增
**配置示例**
```yaml
cache:
file:
max_entries: 10000
max_size: 256MB # 内存上限
inactive: 20s
lru_eviction: true # 启用 LRU 淘汰
proxy:
enabled: true
storage: memory # memory/disk
max_size: 1GB
cache_lock: true # 防止缓存击穿
stale_while_revalidate: 60s # 过期缓存复用
rules:
- path: /api/cacheable
methods: [GET]
statuses: [200, 301, 302]
max_age: 10m
```
#### 5.4 日志系统
**扩展 Phase 2 的 zerolog 实现**,增加文件输出和访问/错误日志分离。
**实现**
```go
// internal/logging/logging.go
import (
"io"
"github.com/rs/zerolog"
)
// Logger 日志管理器
type Logger struct {
accessLog zerolog.Logger // 访问日志
errorLog zerolog.Logger // 错误日志
}
// New 创建日志管理器
func New(cfg *LoggingConfig) *Logger {
// 访问日志stdout 或文件
accessOut := getOutput(cfg.Access.Path)
accessLog := zerolog.New(accessOut).With().Timestamp().Logger()
// 错误日志stderr 或文件
errorOut := getOutput(cfg.Error.Path)
errorLevel := parseLevel(cfg.Error.Level)
errorLog := zerolog.New(errorOut).Level(errorLevel).With().Timestamp().Logger()
return &Logger{accessLog: accessLog, errorLog: errorLog}
}
// LogAccess 记录访问日志nginx 格式变量)
func (l *Logger) LogAccess(r *http.Request, status int, size int64, duration time.Duration) {
l.accessLog.Info().
Str("remote_addr", r.RemoteAddr).
Str("request", fmt.Sprintf("%s %s", r.Method, r.URL.Path)).
Int("status", status).
Int64("body_bytes_sent", size).
Dur("request_time", duration).
Msg("")
}
// getOutput 获取输出目标stdout/stderr/文件)
func getOutput(path string) io.Writer {
if path == "" {
return os.Stdout
}
f, _ := os.OpenFile(path, os.O_APPEND|os.O_CREATE|os.O_WRONLY, 0644)
return f
}
```
**日志格式变量**(支持 nginx 风格配置):
- `$remote_addr` - 客户端 IP
- `$request` - 请求行(方法 + 路径)
- `$status` - 响应状态码
- `$body_bytes_sent` - 响应体大小
- `$request_time` - 请求耗时
**配置示例**
```yaml
logging:
access:
path: /var/log/lolly/access.log # 留空则输出到 stdout
format: json # json 或 textPhase 2 ConsoleWriter
error:
path: /var/log/lolly/error.log # 留空则输出到 stderr
level: info # debug/info/warn/error
```
#### 5.5 状态监控端点
**实现**
```go
// internal/server/status.go
// StatusHandler 状态监控处理器
type StatusHandler struct {
server *Server
}
// 返回数据
type Status struct {
Connections int
Requests int64
BytesSent int64
BytesReceived int64
Uptime time.Duration
}
```
**配置示例**
```yaml
monitoring:
status:
path: /_status # 状态端点路径
allow: [127.0.0.1] # 仅允许本地访问
```
### 验证方法
```bash
# 重写测试
curl http://localhost:8080/old/page # 应重定向到 /new/page
# 压缩测试
curl -H "Accept-Encoding: gzip" -I http://localhost:8080/index.html
# 应返回 Content-Encoding: gzip
# 缓存测试
curl -I http://localhost:8080/static/test.txt
# 应返回缓存相关头部
# 日志测试
cat /var/log/lolly/access.log
# 状态监控测试
curl http://localhost:8080/_status
```
---
## 第六阶段:高级功能
### 目标
实现 TCP/UDP Stream 代理、性能优化、优雅升级。
### 任务列表
#### 6.1 TCP/UDP Stream 代理
**实现**
```go
// internal/stream/stream.go
// StreamServer TCP/UDP 代理服务器
type StreamServer struct {
listeners map[string]*net.Listener
upstreams map[string]*StreamUpstream
}
// StreamUpstream Stream 上游
type StreamUpstream struct {
targets []*StreamTarget
balancer Balancer
}
// StreamTarget Stream 目标
type StreamTarget struct {
addr string
healthy bool
}
```
**配置示例**
```yaml
stream:
- listen: 3306
protocol: tcp
upstream:
targets: [mysql1:3306, mysql2:3306]
load_balance: round_robin
- listen: 53
protocol: udp
upstream:
targets: [dns1:53, dns2:53]
```
#### 6.2 优雅升级(热升级)
**实现**
```go
// internal/server/upgrade.go
// GracefulUpgrade 优雅升级
func GracefulUpgrade(newBinary string) error
// 逻辑:
// 1. 启动新进程,继承监听 socket
// 2. 新进程开始接受新连接
// 3. 旧进程停止接受新连接,完成现有请求后退出
```
**信号处理**
- `SIGUSR2`:触发升级
- `SIGWINCH`:优雅关闭 worker
#### 6.3 性能优化
**优化点**
##### 6.3.1 连接复用
```go
// http.Transport 连接池配置
transport := &http.Transport{
MaxIdleConns: 100, // 最大空闲连接数
MaxIdleConnsPerHost: 32, // 每主机最大空闲连接
IdleConnTimeout: 90 * time.Second, // 空闲连接超时
MaxConnsPerHost: 0, // 每主机最大连接数0=无限制)
}
```
##### 6.3.2 缓冲池
```go
// 使用 sync.Pool 实现分级缓冲池
var bufferPool = sync.Pool{
New: func() interface{} {
return make([]byte, 32*1024) // 32KB 缓冲区
},
}
```
##### 6.3.3 零拷贝sendfile
```go
// internal/handler/sendfile.go
// SendFile 零拷贝文件传输(仅 Linux
// 大文件(>= 8KB使用 sendfile 系统调用
func SendFile(w http.ResponseWriter, f *os.File, offset, length int64) error {
// Linux: syscall.Sendfile
// macOS: syscall.Sendfile不同签名
// Windows: syscall.TransmitFile
// 其他平台: 降级为 io.Copy
}
// 跨平台兼容方案
// - Linux: sendfile(out_fd, in_fd, offset, count)
// - macOS: sendfile(in_fd, out_fd, offset, &len, sf_hdtr, flags)
// - Windows: TransmitFile(socket, handle, bytes_to_write, ...
// - Fallback: io.CopyBuffer
```
##### 6.3.4 Goroutine 池(可选)
```go
// internal/server/pool.go
// GoroutinePool Goroutine 池配置
type GoroutinePool struct {
maxWorkers int // 最大 worker 数
minWorkers int // 最小 worker 数(预热)
idleTimeout time.Duration // 空闲超时
taskQueue chan Task // 任务队列
}
// 配置示例
performance:
goroutine_pool:
enabled: true // 启用池化(高 QPS 场景推荐)
max_workers: 10000 // 最大并发数
min_workers: 100 // 预热 worker 数
idle_timeout: 60s // 空闲超时
```
##### 6.3.5 对象池
```go
// 使用 sync.Pool 复用对象
var requestPool = sync.Pool{
New: func() interface{} {
return new(Request)
},
}
```
##### 6.3.6 代理缓存锁(防击穿)
```go
// internal/cache/proxy_cache.go
// ProxyCache 代理缓存(增加缓存锁)
type ProxyCache struct {
storage Storage
rules []CacheRule
maxAge time.Duration
lock *sync.RWMutex // 缓存锁,防止缓存击穿
pending map[string]*chan struct{} // 正在生成的缓存项
}
// 缓存锁机制:
// 1. 请求到达时检查是否有 pending 请求
// 2. 有则等待 pending 完成
// 3. 无则创建 pending生成缓存后广播
```
#### 6.4 信号处理完善
**完整信号支持**
| 信号 | 行为 |
|------|------|
| `SIGTERM/SIGINT` | 快速停止 |
| `SIGQUIT` | 优雅停止 |
| `SIGHUP` | 重载配置 |
| `SIGUSR1` | 重新打开日志 |
| `SIGUSR2` | 热升级 |
### 验证方法
```bash
# TCP Stream 测试
# 启动 MySQL 后端
mysql -h localhost -P 3306 # 应通过 lolly 代理连接
# 热升级测试
kill -USR2 <pid> # 触发升级
ps aux | grep lolly # 应有两个进程
# 性能测试
# 使用 wrk 或 ab 进行压力测试
wrk -t4 -c1000 -d30s http://localhost:8080/
```
---
## 文件依赖关系图
```
Phase 1:
cmd/lolly/main.go → internal/config/config.go
cmd/lolly/main.go → internal/middleware/middleware.go
Phase 2:
internal/server/server.go → internal/config/config.go
internal/server/server.go → internal/handler/router.go
internal/server/server.go → internal/logging/logging.go
internal/handler/router.go → internal/handler/static.go
internal/handler/router.go → internal/middleware/middleware.go
Phase 3:
internal/handler/router.go → internal/proxy/proxy.go
internal/proxy/proxy.go → internal/loadbalance/balancer.go
internal/proxy/proxy.go → internal/proxy/health.go
Phase 4:
internal/server/server.go → internal/ssl/ssl.go
internal/middleware/middleware.go → internal/middleware/security/access.go
internal/middleware/middleware.go → internal/middleware/security/ratelimit.go
internal/middleware/middleware.go → internal/middleware/security/auth.go
internal/middleware/middleware.go → internal/middleware/security/headers.go
Phase 5:
internal/middleware/middleware.go → internal/middleware/rewrite/rewrite.go
internal/middleware/middleware.go → internal/middleware/compression/compression.go
internal/proxy/proxy.go → internal/cache/proxy_cache.go
internal/server/server.go → internal/logging/logging.go扩展
Phase 6:
cmd/lolly/main.go → internal/stream/stream.go
internal/server/server.go → internal/server/upgrade.go
internal/server/server.go → internal/server/pool.go可选
```
---
## 总体进度追踪
| 阶段 | 状态 | 主要功能 |
| ------- | ------ | ------------------------- |
| Phase 1 | ✅ 完成 | 项目骨架、配置系统 |
| Phase 2 | ✅ 完成 | HTTP 核心、静态文件、路由 |
| Phase 3 | ✅ 完成 | 反向代理、负载均衡 |
| Phase 4 | ✅ 完成 | SSL/TLS、安全控制 |
| Phase 5 | ✅ 完成 | 重写、压缩、缓存、日志 |
| Phase 6 | ✅ 完成 | Stream、性能优化、热升级 |
**Phase 2 技术选型变更**
- HTTP 库:使用 [fasthttp](https://github.com/valyala/fasthttp) 替代 `net/http`(性能提升 6 倍)
- 日志库:使用 [zerolog](https://github.com/rs/zerolog)(零分配,~40ns/op
---
## 参考文档
详细功能参考 `docs/` 目录:
- HTTP 核心:`docs/03-nginx-http-core.md`
- 代理负载均衡:`docs/04-nginx-proxy-loadbalancing.md`
- SSL/HTTPS`docs/05-nginx-ssl-https.md`
- URL 重写:`docs/06-nginx-rewrite.md`
- 压缩缓存:`docs/07-nginx-compression-caching.md`
- 日志监控:`docs/08-nginx-logging-monitoring.md`
- 安全控制:`docs/09-nginx-security.md`
- Stream 代理:`docs/10-nginx-stream-tcp-udp.md`
- 性能优化:`docs/12-nginx-performance-tuning.md`
**代码注释规范**`docs/comments.md`(必须遵循)