Golang 怎么做到真正的平滑无缝重启服务? - V2EX
V2EX = way to explore
V2EX 是一个关于分享和探索的地方
Sign Up Now
For Existing Member  Sign In
DavidNineRoc

Golang 怎么做到真正的平滑无缝重启服务?

  •  
  •   DavidNineRoc Oct 16, 2020 3342 views
    This topic created in 2029 days ago, the information mentioned may be changed or developed.

    加入有 10 台从服务器做负载均衡, 更新 Golang 服务是不是,

    1. 把 X 服务器踢出 SLB
    2. 更新代码, build, run
    3. 把 X 服务器加入到 SLB
    4. 下一台服务器重复 1,2,3

    对于PHP服务直接一键更新代码即可更新服务,除非安装扩展重启php-fpm


    我看到有一个帖子说.

    t/714891#reply6

    • 通过Docker, 平滑重启Signal
    • 这几种方式和PHP安装扩展类型,和更新PHP服务不同

    这几种方式, 不管你怎么平滑, 总会有那么一瞬间停止服务. 还是说我理解的和他们说的不一样?


    有专业的人士说一下实际的更新方案吗?

    7 replies    2020-10-17 13:00:02 +08:00
    cloverstd
        1
    cloverstd  
       Oct 16, 2020   1
    为啥不是先 build 后,直接分发可执行文件呢

    如果是 HTTP 层的,用 https://golang.org/pkg/net/http/#example_Server_Shutdown 去关闭服务,同时停止接受新的请求,等到正在处理的请求处理完,然后把这台机器踢出 SLB,然后发新的,新的起来了,再注册到 SLB 去

    如果是 TCP 长连接的,只能用 fork,把 FD 传给新起来的进程
    ETiV
        2
    ETiV  
       Oct 16, 2020 via iPhone
    可以学习下 nginx -s reload 的实现,或者干脆把专业的事情交给专业的 app 去干…

    假设两个 service:p 、q,p 正在运行

    1. 拉起 q
    2. 为 q 做 readiness 状态检查
    3. 检查无误,更新 nginx proxy_pass 的地址(从 p 监听转为 q 的监听)
    4. 执行 nginx -s reload


    如果你要自己做,参考 nginx 的话,就需要自己把网络监听层抽象出来(只转发而不做任何业务逻辑),重启(不是重启,而应是重载)的时候不重启这个监听端口的主进程,而是启动 q 服务(作为子进程)、做健康检查、都没问题后阻止向 p 服务转发新的请求;待 p 业务处理的请求完成后,销毁 p 服务的子进程。
    DavidNineRoc
        3
    DavidNineRoc  
    OP
       Oct 16, 2020
    @cloverstd build 后, 在杀死老进程启动新进程这一瞬间服务停止
    @ETiV 现在写的业务 golang 程序也是使用 nginx 反向代理访问的. 不过在更新 golang 程序会停止服务(只是一些统计服务,不影响). 想知道实际如果是 web 服务, 应该怎么做更新. 如我在 golang 只监听了 8080 端口, nginx 反向代理到 8080, 并配置好域名. 这时候怎么做到平滑更新.
    lavvrence
        4
    lavvrence  
       Oct 16, 2020
    都用 Go 了那就容器+容器编排。Kubernetes 滚动更新: https://kubernetes.io/zh/docs/tutorials/kubernetes-basics/update/update-intro/
    monsterxx03
        5
    monsterxx03  
       Oct 16, 2020
    不管是物理机还是 k8s 和你说的其实都差不多, 多一点细节

    1. lb 那边先停止把新的 request 发送到要停止的 server, 等待一个 graceful timeout 时间让 server 把当前请求都处理完, 再把它下线, 在用户层面就不会有请求被打断, 除非是异常的慢连接.
    3. lb 在把 server 加回去之前要先 health check 通过.

    nginx 可以通过 lua 模块来实现.

    说 docker 发个 singal 就能 graceful restart 的是在扯淡.

    不依赖 lb, 在 golang 代码层面实现 graceful restart 也可以, 一般是和 nginx 一样通过 fork 子进程+ 复制 fd 实现的, 比如 https://github.com/cloudflare/tableflip

    一般优先从 lb 层做, 这种原地更新的方式局限性太大了, 除非规模特别小,或业务特殊.
    ETiV
        6
    ETiV  
       Oct 16, 2020
    @DavidNineRoc

    问题就在于你新旧两个 golang 服务不要监听同一个端口,当旧的在监听 8080,新的就监听 8081

    8081 健康检查通过后,修改 nginx 配置( sed -i 's/:8080/:8081/')、再 reload nginx

    当下一个新版本来了之后,启动新服务,监听 8080 。再走一遍上面的逻辑就好了~

    tick 、tock ; tick 、tock……
    DavidNineRoc
        7
    DavidNineRoc  
    OP
       Oct 17, 2020
    @jaylee4869 用了容器部署, 不过是把 build 和 run 命令写在 docker-compose, 每次更新代码 restart 容器一下. 这个链接没看懂是多台服务器更新还是怎么的, 多台我知道可以踢下线更新好后自动拉上线. 单台服务器的话只能换端口换地址吗? 换的话就得改代码配置文件, 感觉不是一个好的方案.

    @monsterxx03 现在就是通过 docker 发送信号,然后重启, 这样子肯定会停止服务一瞬间. 感觉这种应该用第三方应用来实现, 不然代码写这种不是很友好.
    @ETiV 这个方案是不是每次更新都得换一个端口, 感觉 nginx 配置文件得改到死 >_<
    About     Help     Advertise     Blog     API     FAQ     Solana     939 Online   Highest 6679       Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 36ms UTC 20:19 PVG 04:19 LAX 13:19 JFK 16:19
    Do have faith in what you're doing.
    ubao msn 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