docs: 精简并重构 README 文档结构
移除冗余的配置示例、生产清单和常见问题章节,新增核心模块依赖关系、
设计模式和性能优化设计等架构文档,统一 Markdown 表格格式。
💘 Generated with Crush
Assisted-by: mimo-v2.5-pro via Crush <crush@charm.land>
This commit is contained in:
parent
3a09ca4f48
commit
0e8b99e17f
718
README.md
718
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
|
||||
xfy
|
||||
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user