blog/docs/code/kotlin/kotlin-cloud.md

146 lines
4.7 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

---
title: Spring Cloud 如何实现服务熔断服务降级
date: 2020-06-08 16:29:04
tags: [kotlin, Spring Cloud]
categories: [kotlin, Spring]
author: Karl
---
# Why
在微服务架构中,由于调用关系的复杂性,如果调用链路中的某个资源不稳定,最终会导致请求发生堆积。可能导致服务间延迟增加,备份队列,线程和其他系统资源紧张,导致整个系统发生更多的级联故障。
为了维护服务的稳定,我们需要在调用链路中某个资源出现不稳定状态时(例如调用超时或异常比例升高),对这个资源的调用进行限制,让请求快速失败,避免影响到其它的资源而导致级联错误。当资源被降级后,在接下来的降级时间窗口之内,对该资源的调用都自动熔断(默认行为是抛出 DegradeException
# How
- 服务熔断
一般发生于下游服务,下游服务发生故障时,将服务熔断不可用
电路中的保险丝,超过负荷,直接熔断,断电,不可用,保护整体安全
- 服务降级
将某一服务降级暂时不可用,为了服务整体的稳定,牺牲部分不重要的功能,保证核心功能的进行
妈妈让小明去买酱油给了10块钱小明到超市看到自己喜欢的玩具2块钱拿上玩具和酱油去柜台结账发现一共需要12元为了完成妈妈的任务选择不买玩具。等下次在买玩具
所以从上述分析来看,两者其实从有些角度看是有一定的类似性的:
目的很一致:都是从可用性可靠性着想,为防止系统的整体缓慢甚至崩溃,采用的技术手段;
最终表现类似:对于两者来说,最终让用户体验到的是某些功能暂时不可达或不可用;
自治性要求很高:熔断模式一般都是服务基于策略的自动触发,降级虽说可人工干预,但在微服务架构下,完全靠人显然不可能,开关预置、配置中心都是必要手段;
而两者的区别也是明显的:
触发原因不太一样,服务熔断一般是某个服务(下游服务)故障引起,而服务降级一般是从整体负荷考虑;
# What
由于我司使用nacos作为服务注册和发现所以我们使用sentinel进行熔断降级。
首先导入依赖
```gradle
// Gradle
implementation('com.alibaba.cloud:spring-cloud-starter-alibaba-sentinel') {
exclude module: 'guava'
}
```
```pom
// Maven
\<dependency\>
\<groupId\>com.alibaba.cloud\</groupId\>
\<artifactId\>spring-cloud-starter-alibaba-sentinel\</artifactId\>
\</dependency\>
```
配置文件中打开sentinel
```
feign:
sentinel:
enabled: true
```
**使用语言 kotlin**
阅读@FeignClient源码我们发现fallback是由spring创建
```
/**
* Fallback class for the specified Feign client interface. The fallback class must
* implement the interface annotated by this annotation and be a valid spring bean.
* @return fallback class for the specified Feign client interface
*/
Class\<?\> fallback() default void.class;
/**
* Define a fallback factory for the specified Feign client interface. The fallback
* factory must produce instances of fallback classes that implement the interface
* annotated by {@link FeignClient}. The fallback factory must be a valid spring bean.
*
* @see feign.hystrix.FallbackFactory for details.
* @return fallback factory for the specified Feign client interface
*/
Class\<?\> fallbackFactory() default void.class;
```
1.fallbackFactory
```kotlin
package com.karl.cloud;
import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.web.bind.annotation.GetMapping;
import com.karl.DTO.UserInfoDTO;
@FeignClient(value = "karl-service-user", fallbackFactory = UserFallbackFactory::class)
interface UserFeign {
@GetMapping("/karl/user")
fun getUser(): UserInfoDTO
}
@Component
class UserFallbackFactory: FallbackFactory\<UserFeign\> {
val logger = LoggerFactory.getLogger(UserFallbackFactory::class.java)!!
override fun create(cause: Throwable): DataFeign {
logger.error(cause.message, cause)
return UserFallback()
}
}
class UserFallback: UserFeign {
override fun getUser(): UserInfoDTO{
return UserInfoDTO()
}
}
```
2.fallback
```kotlin
package com.karl.cloud;
import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.web.bind.annotation.GetMapping;
import com.karl.DTO.UserInfoDTO;
@FeignClient(value = "karl-service-user", fallback = UserFallback::class)
interface UserFeign {
@GetMapping("/karl/user")
fun getUser(): UserInfoDTO
}
@Component
class UserFallback: UserFeign {
override fun getUser(): UserInfoDTO{
return UserInfoDTO()
}
}
```