设计模式学习笔记 - 项目实战三:设计实现一个支持自定义规则的灰度发布组件(分析)

概述

到现在为止,我们已经学习了接口限流框架和接口幂等框架两个实战项目。接下来,再带你实战一个新的项目:灰度发布组件。这是最后一个实战项目。还是老套路,把它分为分析、设计、实现三个部分,对应三篇文章来讲解。本章,我们对灰度发布组件进行需求分析,搞清楚这个组件应该具有哪些公功能性需求和非功能性需求。


需求场景

还记得之前接口限流和幂等框架的项目背景吗?我们开发了一个公共服务平台,提供公共业务功能,给其他产品的后端系统使用,避免重复开发相同的业务。

最初,公共服务平台提供的是,基于某个开源 RPC 框架的 RPC 格式的接口。在上线一段时间后,发现这个开源 RPC 框架的 Bug 很多,多次因为框架本身的 Bug,导致整个公共服务平台的接口不可用,但因因为团队成员对框架源码不熟悉,并且框架的代码质量本身也不高,排查、修复起来花费了很长时间,影响面非常大。所以,评估下来之后,决定最终替换掉它。

对于引入新框架,我们的要求是成熟、简单,并且与我们现有的技术栈(Spring)相吻合。这样,即便除了问题,我们也能利用之前积累的知识、经验来快速解决。所以,我们决定直接使用 Spring 框架来提供 RESTful 格式的远程接口。

把 RPC 接口替换成 RESTful 接口,除了需要修改公共服务平台的代码之外,调用方的接口调用代码也要做相应的修改。此外,对于公共服务平台的代码,尽管我们只是改动接口暴露方式,对业务代码基本上没有改动,但是,我们也并不能保证就完全不出问题。所以,为了保险起见,我们希望灰度替换掉老的 RPC 服务,而不是一刀切。

我们来看下具体如何来做。

因为替换的过程是灰度的,所以老的 RPC 服务不能下线,同时还要部署另外一套新的 RESTful 服务。我们先让业务不是很重要、流量不大的某个调用方,替换成调用新的 RESTful 接口。经过这个调用方一段时间的验证之后,如果新的 RESTful 接口没有问题,我们再逐步让其他调用方,替换成调用新的 RESTful 接口。

但是,如果万一中途出现问题,我们就需要将调用方的代码回滚,再重新部署,这就会导致调用方一段时间内服务不可用。而且,如果新的代码还包含调用方自身新的业务代码,简单通过 Git 回滚代码重新部署,会导致新的业务代码也被回滚。所以,为了避免这种情况发生,我们就得手动将调用新的 RESTful 接口的代码删除,再改回为调用老的 RPC 接口。

此外,为了不影响调用方本身业务的开发进度,调用方基于回滚之后的老代码,来做新功能开发,那替换成 RESTful 接口的那部分代码,要想再重新 merge 回去就比较难了,有可能会出现代码冲突,需要再重新开发。

怎么解决代码回滚成本比较高的问题呢?

在替换新的接口调用方式时,调用方不用直接将 RPC 接口的代码逻辑删除,而是新增调用 RESTful 接口的代码,通过一个功能开关,灵活切换走老的代码逻辑。代码示例如下所示。如果 callRestfulApi 为 true,就会走新的代码逻辑,调用 RESTful 接口,相反,就会走老的代码逻辑,继续调用 RPC 接口。

boolean callRestfulApi = true;
if (!callRestfulApi) {
	// 老的调用RPC接口的代码逻辑
} else {
	// 老新调用RESTful接口的代码逻辑
}

不过,更改 callRestfulApi 的值需要修改代码,而修改代码需要重新部署,这样的设计还不够灵活。优化的方法是,把这个值放到配置文件或者配置中心就可以了。

为了更加保险,不只是使用功能开关做新老接口调用方式的切换,我们还希望调用方在替换某个接口时,先让小部分接口请求,调用新的 RESTful 接口,剩下的大部分接口请求,还是调用老的 RPC 接口,验证没问题后,在逐步加大调用新接口的比例最终,将所有的接口请求都替换成调用新的接口这就是所谓的 “灰度”

