开发者学堂课程【微服务框架 Spring Cloud 快速入门:服务降级】学习笔记与课程紧密联系,让用户快速学习知识
课程地址:https://developer.aliyun.com/learning/course/614/detail/9363
服务降级
内容介绍
一、服务降级是什么
二、服务降级处理
三、接口处理
四、测试
一、服务降级是什么
1、整体资源快不够了,忍痛将某些服务先关掉,待渡过难关,再开启回来,这就是降。
2、假设现在有三个项目组,都很平等,每个项目组有五个开发兄弟,分别是a组,b组,c组,abc三个系统都有对应的服务来访问,突然老板由于客户变动极其重视a系统,现在a系统访问的压力极大,现在五个程序员扛不住,从保证优先级的角度,那么a系统的项目经理是不是只好求老大从系统c借调对应的工程师,整体资源快不够了,比方a或者是大系统,需要像弹性云一样,平时它只需50这个数量,现在某一个时间段非常高,它像有一个弹性一样嫌忙分开,就需要从其他项目组借调一些程序员,假设 a 项目组从 c 借调了4个程序员,所以c就只剩下一个程序员勉强维持,忍痛让 c 先暂时关闭,a 现在是保障了,但是c回,还有些部分服务和请求在发送着,这就好比银行 abc 三个窗口,现在c窗口4个业务员要去干别的事,那么这个窗口只好挂一个牌子暂停服务,不能给调动者一点说明都没有,否则调动者会生气,所以为了保证其他的,假设先把c关闭渡过难关之后,c 支援其他的,c 被关闭之后表示这个服务暂时不可用,它的系统资源节约出来去给 a,但是 c 是还有一堆老客户来找它,那么就应该给老客户一个回应,一个友好的降级处理,保证服务和维系,之后等 a 度过难关之后,再回来重新开启 c,这就是资源抢占和分配的问题。
二、服务降级处理
1、服务降级处理是在客户端实现完成的,与服务端没有关系。把c当做一个银行窗口,贴个牌子写着暂停服务,服务降级降了 c 的,它降了之后把资源节约出来去支援别的,像弹性云一样的概念。
2、Fallbackmethod 兜底的处理异常,处理超时,不顺利情况的一个处理方法,但是业务方法 get,再加一个其他的,导致每一个真是的业务方法都会有一个兜底处理异常的 fallbackmethod 方法,这会带来两个问题。
(1)方法膨胀,有一个 get 方法做真实的业务逻辑处理,必然会有一个针对于 get的fallbackmethod 方法,假设下面有一个 update 方法,那就会有 fallbackmethod 方法,那么加一个业务逻辑方法,就要加一个@hystrixcommand,容易方法膨胀。
(2)第二个根据 spring 原则,aop 面向切面的编程,这个技术叫 spring cloud,只要是 spring 的思想概念都可以用,现在是把主干的业务逻辑和处理异常的切面整合在一起,它们产生的高耦合,在学 spring 的时候面向切面的时候学过至若前置通知,后置通知,环绕通知,异常通知,把前面的方法整理出来一个意思,@HystrixC ommand(fallbackMethod = " processHystrix_Get" )它就是一个异常通知的处理,最好实现一种效果就是业务方法跟异常处理不要耦合在一起,这里面应该还是干干净净的主逻辑方法,所以要借鉴这种思想完成新的内容,实现解耦和分离,假设有10个业务逻辑方法,对应的也要加上10个@hystrixcommand注解。第一个方法膨胀,第二个处理异常和业务逻辑绑定在一起,高耦合。
三、接口处理
1、这些方法要调用接口才能用,如果@hystrixcommand调用异常的方式熔断的处理方式通通在接口绑定,就可以跟主逻辑解耦。
2、修改 microservicecloud-api 工程,根据已经有的 DeptClientService 接口新建一个实现了 FallbackFactory 接口的类 DeptClientServiceFallbackFactory。向调用方返回一个符合预期的、可处理的备选响应(FallBack),而不是长时间的等待或者抛出调用方无法处理的异常会进行服务的降级,进而熔断该节点微服务的调用,快速返回”错误”的响应信息。
public interface DeptService
{
public boolean add(Dept dept);
public Dept get(Long id);
public List<Dept> list();
}
这个接口里面也有这些方法,这是以前的 DeptService,也借复制一份,重新叫DeptClientService,这个里面也是有这一堆方法,这一堆方法里面来进行针对每一个方法在接口上写熔断处理,这样就跟主程序解耦了。这是第一步。
主程序代码如下:
@RestController
public class DeptController
@Autowired
private DeptService service = null;
@RequestMapping(value = "/dept/get/(id]", method = RequestMethod . GET)
//一旦调用服务方法失败并抛出了错误信息后,会自动调用 @Hystr ixCommand 标注好的fallbackMethod 调用类中的
@HystrixCommand(fallbackMethod = "processHystrix_ Get")
public Dept get(@PathVariable("id") Long id)
{
Dept dept = this . service. get(id);
if (null == dept) {
throw new RuntimeException
("该D: " + id + "没有没有对应的信息");
}
return dept;
3、Api 是公共接口,点击 service,有个 DeptClientService,之前在讲feign的时候写过了,现在可能在 controller 调用 get 方法出错,get 方式实质上也就是调用service 接口,为了解耦直接在DeptClientService做动作,修改 microservicecloud-api 工程,根据已经有的 DeptClientService 接口,新建一个实现了 FallbackFactory 接口的类 DeptClientServiceFallbackFactory。
在service下新建一个类叫 DeptClientServiceFallbackFactory这个名字。
这个类要实现 implements FallbackFactory 这个接口,而这个接口里面要实践DeptClientService 接口。
代码如下:
public class DeptClientServiceFallbackF actory implements FallbackFactory<DeptClientService>
针对于这个 DeptClientService 接口里面的方法进行服务的降级处理,比方现在不想在 get 的方法的上面标着@Hystr ixCommand( fallbackMethod = " processHystrix Get"),把它提到接口上,针对于这个接口,新建了DeptClientServiceFallbackF 这个类,它要实现 FallbackFactory 接口,Fallback 叫备选相应,FallbackFactory 这个里面只有一个未实现方法叫 create,针对于DeptClientService,输入以下代码:
public class DeptClientServiceFallbackFactory implements FallbackFactory<DeptClientService>
{
@Override
public DeptClientService create(Throwable cause)
{
return new DeptClientService() {
@Override
public List<Dept> list()
return null;
}
@Override
public Dept get(long id)
{
return null;
}
@Override
public boolean add(Dept dept)
{
return false;
}
};
相当于 DeptClientService 里面带着 get,add,list,就是通过 DeptClientService这个接口要调用的方法,每一个熔断机制都放在这个类里面处理,就实现了跟前面hystrixcommand 进行解耦。
注意:千万不要忘记在 DeptClientServiceFallbackFactory 类上面新增@Component 注解。否则不好使。
新建一个类 DeptClientServiceFallbackFactory,这个类要实现 FallbackFactory接口,由它统一来处理熔断,对 DeptClientService 接口,这个接口里面有增删改查的方法,FallbackFactory 这个接口里面只有一个 create,针对 DeptClientService创造熔断,没有对应的信息,Consumer 客户端提供的降级信息,此刻服务 Provider 已经关闭,现在要模拟的情况就是之前的把c暂停服务,假设查c get不好使,那么这时应该给一个回应,那么这个回应写的信息就故意写成这样,就是说待会忍痛将某些服务先关掉,会主动的关掉微服务,但是现在还模拟有其他用户请求来调用已经被关掉的微服务应该怎么办?那么这个时候return new Dept() . setDeptno( id) . setDname("该ID:”+ id + "没有对应的信息,Consumer 客户端提供的降级信息,此刻服务Provider已经关闭. setDt source("no this database in MySQL");这句话就会弹出来。
代码如下:
package com.atguigu.springcloud. service;
import java.util.List;
import org.springframework.stereotype.Component
import com.atguigu.springcloud.entities.Dept;
import feign.hystrix.FallbackFactory;
@Component
/不要忘记添加,不要忘记添加
public class DeptClientServiceFallbackFactory implements FallbackFactorycDeptclientService>
{
@override
public DeptClientService create(Throwable throwable)
{
return new DeptClientService(){
@override
public Dept get(long id)
{
return new Dept().setDeptno(id).setDname
("该ID: " +id +“没有没有对应的信息,Consumer客户端提供的降级信息,此刻服务Provider已经关闭”)
.setDb_source("no this database in MySQL");
}
@Override
public List<Dept> list()
{
return null;
}
@override
public boolean add(Dept dept)
{
return false;
}
};
}
是针对下面服务做服务降级处理
@FeignClient(value="MICROSERVICECLOUD -DEPT")
public interface DeptClientService
{
@RequestMapping(value = "/dept/get/{id}", method = RequestMethod.GET)
public Dept get(@PathVariable("id") long id);
@RequestMapping(value = "/dept/list", method = RequestMethod.GET)
public List<Dept> list();
@RequestMapping(value = "/dept/add",method = RequestMethod.PoST)
public boolean add (Dept dept);
}
4、修改 api 工程,DeptClientService 这个接口,昨天讲 feign 时是针对MICROSERVICECLOUD-DEPT 这个微服务加上 feign 的功能,那么现在加上服务熔断,在注解@FeignClient中添加 fallbackFactory 属性值。又添加了DeptClientServiceFallbackFactory要重新 Client 因素,重新打包 api 给别人调用,切记不像用get方法添加一个hystrixcommand要实现解耦,用spring面向切面编程的置入加异常通知,避免代码膨胀和业务逻辑和异常处理分离,不想一个方法添加一个,这些方法都是接口来的,所以针对接口,有三个或三十个出事了找fallbackFactory,fallbackFactory有DeptClientServiceFallbackFactory,因为它是负责收尾的,那么list和add不写了,只写一个get演示。右键点击api,clean,可以看到success,再install,可以再次看到success,现在又多了两个功能。
5、microservicecloud-consumer-dept-feign 工程修改YML
代码如下:
server:
port: 80
修改部分,添加进来
feign:
hystrix:
enabled: true
eureka:
client:
register-with-eureka: false
service-url:
defaultZone: http://eureka7001.com:7001/eureka/ ,http:/leureka7002.com:7002/eurek a/ ,http: / /eureka7003.com:7003/euneka/
四、测试
1、3个eureka 先启动
微服务microservicecloud-provider-dept-8001启动
microservicecloud-consumer-dept-feign启动
共计五个工程,
4、正常访问测试
http://localhost/consumer/dept/get/1
{" deptno" : 1,"dname" :"开发部", "db_source" :"clouddb01"}
代表访问成功
{' deptno" :2, "dname":^"该ID:2没有没有对应的信息, Constumer客户端提供的降级信息,此刻服务Provider已经关闭" , "db_source" :" othis database in MySQL"}
代表降级成功
5、故意关闭微服务 microservicecloud-provider-dept-8001
比如c本来好好的,突然关掉,暂停服务,如果其他人调用,就会收到友好提示,启动7001,7002,7003,此时是provider-dept-8001,跟前面没关系,为什么是dept-feign?服务降级是在客户端,与服务端没关系,服务端最后已经要暂停了,最后 dept-feign 启动,服务已经全部启动完成,在 eureka 上面可以看到服务已经全部启动完成,先看正常访问。
接下来估计关闭微服务 microservicecloud-provider-dept-8001,关闭8001服务,现在有集群和消费者,就像 c 兄弟是8001,抽调过去支援 a 系统,忍痛将这个服务关掉,但是有可能这个服务还是在访问,假设刚才是1,现在是2,可以看到Consumer客户端提供的降级信息,此刻服务 Provider 已经关团,这个就是在之前代码中写的内容,可以根据诉求,随便写任何内容都可以,首先去调用,也看到了提示信息,客户端自己调用提示
http://localhost/consumer/dept/get/1此时服务端 provider 已经 down了,但是做了服务降级处理,也就是现在的 consumer,让客户端在服务端不可用时也会获得提示信息而不会挂起耗死服务器。这就彻底把8001的暂停服务的损害情况降低到最少,如果就算现在去调,收到提示之后此服务已经关闭,就好比本窗口暂停服务,今天下午两点以后才能办公,任何服务在看到这个消息,都不会再反复的调用了,这样变相的服务就降级了,因为调用的人就不多了,这样就起到了对服务的一种保护和友好的提示,这样的一种信息让客户端在服务端不可用时也会获得提示信息而不会挂起耗死服务器,这就是服务降级。