有没有办法实现简单的 Go 服务 leader 选举? - V2EX
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 6116 次点击
    这是一个创建于 1011 天前的主题,其中的信息可能已经有所发展或是发生改变。

    需要从服务实例中选出一个 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 是谁。
    Amex
        27
    Amex  
       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
    yemoluo
        30
    yemoluo  
       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 的倒是一个没见过。
    nxcdJaNnmyF9O90X
        40
    nxcdJaNnmyF9O90X  
       2023-01-07 12:43:14 +08:00
    @starqoq 还要考虑 做到两个维护
    F281M6Dh8DXpD1g2
        41
    F281M6Dh8DXpD1g2  
       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     Solana     952 人在线   最高记录 6679       Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 33ms UTC 19:27 PVG 03:27 LAX 12:27 JFK 15:27
    Do have faith in what you're doing.
    ubao snddm index pchome yahoo rakuten mypaper meadowduck bidyahoo youbao zxmzxm asda bnvcg cvbfg dfscv mmhjk xxddc yybgb zznbn ccubao uaitu acv GXCV ET GDG YH FG BCVB FJFH CBRE CBC GDG ET54 WRWR RWER WREW WRWER RWER SDG EW SF DSFSF fbbs ubao fhd dfg ewr dg df ewwr ewwr et ruyut utut dfg fgd gdfgt etg dfgt dfgd ert4 gd fgg wr 235 wer3 we vsdf sdf gdf ert xcv sdf rwer hfd dfg cvb rwf afb dfh jgh bmn lgh rty gfds cxv xcv xcs vdas fdf fgd cv sdf tert sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf shasha9178 shasha9178 shasha9178 shasha9178 shasha9178 liflif2 liflif2 liflif2 liflif2 liflif2 liblib3 liblib3 liblib3 liblib3 liblib3 zhazha444 zhazha444 zhazha444 zhazha444 zhazha444 dende5 dende denden denden2 denden21 fenfen9 fenf619 fen619 fenfe9 fe619 sdf sdf sdf sdf sdf zhazh90 zhazh0 zhaa50 zha90 zh590 zho zhoz zhozh zhozho zhozho2 lislis lls95 lili95 lils5 liss9 sdf0ty987 sdft876 sdft9876 sdf09876 sd0t9876 sdf0ty98 sdf0976 sdf0ty986 sdf0ty96 sdf0t76 sdf0876 df0ty98 sf0t876 sd0ty76 sdy76 sdf76 sdf0t76 sdf0ty9 sdf0ty98 sdf0ty987 sdf0ty98 sdf6676 sdf876 sd876 sd876 sdf6 sdf6 sdf9876 sdf0t sdf06 sdf0ty9776 sdf0ty9776 sdf0ty76 sdf8876 sdf0t sd6 sdf06 s688876 sd688 sdf86