文章首发于公众号 松花皮蛋的黑板报
做者就任于京东,在稳定性保障、敏捷开发、高级JAVA、微服务架构有深刻的理解架构
为何今天要讨论这个话题呢?由于我最近上线时就犯了一个错误,想把这事和后来的复盘分享给你们,事故的过程若是没看懂能够直接往下拉看复盘。负载均衡
过程是这样的:个人需求是在方法参数POJO类中新增一个可选参数,我将这个参数定义在POJO类的父类的最后一个。其中提供的是远程调用RPC服务,因此须要打一个描述类的JAR包供调用方使用,这个JAR包包含服务接口和入参、出参实体。框架
联调测试时使用的是1.1-SHAPSHOT版本,上线前我将版本号修改为1.0-SHAPSHOT版本,而且将私服中1.0-SHAPSHOT快照包更新了,业务代码没作任何改动。快照包的意思是同一个版本每次更新时都从新生成一个附有时间戳的包,当你构建下载包时都会下载指定版本最新更新的包,好比能够同时存在1.0-SHAPSHOT-2019101309和1.0-SHAPSHOT-2019080808版本。我当时上线后验证是经过的,说明版本是向下兼容的,就是调用方使用的1.0-SHAPSHOT-201908080也能正常调用个人1.0-SHAPSHOT-2019101309版本的服务。过几个小时后调用方使用了1.1-SHAPSHOT版本的包上线了,全量上线后,发现请求根本达到不了我这,由于在RPC框架中序列化异常了,此时调用方开始回滚,使用1.0最新的1.0-SHAPSHOT-2019101309开始构建上线,仍是出错了。因而我比较着急也开始回滚,不过呢,我是将历史构建的包发布上线,也就是说使用的是1.0旧的1.0-SHAPSHOT-201908080包,固然毫无疑问仍是会调用出错,此时才发现调用方回退时从新构建了,因而联系私服的同事将1.0最新的1.0-SHAPSHOT-2019101309删除,随后通知调用方从新构建上线,此时服务才恢复。运维
整个过程双方都有不少操做缺陷,好比我上线的并非严格测试的包,甚至没有通过双方回归验证。好比我处理线上问题的方法方式,我实际上是不须要回滚的。好比我告知了下游使用的版本号,可是下游仍是使用了测试的版本。再好比下游没有进行灰度发布验证、异常后回退时从新构建了,等等。一个看似很简单的上线却失败了,说明上线发版规范没有彻底把握好。微服务
读者可能以为上线变动没有值得深刻探讨的地方,上线无非就是将要发布的包经过必定的技术手段替换如今线上运行的包,或者将配置信息覆盖更新,而后重启服务,而且如今都是经过鼠标点点按钮就能完成的事。可是呢,这其中有不少细节,稍微不注意就会像我同样犯错。接下来我将说说上线前、上线中、上线后、上线失败须要注意的地方。性能
先来讲说上线前,这个上线包含新增实例分组发布、新增机器发布、在原有机器上发布。新增实例分组意味着你须要和旧分组仔细对比配置,包括日记级别配置。新增机器发布意味着你的机器网段多是新的、你的调用外网服务权限多是没有的、你的依赖系统库多是没有安装的、你的IP可能不在白名单内,这些都是我在实际工做中碰到过的问题。测试
当上线条件和环境具有,包括前面说的机器配置,还包括上线时间,咱们就能够提出上线申请了。原则上节假日(包括周末)前一天、重大促销活动(好比产品发布会)当天、流量高峰时间段都是不容许上线的。上线申请内容通常包括背景描述、操做对象、操做步骤、CHECKLIST、预期结果、回滚方案,还会包括自测状况。任何操做都应该有明确的文字说明,拒绝模糊或仅在大脑中认为可行的方案。同时你的操做变动还得周知产品、测试人员和其余同事,不能只有你、代码评审者、领导知道本次变动操做。避免当其余服务受到牵连时,其余人只能经过查看上线记录或者翻查代码提交记录才知道应该找谁。若是你修改的是公共代码或者协议,那更要提早周知了。spa
上线前检查还有一个须要注意的地方,就是确保你构建出来的上线包包括了你合并的代码块,如今大部分的平台构建出来的上线包,包名会附有最新提交到GIT代码仓库的COMMIT_ID,很是直观明了。对象
当上线前检查完成后,就能够发布部署了,通常将操做的服务实例按分组、机房分别分批部署,我这里强调的是分组、分机房,强调的是并不只仅是以所有实例按多少比例部署,固然咱们一般按30%的比例进行分批部署。不过,若是你的比例恰好命中某个分组或者某个机房所有实例时,那就意味着这个分组、机房的服务在全量上线,就颇有可能出现无服务提供者的状况,若是上线失败,状况就不是短暂性的了。blog
分批部署第一步通常是每一个机房选择一台进行发布验证,这样有助于咱们及时地发现问题,避免影响扩散,甚至有些功能须要数据的积累才能验证,因此有时也会分时间段部署,每间隔一个小时部署一小比例的服务实例。固然分批部署只是咱们规避线上风险的手段,不具有测试的目的,不能取代测试,也就是禁止将没有进行测试的包部署到生产环境,那怕只是修改了RPC服务的JAR包版本号。
分批部署通常须要验证原有功能是否有受到影响、业务监控是否有异常、服务实例是否正常启动、流量是否正常到达、功能是否生效是否有缺陷、程序资源消耗是否正常、程序性能是否正常。我碰到过发布平台显示上线成功,可是服务实例OOM崩溃了,若是此时贸然将此实例挂载到服务下,等待个人就是异常告警了。我还碰到过同事将新扩的机器部署后,却忘记挂载流量的状况,浪费了时间还浪费了机器资源,所幸原有机器成功抗住了流量。
说到这啊,我再补充一种状况,部署时发现有台机器连通性异常了,处在运维状态,可能只是发包使用的端口受到影响而已,服务监听的端口是没有受到影响的,此时你须要将这台机器流量摘掉,避免状态正常后流量打到了错误的服务版本了。为何要将这个事单独拿出来讲呢,实际上是想强调咱们要确认所有实例都更新为新功能版本了,包括避免漏发实例。
上线变动是事故的高发场景,当真的发生问题时,咱们也不要慌张,先报备领导,而后第一时间止损和恢复服务。若是在发第一台验证的时候就出现异常了,最快的方式是修改Nginx配置将流量打到其余正常机器上,若是你摘取流量或者中止实例,其实都是有非同步状态的,由于用户接入层的负载均衡心跳检测多是有延迟的。若是全量发布后发现异常,按照应急预案也没法及时止损的话,只能选择回滚服务,要避免形成二次影响。
实际上,当用户碰到问题时极少会选择反馈,沉默的是大多数,因此上线务必进行充分验证和全方面的监控,不要干等着用户来反馈,当用户来反馈时影响范围可能很大了。那么咱们就须要规范化工做过程和输出,提升稳定性和质量。
好,本次的分享就到这,若是有帮助到你,欢迎点个在看或者分享给你的朋友们。
文章来源:www.liangsonghua.me
做者介绍:京东资深工程师-梁松华,在稳定性保障、敏捷开发、JAVA高级、微服务架构方面有深刻的理解