Spring Cloud Alibaba 使用

Spring Cloud Alibaba 致力于提供微服务开发的一站式解决方案。此项目包含开发分布式应用微服务的必需组件,方便开发者通过 Spring Cloud 编程模型轻松使用这些组件来开发分布式应用服务。
依托 Spring Cloud Alibaba,您只需要添加一些注解和少量配置,就可以将 Spring Cloud 应用接入阿里微服务解决方案,通过阿里中间件来迅速搭建分布式应用系统。

一. 为什么使用?

很多人可能会问,有了 spring cloud 这个微服务的框架,为什么又要使用 spring cloud alibaba 这个框架了?最重要的原因在于 spring cloud 中的几乎所有的组件都使用 Netflix 公司的产品,然后在其基础上做了一层封装。然而 Netflix 的服务发现组件 Eureka 已经停止更新,我们公司在使用的时候就发现过其一个细小的 Bug;而其他的众多组件预计会在明年(即 2020 年)停止维护。所以急需其他的一些替代产品,也就是 spring cloud alibaba,目前正处于蓬勃发展的态式。

二. 注册中心 Nacos

nacos 是阿里巴巴研发的一个集注册中心与配置中心于一体的管理平台,使用其他非常的简单。下载地址为:
https://github.com/alibaba/nacos/releases,nacos 的主页如下图所示:

其中默认的登录名和密码是:nacos/nacos

2.1 更改用户名和密码

A. 分别执行 conf 目录下的 nacos-mysql.sql 两个脚本文件,生成的数据表如下:

B. 重新配置密码
新建一个 springboot 的项目,引入如下的依赖:

1
2
3
4
<dependency>
   <groupId>org.springframework.boot</groupId>
   <artifactId>spring-boot-starter-security</artifactId>
</dependency>

生成密码的 Java 代码:
// 密码加密处理

1
2
3
4
5
public static void main(String[] args) {
   BCryptPasswordEncoder bCryptPasswordEncoder = new BCryptPasswordEncoder();
   // 生成的密码为:$2a$10$04MGTL.cJNZPpR3rFt/I2.43F.V75NH.5wdK.jngaO9Mc91mfonAO
   System.out.println(bCryptPasswordEncoder.encode("admin"));
}

执行如下sql命令:

1
2
insert into users values('nacos','$2a$10$04MGTL.cJNZPpR3rFt/I2.43F.V75NH.5wdK.jngaO9Mc91mfonAO', 1);
insert into roles values('nacos', 'ROLE_ADMIN')

C. 配置数据库的连接
在 conf 目录下的 application.properties 目录下加入如下内容:

1
2
3
4
5
spring.datasource.platform=mysql
db.num=1
db.url.0=jdbc:mysql://mysql:3306/cloud-alibaba?useSSL=false&serverTimezone=UTC&serverTimezone=Asia/Shanghai
db.user=root
db.password=

2.2 nacos 集群配置

A. 将 conf 目录下的 cluster.conf.example 拷贝一份重命名为 cluster.conf,在文件中加入所有集群节点的 ip 和端口号,文件内容如下:
127.0.0.1:8848
127.0.0.1:9948
B. 修改 windows 启动文件 startup.cmd 的配置,修改内容如下:
set MODE=”standalone”  #默认的配置
set MODE=”cluster”     #修改后的内容
注:如果是 Linux 环境不用作任何的修改。
C.启动两个 nacos,界面中出现如下的内容,表示集群配置成功

三. 服务提供方

pom.xml 依赖配置

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
<dependencies>
   <dependency>
       <groupId>org.springframework.boot</groupId>
       <artifactId>spring-boot-starter-web</artifactId>
   </dependency>
   <dependency>
       <groupId>org.springframework.cloud</groupId>
       <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
   </dependency>
</dependencies>
<dependencyManagement>
   <dependencies>
       <dependency>
           <groupId>org.springframework.cloud</groupId>
           <artifactId>spring-cloud-alibaba-dependencies</artifactId>
           <version>0.9.0.RELEASE</version>
           <type>pom</type>
           <scope>import</scope>
       </dependency>
       <dependency>
           <groupId>org.springframework.cloud</groupId>
           <artifactId>spring-cloud-dependencies</artifactId>
           <version>Greenwich.SR2</version>
           <type>pom</type>
           <scope>import</scope>
       </dependency>
   </dependencies>
