最近在工作中发现一个有意思的现象,我用 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行,我没想明白为什么要一步处理,同步处理,就算发送失败重试三次再管也好的….

论consul正确的关闭姿势的更多相关文章

  1. Hibernate中,将session绑定到线程时,在保存和查询数据的代码里,要正确的关闭session

    比如有个保存的方法 // 保存 public void save(){ Transaction t = XXX Session s = getSession.beginTransaction(); X ...

  2. HTTP协议学习笔记---HTTP持久连接和如何正确地关闭HTTP连接

    一,持久连接 什么是持久连接?对于HTTP协议而言,它是基于请求响应模型,Client向Server发请求时,先建立一条HTTP连接,Server给Client响应数据后,连接关闭. 当Client发 ...

  3. 如约而至,Java 10 正式发布! Spring+SpringMVC+MyBatis+easyUI整合进阶篇(十四)Redis缓存正确的使用姿势 努力的孩子运气不会太差,跌宕的人生定当更加精彩 优先队列详解(转载)

    如约而至,Java 10 正式发布!   3 月 20 日,Oracle 宣布 Java 10 正式发布. 官方已提供下载:http://www.oracle.com/technetwork/java ...

  4. java并发系列(五)-----如何正确的关闭一个线程

    正确的关闭一个线程可不是简单的事情,由于线程调度的复杂性以及不可控性(毕竟运行都由操作系统做主),先来了解一下interrupt() 1.interrupt() 根据jdk文档的介绍,如下: inte ...

  5. Fragment全解析系列(二):正确的使用姿势

    作为一个稳定的app,从后台且回到前台,一定会在任何情况都能恢复到离开前的页面,并且保证数据的完整性. 如果你没看过本系列的第一篇,为了方便后面文章的介绍,先规定一个"术语",安卓 ...

  6. Servlet3.0+springmvc5+log4j2正确的开启姿势(WebLookUp)

    前言 java社区占据市场份额比较大的日志组件由log4j 1.×,到logback,再到整合后的升级版 log4j 2.×,有网友测试后据说log4j2的性能最NB.于是开始往自己的springmv ...

  7. linux 如何正确的关闭mongodb

    有的朋友说可以通过下面的命令关闭mongodb: killall mongodb #or kill -9 mongo-pid 上面的方法确实可以关闭mongodb,但是正确的做法不是这样子的,mong ...

  8. How Javascript works (Javascript工作原理) (五) 深入理解 WebSockets 和带有 SSE 机制的HTTP/2 以及正确的使用姿势

    个人总结: 1.长连接机制——分清Websocket,http2,SSE: 1)HTTP/2 引进了 Server Push 技术用来让服务器主动向客户端缓存发送数据.然而,它并不允许直接向客户端程序 ...

  9. springboot actuator shutdown正确的关闭操作

    今天整合ehcache时发现一个很重要的问题,就是程序关闭(硬关闭)之后,持久化到磁盘的缓存数据没能正确写入加载,问题还是硬关闭的问题,所以就使用actuator 进行监听 <dependenc ...

随机推荐

  1. 两个不同的账户登录两个浏览器,导入同样的excel表格。数据出现重复

    1.场景: 两个不同的账户登录两个浏览器,导入同样的excel表格.业务逻辑已经有验重校验,但数据仍然出现重复,锁定是并发问题导致. 2.参考博客: https://cloud.tencent.com ...

  2. 自定义控件LengthValidator

    1.创建自定义验证控件:新建LengthValidator类并继承BaseValidator using System; using System.Collections.Generic; using ...

  3. python中的glob模块的使用

    最近常常用到glob模块,这里做一个简单小结: 用它可以查找符合特定规则的文件路径名.跟使用windows下的文件搜索差不多.查找文件只用到三个匹配符:”*”, “?”, “[]”.”*”匹配0个或多 ...

  4. Json在序列化注意问题

    Java中的Json序列化,不容忽视的getter 问题重现 public class AjaxJson { private boolean success; private String msg; ...

  5. npm包之npm-check-updates

    检查npm的依赖包是否有比较新的版本 安装 npm i -g npm-check-updates 使用 ncu --help // 查看相关命令 ncu // 检查当前项目中有没有哪些依赖包可更新 n ...

  6. 前端知识-控制div标签的显示与隐藏

    //将附件信息列表进行隐藏 var tAppendixDiv = document.getElementById("AppendixDiv"); tAppendixDiv.styl ...

  7. 分析第一个Android程序

    项目结构切换Project, 项目真实目录结构 { 1.    .gradle和idea 两个目录放置的都是Android Studio 自动生成的一些文件,我们无需关心,也不要去手动编辑. 2.AP ...

  8. 思科ASA基本配置

    ------------恢复内容开始------------ ASA基本配置 ciscoasa#show running-config        //讲解已作的默认配置 ciscoasa#conf ...

  9. Greenplum 6 新功能 在线扩容工具GPExpand (转载)

    Gpexpand是Greenplum数据库的扩容工具,可以为集群增加新节点从而可以存储更多的数据,提供更高的计算能力.Greenplum 5及之前,集群扩容需要停机增加新节点,然后对表数据做重分布.因 ...

  10. 洛谷 P3183 [HAOI2016]食物链 题解

    P3183 [HAOI2016]食物链 题目描述 如图所示为某生态系统的食物网示意图,据图回答第1小题现在给你n个物种和m条能量流动关系,求其中的食物链条数.物种的名称为从1到n编号M条能量流动关系形 ...