• 请不要在回答技术问题时复制粘贴 AI 生成的内容
brader
V2EX  ›  程序员

请问你们是如何实现服务不中断的代码发布更新的

  •  
  •   brader · Mar 10, 2023 · 7462 views
    This topic created in 1342 days ago, the information mentioned may be changed or developed.
    目前我知道的一个自动化的方式就是 k8s 的滚动更新。

    大家实际生产中,应该不是每个人都有使用 k8s 吧?
    像你们 java 、go 这些语言,发布新版本的时候,如果不用 k8s ,你们是怎么实现平滑更新过度的,还是直接暴力重启?
    59 replies  •  2023-03-14 09:51:04 +08:00
    lincanbin
    lincanbin
    Mar 10, 2023
    1
    从名字服务里摘掉发布节点,然后等一会儿这个节点就没流量了,就可以发布了。
    brader
    brader
    OP
    Mar 10, 2023
    2
    @lincanbin 额,有点没明白,你用的是代码框架,或者代码自实现的平滑重启效果吗
    seers
    seers
    Mar 10, 2023 via Android
    3
    方法多了去了,Nginx 调整下集群权重
    LeeReamond
    LeeReamond
    Mar 10, 2023
    4
    @lincanbin 名字服务,nameserver ?现代汉语属实是让人摸不到头脑了
    moshiyeap100
    moshiyeap100
    Mar 10, 2023
    5
    比如一个服务有 3 个实例。

    step1: 从注册中心下线 A ,A 没流量了开始更新 A

    更新后,观察 A 是否正常。 如果正常继续更新下一个服务,不正常就下线回滚。


    我们就是这么原始。
    looplj
    looplj
    Mar 10, 2023
    6
    首先看你有几个实例,至少两个实例才能做到
    lincanbin
    lincanbin
    Mar 10, 2023
    7
    @LeeReamond 也可以叫注册中心吧,反正叫法挺多的,就是维护一个服务的实例列表的一个服务
    tmtstudio
    tmtstudio
    Mar 10, 2023❤️5
    8
    php 无所畏惧🤗
    TFong
    TFong
    Mar 10, 2023
    9
    多套环境,A\B 互为蓝绿环境,用户全拉到 A 然后发布 B 完事用户切到 B
    LeegoYih
    LeegoYih
    Mar 10, 2023
    10
    新实例启动完成后,Nginx 配置改为新实例的地址 reload 配置,然后销毁旧实例
    lincanbin
    lincanbin
    Mar 10, 2023
    11
    除了名字服务里来剔除发布节点流量的方法外,reuseport 也是一个很常见的方式。
    libook
    libook
    Mar 10, 2023
    12
    一般正式环境业务不会但节点跑的,多节点就需要负载均衡,那么只需要手动调整负载均衡权重,让一台机器没有入站流量了,再将这台停机升级,恢复流量再处理下一台。

    可以用脚本或程序自动化,持续部署方案比 k8s 出来早很多年就很成熟了。
    daoyu
    daoyu
    Mar 10, 2023
    13
    蓝绿部署、金丝雀部署
    photon006
    photon006
    Mar 10, 2023
    14
    node.js ,小脚本用 pm2 reload ,跟 nginx reload or kill -HUP 类似

    常规项目用 docker service ,参考:

    https://linuxhandbook.com/update-docker-container-zero-downtime
    https://www.tines.com/blog/simple-zero-downtime-deploys-with-nginx-and-docker-compose
    brader
    brader
    OP
    Mar 10, 2023
    15
    @seers 这种很难实现自动化吧?
    brader
    brader
    OP
    Mar 10, 2023
    16
    @moshiyeap100 你们有弄了注册中心,还是蛮复杂的,然后你说的过程,你们是实现了自动化构建发布过程,还是手动更新啊
    brader
    brader
    OP
    Mar 10, 2023
    17
    @ZSeptember 多个实例可以很容易实现自动化更新吗?
    brader
    brader
    OP
    Mar 10, 2023
    18
    @tmtstudio 确实 PHP 更新比较方便,就简单场景,我们直接 git pull 也很少出问题
    brader
    brader
    OP
    Mar 10, 2023
    19
    @SanYuan 就是这个切的过程,不用 k8s 的话,你们实现自动化的架构是怎么实现的?还是单纯手动更新的
    brader
    brader
    OP
    Mar 10, 2023
    20
    @libook 好像网上比较少看到这种架构的教程或者脚本实现啊,自己实现的话,感觉又不那么容易
    brader
    brader
    OP
    Mar 10, 2023
    21
    @LeegoYih 我想到的比较简单的处理方式也是这样的,但是这个方式手动好操作,要做成自动化,不容易吧?
    LeegoYih
    LeegoYih
    Mar 10, 2023
    22
    @brader 不知道你有没有使用类似 Jenkins 之类的工具,结合这些工具还是挺方便的,手写脚本确实比较麻烦
    brader
    brader
    OP
    Mar 10, 2023
    23
    @LeegoYih Jenkins 我用过,但是它的流水线部署本质上,和你写 shell 或者代码,没有很大区别吧,只是它结合了比较多的插件和功能。 还是要自己实现自动化不中断的流程啊
    libook
    libook
    Mar 10, 2023
    24
    @brader #20 运维写几个 shell 脚本通常就可以搞定了。有些 CI/CD 工具,比如 jenkins ,也可以看看。
    sujin190
    sujin190
    Mar 10, 2023
    25
    之前我们的做法是自己再外面套了层守护进程,有守护进程来打开端口,然后创建子进程继承过去,然后重启的时候守护进程先创建新的进程,然后给旧的进程发送停止信号,旧进程会先关闭监听端口,然后等待所有请求处理完后慢慢退出,这样就可以实现完全平滑无异常重启更新了,这个好处是和 nginx 负责均衡啥的都不相干,应用自己就能完成,相对简单

    不过很可惜像 supervisor 啥都不支持这个功能,其实 supervisor 完全可以打开端口后放在固定 fd 上,比如 3 ,或者可以通过参数传递 fd 的值,然后启动子进程后,子进程直接通过 fd 创建 socket 就好了
    brader
    brader
    OP
    Mar 10, 2023
    26
    @sujin190 这种方案就相当于项目代码自实现的 reload 效果了吧,麻烦点就是每个项目都要自己实现这样一个功能
    Alliot
    Alliot
    Mar 10, 2023
    27
    Nginx upstream + healthcheck

    假设 有 a b 2 个节点,发布时先将 A 置为 unhealth 状态,流量全部调度到 b 发布完成后置为 health ,同理发布 b 即可。
    sujin190
    sujin190
    Mar 10, 2023
    28
    @brader 对,不是啥大服务,单节点又没注册中心啥的,网关负载均衡啥的也不在本机,流量不高不低,想随时随意可以重启没啥异常,搞啥都感觉费劲。。
    getoffworkontime
    getoffworkontime
    Mar 10, 2023
    29
    摘除旧服务的时候, 怎么保证旧服务中的任务已经执行完?
    vincent7245
    vincent7245
    Mar 10, 2023
    30
    服务器是分布式的,滚动升级
    brader
    brader
    OP
    Mar 10, 2023
    31
    @Alliot 我手动操作也是采用类似这样的方案,就是自动化好像不好实现
    anonymous2351d00
    anonymous2351d00
    Mar 10, 2023
    32
    做一个 流量转发的中间层 成为 A ,你的服务 v1 版本称为 B1
    假如 A -> B1 现在要发 B2 版本
    保证 A -> B1 的流量控制 部署 B2 ,流量情况 nil -> B2
    部署 B2
    以非常非常快速的手速,光一样的敲动命令来 调整流量转发层 A -> B2
    此时 nil -> B1
    这个版本就好了
    malusama
    malusama
    Mar 10, 2023
    33
    @getoffworkontime 优雅退出
    awanganddong
    awanganddong
    Mar 10, 2023
    34
    这个问题我昨天还在思考。
    比如我们公司用的腾讯云的 lbs

    首先第一步发送 curl ,将 clb 中配置的后端服务的权重置为 0 ,这时候不存在新增请求,只存在存量请求。这个过程中服务器 clb 还可以转发响应。

    接下来就开始关闭 go 进程,这时候 go 代码可以配置优雅退出。等原来 go 进程退出后,就开始启用新的 go 进程。
    cyningxu
    cyningxu
    Mar 10, 2023
    35
    多实例+注册中心?
    f9EHtxE2UtX3fG3
    f9EHtxE2UtX3fG3
    Mar 10, 2023 via Android
    36
    好奇,如果是类似数据库表结构变了,可以这样滚动更新吗
    pengtdyd
    pengtdyd
    Mar 10, 2023
    37
    半夜 3 点钟,断线 30 分钟没什么大不了,影响不了啥业务,不要把公司的业务想的那么重要,就像你穿了一件新衣服走在大街上,你以为别人都是注视你,其实别人压根不关心你穿的啥,别把自己想的太重要。
    brader
    brader
    OP
    Mar 10, 2023 via Android❤️1
    38
    @ccagml 你说的这个问题,和实现平滑更新没很大关系。你这个问题,更多的应该在代码层面实现,做一下版本控制,我这几年一直是这么干的,没遇到啥问题
    samun
    samun
    Mar 10, 2023
    39
    @lincanbin 如果有耗时比较耗时的操作在跑呢 下线了也得等一段时间才能关
    Features
    Features
    Mar 10, 2023
    41
    @tmtstudio PHP 是会受到影响的,高并发场景一堆的 502
    whileFalse
    whileFalse
    Mar 10, 2023 via iPhone
    42
    你有负载均衡器吧!
    Ericcccccccc
    Ericcccccccc
    Mar 10, 2023
    43
    我估计你想找的是 服务发现, 搞明白了这个以及相关问题滚动发布就差不多解决了.
    cctv6
    cctv6
    Mar 10, 2023
    44
    用 docker swarm / service ,比 k8s 简单,方便管理多个节点。发布也是滚动更新。
    lincanbin
    lincanbin
    Mar 10, 2023 via Android
    45
    @samun 那就等他跑完了再发布啊,这种发布工具很容易设计的。
    runze
    runze
    Mar 11, 2023
    46
    @brader #31 APISIX 之类的网关适合这个场景
    daysv
    daysv
    Mar 11, 2023
    47
    问题在于你们运行 DDL DML 怎么实现两个服务无缝切换的? 是搞了两套库吗?
    xiaowoniukai
    xiaowoniukai
    Mar 11, 2023 via iPhone
    48
    apisix
    samun
    samun
    Mar 11, 2023
    49
    @lincanbin 要搞成自动化这就是一个不确定因素了
    hhjswf
    hhjswf
    Mar 11, 2023 via Android
    50
    @pengtdyd 搞不中断部署就是为了不在半夜部署啊。。
    hhjswf
    hhjswf
    Mar 11, 2023 via Android
    51
    @brader 你们业务量不够吧,单表数据亿为单位,你修改表结构会锁表很长时间,这段时间怎么代码层怎么处理这张表 crud ?还是要通过数据库集群做
    dreamusername
    dreamusername
    Mar 11, 2023
    52
    微服务间调用有服务发现,不论是 nacos 类的还是 kubernetes service 类的,这样保证服务间调用可以访问到可用服务;
    服务需要有优雅退出,这样保证任务执行完毕后退出,防止任务中断。
    对外服务,一般为 API 类,有负载均衡,服务在异常状态不路由流量(未就绪、退出等状态)保证用户访问到可用节点。
    chrosing
    chrosing
    Mar 11, 2023
    53
    我们是搞到预发 也和楼上说的两个环境类似。 预发和正式都是同一个库 先更新到预发 然后引导流量慢慢迁移过来 测试没有问题后 在同步服务到正式 然后进行更新 再之后服务完全没问题 流量再引导过去
    bushenx
    bushenx
    Mar 12, 2023 via Android
    54
    项目背景 基于 grpc 的后端业务
    1. 必不可少的就是服务需要支持优雅退出,现在项目用到得 grpc 框架流支持。
    2. 对于无状态服务直接发布一个新节点,将旧节点从注册中心移除就可以了。
    3. 有状态服务我们采用主备机的方式发布新版本。
    lincanbin
    lincanbin
    Mar 12, 2023 via Android
    55
    @samun 所以说服务开发要同意框架,框架要跟运维系统打通。
    这种耗时操作在框架里挂钩子,执行完框架通知运维系统就完全打通了。
    brader
    brader
    OP
    Mar 13, 2023
    56
    @hhjswf 这个就要具体情况具体分析了,即使你的项目非常庞大、访问量非常多,那么也不太可能出现你一个项目的所有表都是很大数据量的情况,所以只是偶尔会接到需要更新这种表的需求,以下两种方案我都在生产中实践过并取得成功:
    方案一:在低峰期更新表结构(看自己的项目情况,像我们在 22 点-05 点都是低峰期)
    方案二:copy 出一张新表并改好新表结构,然后 insert 新表,( insert 新表,rename 旧表,rename 新表),注意前面有 2 个 insert 过程,第一次 insert 完看下最大 id ,然后这就是第二次的条件,分 2 次 insert 是因为第一次 insert 数据量大,耗时久,后续又产生了很多增量数据。
    brader
    brader
    OP
    Mar 13, 2023
    57
    @daysv 我日常的做法是分 2 步走,代码发布前,先更新表结构,思考做前后兼容的变动(实在实现不了的另做打算,很少这种情况吧),新代码里也做版本控制判断,这样我新旧版本都不影响
    hhjswf
    hhjswf
    Mar 13, 2023 via Android
    58
    @brader 方案二你只考虑 insert 吗?有没有可能第二次 insert 期间,系统对第一次 insert 的记录进行删改操作,能同步过去吗
    brader
    brader
    OP
    Mar 14, 2023
    59
    @hhjswf 首先不排除这个可能,因为每人的业务情况不同,对于我来说,几乎没有这样的烦恼,因为第一次 insert 的一般是时间比较靠前的历史数据,不会变动,第二次的近期数据,因为操作时间非常短暂,出现概率就低。
    如果你的业务对历史操作频繁,或者其他不适用情况,就建议你晚上更新,要求强一致就和领导申请锁写。
    没有一套能解决所有问题的一成不变的方案,在于你怎么灵活应用和变通。

    还有你们有使用阿里云的 RDS 、收费版 DMS 的话,建议把他们的工具利用起来,他们有个无锁变更功能还是很强大的,阿里介绍的实现原理大概就是 建新表->追全量->追期间变动的 binlog ,全程自动化透明,我们只要递交变更任务就好
    About   ·   Help   ·   Advertise   ·   Blog   ·   API   ·   FAQ   ·   Privacy   ·   Solana   ·   4475 Online   Highest 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 106ms · UTC 06:47 · PVG 14:47 · LAX 22:47 · JFK 01:47
    ♥ Do have faith in what you're doing.