</dependencyManagement>

配置

1
2
3
4
5
6
7
8
9
spring:
 application:
   # 服务名
   name: alibaba-provider
 cloud:
   nacos:
     discovery:
       #必须配置 ip 地址
       server-addr: 172.18.96.177:8848,172.18.96.177:9948

启动类

1
2
3
4
5
6
7
@SpringBootApplication
@EnableDiscoveryClient  //开启 nacos 的服务发现
public class ProviderApplication {
   public static void main(String[] args) {
       SpringApplication.run(ProviderApplication.class, args);
   }
}

服务页面结果

四. 服务消费方

pom.xml 依赖配置

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
<dependencies>
   <dependency>
       <groupId>org.springframework.boot</groupId>
       <artifactId>spring-boot-starter-web</artifactId>
   </dependency>
   <dependency>
       <groupId>org.springframework.cloud</groupId>
       <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
   </dependency>
</dependencies>
<dependencyManagement>
   <dependencies>
       <dependency>
           <groupId>org.springframework.cloud</groupId>
           <artifactId>spring-cloud-alibaba-dependencies</artifactId>
           <version>0.9.0.RELEASE</version>
           <type>pom</type>
           <scope>import</scope>
       </dependency>
       <dependency>
           <groupId>org.springframework.cloud</groupId>
           <artifactId>spring-cloud-dependencies</artifactId>
           <version>Greenwich.SR2</version>
           <type>pom</type>
           <scope>import</scope>
       </dependency>
   </dependencies>
</dependencyManagement>

配置

1
2
3
4
5
6
7
8
9
10
11
12
server:
 port: 8080
spring:
 application:
   # 服务名
   name: alibaba-consumer
 cloud:
   nacos:
     discovery:
       server-addr: 172.18.96.177:8848,172.18.96.177:9948
       # 不将自己的服务注册到注册中心
       register-enabled: false

启动类配置

1
2
3
4
5
6
7
@SpringBootApplication
@EnableDiscoveryClient
public class ConsumerApplication {
   public static void main(String[] args) {
       SpringApplication.run(ConsumerApplication.class, args);
   }
}

调用服务提供方

1
2
3
4
5
6
7
@RequestMapping
   public Object getUsers() {
       List<ServiceInstance> list = discoveryClient.getInstances("alibaba-provider");
       String targetUrl = list.stream().map(si -> si.getUri() + "/user").findFirst().get();
       List<String> resultList = restTemplate.getForObject(targetUrl, List.class);
       return resultList;
   }

五. Ribbon 负载均衡

Spring Cloud Ribbon 是基于 Netflix Ribbon 实现的一套客户端负载均衡的工具。其主要功能是提供客户端的负载均衡算法,并提供了完善的配置项如连接超时,重试等。简单的说,就是配置文件中列出 Load Balancer 后面所有的机器,Ribbon 会自动的基于某种规则(如简单轮询,随机连接等)去连接这些机器,当然我们也可以使用 Ribbon 自定义负载均衡算法。

5.1 实现负载均衡

Ribbon 只是一个客户端的负载均衡器工具,实现起来非常的简单,我们只需要在注入 RestTemplate 的 bean 上加上@LoadBalanced 就可以了。如下:

1
2
3
4
5
6
7
8
@Configuration
public class WebConfig {
   @LoadBalanced
   @Bean
   public RestTemplate restTemplate() {
       return new RestTemplate();
   }
}

5.2 服务消费方调用

