Skip to content

DefectingCat/lolly

Repository files navigation

Lolly

Go Version License

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

基于 fasthttp 构建,提供比标准 net/http 更高的性能。支持 HTTP/3 (QUIC)、WebSocket、虚拟主机、多种负载均衡算法、故障转移,以及完整的安全与性能优化特性。

特性

核心功能

  • 静态文件服务 - 零拷贝传输(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)或连接失败时,自动重试下一个可用后端:

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 信号触发,零停机升级
  • 配置热重载 - HUP 信号触发,动态更新配置
  • 日志轮转 - USR1 信号触发,重新打开日志文件
  • 优雅关闭 - QUIT 信号触发,等待请求完成
  • 状态监控 - 内置状态端点,统计连接数、请求数、流量
  • pprof 端点 - 内置性能分析端点,支持 PGO 优化

安装

构建

# 克隆仓库
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/ 目录。

运行

# 使用默认配置
./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 格式:

# 导入 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              # 主程序逻辑
│   └── import.go           # nginx 配置导入
├── config/                 # 配置加载、验证、默认值
│   ├── config.go           # 配置结构定义
│   ├── loader.go           # 配置文件加载
│   ├── defaults.go         # 默认配置
│   └── validate.go         # 配置验证
├── server/                 # HTTP 服务器核心
│   ├── server.go           # 服务器实现
│   ├── vhost.go            # 虚拟主机管理
│   ├── pool.go             # Goroutine 池
│   ├── status.go           # 状态端点
│   ├── pprof.go            # pprof 端点
│   ├── pprof_impl.go       # pprof 实现
│   ├── purge.go            # 缓存清除端点
│   ├── internal.go         # 内部端点处理
│   └── upgrade.go          # 热升级管理
├── handler/                # 请求处理器
│   ├── router.go           # 路由器
│   ├── static.go           # 静态文件处理
│   ├── sendfile.go         # 零拷贝传输(通用)
│   ├── sendfile_linux.go   # Linux sendfile 实现
│   └── errorpage.go        # 错误页面管理
├── proxy/                  # 反向代理
│   ├── proxy.go            # 代理核心逻辑
│   ├── websocket.go        # WebSocket 代理
│   ├── health.go           # 健康检查
│   ├── headers.go          # 头部处理工具
│   ├── redirect_rewrite.go # Location 头改写
│   ├── proxy_ssl.go        # SSL 代理
│   └── tempfile.go         # 临时文件管理
├── loadbalance/            # 负载均衡算法
│   ├── balancer.go         # 算法接口
│   ├── algorithms.go       # 算法注册(round-robin 等)
│   ├── consistent_hash.go  # 一致性哈希
│   ├── random.go           # Power of Two Choices
│   └── slow_start.go       # 慢启动算法
├── matcher/                # Location 匹配器
│   ├── matcher.go          # 匹配器接口
│   ├── exact.go            # 精确匹配
│   ├── prefix.go           # 前缀匹配
│   ├── regex.go            # 正则匹配
│   └── radix.go            # 基数树匹配
├── middleware/             # 中间件链
│   ├── middleware.go       # 中间件接口
│   ├── compression/        # Gzip/Brotli 压缩
│   │   ├── compression.go  # 压缩实现
│   │   └── gzip_static.go  # 预压缩文件
│   ├── security/           # 安全中间件
│   │   ├── access.go       # 访问控制
│   │   ├── ratelimit.go    # 限流算法
│   │   ├── sliding_window.go # 滑动窗口
│   │   ├── auth.go         # Basic Auth
│   │   ├── auth_request.go # 子请求认证
│   │   ├── geoip.go        # GeoIP 过滤
│   │   └ headers.go        # 安全头部
│   ├── rewrite/            # URL 重写
│   │   └ rewrite.go        # 重写实现
│   ├── accesslog/          # 访问日志
│   │   └ accesslog.go      # 日志实现
│   ├── bodylimit/          # 请求体大小限制
│   │   └ bodylimit.go      # 限制实现
│   ├── limitrate/          # 响应速率限制
│   │   └ limitrate.go      # 限速实现
│   └── errorintercept/     # 错误页面拦截
│       └ errorintercept.go # 拦截实现
├── lua/                    # Lua 脚本引擎
│   ├── engine.go           # gopher-lua 引擎
│   ├── context.go          # Lua 请求上下文
│   ├── 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          # HTTP/2 适配器
├── http3/                  # HTTP/3 服务器
│   ├── server.go           # QUIC 服务器
│   └── adapter.go          # HTTP/3 适配器
├── 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       # 文件缓存
│   ├── disk_cache.go       # 磁盘缓存
│   ├── tiered_cache.go     # L1/L2 分层缓存
│   └ purge.go              # 缓存清除
├── resolver/               # DNS 解析器
│   ├── resolver.go         # DNS 解析逻辑
│   ├── cache.go            # DNS 结果缓存
│   └ stats.go              # DNS 解析统计
├── variable/               # 变量系统
│   ├── variable.go         # 变量接口
│   ├── builtin.go          # 内置变量
│   ├── 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 接口:

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

负载均衡

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

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

-- 日志
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 重写:

-- 将 /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 - 访问控制:

-- 检查请求头中的 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 - 动态响应:

-- 生成 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 实现动态后端选择:

-- 根据请求路径选择不同后端
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

# 构建镜像
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

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

[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
# 安装服务
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 白名单):

{
  "version": "0.2.1",
  "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% 性能提升:

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

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

生产环境推荐配置

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

故障排除

调试模式

启用详细日志:

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

查看实时日志:

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

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

健康检查

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

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

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

开发

环境要求

  • Go 1.24+
  • make

命令

# 运行测试
make test

# 测试覆盖率
make test-cover

# 基准测试
make bench

# 基准测试(统计模式)
make bench-stat

# 对比基准结果
make bench-compare

# 代码检查
make check

# 格式化
make fmt

# 静态分析
make lint

项目统计

  • Go 文件:290
  • 测试文件:157
  • 核心模块均有完整测试和性能基准测试
  • 中文代码注释

依赖

版本 用途
fasthttp v1.70.0 HTTP 服务器核心
fasthttp/router v1.5.4 HTTP 路由器
quic-go v0.59.0 QUIC/HTTP/3 实现
zerolog v1.35.0 零分配 JSON 日志
gopher-lua v1.1.2 Lua 脚本引擎
klauspost/compress v1.18.5 Gzip/Brotli 压缩
brotli v1.2.1 Brotli 压缩编码
geoip2-golang v1.13.0 GeoIP 查询
golang-lru/v2 v2.0.7 LRU 缓存
uuid v1.6.0 UUID 生成
testcontainers-go v0.42.0 集成测试容器
testify v1.11.1 测试断言
golang.org/x/crypto v0.50.0 加密工具
golang.org/x/net v0.53.0 网络扩展
yaml.v3 v3.0.1 YAML 配置解析

许可证

MIT License

作者

xfy

About

No description, website, or topics provided.

Resources

Stars

Watchers

Forks

Packages

 
 
 

Contributors

Languages