Skip to content

服务发现与 etcd

etcd 在 Vistack 中承担三件事:服务注册与发现领导选举元数据协调

1. 服务注册(transcoder / auth)

transcoder 与 auth 启动时向 etcd 注册自身地址,并通过租约保活

go
// internal/transcoder/registry/etcd.go
const (
    leaseTTL          = 10              // 租约 TTL 10s
    keepAliveInterval = 3 * time.Second // 每 3s 保活一次
)

// key: /vistack/transcoders/{id}   value: {addr}
func Register(ctx context.Context, client *clientv3.Client, prefix, id, addr string) (*Registrar, error) {
    lease, _ := client.Grant(ctx, leaseTTL)
    client.Put(ctx, key, addr, clientv3.WithLease(lease.ID))
    // 后台 keepAlive:失败时重新 Grant + Put
}

注册 key:

服务前缀
transcoder/vistack/transcodersgRPC 地址(如 transcoder:50051
auth/vistack/authgRPC 地址(如 host:50052

保活策略KeepAliveOnce 每 3s 续约,失败则重新 Grant 租约并重新 Put。实例宕机后租约在 10s 内过期,自动从注册表摘除。

2. 服务发现(worker → transcoder)

worker 通过自定义 gRPC resolver(scheme = etcd)动态发现 transcoder:

go
// internal/discovery/etcd.go
type EtcdBuilder struct { client *clientv3.Client; prefix string }

func (b *EtcdBuilder) Scheme() string { return "etcd" }

func (b *EtcdBuilder) Build(target, cc, opts) (resolver.Resolver, error) {
    r := &etcdResolver{...}
    r.update()      // 先拉取当前注册表
    go r.watch()    // 再 Watch 变更
    return r, nil
}
  • update()Get(prefix, WithPrefix()) 拉取全部实例地址,UpdateState 推给 gRPC;
  • watch():Watch 前缀,任何注册/注销事件触发 update(),实现动态上下线
  • 配合 gRPC round_robin 负载均衡,新扩容的 transcoder 自动被 worker 使用,宕机的自动摘除。

3. 领导选举(单例任务)

retry dispatcher 与 watchdog 必须在全局唯一运行,否则多 worker 会重复投递重试消息。通过 etcd 领导选举解决:

go
// internal/core/leader/leader.go
key := "/vistack/leaders/worker-singleton"  // DefaultLeaderKey

e := concurrency.NewElection(sess, key)
e.Campaign(ctx, instanceID)   // 竞选 leader
onElected(leadCtx)            // 只有 leader 执行单例循环
<-e.Done()                    // 失去领导权 → 重新竞选

工作机制:

  • 同一 key 下任意时刻只有一个 leader,其余实例阻塞等待;
  • leader 租约过期(崩溃)→ 其他实例自动接任,无主窗口 ≈ 租约 TTL(10s);
  • worker 启动时若 etcd 不可用,降级为直接运行(仅适合单实例,多实例有重复风险,日志告警)。

4. etcd 在 compose / K8s 中的位置

  • compose:单节点 quay.io/coreos/etcd:v3.5.16,端口 2379;
  • K8s:deploy/k8s/etcd.yaml,带 Service 供集群内访问。

演进方向(roadmap)

方向说明
注册值升级 JSON 元数据{addr, role, version, region, capacity},支持容量感知调度
配置中心动态配置写入 etcd + Watch 热更新(限流阈值、功能开关)
分布式锁concurrency.NewMutex 用于低频全局操作(缓存重建、ref_count 修复)
Snowflake node_id 分配etcd CAS 事务分配,消除哈希碰撞
etcd 集群高可用3~5 节点 + TLS + 认证

基于 MIT License 发布