好得很程序员自学网

<tfoot draggable='sEl'></tfoot>

Spring Cloud Alibaba 使用 Feign+Sentinel 完成熔断的示例

Feign的使用

Feign也是网飞开发的,SpringCloud 使用 Feign 非常简单,我下边演示一下:
首先 服务消费者这边肯定需要一个对应的依赖:

?

1

compile("org.springframework.cloud:spring-cloud-starter-openfeign")

需要启用Feign的话,也得在启动类上面加个注解 @EnableFeignClients
然后,创建一个 Feign 的接口,像这样子

?

1

2

3

4

5

6

7

8

9

10

11

package com.skypyb.sc.feign;

import com.skypyb.sc.entity.User;

import org.springframework.cloud.openfeign.FeignClient;

import org.springframework.web.bind.annotation.PathVariable;

import org.springframework.web.bind.annotation.RequestMapping;

import org.springframework.web.bind.annotation.RequestMethod;

@FeignClient ( "sc-demo-microservice-user" )

public interface UserFeignClient {

  @RequestMapping (value = "/user/{id}" ,method = RequestMethod.GET)

  public User getUser( @PathVariable ( "id" ) Long id);

}

@FeignClient 注解里边的默认属性,也就是name属性是一个客户端的名字,如果使用了Eureka的话,会给他自动解析为 Eureka Server 服务注册表中的服务。
要是配了Ribbon,也会使用默认的负载均衡策略来执行请求。
Feign默认使用SpringMVC的注解声明请求,当然也可以用Feign自带的注解。不过没啥必要,还需要配置东西。
 
我上边这个例子写完了,实际使用的话只需要注入该类然后调用对应的方法就完事了。非常简便。

?

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

package com.skypyb.sc.controller;

import com.skypyb.sc.entity.User;

import com.skypyb.sc.feign.UserFeignClient;

import org.slf4j.Logger;

import org.slf4j.LoggerFactory;

import org.springframework.beans.factory.annotation.Autowired;

import org.springframework.cloud.client.ServiceInstance;

import org.springframework.cloud.client.discovery.DiscoveryClient;

import org.springframework.cloud.client.loadbalancer.LoadBalancerClient;

import org.springframework.web.bind.annotation.GetMapping;

import org.springframework.web.bind.annotation.PathVariable;

import org.springframework.web.bind.annotation.RequestMapping;

import org.springframework.web.bind.annotation.RestController;

import org.springframework.web.client.RestTemplate;

import java.util.List;

@RestController

@RequestMapping ( "/movie" )

public class MovieController {

  private Logger logger = LoggerFactory.getLogger(MovieController. class );

  @Autowired

  private UserFeignClient userFeignClient;

  @GetMapping ( "/user/{id}" )

  public User getUser( @PathVariable ( "id" ) Long id) {

   return userFeignClient.getUser(id);

  }

}

不过有几个点需要注意
在使用@FeignClient 声明的Feign伪装类中:
使用 @PathVariable 注解,必须加上参数!
GET请求无法使用对象作为入参! 要不有多少参数写多少参数(每个都要加@RequestParam([参数名]) 注解),要不就用接受一个Map对象,也得加@RequestParam
POST请求可以接收对象,需要加上@RequestBody注解
 
 
Feign论使用的话,其实已经差不多了。
但是还有一些相关的操作也比较重要。
 
Feign 的请求都是使用的默认配置,我们其实可以实现自己的配置供 Feign 使用以实现编码、解码、日志记录、验证 等等等等。
比如我可以这么定义一个配置类:

?

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

package com.skypyb.sc.config;

import feign.Logger;

import feign.auth.BasicAuthRequestInterceptor;

import org.springframework.context.annotation.Bean;

public class FeignConfiguration {

  @Bean

  public Logger.Level feignLog() {

   return Logger.Level.FULL;

  }

  /**

   * 使用指定的用户名和密码验证所有请求

   * @return

   */

  @Bean

