# Lolly

[![Go Version](https://img.shields.io/badge/Go-1.26%2B-00ADD8?style=flat&logo=go)](https://golang.org)
[![License](https://img.shields.io/badge/License-MIT-blue.svg)](LICENSE)

高性能 HTTP 服务器与反向代理，使用 Go 语言编写。

基于 [fasthttp](https://github.com/valyala/fasthttp) 构建，提供比标准 net/http 更高的性能。支持 HTTP/3 (QUIC)、WebSocket、虚拟主机、多种负载均衡算法、故障转移、代理缓存、Lua 脚本扩展，以及完整的安全与性能优化特性。

> **代码统计**：174 个源文件 | 158 个测试文件 | ~136,000 行 Go 代码 | 测试覆盖率 >80%

## 特性

### 核心功能

- **静态文件服务** - 零拷贝传输（sendfile）、文件缓存、预压缩支持、try_files 配置、符号链接安全检查、ETag 和 304 Not Modified 支持
- **反向代理** - 完整的代理功能，支持请求头/响应头修改、超时控制、故障转移（next_upstream）、Location/Refresh 头改写
- **HTTP/3 (QUIC)** - 基于 quic-go，支持 0-RTT 连接
- **WebSocket** - 完整的 WebSocket 代理支持
- **虚拟主机** - 单进程支持多域名独立配置，server_name 支持通配符和正则匹配
- **多服务器模式** - 单配置文件支持多个独立 server 实例
- **Location 匹配** - nginx 风格的精确/前缀/正则匹配引擎
- **Unix Socket** - 支持 Unix socket 监听
- **配置引入** - include 指令支持配置拆分
- **TCP/UDP Stream** - 四层代理，支持 MySQL、Redis 等服务
- **Lua 脚本** - 基于 gopher-lua 的可编程扩展，支持 nginx-lua 兼容 API（ngx.var/ngx.ctx/ngx.req/ngx.resp/ngx.timer/ngx.location.capture/ngx.shared.DICT）
- **GeoIP 过滤** - 基于 MaxMind GeoIP2 的国家/地区访问控制
- **自定义错误页面** - 支持为特定状态码配置自定义错误页面
- **nginx 配置导入** - 支持将 nginx 配置文件转换为 lolly YAML 配置

### 负载均衡

| 算法                 | 说明                                                     |
| -------------------- | -------------------------------------------------------- |
| Round Robin          | 轮询，均匀分配                                           |
| Weighted Round Robin | 加权轮询，按权重分配                                     |
| Least Connections    | 最少连接，选择活跃连接最少的目标                         |
| IP Hash              | IP 哈希，同一客户端始终路由到同一目标                    |
| Consistent Hash      | 一致性哈希，支持虚拟节点（默认 150），最小化节点变更影响 |
| Random               | Power of Two Choices，随机选择两个后比较，简单高效       |

### 故障转移

支持 `next_upstream` 配置，当后端返回特定错误状态码（502/503/504）或连接失败时，自动重试下一个可用后端：

```yaml
proxy:
  - path: "/api"
    next_upstream:
      tries: 3
      http_codes: [502, 503, 504]
```

### 安全

- **访问控制** - IP/CIDR 白名单与黑名单，支持 trusted_proxies 配置
- **GeoIP 过滤** - 基于 MaxMind GeoIP2 数据库的国家/地区访问控制
- **速率限制** - 令牌桶与滑动窗口算法，支持精确/近似模式
- **连接限制** - 单 IP 并发连接数限制
- **认证** - Basic Auth，支持 bcrypt 与 argon2id；外部 auth_request 子请求
- **安全头部** - HSTS、X-Frame-Options、CSP、Referrer-Policy
- **SSL/TLS** - OCSP Stapling、TLS 1.2/1.3、加密套件配置、Session Tickets 密钥轮换
- **请求体限制** - 可配置全局和路径级别的请求体大小限制

### 性能优化

- **Goroutine 池** - 限制并发 worker 数量，避免 goroutine 爆炸
- **文件缓存** - LRU 淘汰策略，内存上限控制
- **连接池** - 空闲连接复用，减少连接建立开销
- **零拷贝** - 大文件（≥8KB）传输使用 sendfile 系统调用
- **代理缓存** - 支持缓存后端响应，cache_lock 防止缓存击穿
- **PGO 优化** - 支持 Profile-Guided Optimization 构建

### 运维

- **热升级** - USR2 信号触发，零停机升级，支持 Unix Socket 继承
- **配置热重载** - HUP 信号触发，动态更新配置
- **日志轮转** - USR1 信号触发，重新打开日志文件
- **优雅关闭** - QUIT 信号触发，等待请求完成，支持超时配置
- **状态监控** - 内置 `/status` 端点，统计连接数、请求数、流量、上游健康状态、缓存命中率
- **pprof 端点** - 内置性能分析端点，支持 CPU/heap/goroutine/block 分析
- **缓存清理 API** - POST `/purge` 端点，支持按路径清理代理缓存

## 安装

### 构建

```bash
# 克隆仓库
git clone https://github.com/DefectingCat/lolly.git
cd lolly

# 本地构建
make build

# 生产构建（体积优化）
make build-prod

# 性能构建（最大运行时性能）
make build-perf

# PGO 构建（需先收集 profile）
make pgo-collect  # 查看收集指南
make build-pgo

# 跨平台构建
make build-all
```

构建产物位于 `bin/` 目录。

### 运行

```bash
# 使用默认配置
./bin/lolly

# 指定配置文件
./bin/lolly -c /path/to/lolly.yaml

# 生成默认配置
./bin/lolly -g -o lolly.yaml

# 导入 nginx 配置
./bin/lolly --import /etc/nginx/nginx.conf -o lolly.yaml
./bin/lolly -i nginx.conf  # 简写形式

# 显示版本
./bin/lolly -v
```

### nginx 配置导入

lolly 支持将 nginx 配置文件转换为 YAML 格式：

```bash
# 导入 nginx 配置并输出到文件
./bin/lolly --import nginx.conf -o lolly.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
- 其他：gzip、gzip_types、gzip_min_length、client_max_body_size、access_log、error_log、rewrite、return（301/302）、error_page、auth_basic

不支持的指令会在转换时显示警告，需要手动处理。

## 架构

### 请求处理流程

```
                    +------------------+
                    |     Client       |
                    +--------+---------+
                             |
         +-------------------+-------------------+
         |                   |                   |
    +----v----+        +-----v-----+        +----v----+
    | HTTP/1  |        |  HTTP/2   |        | HTTP/3  |
    | (TCP)   |        |  (TLS)    |        | (QUIC)  |
    +----+----+        +-----+-----+        +----+----+
         |                   |                   |
         +-------------------+-------------------+
                             |
                    +--------v---------+
                    |   Middleware     |
                    |     Chain        |
                    +--------+---------+
                             |
         +-------------------+-------------------+
         |                   |                   |
    +----v----+        +-----v-----+        +----v----+
    | Static  |        |   Proxy   |        | Stream  |
    | Handler |        |  Handler  |        | Handler |
    +----+----+        +-----+-----+        +----+----+
         |                   |                   |
    File Cache         Load Balancer        L4 Proxy
         |                   |                   |
    +----+----+        +-----v-----+        +----v----+
    | Disk    |        | Upstream  |        | Backend |
    | I/O     |        | Targets   |        | Servers |
    +---------+        +-----------+        +---------+
```

### 核心模块依赖关系

```
                            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      | 减少重复查询/读取            |

### 目录结构

```
internal/
├── app/                    # 应用入口、信号处理、生命周期
│   ├── app.go              # 主程序逻辑（Start/Stop/Reload）
│   ├── app_common.go       # 通用平台代码
│   ├── app_windows.go      # Windows 平台适配
│   └── import.go           # nginx 配置导入
├── config/                 # 配置加载、验证、默认值（13 文件）
│   ├── config.go           # 根配置结构（支持 single/vhost/multi_server 模式）
│   ├── loader.go           # 配置文件加载
│   ├── defaults.go         # 默认配置
│   ├── validate.go         # 配置验证
│   ├── server_config.go    # 服务器配置
│   ├── proxy_config.go     # 代理配置
│   ├── ssl_config.go       # SSL/TLS 配置
│   ├── security_config.go  # 安全配置
│   ├── cache_config.go     # 缓存配置
│   ├── performance_config.go # 性能配置
│   ├── monitoring_config.go # 监控配置
│   └── variable_config.go  # 变量配置
├── server/                 # HTTP 服务器核心（13 文件）
│   ├── server.go           # 服务器实现（三种运行模式）
│   ├── vhost.go            # 虚拟主机管理
│   ├── pool.go             # Goroutine 池
│   ├── status.go           # 状态端点
│   ├── pprof.go            # pprof 端点
│   ├── pprof_impl.go       # pprof 实现
│   ├── purge.go            # 缓存清除端点
│   ├── internal.go         # 内部端点处理
│   ├── lifecycle.go        # 生命周期管理
│   ├── middleware_builder.go # 中间件构建器
│   ├── init.go             # 初始化逻辑
│   ├── router.go           # 路由器集成
│   ├── upgrade.go          # 热升级管理（Unix）
│   ├── upgrade_windows.go  # 热升级管理（Windows）
│   └── testutil.go         # 测试工具
├── handler/                # 请求处理器
│   ├── router.go           # fasthttp/router 封装
│   ├── static.go           # 静态文件处理（含缓存、ETag、304）
│   ├── sendfile.go         # 零拷贝传输接口
│   ├── sendfile_linux.go   # Linux sendfile 实现
│   ├── sendfile_common.go  # 通用实现
│   ├── autoindex.go        # 目录列表生成
│   ├── fileinfo_cache.go   # FileInfo 缓存
│   └── errorpage.go        # 错误页面管理
├── proxy/                  # 反向代理
│   ├── proxy.go            # 代理核心（负载均衡、缓存、故障转移）
│   ├── websocket.go        # WebSocket 代理
│   ├── health.go           # 主动健康检查
│   ├── health_match.go     # 健康检查匹配逻辑
│   ├── headers.go          # 头部处理工具
│   ├── header_modifier.go  # 头部修改器
│   ├── redirect_rewrite.go # Location/Refresh 头改写
│   ├── proxy_ssl.go        # 上游 SSL/TLS
│   ├── proxy_dns.go        # DNS 解析集成
│   ├── target_selector.go  # 目标选择器（Lua balancer 支持）
│   ├── cache_handler.go    # 代理缓存处理
│   ├── tempfile.go         # 临时文件管理
│   ├── tempfile_cleaner.go # 临时文件清理
│   ├── utils.go            # 工具函数
│   └── validate.go         # 配置验证
├── loadbalance/            # 负载均衡算法
│   ├── balancer.go         # Balancer 接口、RoundRobin、WeightedRR、LeastConn、IPHash
│   ├── algorithms.go       # 算法注册
│   ├── consistent_hash.go  # 一致性哈希（虚拟节点）
│   ├── random.go           # Power of Two Choices
│   └── slow_start.go       # 慢启动算法
├── matcher/                # Location 匹配器
│   ├── matcher.go          # 匹配器接口
│   ├── exact.go            # 精确匹配
│   ├── prefix.go           # 前缀匹配
│   ├── regex.go            # 正则匹配
│   ├── radix.go            # 基数树匹配
│   ├── conflict.go         # 冲突检测
│   ├── location.go         # Location 定义
│   ├── named.go            # 命名捕获组
│   └── prefix_priority.go  # 前缀优先级排序
├── middleware/             # 中间件链
│   ├── middleware.go       # 中间件接口
│   ├── compression/        # Gzip/Brotli 压缩
│   │   ├── compression.go  # 压缩实现
│   │   └── gzip_static.go  # 预压缩文件
│   ├── security/           # 安全中间件
│   │   ├── access.go       # IP/CIDR 访问控制
│   │   ├── ratelimit.go    # 令牌桶限流
│   │   ├── sliding_window.go # 滑动窗口限流
│   │   ├── auth.go         # Basic Auth（bcrypt/argon2id）
│   │   ├── auth_request.go # 子请求认证
│   │   ├── geoip.go        # GeoIP 过滤
│   │   └── headers.go      # 安全头部
│   ├── rewrite/            # URL 重写
│   ├── accesslog/          # 访问日志（nginx 兼容格式）
│   ├── bodylimit/          # 请求体大小限制
│   ├── limitrate/          # 响应速率限制
│   └── errorintercept/     # 错误页面拦截
├── lua/                    # Lua 脚本引擎
│   ├── engine.go           # gopher-lua 引擎
│   ├── context.go          # 请求上下文
│   ├── register.go         # API 注册
│   ├── socket_manager.go   # Socket 管理
│   ├── filter_writer.go    # header/body_filter
│   └── api_*.go            # nginx-lua 兼容 API（20+ 文件）
├── http2/                  # HTTP/2 服务器
│   ├── server.go           # HTTP/2 实现
│   └── adapter.go          # 适配器
├── http3/                  # HTTP/3 服务器
│   ├── server.go           # QUIC 服务器
│   └── adapter.go          # 适配器
├── stream/                 # TCP/UDP Stream 代理
│   ├── stream.go           # 四层代理
│   └── ssl.go              # Stream SSL
├── ssl/                    # TLS 配置
│   ├── ssl.go              # TLS 管理器
│   ├── ocsp.go             # OCSP Stapling
│   ├── session_tickets.go  # Session Tickets 轮换
│   └── client_verify.go    # 客户端证书验证
├── cache/                  # 缓存系统
│   ├── backend.go          # 缓存后端抽象
│   ├── file_cache.go       # 文件缓存（LRU）
│   ├── disk_cache.go       # 磁盘缓存
│   ├── tiered_cache.go     # L1/L2 分层缓存
│   └── purge.go            # 缓存清除
├── resolver/               # DNS 解析器
│   ├── resolver.go         # DNS 解析
│   ├── cache.go            # DNS 缓存
│   └── stats.go            # 解析统计
├── variable/               # 变量系统
│   ├── variable.go         # 变量接口
│   ├── builtin.go          # 内置变量（$remote_addr 等）
│   ├── pool.go             # 变量池
│   └── ssl.go              # SSL 变量
├── converter/              # 配置转换器
│   └── nginx/              # nginx 配置导入
│       ├── parser.go       # nginx 语法解析
│       └── converter.go    # YAML 转换
├── logging/                # 日志系统
│   └── logging.go          # zerolog 封装
├── netutil/                # 网络工具
│   ├── ip.go               # IP 解析
│   ├── host.go             # 主机名处理
│   └── url.go              # URL 处理
├── mimeutil/               # MIME 类型
│   └── detect.go           # MIME 检测
├── sslutil/                # SSL 工具
│   └── certpool.go         # 证书池
├── utils/                  # 通用工具
│   ├── httperror.go        # HTTP 错误处理
│   └── internal.go         # 内部工具
├── version/                # 版本信息
│   └── version.go          # 版本定义
└── benchmark/              # 基准测试
    └── tools/              # 测试辅助工具
```

### 核心设计

#### 中间件链

请求处理流程：

```
Request → AccessLog → AccessControl → RateLimiter → Auth → AuthRequest → BodyLimit →
Rewrite → Compression → SecurityHeaders → ErrorIntercept → Handler
```

每个中间件实现 `Middleware` 接口：

```go
type Middleware interface {
    Name() string
    Process(next fasthttp.RequestHandler) fasthttp.RequestHandler
}
```

#### 负载均衡

所有负载均衡器实现 `Balancer` 接口，支持健康目标过滤和故障转移排除：

```go
type Balancer interface {
    Select(targets []*Target) *Target
    SelectExcluding(targets []*Target, excluded []*Target) *Target
}
```

#### 代理缓存

支持：

- **缓存锁**（cache_lock）- 防止缓存击穿，同一缓存键只允许一个请求访问后端
- **过期复用**（stale-while-revalidate）- 允许在后台刷新时返回过期缓存
- **后台刷新** - 异步更新缓存，不影响请求响应时间
- **错误回退**（stale-if-error）- 后端错误时返回过期缓存
- **超时回退**（stale-if-timeout）- 后端超时时返回过期缓存

## Lua 脚本

Lolly 提供基于 gopher-lua 的 Lua 脚本扩展能力，支持 nginx-lua 兼容 API。

### 执行阶段

```
请求到达 → 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, 记录请求信息                 |

### 支持的 API

```lua
-- 日志
ngx.log(ngx.ERR, "error message")
ngx.log(ngx.WARN, "warning message")
ngx.log(ngx.INFO, "info message")

-- HTTP 状态码常量
ngx.HTTP_OK = 200
ngx.HTTP_NOT_FOUND = 404
ngx.HTTP_INTERNAL_SERVER_ERROR = 500
-- 更多: HTTP_MOVED_PERMANENTLY, HTTP_BAD_REQUEST, HTTP_FORBIDDEN 等

-- 特殊常量
ngx.OK, ngx.ERROR, ngx.AGAIN, ngx.DONE, ngx.DECLINED

-- 内置变量（ngx.var）
local uri = ngx.var.uri
local method = ngx.var.request_method
local remote_addr = ngx.var.remote_addr
local host = ngx.var.host
local request_uri = ngx.var.request_uri
local scheme = ngx.var.scheme
local server_port = ngx.var.server_port
-- 任意请求头: ngx.var.http_xxx（如 ngx.var.http_user_agent）
-- 任意查询参数: ngx.var.arg_xxx（如 ngx.var.arg_token）

-- 请求操作（ngx.req）
ngx.req.get_method()          -- 获取 HTTP 方法
ngx.req.get_uri()             -- 获取 URI 路径
ngx.req.set_uri("/new_path")  -- 设置 URI
ngx.req.set_uri_args("a=1&b=2") -- 设置查询参数
ngx.req.get_uri_args()        -- 获取查询参数表
ngx.req.get_headers(max?)     -- 获取请求头表
ngx.req.set_header("X-Custom", "value")
ngx.req.clear_header("X-Custom")
ngx.req.get_body_data()       -- 获取请求体
ngx.req.read_body()           -- 确保请求体已读取

-- 响应操作（ngx.resp）
ngx.resp.get_status()         -- 获取响应状态码
ngx.resp.set_status(200)      -- 设置响应状态码
ngx.resp.get_headers(max?)    -- 获取响应头表
ngx.resp.set_header("X-Response", "value")
ngx.resp.clear_header("X-Response")

-- 快捷响应
ngx.say("Hello World")        -- 输出内容并换行
ngx.print("Hello World")      -- 输出内容不换行
ngx.flush(wait?)              -- 刷新响应缓冲区
ngx.redirect("/new", 302)     -- 重定向
ngx.exit(200)                 -- 结束请求处理

-- 请求上下文（ngx.ctx，每请求独立的 table）
ngx.ctx.user_id = 123
local id = ngx.ctx.user_id

-- 共享字典（ngx.shared.DICT）
local dict = ngx.shared.DICT
dict:set("key", "value", 3600)   -- 设置（含过期时间）
dict:add("key", "value", 3600)   -- 仅键不存在时添加
dict:replace("key", "value")     -- 仅键存在时替换
local val = dict:get("key")      -- 获取值
dict:incr("counter", 1)          -- 数值自增
dict:delete("key")               -- 删除键
dict:flush_all()                 -- 清空所有条目
dict:flush_expired(max?)         -- 清除过期条目
dict:get_keys(max?)              -- 获取所有键
dict:size()                      -- 获取条目数
dict:free_space()                -- 获取剩余容量
-- 元表语法: dict["key"] = value / val = dict["key"]

-- Socket（ngx.socket.tcp，受限）
local sock = ngx.socket.tcp()
sock:connect("127.0.0.1", 8080)
sock:settimeout(5000)            -- 设置超时（毫秒）
sock:settimeouts(1000, 2000, 3000) -- 分别设置连接/发送/读取超时
sock:send("GET / HTTP/1.0\r\n\r\n")
local response = sock:receive("*a") -- 读取全部
local line = sock:receive("*l")     -- 读取一行
local reader = sock:receiveuntil("--boundary") -- 按模式读取
sock:close()

-- 定时器（ngx.timer）
local timer_id = ngx.timer.at(5, function()
    ngx.log(ngx.INFO, "timer fired")
end)
ngx.timer.running_count() -- 获取运行中的定时器数量
-- handle:cancel()        -- 取消定时器（通过返回的 handle）

-- 子请求（ngx.location.capture）
local res = ngx.location.capture("/internal/auth", {
    method = ngx.HTTP_GET,
    body = "request body",
    args = "a=1&b=2"
})
-- res.status, res.body, res.headers

-- 动态负载均衡（ngx.balancer）
ngx.balancer.set_current_peer("backend:8080") -- 设置后端地址
ngx.balancer.set_more_tries(3)                -- 设置重试次数
local fail_type = ngx.balancer.get_last_failure() -- 获取上次失败类型
local targets = ngx.balancer.get_targets()    -- 获取所有可用目标
local client_ip = ngx.balancer.get_client_ip() -- 获取客户端 IP
```

### 示例脚本

**rewrite.lua** - URL 重写：

```lua
-- 将 /api/v1/* 重写为 /v1/*
local uri = ngx.var.uri
if string.match(uri, "^/api/v1/") then
    local new_uri = string.gsub(uri, "^/api/", "")
    ngx.req.set_uri(new_uri)
end
```

**access.lua** - 访问控制：

```lua
-- 检查请求头中的 token
local token = ngx.req.get_headers()["X-Token"]
if not token or token == "" then
    ngx.exit(401)
    return
end

-- 验证 token（示例）
if token ~= "valid-token" then
    ngx.exit(403)
    return
end
```

**content.lua** - 动态响应：

```lua
-- 生成 JSON 响应
ngx.header["Content-Type"] = "application/json"
local response = {
    status = "ok",
    timestamp = os.time(),
    request_id = ngx.var.request_id
}
ngx.say(require("cjson").encode(response))
ngx.exit(200)
```

### 安全限制

默认沙箱模式禁用以下 Lua 库：

- `os`（除 os.time）
- `io`
- `file`

可通过配置 `lua.sandbox: false` 启用完整库访问（生产环境不建议）。

### 动态负载均衡

使用 `balancer_by_lua` 实现动态后端选择：

```lua
-- 根据请求路径选择不同后端
local uri = ngx.var.uri
if string.match(uri, "^/api/") then
    ngx.balancer.set_current_peer("api-backend", 8080)
elseif string.match(uri, "^/static/") then
    ngx.balancer.set_current_peer("static-backend", 8080)
else
    ngx.balancer.set_current_peer("default-backend", 8080)
end
```

## 部署

### Docker

```bash
# 构建镜像
docker build -t lolly:latest .

# 运行容器
docker run -d \
  --name lolly \
  -p 80:80 \
  -p 443:443 \
  -p 443:443/udp \
  -v /etc/lolly:/etc/lolly:ro \
  -v /var/www:/var/www:ro \
  -v /var/log/lolly:/var/log/lolly \
  lolly:latest
```

### Docker Compose

```yaml
version: "3"
services:
  lolly:
    image: lolly:latest
    ports:
      - "80:80"
      - "443:443"
      - "443:443/udp"
    volumes:
      - ./lolly.yaml:/etc/lolly/lolly.yaml:ro
      - ./html:/var/www/html:ro
      - ./logs:/var/log/lolly
    restart: unless-stopped
```

### systemd

创建 `/etc/systemd/system/lolly.service`：

```ini
[Unit]
Description=Lolly HTTP Server
After=network.target

[Service]
Type=simple
User=lolly
Group=lolly
ExecStart=/usr/local/bin/lolly -c /etc/lolly/lolly.yaml
ExecReload=/bin/kill -HUP $MAINPID
Restart=on-failure
LimitNOFILE=65535

[Install]
WantedBy=multi-user.target
```

```bash
# 安装服务
sudo systemctl daemon-reload
sudo systemctl enable lolly
sudo systemctl start lolly

# 管理服务
sudo systemctl reload lolly   # 重载配置
sudo systemctl restart lolly  # 重启服务
sudo systemctl status lolly   # 查看状态
```

## 监控

### 状态端点

访问 `/status`（需配置 `monitoring.status.allow` 白名单）：

```json
{
  "version": "0.2.2",
  "uptime": "2h30m15s",
  "connections": 150,
  "requests": 125000,
  "bytes_sent": 5368709120,
  "bytes_received": 1073741824,
  "pool": {
    "workers": 256,
    "IdleWorkers": 200,
    "MaxWorkers": 10000,
    "MinWorkers": 100,
    "QueueLen": 0,
    "QueueCap": 1000
  },
  "upstreams": [
    {
      "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 }
      ],
      "healthy_count": 2,
      "unhealthy_count": 0,
      "latency_p50_ms": 5.2,
      "latency_p95_ms": 12.5,
      "latency_p99_ms": 25.0
    }
  ],
  "rate_limits": [
    {
      "zone_name": "api_limit",
      "requests": 50000,
      "limit": 100,
      "rejected": 150
    }
  ],
  "ssl": {
    "handshakes": 2500,
    "session_reused": 800,
    "reuse_rate_percent": 32.0
  },
  "cache": {
    "file_cache": {
      "entries": 5000,
      "max_entries": 50000,
      "size": 134217728,
      "max_size": 268435456
    },
    "proxy_cache": {
      "entries": 2000,
      "pending": 5
    }
  }
}
```

### pprof 端点

启用 `monitoring.pprof.enabled: true` 后访问：

- `/debug/pprof/` - pprof 索引
- `/debug/pprof/profile?seconds=30` - CPU profile
- `/debug/pprof/heap` - 内存分配
- `/debug/pprof/goroutine` - Goroutine 分析
- `/debug/pprof/block` - 阻塞分析

## 信号处理

| 信号            | 行为                   |
| --------------- | ---------------------- |
| SIGTERM, SIGINT | 快速停止               |
| SIGQUIT         | 优雅停止，等待请求完成 |
| SIGHUP          | 重载配置               |
| SIGUSR1         | 重新打开日志文件       |
| SIGUSR2         | 热升级                 |

## 性能

基于 fasthttp，相比标准 net/http 有显著性能提升：

- 避免不必要的内存分配（零分配设计）
- 优化的事件循环
- 高效的连接池管理
- 零拷贝传输（sendfile）
- Goroutine 池复用

### 基准测试

在 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 连接 | -        | -        |

### PGO 优化

支持 Profile-Guided Optimization 构建，可获得额外 5-15% 性能提升：

```bash
# 1. 启用 pprof 端点
# 2. 运行代表性工作负载
# 3. 收集 CPU profile
curl http://localhost:8080/debug/pprof/profile?seconds=30 > default.pgo

# 4. 使用 PGO 构建
make build-pgo
```

### 生产环境推荐配置

```yaml
performance:
  goroutine_pool:
    enabled: true
    max_workers: 10000 # 根据 CPU 核数调整
    min_workers: 100
    idle_timeout: 60s
  file_cache:
    max_entries: 50000 # 根据内存调整
    max_size: 268435456 # 256MB
  transport:
    idle_conn_timeout: 90s
    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                |

## 与 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 优势**：

- YAML 配置更易读、易于解析和生成
- 单二进制部署，无依赖
- Go 原生扩展，无需 C 编译环境
- 现代 Go 库生态系统

**NGINX 优势**：

- 经过大规模生产验证
- 丰富的第三方模块生态
- 更完整的功能集（邮件代理等）

### 从 NGINX 迁移

常见配置转换示例：

| 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. 健康检查配置略有差异

## 故障排除

### 调试模式

启用详细日志：

```yaml
logging:
  error:
    level: "debug"
  access:
    format: "combined"
```

查看实时日志：

```bash
# 查看错误日志
tail -f /var/log/lolly/error.log | jq .

# 查看访问日志
tail -f /var/log/lolly/access.log
```

### 健康检查

```bash
# 检查状态端点
curl http://localhost:8080/status | jq .

# 检查后端健康
curl http://localhost:8080/status | jq '.upstreams'

# 检查缓存命中率
curl http://localhost:8080/status | jq '.cache'
```

## 开发

### 环境要求

- Go 1.26+
- make

### 命令

```bash
# 运行测试
make test

# 测试覆盖率
make test-cover

# 基准测试
make bench

# 基准测试（统计模式）
make bench-stat

# 对比基准结果
make bench-compare

# 代码检查
make check

# 格式化
make fmt

# 静态分析
make lint
```

### 项目统计

- Go 源文件：174 个
- 测试文件：158 个
- 总代码行数：~136,000 行
- 测试覆盖率：>80%
- 中文代码注释
- 所有核心模块均有完整单元测试和性能基准测试

## 依赖

| 库                                                                       | 版本    | 用途             |
| ------------------------------------------------------------------------ | ------- | ---------------- |
| [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.1 | 零分配 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 配置解析    |

## 许可证

MIT License

## 作者

xfy

