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

【转】Spring Framework灰度发布

今天简单介绍下SpringFramework微服务中几种服务发布策略以及实现方式。我接触过的有蓝绿、滚筒和灰度发布。

 

蓝绿发布:

简单说就像美帝选总统投票一样,非蓝即绿一刀切,这个其实也是传统软件架构最常使用的升级方式,只不过服务需要重启才能生效,而在微服务中这种部分节点的替换是热部署上去的。

微服务中的蓝绿部署依赖的是Spring Cloud Zuul + Spring Cloud Config + Spring Cloud Eureka,实现方式如下:

我准备了5个节点:

1 GreenBlue-Config-server:配置注册中心

配置文件application.yml如下:

server:
port: 8090

spring:
cloud:
config:
server:
git:
uri: https://github.com/yejingtao/forblog
search-paths: /config
username: username
password: username
application:
name: greenblue-config-server

eureka:
client:
serviceUrl:
defaultZone: http://peer1:1111/eureka/,http://peer2:1112/eureka/
2 GreenBlue-Zuul: API网关

配置文件bootstrap.properties如下:

spring.application.name=greenblue-zuul
spring.cloud.config.profile=dev
spring.cloud.config.label=master
server.port=7002


eureka.client.serviceUrl.defaultZone=http://peer1:1111/eureka/,http://peer2:1112/eureka/

spring.cloud.config.discovery.enabled=true
spring.cloud.config.discovery.serviceId=greenblue-config-server

management.security.enabled=false
3 GreenBlue-Eureka:服务注册中心,peer1、peer2做了高可用性

4 GreenBlue-Service-green:绿营服务端,application-name=greenblue-service-green

5 GreenBlue-Service-blue:蓝营服务端,application-name=greenblue-service-blue

另外git仓库上文件名为greenblue-zuul-dev.properties的内容只有2行:

zuul.routes.user-service.path=/api-service/**
zuul.routes.user-service.serviceId=greenblue-service-blue
(PS:本案例只能演示蓝绿部署如何割接不能直接用于生产,因为生产上还需要做蓝绿服务节点的高可用性、Spring Cloud Bus的配置推动、每个节点环境参数的Config统一管理、Zuul鉴权过滤、config-server安全控制等)

节点部署与发布如下:

 

验证步骤:

1 git仓库中边缘服务网关/api-service配置成blue,green节点不需要部署和启动,此时通过zuul访问/api-service是blue提供的服务

 

2部署green并注册到eureka上,我们要用它替换blue

3 git仓库中的/api-service配置改成green,同时调用zuul服务的refresh方法使修改生效

 


蓝绿方式的优点是:一旦新服务green发现有bug或其它问题,我们可以重新切换回blue,由于blue没有被我们动过一丝一毫所以我可以认为这次服务的回滚是绝对安全的(数据回滚等除外),当我们将新服务green修复好后又可以最快的速度最小的代价发布上去!

蓝绿方式也有明显的缺陷,如果要发布的节点不是边缘服务、或者被其它节点以Eureka上注册的服务名的方式访问,如图:

 

如果我们要做Service-BlueB的升级就会很麻烦,但是路子还是有的:

 


需要多部署一套完整的拓扑才可以满足单独一个节点升级。

所以蓝绿方式的缺点也很明显:会造成硬件资源的浪费,极端情况下我们需要2套硬件资源(取决于系统的拓扑设计和服务拆分,2倍是上限)

 

 

滚筒发布:

滚筒发布与蓝绿发布一刀切的概念完全相反,像轮子一样一圈圈的往前滚,先替换一批节点,观察一段时间,确认没问题后再替换其他的节点。滚筒发布的先决条件是节点必须高可用性,也就是说在替换过程中要保留未被替换的节点继续提供旧服务。

我的节点拓扑如下:

 

 

滚筒发布完全依赖Eureka,所以为了避免混淆我这里将Zuul和config都去掉了,我现在的目的要将Roll-Service-V2版本发布上去。

1我先将Roll-Service-V1的部分节点下线

2将下线的这个节点进行线下升级,将补丁包、新版本之类的升级上去

3再将升级后的V2版本注册到Eureka上

 

4观察一段时间确定V2版本OK后,再将剩下的V1版本按批次用相同的方式部署发布。

 

滚筒发布有3个优点:1,机器利用率100%,没有硬件上的浪费;2,发布过程平滑,新老功能会并行一段时间;3,对节点服务做精确升级

滚筒发布也有3个缺点:1,发布步骤相对比较繁琐; 2,新版本出现问题不能及时回滚,回滚过程其实也是个滚筒发布的过程; 3节点达到一定数量后滚筒发布就会变得很无力,要滚好几次。

 

灰度发布:

灰色,黑白之间的颜色,如果旧版本为白新版本为黑,灰度发布就是由白变黑的渐进过程。寻龙诀电影里黄渤在下洞盗墓之前会弄个鸟笼里面关着个金丝雀,从洞口到墓底慢慢放下去,洞口为白墓底为黑,放到底金丝雀不死,发布成功。放到一半金丝雀不叫了,发布失败,放弃本次盗墓(扯多了)。

灰度发布的核心是Eureka+客户端负载均衡,发布过程直接上图:

 

将V2以相同的服务名注册到Eureka上利用Ribbon等客户端负责均衡技术就可以请求得到这个新版本,如图如果客户端使用的轮询策略那相当于对版本升级了25%,如果V2版本这25%的功能稳定没问题了可以按硬件条件继续添加新V2节点或者下线老V1版本直到100%。假如升级到50%我们发现V2版本有重大Bug,直接停掉所有V2服务,剩下50%V1版本短时间内仍可以提供稳定的服务。

如果说V2版本升级100%了需要回滚怎么办?黄渤发现金丝雀到了洞底后扔活蹦乱跳于是跳了下去结果自己被毒死了。这种情况一般要迅速部署几个V1版本的节点注册到Eureka上,同时下线V2节点,能不能抢救的回来看对业务影响多大了。

 

灰度发布的特点:1,发布过程平滑,进退自如 2,需要冗余的硬件,但不需要像蓝绿那么多。

 

这三种热部署发布方式没有好坏之分,完全根据自己的硬件条件和业务场景来选择,而且同一个大服务群中可以对不同的微服务模块使用不同的发布方式。个人比较推崇灰度发布,硬件要求不高,易操作,升级平滑。

 

 

最后了解下SpringFramework框架下服务节点如何下线:

大方向上分为Eureka注册端下线和节点服务自下线两种。

1 Eureka注册端下线:

$ curl -X PUT "http://peer2:1112/eureka/apps/HELLO-SERVICE/localhost:hello-service:8081/status?value=OUT_OF_SERVICE"
变量对应下图一看便知:

 

执行成功后服务会尝试设置为下线,下线成功后Eureka中服务状态会发生变化:

 


过15秒左右client客户端已经不会再分发到该OUT节点上了。此时可以把节点从Eureka上注销掉

$ curl -X DELETE "http://peer2:1112/eureka/apps/HELLO-SERVICE/localhost:hello-service:8081 "


此时微服务节点算是完全的隔离出来了,要杀要剐随你便了。

(PS:如果OUT_OF_SERVICE后没删除之前后悔了,可以将命令中Status改为UP执行下就好)

 

2 节点端服务下线

利用了Spring Boot Actuator的shutdown命令

Pom依赖添加actuator

配置添加endpoints.shutdown.enabled = true

对要下线的节点执行命令curl -X POST host:port/shutdown

 

个人推崇第一种方式,因为第二种方式很不安全,虽然可以进行权限控制,但是Eureka自带的功能那么好为啥还要另辟蹊径呢。
---------------------
作者:牛麦康纳
来源:CSDN
原文:https://blog.csdn.net/yejingtao703/article/details/78562895
版权声明:本文为博主原创文章,转载请附上博文链接!

相关文章:

  • 配置linux实现路由功能
  • Algs4-1.2.19字符串解析
  • 深度学习工程模板
  • Spring Framework 4.2 中的新功能和增强功能
  • vue build后。静态资源的404问题探究,解决
  • nginx启动失败问题集锦
  • 第2章 变量和基本类型 附2 --声明和定义的区别
  • MySQL,binlog2sql回滚操作测试
  • 2015年9月30日的作业
  • 201771010126 王燕《面向对象程序设计(Java)》第九周学习总结
  • icomoon用法
  • [BZOJ] 2044: 三维导弹拦截
  • this class is not key value coding-compliant for the key XXX错误的解决方法
  • JavaSE小实践1:Java爬取斗图网站的所有表情包
  • LeetCode——Implement Trie (Prefix Tree)
  • 2017 前端面试准备 - 收藏集 - 掘金
  • Angular 响应式表单 基础例子
  • co.js - 让异步代码同步化
  • JAVA SE 6 GC调优笔记
  • Node项目之评分系统(二)- 数据库设计
  • Python实现BT种子转化为磁力链接【实战】
  • TiDB 源码阅读系列文章(十)Chunk 和执行框架简介
  • windows-nginx-https-本地配置
  • 看完九篇字体系列的文章,你还觉得我是在说字体?
  • 可能是历史上最全的CC0版权可以免费商用的图片网站
  • 区块链共识机制优缺点对比都是什么
  • 入门级的git使用指北
  • 使用前端开发工具包WijmoJS - 创建自定义DropDownTree控件(包含源代码)
  • #pragam once 和 #ifndef 预编译头
  • #pragma data_seg 共享数据区(转)
  • (每日持续更新)信息系统项目管理(第四版)(高级项目管理)考试重点整理第3章 信息系统治理(一)
  • (免费领源码)python+django+mysql线上兼职平台系统83320-计算机毕业设计项目选题推荐
  • (七)c52学习之旅-中断
  • (一)80c52学习之旅-起始篇
  • ****Linux下Mysql的安装和配置
  • .NET DataGridView数据绑定说明
  • .NET 程序如何获取图片的宽高(框架自带多种方法的不同性能)
  • .NET 动态调用WebService + WSE + UsernameToken
  • .NET设计模式(8):适配器模式(Adapter Pattern)
  • .skip() 和 .only() 的使用
  • /proc/stat文件详解(翻译)
  • @Conditional注解详解
  • @converter 只能用mysql吗_python-MySQLConverter对象没有mysql-connector属性’...
  • [3D游戏开发实践] Cocos Cyberpunk 源码解读-高中低端机性能适配策略
  • [Angular 基础] - 数据绑定(databinding)
  • [BUUCTF 2018]Online Tool(特详解)
  • [BZOJ4010]菜肴制作
  • [C#]winform制作仪表盘好用的表盘控件和使用方法
  • [codeforces]Checkpoints
  • [Excel VBA]单元格区域引用方式的小结
  • [flask] flask的基本介绍、flask快速搭建项目并运行
  • [HTML]Web前端开发技术29(HTML5、CSS3、JavaScript )JavaScript基础——喵喵画网页
  • [ICCV2017]Neural Person Search Machines
  • [JS] node.js 入门
  • [leetcode] Longest Palindromic Substring