// 直接写上服务名即可
List resultList = restTemplate.getForObject(“http://alibaba-provider/user“, List.class);

5.3 负载均衡策略

Ribbon 提供了一个很重要的接口叫做 IRule,其中定义了很多的负载均衡策略,默认的是轮询的方式,以下是 Ribbon 的负载均衡策略:

类名 描述
RoundRobbinRule 轮询
RandomRule 随机挑选
RetryRule 按照轮询的方式去调用服务,如果其中某个服务不可用,但是还是会尝试几次,如果尝试过几次都没有成功,那么就不在调用该服务,会轮询调用其他的可用服务。
AvailabilityFilteringRule 会先过滤掉因为多次访问不可达和并发超过阈值的服务,然后轮询调用其他的服务
WeightedResponseTimeRule 根据平均响应时间计算权重,响应越快权重越大,越容易被选中。服务刚重启的时候,还未统计出权重会按照轮询的方式;当统计信息足够的时候,就会按照权重信息访问
ZoneAvoidanceRule 判断 server 所在的区域性能和可用性选择服务器
BestAvailableRule 会过滤掉多次访问都不可达的服务,然后选择并发量最小的服务进行调用,默认方式

改变 Ribbon 的负责均衡策略:

1
2
3
4
@Bean
public IRule getRule() {
   return new RandomRule();
}

5.4 自定义负载均衡策略

我们自定义的负载均衡策略需要继承 AbstractLoadBalancerRule 这个类,然后重写 choose 方法,然后将其注入到容器中,如下所示:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
public class Customize_Rule extends AbstractLoadBalancerRule {
   private static Logger logger = LoggerFactory.getLogger(Customize_Rule.class);
   private int currentIndex = 0; //当前调用的索引
   private int num = 1; //次数
   private int limit = 5;
   /**
    * 初始化工作
    * @param iClientConfig
    */
   @Override
   public void initWithNiwsConfig(IClientConfig iClientConfig) {
   }
   @Override
   public Server choose(Object key) {
       ILoadBalancer balancer = getLoadBalancer();
       return choose(balancer, key);
   }
   private Server choose(ILoadBalancer balancer, Object key) {
       Server server = null;
       while(null == server) {
           //获取所有可用的服务
           List<Server> reachableServers = balancer.getReachableServers();
           if (0 == reachableServers.size()) {
               logger.error("没有可用的服务");
               return null;  //退出 while 循环
           }
           int total = reachableServers.size(); //可用服务的数量
           synchronized (this) {
               /**
                * 有种极端情况,当我们在使用最后一个服务的时候,其他的服务都不可用,可能导致索引越界异常
                */
               if (currentIndex + 1 > total) {
                   currentIndex = 0;
                   server = reachableServers.get(currentIndex);  //获取第一个服务
                   num = 0;
                   num++;
               } else {
                   if(limit == num) {
                       currentIndex++;
                       num = 0;
                       if(currentIndex == total) {
                           currentIndex=0;
                           server = reachableServers.get(currentIndex);  //获取第一个服务
                           num++;
                       }else{
                           server = reachableServers.get(currentIndex);
                           num++;
                       }
                   }else {
                       server = reachableServers.get(currentIndex);
                       num++;
                   }
               }
           }
       }
       return server;
   }
}

将其注入到容器中,方式如下:

1
2
3
4
@Bean
public IRule getRule() {
   return new Customize_Rule();
}

六. Feign 负载均衡

feign 是基于 Ribbon 的另外一个负载均衡的客户端框架,只需要在接口上定义要调用的服务名即可,使用起来非常的简单。
pom.xml 依赖

1
2
3
4
<dependency>
   <groupId>org.springframework.cloud</groupId>
   <artifactId>spring-cloud-starter-openfeign</artifactId>
</dependency>

启动类配置
需要在启动类上加上@EnableFeignClients 这个注解

1
2
3
4
5
6
7
8
@SpringBootApplication
@EnableDiscoveryClient
@EnableFeignClients
public class ConsumerApplication {
   public static void main(String[] args) {
       SpringApplication.run(ConsumerApplication.class, args);
   }
}

服务接口配置

1
2
3
4
5
@FeignClient(name="alibaba-provider")
public interface UserService {
   @RequestMapping("/user")
   public List<String> getUsers();
}

七. 熔断与服务降级

分布式系统中一个微服务需要依赖于很多的其他的服务,那么服务就会不可避免的失败。例如 A 服务依赖于 B、C、D 等很多的服务,当 B 服务不可用的时候,会一直阻塞或者异常,更不会去调用 C 服务和 D 服务。同时假设有其他的服务也依赖于 B 服务,也会碰到同样的问题,这就及有可能导致雪崩效应。
如下案例:一个用户通过通过 web 容器访问应用,他要先后调用 A、H、I、P 四个模块,一切看着都很美好。

由于某些原因,导致 I 服务不可用,与此同时我们没有快速处理,会导致该用户一直处于阻塞状态。

当其他用户做同样的请求,也会面临着同样的问题,tomcat 支持的最大并发数是有限的,资源都是有限的,将整个服务器拖垮都是有可能的。

Sentinel 是一个用于分布式系统的延迟和容错的开源库,在分布式系统中,许多依赖会不可避免的调用失败,例如超时,异常等,Hystrix 能保证在一个依赖出现问题的情况下,不会导致整体服务失败,避免级联故障,以提高分布式系统的弹性。
断路器本身是一种开关装置,当某个服务单元发生故障后,通过断路器的故障监控(类似于保险丝),向调用者返回符合预期的,可处理的备选响应,而不是长时间的等待或者抛出无法处理的异常,这样就保证了服务调用的线程不会被长时间,不必要的占用,从而避免故障在分布式系统中的蔓延,乃至雪崩。
Sentinel 在网络依赖服务出现高延迟或者失败时,为系统提供保护和控制;可以进行快速失败,缩短延迟等待时间;提供失败回退(Fallback)和相对优雅的服务降级机制;提供有效的服务容错监控、报警和运维控制手段。
下载地址:https://github.com/alibaba/Sentinel/releases

7.1 依赖

1
2
3
4
<dependency>
   <groupId>org.springframework.cloud</groupId>
   <artifactId>spring-cloud-starter-alibaba-sentinel</artifactId>
</dependency>

7.2 配置

通常情况下我们只需要在服务提供方实现熔断或者服务降级即可,但是如果要相对服务消费方是实现限流,在服务的提供方和消费方都需要加如下配置。

1
2
3
4
5
6
7
8
spring:
 cloud:
    sentinel:
     transport:
       # sentinel 控制台的地址
       dashboard: localhost:8080
     # 立即加载
     eager: true

7.3 sentinel 的控制面板

在浏览器输入 localhost:8080,使用 sentinel/sentinel 来访问 sentinel 的控制面板:

接下来对 sentinel 的控制面板一一讲解:
实时监控
用于查看接口调用的 QPS(Query Per Second)以及平均响应时间。
簇点链路
查看当前追踪的所有的访问接口,可以添加流量规则降级规则热点规则授权规则
流量规则

资源名:是需要控制的链路的名字,例如/student/all 等
针对来源: 默认为 default 表示所有,也可以针对特定的服务进行设置。
阈值类型: 是指如何进行限制,可以是 QPS,也可以是线程。
单机阈值: 是控制 QPS 或者线程的数量。
流量模式: 直接表示只是针对指定资源进行限制;关联是指当被关联的资源达到阈值时候,指定资源被限制访问;链路是更加细粒度的控制,控制指定资源对链路的限制。
流控效果: 快速失败是指,当无法访问的时候立即给用户一个错误响应;Warm Up(预热)是指经过指定的时间后才达到指定的阈值(sentinel 内有值为 coldFactor 为 3,即请求 QPS 从 threshold / 3 开始,经预热时长逐渐升至设定的 QPS 阈值,参考地址:https://github.com/alibaba/Sentinel/wiki/%E9%99%90%E6%B5%81---%E5%86%B7%E5%90%AF%E5%8A%A8);排队等待只是匀速的通过(每秒指定的 QPS),其他的请求进行排队,但是并不会一直排下去,超过指定的时间就会失败,阈值类型必须设置为 QPS,不能为线程。
降级规则

资源名: 要实现降级的资源。
降级策略:

  1. RT(平均响应时间)

如果在一秒钟之内进入的请求的平均响应时间小于 1ms,那么在未来 5s 钟之内所有的请求都会熔断降级。 2) 异常比例
如果在一秒钟之内的请求数异常比例大于指定的数据,那么在未来的时间窗口内会一直熔断降级。统计单位为 s. 3) 异常数
如果在一分钟之内,异常数量大于指定的值,那么在指定的时间窗口内请求一直会熔断降级,注意时间窗口的值一般设置要大于 60,因为设置如果小于 60,可能会一直处于熔断状态。
热点规则
热点规则是针对具体的请求参数进行设置,例如如下的方法:

