• 论consul正确的关闭姿势


    最近在工作中发现一个有意思的现象,我用 ctrl+c 关闭本地 consul 的时候,报警系统并没有发出告警,说我的 node 异常,自己看了一下代码,发现 consul 的关闭还是有点猫腻的,仔细来讲讲

    consul agent 在正常关闭的时候会向集群发送 leave 信令,宣告自己离开集群,那么什么才叫正常关闭呢?

    还是上代码:
    摘自command.go handleSignals方法

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    func (c *Command) handleSignals(config *Config, retryJoin <-chan struct{}, retryJoinWan <-chan struct{}) int {
    signalCh := make(chan os.Signal, 4)
    signal.Notify(signalCh, os.Interrupt, syscall.SIGTERM, syscall.SIGHUP)
     
    // Wait for a signal
    WAIT:
    var sig os.Signal
    select {
    case s := <-signalCh:
    sig = s
    case <-c.rpcServer.ReloadCh():
    sig = syscall.SIGHUP
    case <-c.ShutdownCh:
    sig = os.Interrupt
    case <-retryJoin:
    return 1
    case <-retryJoinWan:
    return 1
    case <-c.agent.ShutdownCh():
    // Agent is already shutdown!
    return 0
    }
    c.Ui.Output(fmt.Sprintf("Caught signal: %v", sig))
     
    // Check if this is a SIGHUP
    if sig == syscall.SIGHUP {
    if conf := c.handleReload(config); conf != nil {
    config = conf
    }
    goto WAIT
    }
     
    // Check if we should do a graceful leave
    graceful := false
    if sig == os.Interrupt && !(*config.SkipLeaveOnInt) {
    graceful = true
    } else if sig == syscall.SIGTERM && config.LeaveOnTerm {
    graceful = true
    }
     
    // Bail fast if not doing a graceful leave
    if !graceful {
    return 1
    }
     
    // Attempt a graceful leave
    gracefulCh := make(chan struct{})
    c.Ui.Output("Gracefully shutting down agent...")
    go func() {
    if err := c.agent.Leave(); err != nil {
    c.Ui.Error(fmt.Sprintf("Error: %s", err))
    return
    }
    close(gracefulCh)
    }()
     
    // Wait for leave or another signal
    select {
    case <-signalCh:
    return 1
    case <-time.After(gracefulTimeout):
    return 1
    case <-gracefulCh:
    return 0
    }
    }

    首先 agent 监听了三个系统信令,os.Interrupt, syscall.SIGTERM, syscall.SIGHUP

    看26行,syscall.SIGHUP,用于 reloadconfig, 这个忽略掉

    接下来才是进入正题,如何正确的关闭 consul

    首先我们要知道 consul agent 关闭后 consul server 一般是什么体现.

    1. consul ui 显示 Node 异常, check 显示是 fialling
    2. consul ui 中搜索不到这个 node

    是什么造成这个差别呢,答案在上面代码里面的第49行到55行,正常关闭后, node 会向 server 发送一条 leave 的信令,告诉 server 我离开了,你不用管我了,但是如果是宕机的话,又不能发送这个 leave 信令,让 server 知道我falling 了,这里通过34行定义的graceful来处理,如果配置里面说需要发送 leave 信令,那么就发送一个.
    这里说一下, consul 的 service 或者 node 状态监控可以通过consul_alert这个项目来做(这里吐个槽,虽然我在用这个程序做报警,但是真心觉得这个代码写得不敢恭维,不停的 exet 子进程,不停的初始化,想要写alert 扩展的,一定要考虑重复初始化到知道内存泄漏)

    原理说完,槽吐完,接下来说点好的,这也是我觉得 consul 开发者很贴心的一个地方.

    作者把os.Interrupt, syscall.SIGTERM两个信令分开处理,

    os.Interrupt

    这个信令对应的其实就是 ctrl+c, 这一般是我们在开发时才会用到,那么和这个信令配合的配置是config.SkipLeaveOnInt ,这个配置项不配置,默认就是 false, 那么`sig == os.Interrupt && !(config.SkipLeaveOnInt)` 就为 true, 接着就会执行 leave信令,这完全适用于我们在开发环境中,使用自己开发电脑上的 consul agent, 退出就自动注销,不用怕收到报警.

    syscall.SIGTERM

    这个信令一般我们执行kill -15 ${pid}就会发送,当然kill ${pid}默认就是发送15号信令,这个信令配合config.LeaveOnTerm配置项来处理是否发送 leave 信令,这种一般是 agent 在后台运行时才会用到的,这种情况大家都知道主要场景是在生产环境,如果配置config.LeaveOnTerm= true 的话,那么停机维护的时候,也收不到烦人的报警.贴心吧

    有人说,宕机怎么办,我很遗憾的告诉你 os.KILL 信令,程序接收到也没有时间执行下面的操作,直接被杀掉了,在服务器宕机的时候也许都没机会发出 kill 命令,在程序被 kernel 杀掉也就是 kill -9,当然程序也没办法执行下面的操作,当然在 server 端看到的状态就是 falling,接收收到报警,找运维人员处理就好了.

    最后总结一下,关闭 consul 的正确姿势:

    在前台运行的情况下:

    ctrl+c +最简化配置即可正常关闭,

    在后台运行的情况下:

    配置中指定LeaveOnTerm: true,维护时,使用 kill -15 ${pid}来关闭进程,即可正常关闭掉 node, 并注销成功.

    补充说明:
    leave 的信令发送时异步发送的,所以如果网络不太好的情况下,也许会 leave 还没完全发出去程序就关闭掉了.代码见上面49行,我没想明白为什么要一步处理,同步处理,就算发送失败重试三次再管也好的….

  • 相关阅读:
    use tomcat to access the file cross the environment
    data audit on hadoop fs
    Good practice release jar to Nexus
    套路!从Ruby 到 Cocoapods的发布
    单元测试之NSNull 检测
    UIwebView 和 H5交互详情
    IT 需要知道的一些专业名词和解释 (长期更新)
    Git 操作 学习资源 网址
    GCD
    软件工程——个人总结
  • 原文地址:https://www.cnblogs.com/ExMan/p/11991292.html
Copyright © 2020-2023  润新知