  public BasicAuthRequestInterceptor basicAuthRequestInterceptor(){

   return new BasicAuthRequestInterceptor( "user" , "614" );

  }

}

该类配置了对应的日志记录器,和一个简单的效验,以应对请求的验证。
在对应的Feign伪装类中,上边的@FeignClient注解改一下,就可以使用自己写的配置:

?

1

@FeignClient(name = "sc-demo-microservice-user" , configuration = FeignConfiguration.class)

之所以在 @FeignClient 注解中指定配置,是因为我的配置类是没有加 @Configuration 注解的,我想要实现细粒度的控制。 推荐这样做。
如果加了@Configuration 注解,则 Spring 会将其自动解析自动应用到全局,这样子就不方便为每个请求进行细粒度调整。

Alibaba的使用

首先肯定是要上pom.xml配置起来。加上对应的依赖。

?

1

2

3

4

5

6

7

8

< dependency >

  < groupId >com.alibaba.cloud</ groupId >

  < artifactId >spring-cloud-starter-alibaba-sentinel</ artifactId >

</ dependency >

< dependency >

  < groupId >org.springframework.cloud</ groupId >

  < artifactId >spring-cloud-starter-openfeign</ artifactId >

</ dependency >

接着写个Feign接口

?

1

2

3

4

5

6

7

8

9

10

11

12

13

14

package com.skypyb.provider.feign;

import com.skypyb.provider.fallback.HelloServiceFallback;

import org.springframework.cloud.openfeign.FeignClient;

import org.springframework.web.bind.annotation.PathVariable;

import org.springframework.web.bind.annotation.RequestMapping;

/**

  * Feign客户端

  * 指定调用 sc-demo-alibaba-provider 的服务

  */

@FeignClient (value = "sc-demo-alibaba-provider" ,fallback = HelloServiceFallback. class )

public interface NacosHelloFeign {

  @RequestMapping (value = "/provider/hello/{msg}" )

  String hello( @PathVariable ( "msg" ) String msg);

}

调用的话就是这样子调用:

?

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

package com.skypyb.provider.controller;

import com.skypyb.provider.feign.NacosHelloFeign;

import org.springframework.beans.factory.annotation.Autowired;

import org.springframework.cloud.client.ServiceInstance;

import org.springframework.cloud.client.loadbalancer.LoadBalancerClient;

import org.springframework.web.bind.annotation.GetMapping;

import org.springframework.web.bind.annotation.PathVariable;

import org.springframework.web.bind.annotation.RequestMapping;

import org.springframework.web.bind.annotation.RestController;

import org.springframework.web.client.RestTemplate;

import javax.annotation.Resource;

@RequestMapping ( "/consumer" )

@RestController

public class NacosConsumerController {

  @Autowired

  private LoadBalancerClient loadBalancerClient;

  @Autowired

  private RestTemplate restTemplate;

  @Resource

  private NacosHelloFeign nacosHelloFeign;

  @GetMapping (value = "/hello/{msg}" )

  public String hello( @PathVariable ( "msg" ) String msg) {

   //使用 LoadBalanceClient 和 RestTemplate 结合的方式来访问

   ServiceInstance serviceInstance = loadBalancerClient.choose( "sc-demo-alibaba-provider" );

   String url = String.format( "http://%s:%s/provider/hello/%s" ,

     serviceInstance.getHost(), serviceInstance.getPort(), msg);

   return restTemplate.getForObject(url, String. class );

  }

  @GetMapping (value = "/hello/feign/{msg}" )

  public String helloFeign( @PathVariable ( "msg" ) String msg) {

   return nacosHelloFeign.hello(msg);

  }

}

哎,观察我的NacosHelloFeign类,这里可以看到,我这用了一个fallback回退,这个回退指定的就是Sentinel 的实现,其实写起来和特么的Hystrix一模一样。不得不说SpringCloud这一点是真的做得好。

?

1

2

3

4

5

6

7

8

9

10

11

12

13

14

package com.skypyb.provider.fallback;

import com.skypyb.provider.feign.NacosHelloFeign;