1
2
3
4
5
6
@RequestMapping("/edit")
@SentinelResource("edit")   //必须的有
public Object edit(@RequestParam(required = false) String id,
                  @RequestParam(required = false) Integer age) {
   return this.studentService.commons();
}

资源名: 是@SentinelResource 中设置的值
参数索引: 对那个参数进行 QPS 限制,通过索引来指定。
单机阈值:指定在统计时长内的阈值。
**统计窗口时长: **统计的 QPS 的时间。
系统规则

LOAD: 仅对 Linux/Unix-like 机器生效,参考值一般是 CPU cores * 2.5
**RT: **当单台机器上所有入口流量的平均 RT 达到阈值即触发系统保护,单位是毫秒。
**线程数: **当单台机器上所有入口流量的并发线程数达到阈值即触发系统保护。
入口 QPS: 当单台机器上所有入口流量的 QPS 达到阈值即触发系统保护。
授权规则
授权规则是指可以将特定的访问应用加入黑名单或者白名单,但是必须在访问的时候携带应用的名称。代码实现部分如下:

1
2
3
4
5
6
7
8
9
10
11
@Component
public class SentinelOriginParser implements RequestOriginParser {
   @Override
   public String parseOrigin(HttpServletRequest httpServletRequest) {
       String origin = httpServletRequest.getParameter("origin");
       if(StringUtil.isBlank(origin)) {
           throw new IllegalArgumentException("origin parameter must be specified.");
       }
       return origin;
   }
}

