当前位置: 首页 > news >正文

网站建设国家标准房地产网站系统

网站建设国家标准,房地产网站系统,杭州百度推广电话,现在还可以做夺宝网站简介#xff1a; 一个较大的业务或系统改动#xff0c;往往会影响整个产品的用户体验或操作流程。为了控制影响面#xff0c;可以选取一批特定用户、流程、单据等#xff0c;只允许这一部分用户或数据按照变更后的新逻辑在系统中流转#xff0c;而另一部分用户仍然执行变更…简介 一个较大的业务或系统改动往往会影响整个产品的用户体验或操作流程。为了控制影响面可以选取一批特定用户、流程、单据等只允许这一部分用户或数据按照变更后的新逻辑在系统中流转而另一部分用户仍然执行变更前的老逻辑。这一步是线上系统灰度方案的起点。 作者 | 既同 来源 | 阿里技术公众号 一 灰度的基本概念 1 一个典型的灰度方案 一个较大的业务或系统改动往往会影响整个产品的用户体验或操作流程。为了控制影响面可以选取一批特定用户、流程、单据等只允许这一部分用户或数据按照变更后的新逻辑在系统中流转而另一部分用户仍然执行变更前的老逻辑。这一步是线上系统灰度方案的起点。 将用户按照特定规则分隔为两类之后我们主要需要关注命中灰度的这部分用户是否按照预期执行了新逻辑、产生了符合预期的数据以及系统整体的变化等。此阶段即灰度观察阶段线上验证工作也是其中的关键步骤。 随着系统中使用新逻辑的用户、订单等数据的逐步累计即可证明新系统的正确性、有效性那么更多的用户就应当被迁移进新逻辑中这一阶段一般称作灰度推进。灰度推进有时是小流量验证后立即切全量的也有需要逐步放量的这需要结合实际业务系统能力做出决定。 最终全部用户被纳入到新逻辑的范围内此时需要决定是否将灰度逻辑本身和系统中的老业务逻辑同步下线全部用户仅可以使用新逻辑此时即灰度完成。也有由于历史数据原因长期无法完成全量灰度切换的此时业务系统中将会长期驻留两套逻辑。 2 灰度在解决什么问题 一个变更如果在发布后立即全量上线那么如果出现系统、逻辑、数据等问题将会是灾难性的比如全部用户无法创建新订单、全部新订单出现脏数据等甚至有可能会影响到变更前的数据。 灰度过程就是在规避变更过程中这个最大的风险全局影响。通过减小影响范围再配合灰度线上验证、监控报警等手段将出现问题时影响面控制在有限的范围内如减少订正的数据量或降低资损金额等。 安全生产规则中所谓的“无灰度不发布”就是这个思想通过灰度尽可能的减少问题的影响面。如果通过灰度过程发现一个线上问题那么去掉灰度的保护可能就会产生一个严重的故障。 3 灰度会带来什么风险 灰度方案可以规避全局性的影响但是会不会带来其他的风险呢答案是肯定的工程中没有一劳永逸的银弹。 首先是如何发现灰度过程中的问题 这与上线过程中的监控报警有一定的相似性二者主要都是依赖日志监控报警规则的建设和配置但二者又存在一定的差异如报警阈值如何配置才能有效发现小流量异常灰度名单外的老逻辑会不会触发新逻辑的监控报警灰度系统影响的上下游是否也有对应的灰度监控这些问题都可能影响灰度问题能否被发现与发现问题的时效性。 此外对灰度系统要重点关注资损风险。资损字段在上线前一定要做好核对的保障或者至少应当在灰度开始阶段之前完成尤其是对新变更引入或影响的资损字段要做到全覆盖“无核对不上线”。 灰度过程中还可以协同客户、运营、产品等多条线的同学做好布防及时感知处理相关舆情使用非技术手段作为问题发现的兜底与补充。 其次如何控制灰度中问题的影响面 灰度过程中产生的灰度数据不能侵入非灰度数据反之亦然要确保二者的充分隔离。 但是灰度系统需要与上下游联动灰度本身也需要推进一旦遇到问题还需要进行灰度停止、灰度回退等更复杂的操作因此灰度整体是一个动态的过程而在整个动态过程中需要严格保持灰度数据非灰度数据的隔离否则将会导致问题影响面扩大化危及整个系统甚至发生严重故障。 这里尤其需要注意的是灰度停止与灰度回退的复杂性如果灰度停止手段不能生效那么问题影响就无法得到有效控制灰度回退则需要涉及阻断灰度流程、修改已有灰度数据、修复错误数据等一般来说是整套灰度方案中最复杂的部分。 最后发生问题时的处理也会比较复杂 生产系统往往没有太多的资源或条件进行AB-test灰度与非灰度数据都是真实的业务数据一旦出现问题并不能通过删除灰度数据或脏数据的方式解决问题一般需要进行数据订正或发布新的变更进行修复。数据订正的数量、订正数据的正确性、如何甄别灰度用户、如何保证新变更的正确性、如何保证新变更可以有效修复问题数据等都是恢复过程中的难点工作与潜在风险。 本章结语 复杂的灰度方案会引入各种各样问题与风险整个系统的复杂度也将成倍的增加对灰度的质量保障方案也会同时变得更为复杂。那么如何有效的控制这些风险同时高质量的达成项目目标呢我们常说好质量不是测出来的对于复杂的灰度系统来说这句话同样适用。一个高质量的灰度方案不仅需要完善的测试更要依赖于良好的设计。保障安全生产和达成项目目标二者绝不是矛盾的只要灰度方案设计得当鱼与熊掌可兼得之。 二 灰度设计要解决的基本问题 1 灰度维度的选取 生产系统中常见的灰度的规则有用户id尾号、业务单据id尾号、白名单、黑名单、时间戳等。 白名单常用于线上测试如使用测试账号等进行单独的验证。这种方式不适合单独使用因为无法快速扩大灰度范围但是推荐与其他方式联合使用增加灰度过程的灵活性。 黑名单则是一种兜底手段可以对特殊用户如数据量特别大用户、重点客户等进行屏蔽减少或避免其受到灰度的影响尤其是在灰度过程出现问题时直接阻断其进入系统中的问题逻辑。 采用用户id尾号或业务单据id尾号作为灰度key是更常见的灰度区分方式。但如何选取这类灰度key需要注意几个要点。 第一选取的key应当是均匀分布或近似均匀分布的如集团的havanaId等否则全量用户无法分批分散的命中新逻辑灰度的逐步放量的能力就失去了作用极端地整个灰度能力会退化为布尔化的全局开关。 这里容易犯的错误并不是使用了全部相同的灰度key而是误认为某个id是均匀分布的。举例来说某单元化应用中如果使用用户id的后四位作为灰度key那么很可能会出问题因为用户id已经是用于区分单元化的标记了。常见的id的生成本身是随机的但触达业务系统时可能已经带有某种特定的规律了因此需要对此类情况做好识别与防范。 第二计算key的逻辑需要尽量简化 系统中使用灰度key来判别走新逻辑还是旧逻辑这个条件判断一般会在系统中反复出现、多次执行此时如果设计特别复杂计算方式则会给系统带来额外的开销。除此之外简化key的计算逻辑也会带来业务语义上的简化便于整个业务链上的技术同学与非技术同学快速理解也便于遇到问题时快速定位与排查更有利于系统的长期维护。 第三要结合业务实际选取 如果选取一个当次变更新增的业务字段作为灰度key那么上下游系统是否需要做同步改造离线数据报表是否需要配合改造如果选取一个对下游业务未记录的或无意义的字段呢这些都是通过合理设计可以节省的改造成本。 因此在选取灰度key时需要选取上下游业务已有的、通用的、具有业务意义的字段。 2 简化灰度逻辑 灰度逻辑仅仅是将一个用户或单据非此即彼的区分开因此灰度逻辑不仅没有必要做的太过复杂而且还应当尽量简化如果业务上有条件最好能用一个字段或一个变量搞定。 首先有利于完成灰度进度的调整如灰度推进灰度暂停等可以通过单变量的调整快速完成否则一次性调整几个灰度变量会出现灰度推进情况不符合预期、灰度覆盖不全灰度数据不一致等复杂问题。比如同时调整用户id覆盖范围与订单创建时间则可能导致一部分用户被跳过也可能导致调整后的灰度范围远超预期等问题。其实这类问题在实际生产中是最常见的回想一下每次在灰度推进或灰度暂停等进度调整时是不是都需要多人共同监督灰度脚本反复确认发布内容甚至在加入了如此重的流程之后仍然不能达到百分百的无问题。 其次开始灰度后灰度数据往往错综复杂如果需要多个条件协同判断对问题定位则是不利因素甚至可能会导致误判。还用上面的用户id时间戳的例子来说原本是灰度逻辑出错时产生的数据可能被误判成由于时间未到而走旧逻辑产生的数据这种复杂性导致的误判将会严重影响线上问题的止血与处理效率。 最后对可灰度的用户或单据应当宽进严出适当提升灰度准入的门槛这样做有利于将大部分数据快速的排除到灰度范围之外。因为总体而言当我们决定采用灰度方案去推动变更时我们总是抱着对系统悲观的态度防止潜在的问题快速扩大化。因此在初始阶段让尽可能少的数据走到新逻辑可以给我们留出时间做人工数据校验、监控报警有效性校验、核对有效性校验等等工作防止第一波灰度用户出问题时直接演变成大问题。那样的话就完全失去了做灰度的意义。 这里还要做一个简短的解释减少灰度变量和灰度命中宽进严出二者并不矛盾前者一般是动态的、配置在开关内供应用读取的后者一般是静态写在代码中的固定条件。举例来说某一个变更使用用户id作为灰度变量但初期应当设置仅对某等级以上的用户开放的门槛。 3 灰度数据如何初始化 灰度最好是可以从0启动的就是说无需事先通过数据订正或批量触发的方式修改初始数据而是通过某个真实的业务请求来触发比如用户下单等。这里常见的做法是当业务请求中的数据命中灰度之后在创建对应的DB记录时打上特殊的标记用以标识灰度命中。如果有必要的话还可以单独建立新的表在DB中写入一条新记录就代表相关的用户或单据命中灰度。 这种方式的优点就是0启动无需前置数据准备流程但问题是整体的灰度进展可能会变慢。因为在上线前产生的部分部分线上数据已经被确定为仅能走旧逻辑想要进行全量灰度后的灰度逻辑下线一般来说只能等待业务数据自然关闭。 举一个简化的例子灰度启动前已经付款的订单走旧逻辑如果不对这部分订单数据做处理那么只能等待这部分订单全部确认收货才能对灰度逻辑和旧逻辑进行整体下线。而在实际的生产系统还要考虑退款、计费等等相关流程所以等待的周期只会变得更长。 但有些灰度方案并不能简单的通过请求中携带的数据进行灰度初始化还需要对全量的用户数据做一次初始化。比如将线上A系统中的数据按一定规则导入本次变更涉及的B系统中作为灰度过程的数据准备。这样做的好处有两个。 第一是可以在一些场景中简化灰度门槛的判断即可认定所有的数据全部符合某一个前提条件节约一次判断。而且这次查询一般会是一个查库操作而使用全量业务数据去查库常常会出现DB性能问题甚至会出现由于灰度数据的分布问题导致分布式DB出现单库单表的热点这里的DB问题不做深入。总之这个方案可以有效减轻甚至规避此类问题。 第二就是在业务上可以加速整体的灰度进度缩短从灰度开始到全量的周期有时出于业务的考量我们可能不得不选择这个方案。 但这样做的缺点也是明显的。举例来说比如数据初始化的方案是从A表导入B表那么首先需要对数据迁移的逻辑进行经过额外的验证工作之后进行迁移数据时也需要占用一定的项目周期还要在设计中考虑迁移数据过程AB系统的数据一致性如何保障比如迁移数据的过程中A系统有产生了新的业务数据要迁移吗还是迁移时要对A表的部分记录加锁或者甚至停掉A表对应的服务真的需要停服务的话那这也太不互联网了。 4 灰度过程中保持数据一致性 前文描述了灰度初始阶段的问题但是灰度过程往往会从前一个业务步骤开始随后才会影响下一个业务步骤。举例来说同一个用户在t时刻命中了灰度规则并在写表时打标命中灰度而在之后的t1时刻发生了一个需要更新表记录的操作但由于灰度回退或其他原因导致没有命中灰度规则这时要怎么判定 这类问题其实就是灰度数据一致性的问题也是灰度设计中最核心的问题。 原则1以已有的灰度命中数据为准 在很多业务场景下前一步写表后一步更新的操作是非常常见的创建时打标无需多言更新时的基本的判断原则应当是将已有的灰度数据作为判断标准而不是以灰度key是否命中为判断标准。即后一步更新操作时总是以查DB的结果为准DB中记录为灰度命中那么就要执行新逻辑否则按照灰度未命中的旧逻辑执行。 原则2优先考虑灰度推进过程中数据的一致性 当灰度推进时更多的用户或单据会被纳入到灰度命中的范围内因此要考虑此部分数据能否进入新逻辑。 举例来说以用户当月账单id尾号为灰度规则那么用户的当月账单一旦被打标为灰度命中后续账单再次更新时也一定要遵循新逻辑而在账单创建时如果为灰度未命中那么这笔账单将会一直保持旧逻辑直到结清。 这个原则与前一条有一定的相似性但核心关注的是灰度进展导致的灰度key命中情况在创建和更新两个阶段发生了变化这时一般仍要遵循以DB记录打标为准的原则。 另一方面灰度推进前已命中灰度的数据要确保在灰度推进后仍能命中灰度。这是一条不言自明的规则在确保数据一致性的基础上只有这样才能被称为灰度推进。但在实际操作推进的过程中有时会因灰度开关配置错误等原因违背了这一规则因此可以考虑对配置项进行一定的防错设计。 此外灰度推进过程中还需要关注集群内各机器开关数据数据的一致性。首先要确保变更后的灰度开关值被推送到集群内的全部机器中其次为了灰度推进时间的一致性一般会在灰度开关内加入一个生效时间戳避免开关推送延迟可能带来的问题。 原则3如果需要快速推进灰度可以尝试在第一个灰度维度全量后再开始另一个灰度维度 上述原则中提到更新数据时发现记录创建未打标的即使灰度key已被命中仍应使用旧的业务逻辑。但是这样做整体的灰度进展将会被拉到非常长比如确认收货后90天内都可以发起退款那么是否要等到4个月之后才能全量切到新逻辑业务上允许这样做吗 对上述这个例子可以这样做就是当订单创建已经全量灰度后那么就可以理解为创建已经全部切入新逻辑此时继续在付款或确认收货操作时进行灰度打标这样仍然可以保持一次仅对一个变量进行灰度的原则。 这里给出几个不是很理想的快速推进灰度的做法。 1、同时对多个灰度维度做推进 这是上文在讨论简化灰度逻辑时就力图避免的一种设计。与其这样做还不如在验证充分之后对第一个灰度维度直接全量之后再推进第二个灰度维度。 2、在多个入口同时进行灰度打标 这个方式看上去可以加速消除数据创建时未打标的记录但多个入口打同一个标出现问题的时候怎么排查原因更新时要不要覆盖创建时的标记灰度暂停时如何同步停止打标总之这是个复杂度高且验证工作量大的方案。 3、手工数据订正 既然要做数据订正还不如在灰度启动前就做一轮这样在整个灰度方案开始时就可以获得收益。灰度进展中做订正成本更高收益却更低从ROI角度看很不划算。 灰度设计的过程中不要轻易尝试去推翻上述这些简单的原则因为越是简单基础的原则其影响就越大对这些原则的改动往往会造成前述的设计被全盘推翻。 当然也存在一些只创建记录而不再更新的业务这种业务考虑的重点往往不是灰度推进而是下面的灰度暂停回滚策略。 5 灰度暂停与灰度回滚 灰度是服务于安全生产的那么相应的一定要建立适当的熔断与回滚机制。 原则4灰度过程务必具备整体暂停能力也即灰度熔断。 灰度熔断不要求对已经进入灰度的数据进行纠正而是只需要不继续产生更多的灰度数据即可。 为什么灰度不继续推进了还不行还需要加入一个这样的开关下面举个例子。 使用用户id尾号作为灰度key已有n个用户进入新逻辑时我们发现DB侧出现了瓶颈需要修复。这时业务层的应用有三种应对方式可选。 第一立即缩小灰度范围或对代码进行回滚。这是不可取的已经命中灰度进入新逻辑的用户往往不能再轻易的回退到旧逻辑中。 第二不继续推进灰度也不操作灰度开关放任系统继续运行。这也是有风险的因为现阶段只有n个用户进入新逻辑但按照用户群体总数*灰度比例测算可能还有m个用户即将命中灰度进入新逻辑甚至mn如果DB问题不能在用户大量进入之前修复整个系统将面临灾难性的后果。 第三灰度熔断。不操作灰度开关但停止新用户命中灰度规则即目前有n个用户进入新逻辑那么稍后即使有m个用户命中灰度规则也仍然不能进入新逻辑这样就可以确保在DB问题得到修复之前系统保持现状继续运行。 通过这个例子可以充分说明建设灰度暂停能力的必要性。 原则5可操作的灰度回滚方案才是有意义的灰度回滚方案。 一般来讲我们都希望可以做到灰度的可观测、可回滚。但前文反复讲述的这类灰度方案中避免出现数据一致性问题对业务来讲才是更重要和更安全的。出现问题时机械的执行回滚反而会造成更大的影响而使用灰度暂停能力进行快速止血并积极修复问题反而是更合适的。 那么回到灰度回滚方案中来在保证数据一致性等原则的前提下可以设计一个合理的回滚方案吗 我认为应该是可以的但遗憾的是我们在项目实践中没能成功的做到这一点。因为工程中的资源往往都是有限的我们不可能把大量的时间和精力投入到高度复杂的回滚方案中去。 因此对于灰度回滚方案我有一些比较负面的结论 灰度回滚方案的复杂性如果难以控制那么正确性也将难以验证 复杂的设计将带来开发周期和测试周期的延长对业务的伤害可能更大 就像应急预案需要提前演练一样没有人敢在线上直接使用未经验证的回滚方案最终做了也是白做。 所以我建议仅在模型上更为简化的业务中才去考虑设计完整的灰度回滚策略。 本章结语 本章讨论的范围主要是从技术视角出发的已经基本可以满足一个常规的灰度方案的设计要求。但可达成不代表做得好除了技术手段外还有更多的其他类型的手段可以应用到灰度方案中帮助我们将方案变得更加完善、健壮实现可观测、可度量等工程目标构建起高质量的灰度设计方案。 三 更完善的灰度方案 1 具备良好的可测性 我们一般在复杂的项目下才会考虑使用较为细致或复杂的灰度方案在项目本身的业务复杂度之上再叠加灰度引入的技术复杂度此时如何进行完备的测试就成了一个不小的挑战。我们需要明确可测性问题是需要在设计中认真考虑的问题。让系统内的数据流动状态迁移都是可观测的把请求、处理数据的过程值、开关值、分支判断结果等信息明确的、无遗漏的持久化到日志或DB中尤其是灰度是否命中、灰度判定规则等关键信息而不要让复杂的系统变成一个黑盒只有起始的输入和最终的输出。否则的话在调试和测试的阶段都要花费大量的沟通成本甚至可能埋下无法被发现的缺陷。 对于日志的处理应当尽量保持上下游的一致性。最好的代码是自解释的最好的日志也应当是自解释的。上游的系统如果使用了一个灰度标记则下游的系统应当使用相同的标记如果有下游有业务语义的变化可以新增一个字段而不是将上游的同名字段覆盖或清除。这样在跨多个系统或团队进行联调或处理问题时大家对同一个标记或概念都持有同一个理解这是对提效非常有帮助的。举个具体的例子比如上游命中AA规则后记录了AAtrue的日志下游根据AA规则衍生了BB规则那么记录日志时可以保留AA字段的信息再额外记录BBtrue。 对于落库的数据的处理则要考虑可核对性方面的问题。数据在跨系统传递时应明确各个系统中的业务主键是什么下游系统要将上游系统的主键或唯一键落库如果条件允许还要将上游传入的键值作为平铺字段甚至为其在DB中建立索引。这样做的好处首先是为了后续建设核对方便方便使用相同的唯一键查找上下游系统的关联记录。这也是为将来的系统扩展性做考虑如果将来下游系统的下游还需要再接其他系统此时通过上游的这个统一键值即可有效串联多个系统。典型的例子是将交易系统唯一id透传到下游的所有额度明细、账单明细、退款等系统中。 以上这些提升可测性的设计思路不仅针对灰度方案也针对不涉及灰度的方案不仅需要测试同学在设计阶段识别和发现方案的可测性短板也需要开发同学有意识的去面向可测性进行设计。 2 关注全链路的压力 系统改造中需要关注对下游依赖的压力变化灰度设计中也需要考虑这一点尤其是系统压力随着灰度推进而改变的情况。 一种典型的场景是随着灰度推进传递到下游的请求越来越多这是一个比较好理解的例子这里不做过多展开。这种情况下主要需要梳理下游请求的增长率是随着灰度推进线性增长、对数级增长、还是指数级增长指数的情况就很可怕了极易引发故障此外灰度推进结束之后流量模型是相对稳定的、还是继续变化的 实际业务中的情况并不都是这么简单有的场景中在灰度开始启动的时才是下游流量最大的时候。随着灰度的推进下游的流量反而会越来越小。举例来说开始灰度后全量用户都需要查询某服务而命中灰度的用户可以通过其他短路方式规避这个查询。如果评估发现这种特殊情况除了按照常规做出压力评估也可以考虑对依赖方案做调整以规避这种反直觉的情况。 其他的可能性还会有很多再举一个极端的例子本月的流量是随着灰度推进逐渐上升的经过N天后灰度推进至全量流量保持稳定但到了下月1日业务数据需要重新生成由于已经灰度全量导致突然爆发出了非常大的流量给下游系统带来很大的影响。这种极端的场景如果不能提前发现识别并做出合理的应对则可能引起意想不到的严重故障。 除了下游的业务系统我们还要关注DB侧可能存在的瓶颈我们的业务系统一般可以快速地进行集群平行扩容以应对大流量但DB的扩容就比较复杂了可能会涉及到数据迁移、锁库、索引重建等操作有些操作属于高危操作如有不当甚至会影响使用同库或同表的其他业务。当识别到这类问题时需要提前与DBA联系讨论合理的扩容方案在灰度启动之前预留充足的时间完成扩容。 当然所有的压力评估都可以用压测来进行检验。但是要把压测当做对设计成果的验收而不是作为发现问题的兜底手段。即将上线之前才发现系统性的问题可能为时已晚强行上线或延期成本都将是巨大的。 3 灰度的进展与监控 首先监控是灰度前期最重要的观察手段建立完整全面的监控对于上线初期、灰度开放初期、灰度放量初期的数据观察都至关重要上线初期我们重点要关注新代码下的旧业务逻辑是否能正常运行灰度开放初期则要观察何时出现命中新逻辑的数据以及进入了哪些业务分支灰度放量期间则要观察流量的变化是否能与开关调整相匹配报错量是继续处于低位、还是随之线性甚至更快速的增加。此外灰度放量过程中所关注的监控在后续灰度全量后也仍然需要持续观察有些还要建立相应的报警规则。 其次针对灰度方案的核对也有一些不同。常见的核对一般都是以上游系统对应的A表作为左表即核对数据源下游系统的B表作为右表。但是下游系统在灰度阶段会将上游数据做二分类命中灰度的写B表未命中的不写此时建立核对就要反转过来将下游灰度命中后写入的B表作为左表反过来与上游A表建立核对确保所有命中灰度的数据仍与上游保持正确的关联关系。 但这里又有一个问题一个用户本应命中灰度但却没有写入B表我们如何发现这类问题这里我提出一个解法即仍然建立从A到B的核对但在核对规则中加入灰度规则的等效条件语句并随着灰度推进修改核对规则。但这样做核对规则将会非常复杂而且也对如何设计落库字段提出了更高的要求。 最终还可以为整个灰度方案建立一个小型的报表用于速查从落库结果的角度判断某个特定的用户或数据是否已经命中灰度。更进一步的还可以在报表中展示灰度相关的聚合与统计数据判断数据分布是否符合灰度推进节奏下一步需要加快推进还是暂缓。借助这些数据一来为技术侧同学在做答疑或问题排查时提效二来可以向业务侧的同学提供灰度的整体数据或局部情况以便做出更多业务决策。 4 应急策略与修复手段 灰度推进过程中我们可以通过各种方式和渠道获取来自系统和用户的反馈包括但不限于监控、核对、用户咨询等。当发现不符合预期的、甚至存在严重问题的数据与场景时标准的操作是先止血再修复通用的止血方案可以是先将业务逻辑开关关闭、下线或回滚掉新逻辑的代码随后在修复阶段对错误的数据进行订正。 但是回到最初讨论的问题我们为什么要做灰度灰度本身存在的价值就是在问题初期可以控制影响面如果只是机械的执行上述的通用方案为何还要设计复杂的灰度方案 比如灰度方案中的止血开关可以设计成全量下线新逻辑也可以设计成不再产生新的灰度用户这个已经在上一章中举过例子这里不再赘述在有多个灰度维度时还可以设计成调整A维度与调整B维度可分别实现前述的目的。但需要明确的一点是止血开关的语义应当设计的尽量简洁、无歧义因为止血的意义就在于短时间内无需复杂判断即可立即执行。 详细判断与分析的工作是在下一步的修复阶段完成的。上一章也提到一般意义上的回滚可能引发更大的问题所以可以在修复代码逻辑或修复数据后继续推进灰度当然进行灰度范围的回滚也是可选项比如撤销之前已经命中灰度的用户或单据将其修改为未命中。但这类回滚除了要考虑前述的数据一致性、系统复杂度等问题还要从业务逻辑上看能否做到前向兼容从产品视角去考量用户体验能否在回滚后得到保障这也是一个要不要去做这类复杂灰度回滚方案的重要判断依据。举例来说前一天用户命中了灰度可以使用某个新功能但第二天灰度回滚后反而不能用了这大概率会引发用户咨询甚至投诉。 安全生产应当摆在重要的位置但工程的目标从来不是单一的。灰度系统的设计在这个部分上一定要有所取舍并不能一味地从系统稳定性的角度出发贪大求全而应当结合实际业务情况平衡由于复杂度提升而引入的设计、开发、测试、运维成本和对产品、用户体验的影响。 5 灰度方案的终点 讨论到这里我们基本把最复杂的部分与可能面临的失败情形都讲完了。下面谈谈在灰度进展一切顺利的情况下还有哪些事项需要我们关注。 首先是灰度完成后对灰度开关的下线。最明显的好处是简化代码复杂度已经完成的灰度基本等同于无用的业务代码。此时还可以把旧逻辑的代码也一同下线全部直接执行新逻辑也方便后续其他同学阅读与维护。不过这一步并不是非做不可而且可能还会遇到一些限制。 灰度的终极目标当然是全量切换到新逻辑中但实现这个目标有时候需要花费很长的时间。举个业务上的例子比如从5月的某一天起开始灰度一个远月账单相关的功能这时已经有部分用户产生了8月份的非灰度账单那么按照预期就要等到9月之后才能在理论上实现全量账单命中灰度。出现这种情况时一般要和业务方充分沟通因为业务上可能无法容忍漫长的灰度周期。压缩整体周期的手段除了将灰度开关推到全量还需要通过数据订正等方式让加速数据层面的灰度推进。 不过真实的情况可能更复杂继续拿上面的例子来说这笔8月账单如果出现用户逾期那到9月时也仍然没有实现全量。在交易相关的系统中也有类似的例子付款、确认收货、退款每个周期都可以很长如果再遇到纠纷等场景叠加在一起的情况周期更是不可控所以基本不可能在设计中对这类长尾值进行良好的处理。一般来说在整体趋近于全量后总会有个别的异常数据、离群数据的出现。所以从工程的角度来看只要非灰度的数据趋于收敛就是符合预期、可以接受的情况。 6 灰度的代价 前边我们反复提到过在设计灰度方案中要有所取舍尤其是要对最复杂的部分做取舍。不过简单的部分就没有代价了吗不是的。项目中实现了一套灰度方案就一定会付出相应的成本。应当总是从成本收益比的角度出发来评价一个设计方案的价值进而决定其最终应被保留还是被舍弃。 首当其冲的代价就是复杂度的提升这一点已经在上文多次提到。一般来讲我们是能够在复杂项目中承受这一点的因为项目本身的复杂度已经不低了从边际效应的角度来理解再加一点复杂度也不会造成太多额外的开销。但是对简单的项目我们就要思考是否需要采用灰度了或者出于安全生产的需要我们一定要进行灰度那简单的项目也一定要匹配最简化的灰度方案避免造成大炮打蚊子式的浪费。 其次要面临的问题是发布时间延迟。设计、开发、验证环节都要花费额外的工作量和研发周期来保障灰度逻辑的正确性与有效性而且大概率还会出现修复灰度问题的时间。如何在项目开始时合理评估灰度引入的工作量也不是容易的事情因为灰度逻辑往往与业务逻辑正交。单从用例数量的视角看理论上每增加一个灰度开关相关的功能用例数量就要翻一倍。当然我们可以结合实际业务排除一些用例但这样的用例数量增长趋势对于项目整体而言并不是一个好信号。 接下来还有一个问题就是灰度会使项目周期拉长。这里的周期指的是从发布后到灰度全量的周期。上面已经有案例说明5月开始灰度的项目到9月甚至更晚才能真正完成全量这听起来就让人难以接受。极端地这种漫长的灰度过程还可能会影响下一个项目的设计与上线甚至会将影响扩散到下游系统中。如果出现这种情况已经可以算作是设计失败了。 最后就是要慎重考虑不做灰度。不做灰度其实是反规则的一般我们也不建议这样做。但工程上的事情总会有例外有时也会遇到一些业务场景无法灰度或者灰度还不如不灰度。如果决定不做灰度方案那最好把灰度带来的问题和不做灰度的收益都提前整理好同时也要充分评估放弃灰度的风险让项目组的其他同学都能理解认同这个决策。 本章结语 一个项目或产品的质量从来不是测试测出来的而是在设计阶段就构建起来的。希望通过上述两章提及的各类设计手段与思路给大家更多的输入与启发在将来设计构建出更稳定健壮的工程。也欢迎大家对文章中的各项内容给予补充、指正。 下一章将从测试的角度讨论如何保障复杂灰度方案的正确性。 四 灰度方案的质量保障 之前的章节主要针对灰度方案的设计展开但一个系统的正确性、稳定性除了要依赖有效的设计还需要全面合理的测试来保障。这一章就对灰度方案的质量保障体系进行详细的讨论列举灰度系统中的各个测试覆盖要点。 1 灰度基本逻辑 这是最基础的测试点即如何将数据非此即彼的区分开满足预设的条件即为命中灰度否则不命中灰度。 灰度命中的结果不仅要是可预期的还应当是稳定的。使用同样的数据与配置不能在某次请求时命中灰度另一次请求时却未命中灰度否则将产生严重的问题。 举例来说如果用户A在第一次命中灰度后在将命中结果落库时但意外的影响了灰度判断条件那么稍后用户A再来请求时就可能出现无法再次命中灰度的问题。这类型的低级缺陷要尽早发现否则会阻塞后续的其他测试。 2 灰度命中后的持久化 命中灰度的数据有时还需要持久化到数据库中在测试中除了检查灰度标记还要检查新增的字段。如果灰度命中后写入全新的表也要对全部字段进行完整的校验。 落库的数据与上游有关联关系的要检查记录是否一致如果可行最好推动开发将其设为平铺字段方便在上下游间建立核对。单据号等字段具备唯一性的要额外做幂等性测试防止同一条灰度命中数据多次写入。 除了结果数据过程数据也至关重要。判断灰度过程中可能经历了多个条件那么需要将每个条件的输入值、判断结果值都打印在日志中方便联调与后续问题排查。此外还要检查日志中变量名的唯一性与变量值的正确性防止打印语义混淆的废日志。 3 灰度兼容性 由于灰度过程中的请求会分为两部分因此系统内应当对两类请求都有相应的处理能力即在灰度全量之前旧逻辑仍要保持可用。 新版本代码中的旧逻辑在本质上已经和上一个版本的逻辑有所差异因为上一个版本中是未经灰度判断直接执行旧逻辑而新版本代码中是多一层判断逻辑的。这层判断逻辑有时可能还会在入参上添加各类标记后再进入系统的下游模块流转并会引发更多复杂的情况。比如系统对未命中灰度的数据加入了一个属性但下游流程判断有任意标记的流量都不再处理那么这种情况下的旧逻辑就会受到影响。 如果灰度系统涉及多个应用还要考虑应用间的兼容性。常见的测试要点包括 灰度系统是否影响了上下游的流程交互如命中未灰度走A应用灰度命中则不走A应用这样对A应用的监控和核对是否会造成影响 灰度是否新引入了下游依赖原有的依赖关系是否被解除或需要削弱强弱依赖的设计是否合理具体的依赖关系如何是否引入了循环依赖或者数据流是否构成回环 上下游应用均有改动时在下游应用先行发布后是否会影响尚未发布的上游应用。 4 灰度推进 灰度从0开始到部分覆盖再到全量覆盖这个灰度推进的过程也需要测试重点关注。 首先是一头一尾的情况灰度开关配置为全量老逻辑和全量新逻辑的情况下请求的结果是否符合预期 其次是灰度推进的过程中如果用户A在上一次请求时未命中灰度但下次请求时由于灰度范围扩大而命中了灰度那么用户A的请求能否正常处理用户A能否按照预期被纳入或排除出灰度新逻辑的范围内 最后还要评估灰度推进可能引起的兼容性问题这里要关注的点是在灰度开关变化的情况下动态的评估内部逻辑的兼容性而这可能是上述静态的兼容性测试不能覆盖的点。这里需要结合实际业务与设计方案仔细分析排除可能的、隐藏较深的、重现条件较为复杂的缺陷。举例来说当月A用户第一次请求时未命中灰度故写入一条不带灰度标记的记录意味着本月A用户将不再命中灰度当A用户第二次请求时查询是否存在灰度不命中的记录时服务超时且由于灰度推进导致A用户变为灰度命中故又写入了一条带灰度标记的记录导致库中同时存在两条业务语义存在相矛盾的记录。 5 灰度暂停或灰度熔断 上文已经反复讲过灰度熔断的功能对灰度方案至关重要在某些关键时刻甚至是系统唯一的逃生路径因此对这里需要格外重视。 第一熔断开关关闭时要确保没有新增的灰度流量进入。这里有两层含义一方面是未命中灰度的数据不能再命中灰度另一方面是已经命中灰度的数据要视灰度系统是否可回滚、是否前向兼容决定是否可以继续命中灰度。 第二熔断开关关闭时要保证其他部分的灰度逻辑不受影响这也是基本逻辑测试的一部分。 对此类应急方案的测试还需要结合实际业务场景进行设计考虑比如存在多个其他业务逻辑的开关时是否要对所有开关组合进行测试还是优先测试业务实际使用的组合或者仅测试应急场景下必定出现的且数量有限的几个组合即可。 6 灰度回退 上文提到在可能涉及灰度数据一致性问题的灰度方案中我们一般不推荐引入复杂的灰度回退逻辑。但不可否认的是灰度回退在部分场景下仍然是有价值的此时也需要通过测试手段保障回退能力的质量。 首先是回退过程不再新增灰度命中数据。这里的保障要点与熔断开关打开后是一致的。 第二是回退过程中已命中灰度数据的一致性保障这里最需要关注的场景是在前一个业务流程中已经命中灰度的数据在下一个业务流程中没有命中灰度时系统将会如何处理。如订单创建时命中灰度并打标付款阶段反而不命中灰度则此时需要将灰度标记移除。 此外还要对灰度开关的回退能力进行测试如果灰度开关存在多个维度或限制条件这里的测试用例组合也会非常复杂但与灰度推进逻辑的测试方案有一定的相似性可以作为参考。 最后灰度回退的过程一般还需要借助数据订正的手段对已经落库的灰度数据做变更这里不涉及代码流程的测试可以考虑建立核对规则进行保障。 7 对异常配置的容错 灰度逻辑底层常会依赖一个switch开关或diamond配置项但进行配置时也有可能引入错误。把整个系统看成一个木桶那么配置项常常是最短的那块木板。我们应当通过优化设计规避由配置类问题导致的更严重问题。 首先对灰度开关错配时应用不能接收仍应使用上一次的正确配置。虽然在diamond配置项中输入错误的配置值后中间件层总会将这个错误值持久化但应用可以在此时报错并弃用中间件下发的错误值。 此外如果在业务上有可行性的话还可以在每次接收到错误值时采用默认值来做兜底处理。 典型的例子是前一版本的灰度配置包含尾号为00、01的用户而后一版本的灰度配置中只包含尾号为0的用户不包含尾号为1的。如果这个配置生效那么尾号为01的用户的数据一致性将被破坏此时若对后一版本的配置做校验识别发现尾号为01的用户原本可命中灰度但在推进后反而不命中则可以避免这个问题。 这一点既是测试设计要考虑的异常逻辑也是方案设计阶段需要考虑的防错机制Poka-yoke。 8 对异常数据的容错或报警 如果灰度过程中发现缺失了某个新字段但可以通过一定的回补机制写入的那么最好可以进行静默处理容忍这样的错误数据。比如本应在用户浏览商品时对用户打上灰度标记但后续加购时发现灰度范围内的用户仍然不带灰度标记则此时可以再次对用户进行灰度打标。 但如果系统中核心依赖的字段遇到数据一致性错误时就应当立即停止继续处理。如一个已经带灰度命中标记的订单在确认收货时缺少了一个应当在付款阶段写入的关键的新字段。那么此时应当不作处理通过记录错误日志、抛出异常等手段触发外部的监控报警等待人工介入。 这里可以借助异常注入类的工具来简化测试方案。通过破坏灰度数据的一致性检验系统对异常数据的处理是否符合预期。这部分功能的正确性在遇到灰度回退等复杂情况时将会起到很大的作用如首次请求灰度未命中、二次请求时进行灰度命中补偿或回退时数据订正不完全系统处理此数据时触发报警提醒再次订正等。 9 对外部系统的影响 除了要关注业务系统内部的数据流转情况有时还要考虑对外部系统影响比如在执行到某个节点时对外发送消息而下游有若干外部业务方的监听者需要在收到消息后执行对应的系统逻辑或者最常见的落库的数据会定时的写入离线数据表中。 对外部系统的影响应该在变更前期、设计方案确认后等关键节点及时向下游业务方同步评估下游需要的改动并在预发环境进行有效的串测、验收如有必要还要为新逻辑产生的数据单独建立监控或核对此外在灰度推进阶段需要向下游同步灰度变化节奏观察监控变化情况是否符合预期。 对离线表的影响有两方面首先要为变更的部分建立新的核对规则其次也要评估对原先建立在这些离线表上的核对规则是否有影响是否会导致核对误报或漏报。 10 灰度流量模型分析 灰度过程的流量模型是动态变化的首先在灰度未开始推进的初始状态下就已经与上一版本的流量模型存在一定差异随后随着灰度的推进流量模型又会逐渐发生变化最终在灰度全量后达到稳定。 在变更上线后、灰度启动前的阶段一般不会与上一个版本的服务或DB依赖存在太大的出入否则这些变化也应当被纳入灰度流程。这阶段主要需要对服务调用和DB新增字段进行评估判断是否存在复杂的计算逻辑或对DB读写存在影响。 相比之下灰度推进阶段需要分析的点会比较多。灰度推进过程中灰度判断逻辑的查询接口按灰度命中结果分流后两套业务逻辑接口落库时的DB其他依赖或下游方的流量都在同步的变化着。这里需要对这些变化点做逐个梳理再分析流量变化可能引起的后果。 下面列举几个常见的随着压力逐渐变大性能出现较大问题的场景 触发下游服务限流导致本系统的业务失败率升高下游服务rt变长本系统业务随之超时失败率升高灰度推进时命中灰度的key值选取不当经过分库分表规则后导致单库热点灰度推进时推进范围过大导致短时间写库请求过大引起整库流量或性能抖动为灰度字段添加的DB索引不适用于灰度推进过程中的流量模型导致DB性能不及预期。 灰度全量之后流量模型将会达到或逐步达到一个新的稳定态除了继续观察上述灰度推进过程中的各个要点还要考虑在全量之后做切换的动作比如对灰度判断逻辑做短路以减少一次查询或者将灰度条件的查询操作从一个接口迁移到另一个性能更好的接口上。总之这个阶段可能只有性能优化不太会有让整体性能变差的情况此类优化除了确保基本功能的正确性外无需过多关注。 11 对灰度系统进行压测 从上一节的列举的情况看压力瓶颈常会出现在新增的服务接口与DB这两处需要结合业务具体分析。但分析并不是万能的新的接口或新的库表在上线前一般要按照规划的流量要求进行一轮压测确保没有因为分析遗漏导致的隐藏缺陷。 压测流量的设定需要结合当前线上业务的接口调用量进行评估可按灰度全量后的流量值再放大1.2~2倍计算。放大的目的一方面是为了应对峰值流量另一方面是为了快速暴露问题。常见的问题是流量在下游被成倍放大比如一次请求调用了两次某接口当流量较小时二者间的倍数关系体现的不明显可能还会被误认为同时间段线上真实流量增大引起的扰动导致无法发现问题但流量较大时倍数关系将会立即显现。 如果压测流量较大需要在发布上线后使用线上集群做压测那么还要考虑影子数据与真实数据隔离的问题。使用影子请求压测时需要按照全量灰度命中的新逻辑来执行而对线上真实请求还不能开放灰度。这种情况需要在代码中额外添加一个供压测使用的开关通过在入口处判断请求的压测流量标记字段判断是否执行灰度逻辑。 12 为灰度建立核对规则 为了保证新项目上线后及时发现线上数据可能存在的问题最晚在灰度启动之前就要将相关的核对规则全部上线。 在灰度项目中常会出现灰度命中与未命中时落表不一致的情况。此时建立核对就要考虑如何选取左表。我们把系统的全量请求作为全集把命中灰度的部分作为子集那么灰度命中子集中的数据必然要与全集的数据保持一定的关系。反之则不然因为全集中还有部分灰度未命中的数据无法与灰度命中子集中的数据保持一致。 举例来说灰度系统位于下游需要与上游系统进行核对确保上游发来的请求全部被正确的处理了。这时就要用命中灰度之后的表作为左表上游请求的表作为右表来建立核对。 此外对于灰度未命中的部分也需要建立核对来保障一致性。这里的处理方式有两类如果灰度命中只是新增落表而不影响原有落表逻辑那么可以先为旧逻辑做全量核对即在灰度启动后无论是否命中都仍然应当遵循旧逻辑下的一致性约束如果灰度命中后数据将会从旧表中迁走只写入新表就需要对灰度未命中的部分也进行上下游关系、子集全集关系的分析然后选取子集作为左表建立核对这与灰度命中的处理方式是相似的。 上述的原则可以帮助我们检查在灰度命中与未命中两种情况下数据总是一致的但是无法确保灰度命中与否这一结果的正确性。要想确保这一点主要还是要依赖基本的功能测试其次可以考虑在核对规则中引入与灰度规则等价的条件语句并在每次灰度推进之后同步修改这个条件语句。不过这种解法一般只能用在实时或准实时核对中对离线数据的核对可能并不适用因为离线表中历史数据所遵循的灰度规则与当下的灰度规则可能是不一致的。如有需要可以通过手工单次查询离线表并结合灰度开关操作记录对结果进行判断。 最后对于灰度系统的核对规则我们还要适当提升时效性因为从发现问题效率的角度讲实时类型的核对是远优于离线与隔日核对的。灰度初期发现问题的概率更大修复的成本也更小但前提是能够及时的发现。 本章结语 灰度方案的质量保障策略与设计策略是相匹配的复杂的灰度系统设计一定会对应复杂的灰度测试方案。回到灰度本身的意义来看它本就是服务于安全生产的因此对灰度系统进行良好的全面的测试覆盖更是底线中的底线务必要作为测试工作的重点。本文在此抛砖引玉希望大家能在灰度质量保障这个话题上分享更多的经验与心得。 原文链接 本文为阿里云原创内容未经允许不得转载。
http://www.yutouwan.com/news/251001/