import org.springframework.stereotype.Component;

/**

  * 熔断类

  * 要是 Feign 的接口调用失败(或者被快速失败)就会走这个类的方法进行处理

  */

@Component

public class HelloServiceFallback implements NacosHelloFeign {

  @Override

  public String hello(String msg) {

   return "触发熔断机制~" ;

  }

}

哎,观察我的NacosHelloFeign类,这里可以看到,我这用了一个fallback回退,这个回退指定的就是Sentinel 的实现,其实写起来和特么的Hystrix一模一样。不得不说SpringCloud这一点是真的做得好。

?

1

2

3

4

5

6

7

8

9

10

11

12

13

14

package com.skypyb.provider.fallback;

import com.skypyb.provider.feign.NacosHelloFeign;

import org.springframework.stereotype.Component;

/**

  * 熔断类

  * 要是 Feign 的接口调用失败(或者被快速失败)就会走这个类的方法进行处理

  */

@Component

public class HelloServiceFallback implements NacosHelloFeign {

  @Override

  public String hello(String msg) {

   return "触发熔断机制~" ;

  }

}

当然,配置肯定是得配置的,他也不会直接就给你用了。
Sentinel 虽说是适配了 Feign 组件。但默认是关闭的。需要在配置文件中配置打开它,在配置文件增加以下代码:

?

1

2

3

feign:

  sentinel:

  enabled: true

其实到现在,整个Feign的使用+熔断限流机制就已经配完了。
不过Sentinel 比起Hystrix真正优越的地方还没来呢。
那就是: 控制台。
这个控制台功能丰富、UI好看,比Hystrix那是高到不知道哪里去了。
要是用控制台,又不得不下载代码、打包、编译、运行。
 
所幸,我们有神器docker。我在docker hub 上找了个镜像,直接用就可以了,镜像地址:https://hub.docker测试数据/r/bladex/sentinel-dashboard
直接执以下命令,将sentinel控制台起开绑到8858端口

?

1

2

docker pull bladex /sentinel-dashboard

docker run --name sentinel -d -p 8858:8858 -d bladex /sentinel-dashboard

然后自己的yml文件也得改一下,毕竟都上控制台了,也得把自己这个服务给注册进去。
全部的yml文件如下所示:

?

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

spring:

  application:

  name: sc-demo-alibaba-consumer

  cloud:

  nacos:

   discovery:

   server-addr: 192.168.1.14:8848 #注册进 nacos

  sentinel:

    transport:

    port: 18081 #这个端口的意思是自己这个服务开个端口和 sentinel 控制台交互

    dashboard: 192.168.1.14:8858 # sentinel 控制台的端口

server:

  port: 8081

feign:

  sentinel:

  enabled: true

management:

  endpoints:

  web:

   exposure:

   include: "*"

可以看到配置里有一个 sentinel.transport.port属性,这个属性的意思是在自己本体这个服务里边,在开个新的端口专门用来和 Sentinel 控制台交互
Sentinel 控制台自身也有,默认端口则是8719
 
到这里就差不多了,所有东西打开,然后就可以访问 http://ip:8858 进入Sentinel 控制台,默认账号密码都是sentinel
有一点还需要注意,那就是为了确保客户端有访问量,Sentinel 会在客户端首次调用的时候进行初始化,开始向控制台发送心跳包。意思就是说你一个服务注册进我这来,首先还是看不到的。
你得先经过别人的请求,我才会去监控你,所以在服务刚启动的时候进入Sentinel 控制台找不到自己的服务是很正常的,只要启动时没有报错就不会有问题。

以上就是Spring Cloud Alibaba 使用 Feign+Sentinel 完成熔断的示例的详细内容,更多关于Spring Cloud Alibaba 使用Feign+Sentinel 完成熔断的资料请关注其它相关文章!

原文链接:https://HdhCmsTestskypyb测试数据/2019/09/jishu/1075/

查看更多关于Spring Cloud Alibaba 使用 Feign+Sentinel 完成熔断的示例的详细内容...

  阅读:11次