Loading [MathJax]/jax/output/CommonHTML/config.js
前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >专栏 >利用etcd选举sdk实践master/slave故障转移

利用etcd选举sdk实践master/slave故障转移

作者头像
有态度的马甲
发布于 2022-08-23 07:07:41
发布于 2022-08-23 07:07:41
40900
代码可运行
举报
文章被收录于专栏:精益码农精益码农
运行总次数:0
代码可运行

本次记录[利用etcd选主sdk实践master/slave故障转移], 并利用etcdctl客户端验证选主sdk的工作原理。

master/slave高可用集群

本文目标

在异地多机房部署节点,slave作为备用实例启动,但不接受业务流量, 监测到master宕机,slave节点自动提升为master并接管业务流量。

基本思路

各节点向etcd注册带租约的节点信息, 并各自维持心跳保活,选主sdk根据目前存活的、最早创建的节点信息键值对 来确立leader, 并通过watch机制通知业务代码leader变更。

讲道理,每个节点只需要知道两个信息就能各司其职

  • • 谁是leader ==> 当前节点是什么角色===> 当前节点该做什么事情
  • • 感知集群leader变更的能力 ===》当前节点现在要不要改变行为

除了官方etcd客户端go.etcd.io/etcd/client/v3, 还依赖go.etcd.io/etcd/client/v3/concurrency package:实现了基于etcd的分布式锁、屏障、选举

选主过程

实质

api

竞选前先查询leader了解现场

查询当前存活的,最早创建的kv值

*concurrency.Election.Leader()

初始化时,各节点向etcd阻塞式竞选

各节点向etcd注册带租约的键值对

*concurrency.Election.compaign

建立master/slave集群,还能及时收到变更通知

通过chan传递最新的leader value

*concurrency.Election.Observe()

重点解读

1.初始化etcd go客户端

注意:etcd客户端和服务端是通过grpc来通信,目前新版本的etcd客户端默认使用非阻塞式连接, 也就是说v3.New函数仅表示从指定配置创建etcd客户端。

为快速确定etcd选举的可用性,本实践使用阻塞式创建客户端:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
cli, err := v3.New(v3.Config{
  Endpoints:   addr,
  DialTimeout: time.Second * 5,
  DialOptions: []grpc.DialOption{grpc.WithBlock()},
 })
 if err != nil {
  log.WithField("instance", Id).Errorln(err)
  return nil, err
 }
2. 竞选

使用阻塞式命令compaign竞选之前,应先查询当前leader:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
// 将id:ip:port作为竞选时写入etcd的value
func (c *Client) Election(id string, notify chan<- bool) error {
 //竞选前先试图去了解情况
 ctx, cancel := context.WithTimeout(context.Background(), time.Second*3)
 defer cancel()
 resp, err := c.election.Leader(ctx)
 if err != nil {
  if err != concurrency.ErrElectionNoLeader {
   return err
  }
 } else { // 已经有leader了
  c.Leader = string(resp.Kvs[0].Value)
  notify <- (c.Leader == id)
 }

 if err = c.election.Campaign(context.TODO(), id); err != nil {
  log.WithError(err).WithField("id", id).Error("Campaign error")
  return err
 } else {
  log.Infoln("Campaign success!!!")
  c.Leader = id
  notify <- true
 }
 c.election.Key()
 return nil
}

参选:将持续刷新的leaseID作为key,将特定的客户端标记(这里使用ip:port)作为value,写到etcd.

当选:当前存活的、最早创建的key是leader , 也就是说leader故障转移并不是随机的

3. watch leader变更

golang使用信道完成goroutine通信,

本例声明信道: notify = make(chan bool, 1)

一石二鸟:监听该信道能够知道集群leader是否发生变化;信道内传的值表示当前节点是否是leader

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
func (c *Client) Watchloop(id string, notify chan<- bool) error {
 ch := c.election.Observe(context.TODO()) // 观察leader变更
 tick := time.NewTicker(c.askTime)

 defer tick.Stop()
 for {
  var leader string

  select {
  case _ = <-c.sessionCh:
   log.Warning("Recv session event")
   return fmt.Errorf("session Done") // 一次续约不稳,立马退出程序
  case e := <-ch:
   log.WithField("event", e).Info("watch leader event")
   leader = string(e.Kvs[0].Value)
   ctx, cancel := context.WithTimeout(context.Background(), time.Second*3)
   defer cancel()
   resp, err := c.election.Leader(ctx)
   if err != nil {
    if err != concurrency.ErrElectionNoLeader {
     return err
    } else { // 目前没leader,开始竞选了
     if err = c.election.Campaign(context.TODO(), id); err != nil {
      log.WithError(err).WithField("id", id).Error("Campaign error")
      return err
     } else { // 竞选成功
      leader = id
     }
    }
   } else {
    leader = string(resp.Kvs[0].Value)
   }
  }
  if leader != c.Leader {
   log.WithField("before", c.Leader).WithField("after", leader == id).Info("leader changed")
   notify <- (leader == id)
  }
  c.Leader = leader
 }
}

c.election.Observe(context.TODO()) 返回最新的leader信息,配合select case控制结构能够及时拿到leader变更信息。

如题:通过Leader字段和chan <- bool信道, 掌控了整个选举集群的状态, 可根据这两个信息去完成业务上的master/slave故障转移。

使用etcdctl确定leader

election.Leader的源码证明了[当前存活的,最早创建的kv为leader]

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
// Leader returns the leader value for the current election.
func (e *Election) Leader(ctx context.Context) (*v3.GetResponse, error) {
 client := e.session.Client()
 resp, err := client.Get(ctx, e.keyPrefix, v3.WithFirstCreate()...)
 if err != nil {
  return nil, err
 } else if len(resp.Kvs) == 0 {
  // no leader currently elected
  return nil, ErrElectionNoLeader
 }
 return resp, nil
}

等价于

./etcdctl get /merc --prefix --sort-by=CREATE --order=ASCEND --limit=1

-- sort-by :以某标准(创建时间)检索数据 -- order :以升/降序给已检出的数据排序 -- limit:从以检出的数据中取x条数据显示

本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2022-04-19,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 精益码农 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
暂无评论
推荐阅读
编辑精选文章
换一批
一种基于etcd实践节点自动故障转移的思路
自动故障转移是服务高可用的一种实现方式。mongodb,redis哨兵集群、 etcd都具备某种程度的故障转移能力。
有态度的马甲
2025/04/07
880
一种基于etcd实践节点自动故障转移的思路
etcd使用场景——Master选举分析与实现
  etcd有多种使用场景,Master选举是其中一种。说起Master选举,过去常常使用zookeeper,通过创建EPHEMERAL_SEQUENTIAL节点(临时有序节点),我们选择序号最小的节点作为Master,逻辑直观,实现简单是其优势,但是要实现一个高健壮性的选举并不简单,同时zookeeper繁杂的扩缩容机制也是沉重的负担。
andydbhe
2019/07/07
11.6K0
etcd使用场景——Master选举分析与实现
GO 中 ETCD 的编码案例分享
要是对 服务注册与发现,ETCD 还有点兴趣的话,欢迎查看文章 服务注册与发现之ETCD
阿兵云原生
2023/02/16
3620
Etcd基础学习之架构及工作原理
Etcd应用背景说明: 在实际生产环境中,有很多应用在同一时刻只能启动一个实例,例如更新数据库的操作,多个实例同时更新不仅会降低系统性能,还可能导致数据的不一致。但是单点部署也使得系统的容灾性减弱,比如进程异常退出 目前进程保活,也有很多方案如supervisor和systemd。但是如果宿主机down掉呢? 所有的进程保活方法都会无济于事,于是我们可以采用基于etcd自带的leader选举机制,轻松的使服务具备了高可用性。
全栈工程师修炼指南
2022/09/29
4K0
Etcd基础学习之架构及工作原理
又超时了!Etcd分布式锁你用明白了吗?
线上程序报错,错误信息:lock failed: context deadline exceeded, retry
米开朗基杨
2021/04/02
1.4K0
golang-etcd系列(一)--初识
etcd 是一个 golang 编写的分布式、高可用的一致性键值存储系统,是目前容器编排领域火热的 Kubernetes(k8s) 内置的服务发现与节点一致性中间件,用于提供可靠的分布式键值(key-value)存储、配置共享和服务发现等功能。etcd 可以用于存储关键数据和实现分布式调度,在现代化的集群运行中能够起到关键性的作用。
astraw99
2021/09/22
6270
golang-etcd系列(一)--初识
gRPC服务发现&amp;负载均衡
构建高可用、高性能的通信服务,通常采用服务注册与发现、负载均衡和容错处理等机制实现。根据负载均衡实现所在的位置不同,通常可分为以下三种解决方案:
李海彬
2018/07/26
2.9K0
gRPC服务发现&amp;负载均衡
Windows下安装etcd集群及zRPC的简单使用
etcd是CoreOS团队于2013年6月发起的开源项目,它的目标是构建一个高可用的分布式键值(key-value)数据库。etcd内部采用raft协议作为一致性算法,etcd基于Go语言实现。
杨永贞
2021/03/04
3.3K0
Go实现海量日志收集系统(三)
再次整理了一下这个日志收集系统的框,如下图 这次要实现的代码的整体逻辑为: 完整代码地址为: https://github.com/pythonsite/logagent etcd介绍 高可用的分布式
coders
2018/05/28
1K0
golang etcd简明教程
etcd 是一个高可用强一致性的键值仓库在很多分布式系统架构中得到了广泛的应用,本教程结合一些简单的例子介绍golang版本的 etcd/clientv3中提供的主要功能及其使用方法。
KevinYan
2019/11/04
5.1K0
【Golang】使用Go语言操作etcd——配置中心
【etcd】etcd使用与集群搭建 博文中已经大致介绍了 etcd与集群搭建,下面将针对etcd的使用场景之一的 配置中心做开发实战。
DDGarfield
2022/06/23
4.8K0
【Golang】使用Go语言操作etcd——配置中心
etcd框架实践【Go版】
etcd是一个分布式的键值存储系统,由CoreOS公司开发,主要用于为分布式系统提供可靠和高可用的配置管理和服务发现功能。etcd基于Raft一致性算法设计,可以有效地处理网络分区等容错问题,确保数据在集群中的一致性和可靠性。
FunTester
2024/07/05
2470
etcd框架实践【Go版】
深入浅出etcd之raft实现
etcd是coreOS使用golang开发的分布式,一致性的kv存储系统,因其易用性和高可靠性被广泛运用于服务发现、消息发布和订阅、分布式锁和共享配置等方面,也被认为是zookeeper的强有力的竞争者。作为分布式kv,其底层使用raft算法实现多副本数据的强一致性。etcd作为raft开源实现的标杆,在设计上,将 raft 算法逻辑和持久化、网络、线程等完全抽离出来单独实现,充分解耦,在工程上,实现了诸多性能优化,是 raft 开源实践中较早的工业级的实现,很多后来的 raft 实践者都直接或者间接的参考了 ectd-raft 的设计和实现,例如kubernetes,tiDb等。其广泛的影响力和优雅的golang代码实践也使得ectd成为golang的明星项目。在我们实际的分布式存储系统的项目开发中,raft也被应用于元信息管理和数据存储等多个模块,因此熟悉和理解etcd-raft的实现具有重大意义,本文从raft的基本原理出发,深入浅出地分析了raft在ectd中的具体实现。
evin
2019/02/23
9.8K0
深入浅出etcd之raft实现
读猿码系列——1. gRPC+Etcd3的服务发现&负载均衡
xdm好久不见,记得上次更新还是在上次,感谢伙伴们的关注和催更(笑)。这段时间阿巩回看了往期文章,感觉偏重概念理论而缺乏实践以及真正落实到coding上的东西,于是便有了“读猿码系列”,我会到github上找一些star多的或者有趣的开源项目,先clone到本地跑起来,然后从入口函数开始一点点究其本质,本系列文章会记录下来这个过程,也欢迎各位和我一起实践。对了,不要忘记给原作者个star哦~日拱一卒,我们开始吧!
才浅Coding攻略
2022/12/12
8200
读猿码系列——1. gRPC+Etcd3的服务发现&负载均衡
还活在上个时代,Etcd 3.0 实现分布式锁竟如此简单!
传统 Python 单机系统部署中,由于 GIL 的存在,相同进程中我们可以不用处理并发问题。但是随着业务发展需要,原有单机系统演变成分布式或多进程系统后。这将使原有的单机单进程并发控制策略失效。为了解决该问题需要引入一种跨进程、跨机器的互斥锁机制来控制共享资源的访问,这也就是分布式锁的由来。
程序员荒生
2022/05/19
1.3K0
还活在上个时代,Etcd 3.0 实现分布式锁竟如此简单!
如何与 etcd 服务端进行通信?客户端 API 实践与核心方法介绍
学习客户端与 etcd 服务端的通信以及 etcd 集群节点的内部通信接口对于我们更好地使用和掌握 etcd 组件很有帮助,也是所必需了解的内容。
aoho求索
2021/10/26
3.3K0
如何与 etcd 服务端进行通信?客户端 API 实践与核心方法介绍
研究Fabric中Etcd的Raft应用
Fabric的共识服务设计成了可插拔的模块,以此满足了根据不同应用场景切换不同共识选项的需求。在Hyperledger Fabric最新版本中,Fabric系统的共识模块中实现了三种共识算法,其中包括Solo,Kafka以及Raft算法。官方推荐的是使用Raft共识算法,但是为了更好地理解Fabric中的共识模块,我们也简单介绍一下Solo和Kafka这两种共识算法。
KunkkaWu
2022/08/03
1K1
golang context实战
来自官方文档: https://blog.golang.org/context: Incoming requests to a server should create a Context, and outgoing calls to servers should accept a Context. The chain of function calls between them must propagate the Context, optionally replacing it with a derived Context created using WithCancel, WithDeadline, WithTimeout, or WithValue. When a Context is canceled, all Contexts derived from it are also canceled.
王磊-字节跳动
2019/10/21
1.8K0
gRPC服务注册发现及负载均衡的实现方案与源码解析
今天聊一下gRPC的服务发现和负载均衡原理相关的话题,不同于Nginx、Lvs或者F5这些服务端的负载均衡策略,gRPC采用的是客户端实现的负载均衡。什么意思呢,对于使用服务端负载均衡的系统,客户端会首先访问负载均衡的域名/IP,再由负载均衡按照策略分发请求到后端具体某个服务节点上。而对于客户端的负载均衡则是,客户端从可用的后端服务节点列表中根据自己的负载均衡策略选择一个节点直连后端服务器。
KevinYan
2020/11/02
8570
gRPC服务注册发现及负载均衡的实现方案与源码解析
k8s watch 丢事件 - 3
v1.27 的 K8s,在 kube-apiserver 的日志中会看到 “etcd event received with PrevKv=nil” 的字样,资源对象被删除后在 Etcd 中已经不存在了但在 Reflector store 中仍然存在,可以在 Informer 或者 watchCache 中看到对应的对象,依赖 Informer 的组件也不会感知到资源对象被删除,通过 List API 设置 RV=“0” 去 kube-apiserver 的 watchCache 中获取的话也可以看到已经被删除的对象仍然存在。
李鹤
2024/03/23
2340
推荐阅读
相关推荐
一种基于etcd实践节点自动故障转移的思路
更多 >
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档
本文部分代码块支持一键运行,欢迎体验
本文部分代码块支持一键运行,欢迎体验