利用redis实现选举
通常情况下, 选举会使用etcd专门的数据库。但是如果已经有redis服务器下,为了减少依赖,也可以使用redis实现。
定义结构, 存放一些配置东西
type Election struct {
// 连接 redis 客户端, 其他能实现锁的公共存储也行
Connect *services.Redis
runUid string // 进程唯一id
key string // 队列名称
isRunNode bool
lockTime int
awakens []interface{}
}
定义监控循环
func (k *Election) Run() {
// 标识当前节点抢到执行权利
for !k.check() {
time.Sleep(time.Duration(k.lockTime) * time.Second)
}
// 执行节点才可以走下去,循环闭包函数执行它
for _, awaken := range k.awakens {
switch awaken.(type) {
case func():
awaken.(func())()
default:
log.Warning("选举后才启动的参数, 请传入闭包")
}
}
}
抢夺锁和保持心跳
func (k *Election) check() bool {
if k.isRunNode {
return true
}
// 沉默节点, 尝试检查runNode是否死机, 抢夺执行权利
ctx := context.Background()
ok := k.Connect.Client.SetNX(ctx, k.key, k.runUid, time.Duration(k.lockTime+10)*time.Second)
if ok.Val() {
k.isRunNode = true
// 设置一个保持心跳的循环
go func() {
ex := time.Duration(k.lockTime) * time.Second
for range time.Tick(ex) {
k.Connect.Client.Expire(context.Background(), k.key, time.Duration(k.lockTime+10)*time.Second)
}
}()
machine, _ := os.Hostname()
log.Info(machine + " 通过了选举")
return true
} else {
k.isRunNode = false
return false
}
}
启动
e := Election{/* TODO 设置 awakens = func ... */}
e.Run()
推荐文章: