当前位置: 首页 > 科技观察

张凯涛:回滚机制详解

时间:2023-03-19 17:05:11 科技观察

回滚是指当程序或数据出现问题时,将程序或数据恢复到最新正确版本的行为。最常见的有事务回滚、代码库回滚、部署版本回滚、数据版本回滚、静态资源版本回滚等,通过回滚机制来保证系统在某些场景下的高可用。1、事务回滚在执行数据库SQL时,如果检测到事务提交冲突,则必须回滚该事务中所有执行过的SQL,以防止数据库中数据不一致。单库事务回滚,直接使用相关SQL。如果涉及分布式数据库,则应考虑使用分布式事务。最常见的是两阶段提交和三阶段提交协议。这种方式实现事务的难度较小,但是对性能的影响较大,因为我们大部分场景需要的是最终一致性,而不是强一致性。因此,可以考虑事务表、消息队列、补偿机制(执行/回滚)、TCC模式(抢占/确认/取消)、Sagas模式(拆分事务+补偿机制)等考虑,以实现最终一致性。例如,在电商下单场景中,会进行抵扣优惠券、预占库存等操作。这涉及到很多子系统。因此,很难使用分布式事务来保证强一致性。我们只需要保证最终一致性就可以了,我们来看一下结算订单时序图。一种情况是当一个订单出错时,之前扣除的优惠券和库存要回滚。但是,当保存订单出错,JVM实例挂掉时,之前扣除的优惠券和库存不会回滚。这种情况下,可以考虑在本地记录事务日志。当JVM实例重启时,分析交易日志返回给当然也可以记录交易日志表,或者通过补偿机制,周期性扫描coupon和inventory使用表,回滚有订单的记录没有关联的订单或已取消的订单。另一种情况是订单还没有付款,比如6小时,还没有付款就得取消订单。这时必须定期扫描订单,然后取消订单,回滚优惠券和库存。不管用什么方法,只要保证最终的一致性即可。2.代码库回滚在开发项目时,必须将代码维护在代码仓库中,这样才能进行版本管理。常见的有SVN、GIT等,SVN是集中式版本控制系统,GIT是分布式版本控制系统。有了版本控制系统,可以记录代码的历史版本,出现问题后可以方便的回滚。当代码文件部署出现问题时,可以通过历史版本查看是谁修改的,是什么修改的,从而快速定位BUG。另外,在实际开发过程中,可能会出现多个版本并行开发的情况。这时候版本控制系统的分支功能就发挥了很大的作用。大家在各自的分支上开发测试,互不影响。开发完成后,将分支合并到主干。能。3.部署版本回滚代码测试完成后,下一步就是部署系统。在部署系统时,需要考虑当代码逻辑出现故障时如何快速恢复。总结就是版本化部署,小版本增量发布,大版本发布。版本灰度发布,架构升级同步发布。1.部署版本控制每次部署时,都应该在部署系统中记录包的前一个版本。发布时应该使用fullrelease,避免增量发布(只发布修改过的类或文件),回到Justrollback,回滚,没有任何约束和限制。2.小??版本的增量发布,比如修复bug,增加一些简单的业务逻辑,我们称之为小版本。增量分发的意思是,比如我们有100台服务器,我们会先发送1台服务器进行验证。3、页面改版等大版本灰度发布。新增功能此时需要灰度发布。一般情况下,两个版本会并行运行一段时间。一些用户访问旧版本,一些用户访问新版本。功能验证成功后或新版本运行良好后才正式发布。例如,我们可以通过类似下面的URL中带有版本号来区分新版本和旧版本。https://cd.jd.com/yanbao/v3?skuId=854073&cat=652,654,832&brandId=8983&area=1_2810_51081_0&callback=yanbao_jsonp_callback不同的版本其实是不同的服务,可以部署在一套集群中。切换回旧版本。4.架构升级并发发布架构升级后,不知道新版本是否能正常使用。因此,新旧版本部署集群会在一段时间内同时存在。然后,当所有流量迁移到新版本集群后,老版本集群就可以下线了。一般我们会使用Nginx作为前端应用的接入层,通过AB方式慢慢引入流量到新版本的集群,比如1%、10%、50%、100%。如果新版集群处理出现问题,必须自动降级到老版集群继续服务。当新版本出现大面积故障时,必须将所有流量引入到老版本集群中。因此,接入层必须能够灵活控制流向。我们可以使用Nginx的error_page来降级失败。proxy_intercept_errorson;recursive_error_pageson;location~*"^/(\d+)\.html$"{proxy_passhttp://new_version/$1.html;error_page500502503504=200/fallback_version/$1.html;}失败降级是一个很重要的特性,key有时用户无法访问或看到白屏。如果有CDN,切换版本的时候记得把CDN去掉。4、数据版本回滚一些特定行业的业务数据中的商品/价格数据需要进行版本化处理,一方面是为了审计需要,另一方面是为了出现问题及时回滚。版本化设计可以基于下图所示的架构。在设计版本化数据结构时,有两种思路:完全和增量。完整版本控制意味着即使只有一个字段发生变化,整个记录也将进行历史版本控制。保存的数据量比较大,但是回滚方便。增量是指只保存变化的字段,保存的数据量小,但是回滚比较麻烦,需要回溯。因此,为了简化处理,一般采用全版本控制机制。另外,在设计消息队列的时候,重要的业务都会复制消息,这样如果业务逻辑出现问题,可以回放历史数据来解决问题。5.静态资源版本回滚在前端开发中,静态资源版本也会经常变化,比如JS/CSS,每次内容变化,我们都会生成一个完整的新版本,放在项目的deploy目录下项目,从而保证版本可追溯,出现问题可以及时回滚。因为静态资源一般都放在CDN,缓存时间设置的比较长,比如1个月。假设发布的版本有问题,需要清除CDN缓存,浏览器缓存也需要清除,而且因为版本覆盖的问题,即使覆盖了也不一定保证操作正确。●向源服务器发布新的静态资源。●清除CDN缓存,以便从源头获取最新的静态资源。●在新的URL中添加一个随机数来清除浏览器缓存,例如。当当前发布版本出现问题时,只需将版本号更改为之前的版本即可,无需清理CDN或浏览器缓存。当然这里应该设置一个合理的服务器端页面缓存时间,比如2分钟,最多2分钟用户可以看到错误的版本。为了方便测试,可以在请求参数中加上版本号,比如http://item.jd.com/2381431.html?version=1.0.15,方便验证旧版本或者测试新版本,可以测试或验证多个版本,无需来回修改服务器代码。【本文为专栏作者张凯涛原创文章,作者微信公众号:凯涛博客(kaitao-1234567)】点此阅读更多本作者好文