feat(backend): 限流/登录失败锁状态外置 Redis(todo #2)
新包 internal/ratelimit:内存/redis(GCRA+Lua) 双实现 + 出错逐调用降级内存 (fail-open 到内存不 fail-closed)。REDIS_ADDR 空=内存模式,行为与既往一致; 配置后跨重启保状态、支持多实例。miniredis 全覆盖测试,零真实外部依赖。 Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
@@ -14,6 +14,7 @@ type Config struct {
|
||||
Storage StorageConfig
|
||||
Session SessionConfig
|
||||
RateLimit RateLimitConfig
|
||||
Redis RedisConfig
|
||||
Pay PayConfig
|
||||
}
|
||||
|
||||
@@ -68,6 +69,14 @@ type RateLimitConfig struct {
|
||||
PublicReadPerMin int `mapstructure:"public_read_per_min"` // 其余公开读接口(单品/release),按 IP
|
||||
ShopRPS int `mapstructure:"shop_rps"` // 认证流量每店每秒,按 shop_id
|
||||
ShopBurst int `mapstructure:"shop_burst"` // 认证流量每店突发
|
||||
// 日配额(分钟级限流之上的第二道反爬闸,0=关闭该闸):同一 IP 每自然日累计上限
|
||||
DailyProductPerIP int `mapstructure:"daily_product_per_ip"` // 单品详情(API + OG 页同池)
|
||||
DailyShopListPerIP int `mapstructure:"daily_shoplist_per_ip"` // 店铺公开商品列表
|
||||
}
|
||||
|
||||
// RedisConfig 限流/登录锁状态外置。Addr 为空 = 内存模式(单实例,重启清零)。
|
||||
type RedisConfig struct {
|
||||
Addr string `mapstructure:"addr"` // 如 127.0.0.1:6379
|
||||
}
|
||||
|
||||
type StorageConfig struct {
|
||||
@@ -99,6 +108,7 @@ func Load() {
|
||||
_ = viper.BindEnv("pay.base_url", "PAY_BASE_URL")
|
||||
_ = viper.BindEnv("pay.secret", "PAY_SECRET")
|
||||
_ = viper.BindEnv("pay.return_url", "PAY_RETURN_URL")
|
||||
_ = viper.BindEnv("redis.addr", "REDIS_ADDR")
|
||||
|
||||
// 默认值
|
||||
viper.SetDefault("server.port", "8080")
|
||||
@@ -123,6 +133,9 @@ func Load() {
|
||||
viper.SetDefault("ratelimit.public_read_per_min", 60)
|
||||
viper.SetDefault("ratelimit.shop_rps", 20)
|
||||
viper.SetDefault("ratelimit.shop_burst", 40)
|
||||
viper.SetDefault("ratelimit.daily_product_per_ip", 1000)
|
||||
viper.SetDefault("ratelimit.daily_shoplist_per_ip", 300)
|
||||
viper.SetDefault("redis.addr", "") // 空=内存模式
|
||||
viper.SetDefault("database.max_idle_conns", 10)
|
||||
viper.SetDefault("database.max_open_conns", 100)
|
||||
viper.SetDefault("storage.upload_dir", "./uploads/images")
|
||||
|
||||
Reference in New Issue
Block a user