相关文章:

  • 怎么建立自己网站 asp小程序注册后如何注销
  • 怎么制作网站教程视频怎样做网站ppt
  • 阿里云服务器windows系统网站搭建教程百度登录个人中心
  • 分销网站建站门户站模板
  • 网站 建设 领导小组设计师学校有哪些
  • 沈阳网站建设方案服务南京的互联网公司
  • 有哪些比较好的企业网站建设wordpress网站好慢
  • 深圳手机网站连云港吧
  • 广东建设监理网站wordpress数据表大学
  • 百度做的网站 后台管理怎么进入网站模板下载百度云链接怎么做
  • 阿里云网站建设的功能企业管理软件系统有哪些
  • 网站建设按什么收费做网站的广告语
  • 网站建设 大学生创业网广州网站推广哪家强
  • 心理咨询网站建设银行个人
  • 做视频网站如何利用用户的弱点成都手工活外发加工网
  • 电子商务网站建设与管理设计报告青岛做网站大公司有哪些
  • 学校网站建设及使用塘沽网站制作公司
  • 一流的商城网站建设python基础教程第二版课后答案
  • 站长之家怎么找网址wordpress+弹窗打开
  • 怎么做网站推广世界杯郑州seo费用
  • 望牛墩镇网站建设公司软件开发案例展示
  • 深圳外贸网站建设wordpress访客
  • 如何与知名网站做友情链接百度seo关键词优化推荐
  • 你接入的网站不属于同一个主体商城英文
  • 国外好玩的网站山西工程建设招标网
  • 南通市住房城乡建设局网站企业数字展厅设计
  • 湘潭培训网站建设沁阳企业自助建站
  • 网站保留密码 怎么做大型网站制作设计
  • 广州网站建设专业乐云seo联盟营销的网络营销方式
  • 集团企业网站建设wordpress 移动版插件