1、springcloud 微服务灰度发布策略
现有Spring Cloud微服务痛点
- 如果你是运维负责人,是否会经常发现,你掌管的测试环境中的服务注册中心,被一些不负责的开发人员把他本地开发环境注册上来,造成测试人员测试失败。你希望可以把本地开发环境注册给屏蔽掉,不让注册。
- 如果你是运维负责人,生产环境的某个微服务集群下的某个实例,暂时出了问题,但又不希望它下线。你希望可以把该实例给屏蔽掉,暂时不让它被调用。
- 如果你是业务负责人,鉴于业务服务的快速迭代性,微服务集群下的实例发布不同的版本。你希望根据版本管理策略进行路由,提供给下游微服务区别调用,例如访问控制快速基于版本的不同而切换,例如在不同的版本之间进行流量调拨。
- 如果你是测试负责人,希望对微服务做A/B测试,那么通过动态改变版本达到该目的。
Spring Cloud微服务痛点场景表现
(1)、基于网关(Zuul)发布策略
Nepxion Discovery是一款对Spring Cloud的服务注册发现的增强中间件,其功能包括多版本灰度发布,黑/白名单的IP地址过滤,限制注册等,支持Eureka、Consul和Zookeeper。现有的Spring Cloud微服务可以方便引入该插件,代码零侵入,使用者只需要做如下简单的事情:
-
引入相关Plugin Starter依赖到pom.xml
-
必须为微服务定义一个版本号(version),在application.properties或者yaml的metadata里
-
必须为微服务自定义一个便于为微服务归类的Key,例如组名(group)或者应用名(application),在application.properties或者yaml的metadata里,便于远程配置中心推送和灰度界面分析
-
使用者只需要关注相关规则推送。可以采用如下方式之一
-
通过远程配置中心推送规则
-
通过控制台界面推送规则
-
通过客户端工具(例如Postman)推送推测
-
简单描述一下,本系统的核心模块“基于版本控制的灰度发布”,从网关(Zuul)开始的灰度发布操作过程
-
灰度发布前
-
假设当前生产环境,调用路径为网关(V1.0)->服务A(V1.0)->服务B(V1.0)
-
运维将发布新的生产环境,部署新服务集群,服务A(V1.1),服务B(V1.1)
-
由于网关(1.0)并未指向服务A(V1.1),服务B(V1.1),所以它们是不能被调用的
-
-
灰度发布中
-
新增用作灰度发布的网关(V1.1),指向服务A(V1.1)->服务B(V1.1)
-
灰度网关(V1.1)发布到服务注册发现中心,但禁止被服务发现,网关外的调用进来无法负载均衡到网关(V1.1)上
-
在灰度网关(V1.1)->服务A(V1.1)->服务B(V1.1)这条调用路径做灰度测试
-
灰度测试成功后,把网关(V1.0)指向服务A(V1.1)->服务B(V1.1)
-
-
灰度发布后
-
下线服务A(V1.0),服务B(V1.0),灰度成功
-
灰度网关(V1.1)可以不用下线,留作下次版本上线再次灰度发布
-
可以看出微服务灰度发布大致思想
(2)、灰度发布--spring-cloud-gateway动态路由实现
网关的大致实现原理如下图:
问题
当某一天,服务1
扩展了一个新功能, 但这一部分功能只针对某一部分用户开发,抽象来说就是:请求方直接圈定了具体的服务节点
,该如何实现呢?
基于 LoadBalancerClientFilter +Ribbon 实现
springcloud-gateway+nacos 实现灰度发布_dark-CSDN博客_nacos 灰度发布
灰度发布--spring-cloud-gateway动态路由实现 - 简书
2、微服务如何优雅关闭服务
向eureka 注册中心发送delete 请求,只是取消注册服务, 当发送心跳时还是会注册到eureka
格式为 eureka地址/eureka/apps/服务名称/实例名称
请求方式为delete
下面是取消注册一个服务的例子。
下图是用postman 发送delete请求
3.通过eureka变更服务状态的方式实现服务上下线,不会再发送心跳注册到eureka server
4. 客户端主动通知注册中心下线,下线后不会再注册到eureka了
如果你的eureka客户端是是一个spring boot应用,可以通过调用以下代码通知注册中心下线。
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RestController;
import com.netflix.discovery.DiscoveryManager;
import com.shm.common.model.RespVO;
import com.shm.common.util.RespUtil;
@RestController
public class OfflineController {
@RequestMapping(value = "/offline", method = RequestMethod.GET)
public RespVO<Object> offLine(){
DiscoveryManager.getInstance().shutdownComponent();
return RespUtil.success();
}
}
5、设置服务的状态,可通过状态变更来实现再eureka的上下线
pom中加入
actuator的包
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
以上的方式都能实现服务的下线,但是有的时候只想要下线某个服务,却不需要发布,等待事情处理完成后上线此服务,则以上方式就做不到了。这时可以通过设置微服务的状态来完成此功能。项目中整合了actuator的话就非常简单了,在项目启动的时候可以看到控制台的输出:
/actuator/service-registry 可以已Get的方式获取当前服务的状态,以Post的方式修改当前服务状态,如将服务设置为Down状态,这样其他微服务接收到此状态后将不调用此服务。将order服务状态设置为Down:
看下执行后的效果:
等到流量都没有进来后,需要发布的话直接发布接口,不需要发布可以直接上线当前服务:
这样一个服务的上线和下线就优雅的完成了,如果项目中没有使用Actuator框架,可以模仿Actuator框架的实现方式,详见类:ServiceRegistryEndpoint
如果要再上线:
总结
以上几种方式都可以实现微服的下线,3和5的方式最为优雅,可以主动下线和上线,在没有新流量进来后可以随时发布,这样在也不用等到半夜12点发布了。
springcloud中微服务的优雅停机(已验证)_梦想起飞的地方.........-CSDN博客_discoverymanager