加上了来源解析后,在往后的访问中必须要携带 origin 参数,在 sentinel 的 dashboard 中可以作如下配置:

集群流控

**是否集群: **是否采用集群
均摊阈值: 就是每个集群节点每秒的 QPS.
**集群阈值模式: **单机均摊是集群中每个节点每秒的 QPS, 总体阈值是整个集群每秒的 QPS.
集群流控

7.4 @SentinelResource

@SentinelResource 是 sentinel 中非常重要的注解,提供了简单易用的功能。其中 blockHandler 注解是限流的处理方法,fallback 是服务降级的处理方法。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
@SentinelResource(value="edit", blockHandler="editBlock", fallback = "editFallback")
@RequestMapping("/edit")
public Object edit(@RequestParam(required = false) String id,
                  @RequestParam(required = false) Integer age) throws Exception {
   Thread.sleep(20);
   return this.studentService.commons();
}
// 限流的处理
public Object editBlock(String id, Integer age, BlockException ex) {
   Map<String, Object> map = new HashMap<>();
   map.put("msg", "限流了.");
   return map;
}
//服务降级的处理方法
public Object editFallback(String id, Integer age) {
   Map<String, Object> map = new HashMap<>();
   map.put("msg", "fallback 服务降级了.");
   return map;
}

八. Feign 与 Sentinel 的整合

配置

1
2
3
4
feign:
 sentinel:
   # 默认是没有提示的
   enabled: true

8.1 服务降级后的处理

可以在@FeignClient 中配置 fallback,来指定服务降级后给用户返回的什么样的数据,fallback 的值为 Class 类型的对象,该类必须要实现该对应的接口。

1
2
3
4
5
6
7
8
9
10
11
12
13
@FeignClient(name="alibaba-provider", fallback = UserServiceFallback.class)
public interface UserService {
   @RequestMapping("/user")
   public List<String> getUsers();
}
UserServiceFallback 的实现如下:
@Component
public class UserServiceFallback implements UserService {
   @Override
   public List<String> getUsers() {
       return Arrays.asList("服务降级了, 这是降级后返回的信息.");
   }
}

8.2 服务降级的异常处理

对于 fallback 来讲,并不能追踪到异常信息,在实际的业务处理过程中,我们往往需要记录异常的信息,那么就要使用 fallbackFactory 属性来实现。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
@Component
public class UserServiceFallbackFactory implements FallbackFactory<UserService> {
   private static Logger logger = LoggerFactory.getLogger(UserServiceFallbackFactory.class);
   @Override
   public UserService create(Throwable cause) {
       return new UserService() {
           @Override
           public List<String> getUsers() {
               logger.info(cause.getMessage());
               return Arrays.asList("服务降级的方法");
           }
       };
   }
}

九. Sentinel 的持久化

通过接入 Sentinel Dashboard 后,在页面上操作来更新规则,都无法避免一个问题,那就是服务重新后,规则就丢失了,因为默认情况下规则是保存在内存中的。sentinel 中持久化的方式有两种,pull 模式和 push 模式。
pull 模式是指站在第三方持久化系统(redis, nacos)的角度,他们去到 sentinel 中定时去拉去配置信息,可能会造成数据的不一致性。
push 模式是站在 sentinel 的角度,将其配置信息主动推送给第三方持久化系统,sentinel 官方也推荐在线上使用该模式。

