如图1中在基于springcloud的微服务架构中,我们使用eureka作为注册中心,zuul作为网关,用户请求会先进入网关,网关中会通过ribbon组件缓存eureka中注册的服务列表,在
图1: 基于springcloud(eureka作为注册中心,zuul作为网关)的微服务架构图
服务列表中进行选择分发,分发到相应的服务.服务间的调用的逻辑也是类似于zuul网管的分发逻辑.当有服务有新版本或修复服务bug后,需要对原有服务进行重新发布部署,在以往我们使用传统的强制发布去发布服务,传统的发布过程如下图2
图2: 传统的服务发布过程
我们这里假设正在发布的是A服务,由于A服务在发布时kill -9 pid没有通知到eureka,euraka服务列表中暂时还会存在这个已经被杀死的服务A,当前的A服务是不可用的,那么当用户请求时如果分发到此服务将不可用,导致用户请求失败,如图3,并且在kill -9 pid结束服务进程时可能存在正在处理的业务或者功能,强制的结束会导致异常中断,脏数据等问题,如图3.
图3: A服务使用传统发布过程发布
传统的强制发布过程严重降低了服务的可用性,在生产环境中服务发布过程中对于用户的体验是极差的不能接受的!进而我们设计了一套优雅的发布过程.
预备知识
Eureka的 RestFul接口:
请求名称 | 请求方式 | HTTP地址 | 请求描述 |
查询所有服务 | GET | /eureka/apps | HTTP code为200时表示成功,返回XML/JSON数据内容 |
变更服务状态 | PUT | /eureka/apps/{appID}/{instanceID}/status?value=DOWN | 服务上线、服务下线等状态变动,HTTP code为200时表示成功 |
引用: Eureka REST operations · Netflix/eureka Wiki · GitHub
Eureka中服务的状态说明:
状态值 | 说明 |
UP | 上线服务 |
DOWN | 删除服务 |
OUT_OF_SERVICE | 将某个实例设置为暂停服务,这个和删除(DOWN)不同,如果你手动调用删除,但如果客户端还活着,定时任务还是会将实例注册上去。但是改成这个状态,定时任务更新不了这个状态 |
Kill -9 和 kill -15的区别:
9) SIGKILL
用来立即结束程序的运行. 本信号不能被阻塞、处理和忽略。如果管理员发现某个进程终止不了,可尝试发送这个信号。
15) SIGTERM
程序结束(terminate)信号, 与SIGKILL不同的是该信号可以被阻塞和处理。通常用来要求程序自己正常退出,shell命令kill缺省产生这个信号。如果进程终止不了,我们才会尝试SIGKILL。
优雅发包过程介绍
整个优雅发布的过程,如图4
图4: 优雅发布的过程
优雅发布过程是如何保证接口可用的
如图5,发布A服务的过程,优先发布’A服务-服务器1’,在优雅发布的第1-7步中服务实例都是可用的,当第7步完成后,所有的服务中(包括zuul网关)的ribbon服务列表缓存中,当前正在发布的实例的状态将会是暂停的,此时新进来的请求将不会再进入当前实例,并且当前实例的请求都应该处理完成并返回了
图5: A服务-服务器1正在使用优雅发布发布中(完成第7步后)
直到’A服务-服务器1’发布成功,’A服务-服务器1’当前服务变为可用状态,紧接着可以发布服务器2-n的A服务, 服务器2-n发布A服务时在第1-7步中服务实例都是可用的,当第7步完成后,所有的服务中(包括zuul网关)的ribbon服务列表缓存中, 服务器2-n中正在发布的实例的状态将会是暂停的,此时新进来的请求将不会再进入正在发布的实例中,并且正在发布的实例的请求都应该处理完成并返回了,如图6
图6: A服务-服务器2-n正在使用优雅发布发布中(完成第7步后)
直到所有的A服务的服务器都发布完成,新版A服务发布结束,整个过程没有请求的丢失和中断
优雅发布带来的优点和解决的痛点