# another **Repository Path**: null_236_5840/another ## Basic Information - **Project Name**: another - **Description**: 灰度策略管理器,为重构、业务迭代保驾护航。 - **Primary Language**: Java - **License**: Apache-2.0 - **Default Branch**: master - **Homepage**: None - **GVP Project**: No ## Statistics - **Stars**: 3 - **Forks**: 0 - **Created**: 2021-03-01 - **Last Updated**: 2021-12-09 ## Categories & Tags **Categories**: Uncategorized **Tags**: None ## README # another #### 你是否有以下痛点 - 基于机器进行灰度发布,灰度期限没有足够的时间,下一个需求就要上线。此时你的业务没有灰度完成,但是必须要全量发布上线,这将加大问题出现的概率风险 - 基于特定的业务范围进行了灰度,还需要在代码中进行if判定,与业务严重耦合。长时间如此的话,业务代码的可读性,可理解性差. - 业务执行频率较高,即便基于参数限定了业务范围,业务范围内发生的错误时仍然错误数据较多,错误量级仍然不可控。修复起来成本较高。比如某电商订单系统,希望对某个城市进行灰度,但是,如果程序错误,这改变不了该城市的数据仍然会出现错误.在业务量高的背景下,你仍然无法处理该城市的错误数据。 - 在业务重构或业务迭代时,没有把握,你更希望有一种机制可以帮你兜底,以做到最小损失. #### 介绍 --- Another是一套轻量、高可用、配置友好的灰度程序管理器。在业务场景迭代或重构中,我们经常的做法就是去冗余另外一个方法。提供一个新实现,并保留老的实现。在新的实现有问题的时候,我们切回老的实现,这样以求最低损失。但是,具体采用哪个实现,一般我们是写死在代码中的,或基于一些中间件存储,进行热切。配置中心被滥用。
Another所做的工作是根据规则引擎来确定一次请求到底执行新方法还是老方法,相关规则引擎的配置和执行,是完全为 灰度而生,目前,我们定义了4个维度的规则,分别是全局开关、业务入参、主机规则、频率规则.如下图所示 ![交互流程 (1)](static/1618389845800.jpg) #### 软件架构 --- ![3R](static/3RFORANOTHER.jpg) - 提供标准注解机制,解耦灰度实现 - 提供Dashboard动态发现并设定规则引擎,动态通知应用端更新 - 高可用支持:自动离线模式,支持应用在启动和运行时,不硬性依赖数据源,即便数据源不可用,应用仍然不受影响。 - 抽象规则引擎,以应对未来的多维度限定规则扩展 - 抽象Datasource,以适配多种存储中间件。目前1.0使用zookeeper实现。 #### 如何接入? --- ##### 第一步:Dashboard下载和启动 - 指定zk地址和服务端口 - --server.port 指定dashboard服务器端口 - --another.zookeeper.host 指定zookeeper地址. ```shell java -jar another-dashboard-1.0.0-SNAPSHOT-spring-boot.jar --server.port=9090 --another.zookeeper.host=127.0.0.1:2181 ``` - 启动后访问地址: - http://localhost:9090/index.html ##### 第二步:应用接入Another - 引入maven支持 TODO 等待上传中央仓库. - 注册another bean - datasource ```java @Configuration public class AnotherDatasourceIniter { //- zookeeper主机地址 @Value("${another.zookeeper.host}") private String host; //- 应用唯一名称 @Value("${another.appname}") private String appName; //- 离线存储地址,如为空,则用默认地址 @Value("${another.offlinepath}") private String offlinePath; @Bean public ZookeeperReadDataSource zookeeperDataSource(){ return new ZookeeperReadDataSource(appName,host,offlinePath); } } ``` - aop aspect ```java @Configuration public class AspectBean { @Bean public AnotherResourceAspect anotherResourceAspect(){ return new AnotherResourceAspect(); } } ``` ##### 第三步: 配置灰度资源以生效 - 方法层面标注 - @AnotherResource 用来声明一个灰度方法(老方法)。其中,name属性表示该灰度资源命名,必须在应用内唯一,anotherMethod用来标明新方法.赋值为新方法的方法名即可. - @AnotherParameterMatch 用来声明一个参数匹配,在Dashboard将会配置相应的参数规则,当参数匹配时,将会执行新方法,否则执行老方法.**其value必须在方法入参维度内唯一** ```java @Service public class TestService { @AnotherResource(name="submitorder",anotherMethod="queryOrderAnother") public void queryOrder(@AnotherParameterMatch("username") String username, @AnotherParameterMatch("mobile") Long mobile, @AnotherParameterMatch("orderMain") OrderMain orderMain){ System.out.println("执行老方法...."); } public void queryOrderAnother(String username,Long mobile,OrderMain orderMain){ System.out.println("通过another执行新方法...."); } } ``` - **注意:当实践到这里,由于后续的dashboard规则配置需要应用启动的支持,我们暂且称之为上线,也就是说,在dashboard上的应用选择和主机勾选,都是需要你来启动对应的应用主机才可以发现的。所以,当启动完dashboard以后,如果无法进行配置,请首先查看你的应用是否已经正常启动** - Dashboard层面创建一个灰度资源映射 - **全局灰度开关** : 这里表示灰度资源的执行全局开关,如关闭,则所有请求执行老方法,如打开,则全局规则校验通过 - **host规则:** host规则表示灰度资源在哪台机器上进行灰度,在host规则下,你可以全量发布你的灰度程序到所有的主机上,你要在哪台机器上进行灰度,取决于你的勾选情况。 - **频率规则**: 频率规则使得灰度策略更加精细化,控制到单位时间内可以执行的次数维度上。分为递增模式和窗口模式两种,如dashboard上提示的那样,你可以选择窗口模式,这样使得灰度资源在固定的时间内执行的频率是固定的。同样,你也可以选择递增模式,随着灰度时间变长,流量也会不断增大。 - **参数规则:** 参数规则表示在配置的入参情况下才会进行灰度策略。由于方法的入参无法穷举所有情况,所以,这里用一个JSON 来描述该入参匹配规则。详情请戳配置页面的**教我填写** ![image-20210421151750204](static/image-20210421151750204.png) #### 未来规划 - 1.0 基本灰度规则实现(待做事项) - 基本类型参数规则 DONE - match规则的帮助填写页面 DONE - dashboard match rule,condition维护的校验 DONE - 高可用,与业务分离,离线启动和加载 DONE - 打包中间件 another-all DONE - readme. - 1.1 增加流量监控与执行结果对比 - AB方法入参不一样的情况 - 新方法老方法结果对比,以应对重构模式下的重构失败入参. - 灰度上线时间监控,提醒研发人员当前已经灰度的周期 - alarm组件 - 老方法新方法执行流程统计占比 - 1.2 多数据源支持 #### 常见问题 --- - spring版本冲突问题 ``` *************************** APPLICATION FAILED TO START *************************** Description: An attempt was made to call the method org.springframework.beans.factory.annotation.AnnotatedBeanDefinition.setRole(I)V but it does not exist. Its class, org.springframework.beans.factory.annotation.AnnotatedBeanDefinition, is available from the following locations: jar:file:/Users/zhanglei10/.m2/repository/org/springframework/spring-beans/5.0.9.RELEASE/spring-beans-5.0.9.RELEASE.jar!/org/springframework/beans/factory/annotation/AnnotatedBeanDefinition.class It was loaded from the following location: file:/Users/zhanglei10/.m2/repository/org/springframework/spring-beans/5.0.9.RELEASE/spring-beans-5.0.9.RELEASE.jar Action: Correct the classpath of your application so that it contains a single, compatible version of org.springframework.beans.factory.annotation.AnnotatedBeanDefinition ``` another 采用spring 5.0.5.RELEASE.版本。如果在使用过程中出现上述异常,请排除相应冲突jar包