9.1 sentinel-dashboard 改造

A. 将 sentinel 的源码 clone 到本地
B. 进入到 sentinel-dashboard 目录下,修改 pom.xml 文件

1
2
3
4
5
<dependency>
   <groupId>com.alibaba.csp</groupId>
   <artifactId>sentinel-datasource-nacos</artifactId>
   <scope>test</scope>
</dependency>
1
2
3
4
<dependency>
   <groupId>com.alibaba.csp</groupId>
   <artifactId>sentinel-datasource-nacos</artifactId>
</dependency>

C. 修改 src\main\webapp\resources\app\scripts\directives\sidebar\sidebar.html 文件
未修改之前的内容

1
2
3
4
5
6
7
8
9
<!-- <li ui-sref-active="active" ng-if="entry.appType==0">  -->
<!-- <a ui-sref="dashboard.flow({app: entry.app})">  -->
<!-- <i class="glyphicon glyphicon-filter"></i>  流控规则 V1</a>  -->
<!-- </li> -->
<li ui-sref-active="active" ng-if="!entry.isGateway">
   <a ui-sref="dashboard.flowV1({app: entry.app})">
       <i class="glyphicon glyphicon-filter"></i>  流控规则
   </a>
</li>

修改之后的内容

1
2
3
4
5
6
7
8
9
10
<li ui-sref-active="active" ng-if="entry.appType==0">
   <a ui-sref="dashboard.flow({app: entry.app})">
       <i class="glyphicon glyphicon-filter"></i>  流控规则
   </a>
</li>
<!--   <li ui-sref-active="active" ng-if="!entry.isGateway">-->
<!--       <a ui-sref="dashboard.flow({app: entry.app})">-->
<!--            <i class="glyphicon glyphicon-filter"></i>  流控规则
          </a>   -->
<!--    </li>-->

D. 将 src\test\java\com\alibaba\csp\sentinel\dashboard\rule\nacos 目录下的四个Java文件拷贝到src\main\java\com\alibaba\csp\sentinel\dashboard\rule 目录下

E. 修改 src\main\webapp\resources\app\scripts\controllers\identity.js 文件,修改内容如下:

F. 重新打包生成 Jar 包,进入到 sentinel 目录下(注:不是 sentinel-dashboard 目录),执行如下命令:
mvn clean                
mvn install -DskipTests
G. 进入到 sentinel-dashboard/target 目录下,执行如下内容:
java -jar sentinel-dashboard.jar

9.2 配置

1
2
3
4
5
6
7
8
9
10
spring:
 cloud:
   sentinel:
     datasource:
       # 这个名字随意,但是要有意义
       flow:
         nacos:
           server-addr: 192.168.31.173:8848
           groupId: SENTINEL_GROUP
           rule-type: flow

9.3 测试

在 sentinel-dashboard 控制面板添加一个流量控制规则

个人微信公众号技术交流QQ群
文章目录
  1. 1. 一. 为什么使用?
  2. 2. 二. 注册中心 Nacos
    1. 2.1. 2.1 更改用户名和密码
    2. 2.2. 2.2 nacos 集群配置
  3. 3. 三. 服务提供方
  4. 4. 四. 服务消费方
  5. 5. 五. Ribbon 负载均衡
    1. 5.1. 5.1 实现负载均衡
    2. 5.2. 5.2 服务消费方调用
    3. 5.3. 5.3 负载均衡策略
    4. 5.4. 5.4 自定义负载均衡策略
  6. 6. 六. Feign 负载均衡
  7. 7. 七. 熔断与服务降级
    1. 7.1. 7.1 依赖
    2. 7.2. 7.2 配置
    3. 7.3. 7.3 sentinel 的控制面板
    4. 7.4. 7.4 @SentinelResource
  8. 8. 八. Feign 与 Sentinel 的整合
    1. 8.1. 8.1 服务降级后的处理
    2. 8.2. 8.2 服务降级的异常处理
  9. 9. 九. Sentinel 的持久化
    1. 9.1. 9.1 sentinel-dashboard 改造
    2. 9.2. 9.2 配置
    3. 9.3. 9.3 测试