那这个灰度功能又该如何实现呢?

首先,我们要决定使用什么来做灰度,也就是灰度的对象。我们可以针对携带时间戳信息、业务 ID 等信息,按照区间、比例或者具体的值来做灰度。我举个例子来解释下。

假设,我们要灰度的是根据用户 ID 查询用户信息接口。接口请求会携带用户 ID 信息,所以,我们可以把用户 ID 作为灰度的对象。为了实现逐渐放量,我们先配置用户 ID 是 918、879、123(具体的值)的查询请求调用新接口,验证没有问题之后,再扩大范围,让用户 ID 再 1020~1120 (区间值)之间的查询请求调用新接口。

如果验证之后还是没有问题,我们再继续扩大范围,让 10%(比例值)的查询请求调用新接口(对应用户 ID 跟 10 取模求余小于 1 的请求)。依此类推,灰度范围逐步扩大到 20%、30%、50% 直到 100%,并且运行一段时间没有问题之后,调用方就可以把老代码逻辑删除了。

实际上,类似的灰度需求场景还是很多的。比如,在金融产品的清结算系统中,我们修改了清结算的算法。为了安全起见,我们可以灰度替换新的算法,把贷款 ID 作为灰度对象,先对某几个贷款应用新的算法,如果没有问题,再继续按照区间或者比例,扩大灰度范围。

此外,为了保证万无一失,提前做好预案,添加或修改一些复杂功能、核心功能,即便不做灰度,我们也建议通过功能开关,灵活控制这些功能的上下线。在不需要重新部署或重启系统的情况下,做到快速回滚或新老代码逻辑的切换。

需求分析

从实现角度来讲,调用方只需要把灰度规则和功能开关,按照某种事先约定好的格式,存储到配置文件或者配置中心,在系统启动时,从中读取配置到内存后,看灰度对象是否落在灰度范围内,依此来判定是否执行新的代码逻辑。但为了避免每个调用方都重复开发,我们把功能开关和灰度相关的代码,抽象封装为一个灰度组件,提供给各个调用方来服用。

这里需要强调一点,这里的灰度,是代码级别的灰度,目的是保证项目质量,规避重大代码修改带来的不确定性风险。实际上,我们平时经常将的灰度,一般都是产品层面或者系统层面的灰度。

  • 所谓产品层面,有限类似 A/B Testing,让不同的用户看到不同的功能,对比两组用户的使用体验,收集数据,改进产品。
  • 所谓系统层面的灰度,往往不在代码层面上实现,一般是通过配置负载均衡或者 API-Gateway,来实现流量分配到不同版本的系统上。

系统层面的灰度是为了平滑上线功能,但比起我们讲到的代码层面的灰度,就没有那么细粒度了,开发和运维成本也相对要高些。

现在,我们就来具体看下,灰度组件有哪些功能性需求。

我们还是从使用的角度来分析。组件使用者需要设置一个 key 值,来唯一标识要灰度的功能,然后根据自己业务的特点,选择一个灰度对象(比如用户 ID),在配置文件或者配置中心,配置这个 key 对应地灰度规则和功能开关。配置的格式类似下面这个样子。

features:
- key: call_newapi_getUserById
  enabled: true // enabled为true时,rule才生效
  rule: {893,342,1020-1120,%30} // 按用户ID来做灰度
- key: call_newapi_registerUser
  enabled: true
  rule: {1391198723, %10} // 按手机号来做灰度
- key: newlog_loan
  enabled: true
  rule: {0-1000} // 按照贷款的金额(loan)来做灰度

灰度㢟在业务系统启动时,会将这个灰度配置,按照实现定义的语法,解析并加载到内存对象中,业务系统直接使用组件提供的灰度判定接口,来判定某个灰度对象是否灰度执行新的代码逻辑。配置的加载、灰度判定逻辑这部分代码,都不需要业务系统来从零开发。

public interface DarkFeature {
	boolean enabled();
	boolean dark(String darkTarget); // darkTarget 是灰度对象,比如前面提到的用户ID、手机号码、金额等
}

所以,总结一下的话,灰度组件跟限流框架很类似,它也主要包含两部分功能:灰度规则配置解析和提供编程接口(DarkFeature)判定是否灰度。

