感谢您对 Pixiu-RLS 项目的关注!本文档将帮助您快速上手项目开发。
- Go: 1.21+
- Redis: 7.0+
- Git: 2.x+
- Make (可选)
- Docker (可选,用于测试)
git clone https://github.com/your-org/pixiu-rls.git
cd pixiu-rlsgo mod download
go mod verify# 使用 Docker
docker run -d -p 6379:6379 --name redis-dev redis:7-alpine
# 或直接启动
redis-server# 开发模式运行
go run ./cmd/rls-http -c configs/rls.yaml
# 或编译后运行
go build -o rls-http ./cmd/rls-http
./rls-http -c configs/rls.yaml# 健康检查
curl http://localhost:8080/health
# 限流测试
curl -X POST http://localhost:8080/v1/allow \
-H "Content-Type: application/json" \
-d '{"ruleId":"global-default","dims":{"ip":"127.0.0.1"}}'Pixiu-RLS/
├── cmd/ # 应用程序入口
│ └── rls-http/ # HTTP 服务主程序
│ └── main.go # 主函数,依赖注入
│
├── internal/ # 内部包(不对外暴露)
│ ├── api/ # HTTP API 层
│ │ ├── dto.go # 数据传输对象
│ │ └── http.go # HTTP 处理器
│ │
│ ├── config/ # 配置管理
│ │ └── config.go # 配置结构和加载
│ │
│ ├── core/ # 核心业务逻辑
│ │ ├── engine.go # 限流引擎(主入口)
│ │ ├── quota.go # 配额控制器
│ │ └── strategy/ # 限流策略实现
│ │ ├── sliding.go # 滑动窗口
│ │ ├── token.go # 令牌桶
│ │ ├── leaky.go # 漏桶
│ │ └── breaker_wrap.go # 熔断装饰器
│ │
│ ├── rcu/ # RCU 无锁快照
│ │ ├── snapshot.go # 快照实现
│ │ └── snapshot_test.go
│ │
│ ├── repo/ # Redis 数据访问层
│ │ ├── redis.go # Redis 客户端封装
│ │ └── lua.go # Lua 脚本定义
│ │
│ ├── rules/ # 规则管理
│ │ └── cache.go # 规则缓存(使用 RCU)
│ │
│ ├── types/ # 公共类型定义
│ │ └── types.go # Decision 等类型
│ │
│ └── util/ # 工具函数
│ ├── hash.go # 哈希函数
│ ├── dim.go # 维度处理
│ └── conv.go # 类型转换
│
├── configs/ # 配置文件
│ └── rls.yaml
│
├── deployments/ # 部署配置
│ └── docker-compose.yaml
│
├── docs/ # 文档
│ ├── API.md
│ ├── DEPLOYMENT.md
│ └── DEVELOPMENT.md (本文件)
│
├── examples/ # 示例代码
│ └── rcu_example.go
│
├── go.mod # Go 模块依赖
├── go.sum
└── README.md # 项目说明
核心限流引擎,协调各个组件:
Allow() → 黑白名单检查 → 维度哈希 → 配额检查 → 策略执行
策略接口和具体实现:
type Strategy interface {
Allow(ctx context.Context, rule config.Rule, dimKey string, now time.Time) (types.Decision, error)
}无锁快照机制,用于高性能规则缓存:
Load(): 无锁读取(0.03ns)Replace(): 原子替换(21ns)
规则缓存管理:
Resolve(): 查找规则ReloadAll(): 全量重载Upsert(): 更新规则
git checkout -b feature/your-feature-name遵循以下规范:
- 使用
gofmt格式化代码 - 添加必要的注释
- 编写单元测试
- 更新文档
# 运行所有测试
go test ./...
# 运行特定包的测试
go test -v ./internal/core/
# 运行测试并查看覆盖率
go test -cover ./...
# 生成覆盖率报告
go test -coverprofile=coverage.out ./...
go tool cover -html=coverage.out# 运行基准测试
go test -bench=. -benchmem ./internal/rcu/
# 对比优化前后性能
go test -bench=BenchmarkLoad -benchmem -count=5 ./internal/rcu/ > old.txt
# ... 修改代码 ...
go test -bench=BenchmarkLoad -benchmem -count=5 ./internal/rcu/ > new.txt
benchstat old.txt new.txt# 格式化
go fmt ./...
# 静态检查
go vet ./...
# 使用 golangci-lint (推荐)
golangci-lint rungit add .
git commit -m "feat: add new feature"
git push origin feature/your-feature-name在 GitHub 上创建 PR,并确保:
- PR 描述清晰
- 所有测试通过
- 代码审查通过
internal/core/strategy/custom.go:
package strategy
import (
"context"
"time"
"github.com/nanjiek/pixiu-rls/internal/config"
"github.com/nanjiek/pixiu-rls/internal/repo"
"github.com/nanjiek/pixiu-rls/internal/types"
)
// Custom 自定义策略
type Custom struct {
repo *repo.RedisRepo
}
// NewCustom 创建自定义策略实例
func NewCustom(rdb *repo.RedisRepo) *Custom {
return &Custom{repo: rdb}
}
// Allow 实现 core.Strategy 接口
func (c *Custom) Allow(ctx context.Context, rule config.Rule, dimKey string, now time.Time) (types.Decision, error) {
// TODO: 实现您的限流逻辑
return types.Decision{
Allowed: true,
Remaining: rule.Limit,
Reason: "custom_allowed",
}, nil
}internal/core/strategy/custom_test.go:
package strategy
import (
"context"
"testing"
"time"
"github.com/nanjiek/pixiu-rls/internal/config"
)
func TestCustom_Allow(t *testing.T) {
strategy := NewCustom(nil)
rule := config.Rule{
RuleID: "test",
Limit: 100,
}
decision, err := strategy.Allow(context.Background(), rule, "test-key", time.Now())
if err != nil {
t.Errorf("unexpected error: %v", err)
}
if !decision.Allowed {
t.Error("expected allowed=true")
}
}在 cmd/rls-http/main.go 中注册:
// 创建策略实例
custom := strategy.NewCustom(rdb)
// 添加到策略映射
strategies := map[string]core.Strategy{
"sliding_window": sliding,
"token_bucket": token,
"leaky_bucket": leaky,
"custom": custom, // 新增
}在 docs/API.md 中添加算法说明。
-
命名:
- 包名:小写,单数,简短
- 变量名:驼峰命名
- 常量:大写驼峰
- 私有成员:小写开头
- 公开成员:大写开头
-
注释:
// NewEngine 创建引擎实例 // 参数: // rdb: Redis 仓库 // strategies: 策略映射 // 返回: // *Engine: 引擎实例 func NewEngine(rdb *repo.RedisRepo, strategies map[string]Strategy) *Engine { ... }
-
错误处理:
// ✅ 好的做法 if err := doSomething(); err != nil { return fmt.Errorf("do something failed: %w", err) } // ❌ 不好的做法 doSomething() // 忽略错误
-
上下文传递:
// ✅ 始终传递 context func (s *Strategy) Allow(ctx context.Context, ...) error { ... }
- 测试文件命名:
xxx_test.go - 测试函数命名:
TestXxx或TestXxx_Scenario - 基准测试命名:
BenchmarkXxx - 使用表驱动测试:
func TestHashDims(t *testing.T) {
tests := []struct {
name string
ruleDims []string
inputDims map[string]string
wantErr bool
}{
{
name: "valid dims",
ruleDims: []string{"ip"},
inputDims: map[string]string{"ip": "192.168.1.1"},
wantErr: false,
},
// 更多测试用例...
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
_, err := HashDims(tt.ruleDims, tt.inputDims)
if (err != nil) != tt.wantErr {
t.Errorf("HashDims() error = %v, wantErr %v", err, tt.wantErr)
}
})
}
}import "log/slog"
slog.SetLogLoggerLevel(slog.LevelDebug)import _ "net/http/pprof"
go func() {
http.ListenAndServe("localhost:6060", nil)
}()访问 http://localhost:6060/debug/pprof/ 查看性能分析。
# 实时监控 Redis 命令
redis-cli MONITOR
# 查看慢查询
redis-cli SLOWLOG GET 10func TestDebug(t *testing.T) {
t.Log("debug info")
t.Logf("value: %v", value)
}运行:
go test -v -run TestDebug- 在
internal/api/dto.go添加请求/响应结构 - 在
internal/api/http.go添加处理器 - 在
RegisterRoutes()中注册路由 - 添加测试
- 更新 API 文档
- 在
internal/config/config.go添加配置结构 - 在
configs/rls.yaml添加默认值 - 更新文档
- 使用 pprof 定位瓶颈
- 编写基准测试
- 优化代码
- 对比优化前后的基准测试结果
- 验证功能正确性
遵循语义化版本 (SemVer):
- 主版本号 (Major):不兼容的 API 修改
- 次版本号 (Minor):向后兼容的功能新增
- 修订号 (Patch):向后兼容的问题修正
- 更新版本号
# 创建发布分支
git checkout -b release/v1.2.0
# 更新 CHANGELOG.md
# 更新版本号- 运行完整测试
go test ./...
go test -race ./...
go vet ./...- 创建 Tag
git tag -a v1.2.0 -m "Release v1.2.0"
git push origin v1.2.0- 构建发布包
# Linux
GOOS=linux GOARCH=amd64 go build -o rls-http-linux-amd64 ./cmd/rls-http
# macOS
GOOS=darwin GOARCH=amd64 go build -o rls-http-darwin-amd64 ./cmd/rls-http
# Windows
GOOS=windows GOARCH=amd64 go build -o rls-http-windows-amd64.exe ./cmd/rls-http- 创建 GitHub Release
go get github.com/new/package
go mod tidy使用 miniredis 或接口 mock:
import "github.com/alicebob/miniredis/v2"
func TestWithMockRedis(t *testing.T) {
mr, _ := miniredis.Run()
defer mr.Close()
// 使用 mr.Addr() 作为 Redis 地址
}在 Redis 中直接执行:
redis-cli EVAL "$(cat internal/repo/sliding_window.lua)" 1 test:key 1000 100 10- Issue: 在 GitHub 提交 Issue
- 讨论: GitHub Discussions
- 邮件: dev@pixiu-rls.io
感谢您的贡献! 🎉
版本: v1.0
最后更新: 2024-01