开始之前先介绍下服务降级
服务降级
什么是服务降级?
服务降级是指 当服务器压力剧增的情况下,根据实际业务情况及流量,对一些服务和页面有策略的不处理,或换种简单的方式处理,从而释放服务器资源以保证核心业务正常运作或高效运作。说白了,就是尽可能的把系统资源让给优先级高的服务。
资源有限,而请求是无限的。如果在并发高峰期,不做服务降级处理,一方面肯定会影响整体服务的性能,严重的话可能会导致宕机某些重要的服务不可用。所以,一般在高峰期,为了保证核心功能服务的可用性,都要对某些服务降级处理。比如当双11活动时,把交易无关的服务统统降级,如查看蚂蚁深林,查看历史订单等等。
服务降级主要用于什么场景呢?当整个微服务架构整体的负载超出了预设的上限阈值或即将到来的流量预计将会超过预设的阈值时,为了保证重要或基本的服务能正常运行,可以将一些 不重要 或 不紧急 的服务或任务进行服务的 延迟使用 或 暂停使用。
降级的方式可以根据业务来,可以延迟服务,比如延迟给用户增加积分,只是放到一个缓存中,等服务平稳之后再执行 ;或者在粒度范围内关闭服务,比如关闭相关文章的推荐。
由上图可得,当某一时间内服务A的访问量暴增,而B和C的访问量较少,为了缓解A服务的压力,这时候需要B和C暂时关闭一些服务功能,去承担A的部分服务,从而为A分担压力,叫做服务降级。
服务降级需要考虑的问题
- 那些服务是核心服务,哪些服务是非核心服务
- 那些服务可以支持降级,那些服务不能支持降级,降级策略是什么
- 除服务降级之外是否存在更复杂的业务放通场景,策略是什么?
自动降级分类
- 超时降级:主要配置好超时时间和超时重试次数和机制,并使用异步机制探测回复情况
- 失败次数降级:主要是一些不稳定的api,当失败调用次数达到一定阀值自动降级,同样要使用异步机制探测回复情况
- 故障降级:比如要调用的远程服务挂掉了(网络故障、DNS故障、http服务返回错误的状态码、rpc服务抛出异常),则可以直接降级。降级后的处理方案有:默认值(比如库存服务挂了,返回默认现货)、兜底数据(比如广告挂了,返回提前准备好的一些静态页面)、缓存(之前暂存的一些缓存数据)
- 限流降级:秒杀或者抢购一些限购商品时,此时可能会因为访问量太大而导致系统崩溃,此时会使用限流来进行限制访问量,当达到限流阀值,后续请求会被降级;降级后的处理方案可以是:排队页面(将用户导流到排队页面等一会重试)、无货(直接告知用户没货了)、错误页(如活动太火爆了,稍后重试)。
Nacos+Sentinel+OpenFeign
1、依赖
注意:SpringCloudAlibaba各个子组件版本一定要和Alibaba对应 比如Sentinel,Seate,Nacos,否则会报一些不知名的错误,排查起来会让人头大!!!
1.1、父依赖
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.6.4</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<groupId>cloud.nacos</groupId>
<artifactId>springcloud_nacos</artifactId>
<version>0.0.1-SNAPSHOT</version>
<packaging>pom</packaging>
<name>springcloud_nacos</name>
<description>springcloud_nacos</description>
<modules>
<module>springcloud_openfeign</module>
<module>springcloud-user</module>
</modules>
<properties>
<java.version>8</java.version>
</properties>
<dependencies>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<!-- springboot-mybatis-->
<dependency>
<groupId>org.mybatis.spring.boot</groupId>
<artifactId>mybatis-spring-boot-starter</artifactId>
<version>2.1.4</version>
</dependency>
<!--mysql-->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>5.1.47</version>
</dependency>
</dependencies>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-alibaba-dependencies</artifactId>
<version>2021.0.4.0</version>
<type>pom</type>
<scope>import</scope>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-dependencies</artifactId>
<version>2021.0.4</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<configuration>
<excludes>
<exclude>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
</exclude>
</excludes>
</configuration>
</plugin>
</plugins>
</build>
</project>
2、消费者
2.1、消费者依赖
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>cloud.nacos</groupId>
<artifactId>springcloud_nacos</artifactId>
<version>0.0.1-SNAPSHOT</version>
</parent>
<groupId>edu.hunan</groupId>
<artifactId>springcloud_openfeign</artifactId>
<packaging>jar</packaging>
<name>springcloud_openfeign</name>
<url>http://maven.apache.org</url>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
</properties>
<dependencies>
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
<exclusions>
<exclusion>
<groupId>com.netflix.ribbon</groupId>
<artifactId>ribbon</artifactId>
</exclusion>
<exclusion>
<artifactId>spring-cloud-commons</artifactId>
<groupId>org.springframework.cloud</groupId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
<version>2.6.3</version>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
</dependency>
<!--OpenFeign-->
<!-- https://mvnrepository.com/artifact/org.springframework.cloud/spring-cloud-starter-openfeign -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-openfeign</artifactId>
<version>3.1.3</version>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-loadbalancer</artifactId>
<version>3.1.3</version>
</dependency>
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-sentinel</artifactId>
<!-- <version>2.2.5.RELEASE</version>-->
<version>2021.0.4.0</version> <!--该版本一定要和父模块中的Alibaba对应-->
</dependency>
<dependency>
<groupId>org.apache.httpcomponents</groupId>
<artifactId>httpclient</artifactId>
<version>4.5.3</version>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>3.8.1</version>
<scope>test</scope>
</dependency>
</dependencies>
</project>
2.2、配置文件
server:
port: 6001
spring:
main:
allow-circular-references: true
application:
name: cloud-openfeign
cloud:
nacos:
discovery:
server-addr: localhost:8849
loadbalance:
ribbon:
enabled: false
sentinel:
transport:
dashboard: localhost:8080
port: 8719
datasource:
url: jdbc:mysql://localhost:3306/cart_user?serverTimezone=UTC&useUnicode=true&characterEncoding=utf-8
driver-class-name: com.mysql.jdbc.Driver
username: root
password: 123456
management:
endpoints:
web:
exposure:
include: "*"
mybatis:
type-aliases-package: openfeign.pojo
#openfeign和sentinel整合,必须配置
feign:
sentinel:
enabled: true
2.3、Service
/**
* 参数详解 :1、被调用方服务名称 2、兜底方法
*/
@FeignClient(value = "cart-user",fallback = OpenFeignImpl.class)
public interface OpenFeign {
@GetMapping("/user/queryuser") //此处路径需和生产者路径对应
String getUser(@RequestParam String username,@RequestParam String password);
}
//实现类
@Component
public class OpenFeignImpl implements OpenFeign{
@Override
public String getUser(String username, String password) {
return "服务暂不可用";
}
}
2.4、Controller
@RestController
@RequestMapping("openfeign")
public class OpenFeignController {
@Lazy
@Autowired
private OpenFeign openFeign;
@GetMapping("/test")
public String testr(){
return openFeign.getUser("李四","123");
}
}
2.5、启动类
@SpringBootApplication()
@EnableDiscoveryClient
@EnableFeignClients() //开启openfeign调用
public class OpenFeignApplication_6001 {
public static void main(String[] args) {
SpringApplication.run(OpenFeignApplication_6001.class,args);
}
}
3、生产者
3.1、生产者依赖
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>cloud.nacos</groupId>
<artifactId>springcloud_nacos</artifactId>
<version>0.0.1-SNAPSHOT</version>
</parent>
<groupId>edu.hunan</groupId>
<artifactId>springcloud-user</artifactId>
<packaging>jar</packaging>
<name>springcloud-user</name>
<url>http://maven.apache.org</url>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
<version>2021.0.1.0</version>
<exclusions>
<exclusion>
<groupId>com.netflix.ribbon</groupId>
<artifactId>ribbon</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>3.8.1</version>
<scope>test</scope>
</dependency>
</dependencies>
</project>
3.2、配置文件
server:
port: 7003
spring:
application:
name: cart-user
cloud:
nacos:
discovery:
server-addr: localhost:8849
datasource:
url: jdbc:mysql://localhost:3306/cart_user?serverTimezone=UTC&useUnicode=true&characterEncoding=utf-8
driver-class-name: com.mysql.jdbc.Driver
username: root
password: 123456
management:
endpoints:
web:
exposure:
include: "*"
mybatis:
type-aliases-package: cloud.pojo
3.3、Mapper
@Mapper
@Repository
public interface UserMapper {
@Select("select username,password from t_user where username=#{username} and password =#{password}")
User queryUser(User user);
}
3.4、Controller
@Slf4j
@RestController
@RequestMapping("/user")
public class UserController {
@Autowired
private UserMapper userMapper;
@GetMapping("/queryuser")
public String queryUser(String username,String password){
User user = userMapper.queryUser(new User(username, password));
if(user!=null){
log.info("用户{}",user);
return "查询成功";
}
log.error("该用户不存在");
return "查询失败";
}
}
3.5、启动类
@SpringBootApplication
@EnableDiscoveryClient
public class UserApplication_7003 {
public static void main(String[] args) {
SpringApplication.run(UserApplication_7003.class,args);
}
}
4、测试
浏览器访问正常服务
现在关闭7003生产者服务访问
ok.成功!!!