infra/

directory
v0.3.7 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Aug 8, 2026 License: Apache-2.0

README

Beauty 基建适配层(pkg/infra

pkg/infra 把各类中间件/编排平台(etcd、Consul、Kubernetes、Redis、Nacos、 Polaris)适配到框架定义的后端无关接口上。核心接口都在纯标准库的接口包里 (pkg/confpkg/dlockpkg/kvstore),infra 子包才引入对应 SDK 依赖——业务 按需 import,不用的后端不进依赖树。

设计约定:

  • 接口在别处,实现在这里conf.ConfigCenter / dlock.Locker+Elector / kvstore.Store 由 infra 子包实现,不重新发明分布式算法,只做薄封装。
  • 一处连接构造:每个后端只有一处 NewClient / NewClientset,配置中心、 分布式锁、KV 存储、服务发现共用它(见各包 client.go / config_client.go)。
  • URL/DSN 工厂conf.New(dsn)dlock.New(dsn) / dlock.NewElector(dsn) 按 scheme 选后端——空导入对应子包即可注册(import _ ".../pkg/infra/etcd")。
  • 如实标注语义:能力和局限写在包注释里(如 Redis 锁是单节点语义、非 Redlock; etcd kvstore 的 TTL 粒度是秒)。不假装提供做不到的强度。

能力矩阵

后端 配置中心 conf 分布式锁/选主 dlock TTL-KV kvstore 服务发现 discover
etcd etcd / etcdv3 ✅ Locker + Elector etcdv3
consul consul ✅ Locker + Elector
k8s configmap / secret ✅ 仅 Elector¹
redis ✅ Locker + Elector²
mysql ✅ Locker + Elector³
nacos nacos
polaris polaris

¹ k8s 基于 Lease 的 leaderelection 是「选主」语义,没有互斥锁原语,故只实现 Elector。 ² Redis 锁是单节点语义(SET NX PX + Lua CAS),不是跨多 master 的 Redlock。 需要更强保证时用 etcd / consul 后端。 ³ MySQL 锁基于 GET_LOCK/RELEASE_LOCK(advisory lock),session-level, 连接断开自动释放。要求 MySQL 5.7.5+(支持同连接多锁)。

配置中心 conf

统一入口 conf.New(dsn),scheme 决定后端。远程后端需空导入对应子包触发注册:

import (
    "github.com/rushteam/beauty/pkg/conf"
    _ "github.com/rushteam/beauty/pkg/infra/etcd" // 注册 etcd/etcdv3 scheme
)

loader, err := conf.New("etcd://127.0.0.1:2379/myapp/config.yaml")
loader.Unmarshal(&cfg)
loader.Watch(ctx, func() { loader.Unmarshal(&cfg) }) // 热更新

各后端 DSN:

etcd://[user:pass@]host1,host2/key?dial_ms=3000
consul://[:token@]host:port/kv/path?datacenter=dc1&namespace=ns
configmap://<namespace>/<name>/<dataKey>?kubeconfig=/path     # 纯 k8s 部署免运维额外配置中心
secret://<namespace>/<name>/<dataKey>?kubeconfig=/path
nacos://host:8848/dataId?namespace=dev&group=DEFAULT_GROUP
polaris://host:8090/key

分布式锁 / 选主 dlock

两个原语:Locker(互斥锁,Lock/TryLock)与 Elector(持续选主,当选期间持有 leaderCtx,失去 leader 时被 cancel)。典型用途——多实例部署下让 Cron 只在 leader 上跑:

import (
    "github.com/rushteam/beauty/pkg/dlock"
    _ "github.com/rushteam/beauty/pkg/infra/etcd" // 注册 etcd 后端
)

elector, err := dlock.NewElector("etcd://127.0.0.1:2379/?ttl=10s")
cron := cron.New(cron.WithLeaderElector(elector, "myservice-cron"), /* handlers... */)

也可直接用互斥锁:

locker, _ := dlock.New("redis://:pass@127.0.0.1:6379/0?ttl=15s")
lock, err := locker.Lock(ctx, "job:reindex")
defer lock.Unlock(ctx)

各后端 DSN(锁的 key 在调用 Lock/Run 时传入,不在 DSN 里;通用 query:prefixttl):

etcd://[user:pass@]host1,host2/?ttl=10s&prefix=/beauty/dlock/&dial_ms=3000
consul://[:token@]host:port/?ttl=15s&prefix=beauty/dlock/&datacenter=dc1&identity=host-a
redis://[:password@]host:port/db?ttl=15s&retry=100ms&prefix=beauty:dlock:
mysql://user:pass@host:3306/dbname?prefix=beauty:dlock:&retry=2s&heartbeat=5s
k8s://?namespace=prod&kubeconfig=/path&identity=pod-a               # 仅 Elector

不想用 DSN 时,每个后端也有直接构造函数:etcd.NewDLock / NewDLockFromConfigconsul.NewDLock*redis.NewDLock*k8s.NewElector / NewElectorFromConfig。 单机/测试用 dlock.NewMemory()(进程内,无需任何后端)。

TTL-KV 存储 kvstore

kvstore.Store 给 counter / cooldown / idempotency 等原语一个跨实例共享的后端 (默认是单进程内存,水平扩展时状态会散落各实例)。方法都是原子操作:IncrSetNXGet/GetIntSetTTLDelete

import beautyredis "github.com/rushteam/beauty/pkg/infra/redis"

store := beautyredis.NewStore(beautyredis.NewClient(&beautyredis.Config{Addr: "127.0.0.1:6379"}))
// 或 etcd:  beautyetcd.NewStoreFromConfig(&beautyetcd.Config{Endpoints: []string{...}})
n, _ := store.Incr(ctx, "quota:user:42", 1, time.Minute)
  • redis:基于 PEXPIRE,支持毫秒级 TTL,Incr 原生原子。适合精确/短冷却。
  • etcd:基于 lease,TTL 粒度是(不足 1s 抬到 1s),Incr 走事务 CAS。 TTL() 可精确查询剩余时间;适合已有 etcd、不想再引 Redis 的场景。

目录一览

子包 内容
etcd/ client.go(连接)、config_client.godlock.gokvstore.gofactory.go
consul/ config_client.go(含连接)、dlock.gofactory.go
k8s/ client.goconfig_center.godlock.go(Elector)、factory.go
redis/ client.godlock.gokvstore.gofactory.go
mysql/ dlock.go(advisory lock)、factory.go
nacos/ config.goconfig_client.gonacos.gofactory.go
polaris/ config_client.gofactory.go

服务发现 discover

注册中心适配在 pkg/service/discover/{etcdv3,consul,k8s,nacos,polaris}, 连接构造复用本目录对应后端的 NewClient / NewClientset

K8s 服务发现 DSN 采用 K8s DNS 风格

k8s://service.namespace[.svc[.cluster.local]]?params

示例:

k8s://payment-internal.mall?port_name=grpc                         # 精确服务
k8s://my-svc.kube-system.svc.cluster.local?port_name=http          # 完整 DNS
k8s://my-service?port_name=grpc                                    # 省略 namespace → default
k8s://*.mall?label_selector=team=payment                           # 通配+标签筛选
k8s://my-svc.prod?kubeconfig=/path/to/config                       # 集群外

可用参数:namespaceservice_type(默认 ClusterIP)、port_namelabel_selectorkubeconfigwatch_timeout

详细说明参见 pkg/service/discover/k8s/README.md

Directories

Path Synopsis
Package k8s 提供基于 Kubernetes 原生选主能力实现 pkg/dlock.Elector 的后端, 使 Cron 等"多实例只该有一个在跑"的场景可以直接用集群内已有的 k8s API, 不必额外运维一套 etcd/Redis。
Package k8s 提供基于 Kubernetes 原生选主能力实现 pkg/dlock.Elector 的后端, 使 Cron 等"多实例只该有一个在跑"的场景可以直接用集群内已有的 k8s API, 不必额外运维一套 etcd/Redis。
Package mysql 基于 MySQL Advisory Lock(GET_LOCK / RELEASE_LOCK)实现 pkg/dlock 的 Locker 与 Elector。
Package mysql 基于 MySQL Advisory Lock(GET_LOCK / RELEASE_LOCK)实现 pkg/dlock 的 Locker 与 Elector。
Package pg 基于 PostgreSQL Advisory Lock 实现 pkg/dlock 的 Locker 与 Elector。
Package pg 基于 PostgreSQL Advisory Lock 实现 pkg/dlock 的 Locker 与 Elector。
Package redis 提供基于 Redis 的基建适配:分布式锁/选主(实现 pkg/dlock)与 带 TTL 的原子 KV 存储(实现 pkg/kvstore.Store,给 counter/cooldown/idempotency 等原语一个真实的跨实例后端)。
Package redis 提供基于 Redis 的基建适配:分布式锁/选主(实现 pkg/dlock)与 带 TTL 的原子 KV 存储(实现 pkg/kvstore.Store,给 counter/cooldown/idempotency 等原语一个真实的跨实例后端)。

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL