V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
The Go Programming Language
http://golang.org/
Go Playground
Go Projects
Revel Web Framework
teli
V2EX  ›  Go 编程语言

有没有办法实现简单的 Go 服务 leader 选举?

  •  
  •   teli · 2023-01-06 18:15:00 +08:00 via Android · 5128 次点击
    这是一个创建于 447 天前的主题,其中的信息可能已经有所发展或是发生改变。

    需要从服务实例中选出一个 leader ,从事一些必须“全局唯一”的事情。

    当 leader 因为各种原因下线后,其它实例要能及时选举出新 leader 。

    要求依赖别太重,或者依赖常用组件服务,比如 redis 。还要考虑这个依赖的组件服务可能掉线可能重连。

    48 条回复    2023-01-09 14:36:11 +08:00
    okayan
        1
    okayan  
       2023-01-06 18:18:35 +08:00
    如果是在 kubernetes 集群里的话,可以直接用 k8s.io/client-go/tools/leaderelection
    lion250258
        2
    lion250258  
       2023-01-06 18:21:30 +08:00
    好像记得 zookeeper 也有这个功能吧
    ikaros
        3
    ikaros  
       2023-01-06 18:22:11 +08:00
    基于 raft 写个状态机,不过感觉有点杀鸡用牛刀 https://github.com/hashicorp/raft
    teli
        4
    teli  
    OP
       2023-01-06 18:25:54 +08:00 via Android
    @lion250258 可能没 zookeeper 这个或这类组件。
    但 redis 应该都有
    stillFox
        5
    stillFox  
       2023-01-06 18:26:05 +08:00
    不想要有重的外部依赖的话,自己现实的工作量也会很重哦。感觉这个开发成本并不一定比外部组件的维护成本低。我记得早期 kafka 的选主也是依赖 zookeeper 来实现的。后来才去掉了。
    virusdefender
        6
    virusdefender  
       2023-01-06 18:28:45 +08:00
    需求不是特别严格的话不难,比如找一个基于数据库或者 redis 的锁的库就行,但是会有一些细节上的问题,比如 redis 可能是单点,要是用集群的话,数据同步可能有延迟,一些极端情况下可能还是不可用或者出现竞争等。
    zoharSoul
        7
    zoharSoul  
       2023-01-06 18:36:57 +08:00
    zookeeper 算常用组件了吧, 用这个就可以呀
    aqqwiyth
        8
    aqqwiyth  
       2023-01-06 18:40:23 +08:00
    redis 原子操作 put 一个 value 为节点的 IP, 然后配置 key 15 秒过期. 5 秒维持一次过期时间.

    value 为节点 IP 的就是 leader, leader 挂了之后 15 秒之后 put 成功的就是下一个 leader
    littlewing
        9
    littlewing  
       2023-01-06 18:49:51 +08:00
    embedded etcd
    hscxrzs
        10
    hscxrzs  
       2023-01-06 19:17:49 +08:00   ❤️ 1
    leader 这东西类似于分布式锁,可以看看按照分布式锁的思路来做。每个实例起一个后台线程,定时去尝试获取分布式锁。对于获取锁成功的那个实例就是 leader ,然后定时去刷新过期时间。如果 leader 挂了,那么其他实例获得分布式锁的就是 leader 了
    teli
        11
    teli  
    OP
       2023-01-06 19:22:39 +08:00 via Android
    @littlewing 这个方案貌似不错。
    不知道资源消耗多少?有实例代码吗?
    CEBBCAT
        12
    CEBBCAT  
       2023-01-06 19:25:58 +08:00
    可否对「“全局唯一”的事情」举个例子?我是觉得常见业务不用 leader 选举也能做到独占,leader 选举这样的设计一般是为了保证同步
    my3157
        13
    my3157  
       2023-01-06 19:27:50 +08:00
    teli
        14
    teli  
    OP
       2023-01-06 19:35:17 +08:00 via Android
    @CEBBCAT 目前需求是全局只有一个实例在干这事
    luyifei
        15
    luyifei  
       2023-01-06 20:05:57 +08:00
    @ikaros raft + 1 ,可以看一下 mit 的 6.824 ,就是用 raft 写的一个分布式 kv 服务
    potatowish
        16
    potatowish  
       2023-01-06 20:12:17 +08:00 via iPhone
    结合 10L 可以用 redis 分布式锁,按一定周期获取锁
    teli
        17
    teli  
    OP
       2023-01-06 20:14:08 +08:00 via Android
    @my3157 看起来很牛掰。但没发现支持 leader 特性。有什么好办法基于这个实现 leader 选举吗?
    teli
        18
    teli  
    OP
       2023-01-06 20:16:36 +08:00 via Android
    @hscxrzs 我首先想到的也是这个办法。但上面有位朋友提醒了我,如果是集群,同步会有延迟。这个有什么好应对办法?
    sadfQED2
        19
    sadfQED2  
       2023-01-06 20:26:45 +08:00 via Android
    为啥不考虑锁,而去搞个选举。选举要考虑各种情况的脑裂,问题一大堆。分布式锁 redis 几行代码就搞定了
    TheCure
        20
    TheCure  
       2023-01-06 20:28:05 +08:00
    Juszoe
        21
    Juszoe  
       2023-01-06 20:32:57 +08:00
    BBCCBB
        22
    BBCCBB  
       2023-01-06 21:18:21 +08:00   ❤️ 1
    别听楼上什么分布式锁 redis 几行代码就搞定了,

    要是其他方案靠谱的话, 就不会有 paxos, raft 了
    my3157
        23
    my3157  
       2023-01-06 21:33:54 +08:00 via Android   ❤️ 1
    @teli 知道那些节点在线,那些不在线,上 /下线都有 event ,节点之间还可以广播数据,选个主还不简单,说个最 low 的方法,获取当前活着的节点列表,把 peer ip + port 转成 int ,选最小活着最大的
    dusu
        24
    dusu  
       2023-01-06 21:42:10 +08:00 via iPhone
    我这边项目选 leader 主要是为了节点挂了服务正常
    所以 redis 的 ping 锁操作可以
    但是不适应于异地集群
    而且也有单点问题
    目前我的简单的解决方案:
    用 cloudflare 的 kv 服务代替 redis 使用
    misaka19000
        25
    misaka19000  
       2023-01-06 23:20:25 +08:00
    直接 redis 分布式锁啊,redis 用哨兵实现高可用就行了
    joesonw
        26
    joesonw  
       2023-01-07 01:57:42 +08:00 via iPhone
    redis setnx 。slave 到 master 断了再去抢,其余的没抢到的直接取值找到 master 是谁。
    SeaTac
        27
    SeaTac  
       2023-01-07 05:11:12 +08:00
    我们用的是改过的 paxos
    3 个 replica ,1 leader 2 follower
    但是实现挺复杂的
    rrfeng
        28
    rrfeng  
       2023-01-07 06:09:26 +08:00 via Android
    最简单的肯定是借助现有的依赖啊,比如你用了数据库,那就在数据库里搞一条记录,所有实例来抢占就行了。
    Redis 也行,有啥用啥。
    defage
        29
    defage  
       2023-01-07 08:12:29 +08:00
    我记得 etcd 有个嵌入的 lib 可以直接用,不是自己部署 etcd 服务,是自己用它的 sdk
    GTim
        30
    GTim  
       2023-01-07 08:47:33 +08:00
    @ikaros 最佳方案,没有之一
    teli
        31
    teli  
    OP
       2023-01-07 08:55:47 +08:00 via Android
    xsen
        32
    xsen  
       2023-01-07 09:07:43 +08:00
    @teli #31 你那个好像有些问题的,这个是可以,
    https://pkg.go.dev/go.etcd.io/etcd/server/v3/embed
    litguy
        33
    litguy  
       2023-01-07 09:18:42 +08:00
    etcd 的锁机制就可以完成你的功能
    几年前我们就是基于这个作的
    sujin190
        34
    sujin190  
       2023-01-07 09:44:32 +08:00 via Android
    既然如此,直接实现成分布式锁的逻辑就是了呗,谁获取锁成功谁就能操作或者是 leader
    solos
        35
    solos  
       2023-01-07 09:45:34 +08:00
    evil0harry
        36
    evil0harry  
       2023-01-07 10:24:10 +08:00
    @okayan 404
    clownpiece
        37
    clownpiece  
       2023-01-07 11:23:00 +08:00
    如果 redis 集群出现故障导致你们 leader 选举出现问题如重复或者无 leader ,那是你们团队的锅,因为 redis 不提供保证。如果用 zk 或者 etcd 出现问题,是对应组件 dba 的锅。
    所以选什么很明显了
    starqoq
        38
    starqoq  
       2023-01-07 11:27:08 +08:00
    西方的选举制度可能不适合我们中国的程序呢。建议程序们开一个党代会选出全局唯一的核心。狗头。
    ihciah
        39
    ihciah  
       2023-01-07 11:53:47 +08:00 via iPhone
    redis 选主没什么问题,简单方便,还不要求节点之间的连通性。
    raft/etcd 杀鸡用牛刀了,你说它能用吧,它确实能用。为啥 etcd 不用 redis ?因为 redis 是单机服务,而 etcd 想解决的就是单点故障。只要你保证 redis 不宕机,那走 redis 就是个 ok 的方案。生产环境不少就是这么选主的,业务自个用 raft 的倒是一个没见过。
    xingjue
        40
    xingjue  
       2023-01-07 12:43:14 +08:00
    @starqoq 还要考虑 做到两个维护
    liprais
        41
    liprais  
       2023-01-07 12:52:28 +08:00
    zookeeper 完事,别给自己找不愉快
    Comolli
        42
    Comolli  
       2023-01-08 02:25:11 +08:00 via iPhone
    Redis vs Etcd vs memberlist vs paxos ,m
    teli
        44
    teli  
    OP
       2023-01-08 13:18:03 +08:00 via Android
    @okayan 暂定是 docker swarm ,而非 kubernetes
    lance6716
        45
    lance6716  
       2023-01-08 21:16:03 +08:00 via Android
    https://pkg.go.dev/go.etcd.io/etcd/clientv3/concurrency#Election.Campaign

    麻了现在 golang 看上去很火,怎么看评论好像没啥真正在用的
    lysS
        46
    lysS  
       2023-01-09 09:49:54 +08:00
    楼上提 redis 的是怎么搞的,和在 go 里面用一个锁有什么区别?
    Chinsung
        47
    Chinsung  
       2023-01-09 11:26:11 +08:00
    一般是集群每台都尝试去做,但是拿到锁的那台再去做,这个都不要求主备一致性的,有啥必要上 paxos 和 raft 这种?
    wei2629
        48
    wei2629  
       2023-01-09 14:36:11 +08:00
    用 consul 抢占 session 就行了。
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   我们的愿景   ·   实用小工具   ·   3204 人在线   最高记录 6543   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 33ms · UTC 12:17 · PVG 20:17 · LAX 05:17 · JFK 08:17
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.