跟限流框架类似,除了功能性需求,我们还要分析非功能性需求。不过,因为前面已经有了限流框架的非功能性需求的讲解,对灰度组件的非功能性需求,其实和它类似,你可以先自己分析下。在下篇文章,到时再给出分析思路。

总结

灰度发布可以分为三个层面的灰度:产品层面的灰度、系统层面的灰度和代码层面的灰度。本章重点讲解代码层面的灰度,通过编程来控制是否执行新的代码逻辑,以及灰度执行新的代码逻辑。

代码层面的灰度,主要解决代码质量问题,通过逐渐放量灰度执行,两降低重大代码改动带来的风险。在出问题之后,在不需要修改代码、重新部署、重启系统的情况下,实现快速的回滚。相对于系统层面的灰度,它可以做的更加细粒度,更加灵活、简单、好维护,但也存在着代码侵入的问题,灰度代码跟业务代码耦合在一起。

灰度组件跟之前讲过的限流框架类似,主要包含配置的解析加载和灰度判定逻辑。此外,对于非功能性需求,在下篇文章讲解。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mfbz.cn/a/583387.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

谈谈进些年的BLE开发项目

加zkhengyang可申请加入蓝牙音频研究开发交流答疑群(课题组) 最早接触BLE项目是在做一款女性按摩器产品上,所谓的生活用品,用的是TI CC2640,资料齐全,上手快,配合手机app通讯开发,当然这个是单模的蓝牙芯…

学习C语言的指针

有一阵没更新了,因为最近比较繁忙,所以更新比较慢,还在慢慢学习 话不多说,开始今天的内容,聊一聊C语言指针。 很多小伙伴可能会被指针这个名字吓到,觉得很难,实际上确实有点难,但是…

cesium教程

环境搭建 vscode安装Visual Studio Code - Code Editing. Redefined nodejs安装Node.js — Run JavaScript Everywhere cesium源码下载编译 cesium官网下载源码https://cesium.com/downloads/ 解压下载的源码 VsCode打开远吗,找到index.html,右键打开 Open wit…

职场人是如何被拉开差距的?

事实上,职场人的差距从第一天就拉开了。 心理学里有一个词,叫做“首因效应,说的是人们在第一次接触时形成的印象,将会决定后续认知的基调。 入职第一天,从自我介绍开始,展示自己的特长,给大家…

unity项目《样板间展示》开发:菜单界面

unity项目《样板间展示》开发:菜单界面 前言UI菜单创建逻辑实现结语 前言 这是这个项目demo教程的最后一节,这节是菜单界面部分的创建 UI菜单创建 创建一个新的场景,在Scene文件中右键选择Create->Scene,创建新的场景 在场景…

【服务器部署篇】Linux下快速安装Jenkins

作者介绍:本人笔名姑苏老陈,从事JAVA开发工作十多年了,带过刚毕业的实习生,也带过技术团队。最近有个朋友的表弟,马上要大学毕业了,想从事JAVA开发工作,但不知道从何处入手。于是,产…

Elasticsearch实现hotel索引库自动补全、拼音搜索功能

Elasticsearch实现hotel索引库自动补全、拼音搜索功能 在这里边我们有两个字段需要用拼音分词器,一个name字段,一个all字段。 然后我们还需要去实现自动补全,而自动补全对应的字段必须使用completion类型。目前我们酒店里面所有的字段都采用的…

暴雨信息| AI“速”不可挡,倒逼算力巨变!

「 “当某一天人工智能的智慧超越人类,你会发现人工智能将会以迅雷不及掩耳之势改变世界,那个改变是不可逆的,极其迅速。” 」 暴雨信息副董事长孙辉在“IPF2024”上的这个观点,正是当今世界在AI影响下急速前行的真实写照。 记得…

高压、单通道、轨对轨输入输出功率运算放大器RS8471

RS8471是一款高压、单通道、轨对轨输入输出的功率运算放大器,它的工作电压范围在4.5V到24V,最大峰值输出电流2.5A,失调电压为3mV,增益带宽积为25MHz,并提供65V/us的高压摆率,确保输出信号快速建立”,这些特…

[Java EE] 多线程(五):单例模式与阻塞队列

1. 单例模式 单例模式是校招中最长考的设计模式之一,首先我们来谈一谈什么是设计模式: 设计模式就好像象棋中的棋谱一样,如果红方走了什么样的局势,黑方就有一定地固定地套路,来应对这样的局势,按照固定地套路来,可以保证在该局势下不会吃亏. 软件开发也是同样的道理,有很多…

(十二)Servlet教程——HttpServletResponse接口

HttpServletResponse接口继承自ServletResponse接口,HttpServletResponse用来封装HTTP响应消息,简称response对象。 每次请求一个Servlet,Servlet容器就会针对每次请求创建一个response对象,并把它作为参数传递给Servlet的service…

Linux网络-文件传输协议之FTP服务(附带命令及截图)

目录 一.FTP简介 二.FTP的数据模式 1.主动模式 2.被动模式 3.两种模式比较 三.安装配置vsftpd 1.安装vsftpd 1.1.安装前关闭防火墙 1.2.安装vsftpd 1.3.查看 1.4.备份 2.配置 3.重启后生效 四.相关实验 1.以win为例 1.1.设置并测试测试连通性 1.2.在终端里创建…

js逆向进阶篇-某团酒店

提示!本文章仅供学习交流,严禁用于任何商业和非法用途,未经许可禁止转载,禁止任何修改后二次传播,擅自使用本文讲解的技术而导致的任何意外,作者均不负责,如有侵权,可联系本文作者删除! 案例分析: 先来看看请求中有哪些参数是需要我们逆向,如下: mtgsig、fp、roh…

Java包装类,128陷阱

包装类 基本数据类型都有自己对应的包装类,因为Java本质是面向对象编程的,一切的内容在Java看来都是对象 但是基本数据类型没有类,也没有对象,这样就有了矛盾 所以诞生了基本类型的包装类 基本数据类型: byte,short,…

知乎热议:未来几年,AI技术在科研领域将有哪些新的发展趋势或突破?

我是娜姐 迪娜学姐 ,一个SCI医学期刊编辑,探索用AI工具提效论文写作和发表。 一年多以来,各种国内外的AI模型和应用应接不暇,从刚开始ChatGPT一家独大,到现在的百花齐放,各种AI模型各有千秋,一时…

星尘智能 AI 机器人 S1——国产机器人的巅峰之作

AI智能机器人真的太炸裂了 国产科技威武-CSDN直播AI智能机器人真的太炸裂了 国产科技威武https://live.csdn.net/v/382519 最近发现了一个国产的机器人,真的让人惊叹不已!它就是星尘智能 AI 机器人 S1! 这个机器人简直太牛逼了!…

Stable Diffusion 参数介绍及用法

大模型 CheckPoint 介绍 作用:定调了作图风格,可以理解为指挥者 安装路径:models/Stable-diffusion 推荐: AnythingV5Ink_v32Ink.safetensors cuteyukimixAdorable_midchapter2.safetensors manmaruMix_v10.safetensors counterf…

2024年的Java版本选择?java 17 安装

文章目录 2024年的Java版本选择?java 1.8 和 java17 什么区别?java 17 安装windows 11安装java 17C:\Program Files\Common Files\Oracle\Java\javapath是什么 2024年的Java版本选择? 3年前,java 1.8是市场主流(还有一…

STM32用HAL库函数实现硬件IIC

/*出处:【STM32入门教程-2024】第12集 IIC通信与温湿度传感器AHT20(DHT20)_哔哩哔哩_bilibili */ AHT20驱动 这篇笔记我主要介绍代码实现,想要了解原理的请自己看视频,我不过多赘述了。 AHT20通信数据帧格式: ①对照手册上的通…

面对网络安全,做好风险评估对企业会带来哪些帮助

随着信息技术的飞速发展,网络安全问题日益凸显,成为企业不容忽视的重要议题。企业作为社会经济活动的主要参与者,其网络安全不仅关系到自身的生存与发展,更与国家的经济安全、社会稳定息息相关。因此,企业必须高度重视…
最新文章