Spring Cloud Netflix的3大组件应用 Eureka&Ribbon&Hystrix

参考:http://blog.csdn.net/a60782885/article/details/69267934


服务发现:(Eureka)

前面提到,Eureka分为服务端和客户端,服务端是服务注册中心,而客户端是提供服务的。


创建服务注册中心(服务端)

首先在pom文件中加入以下依赖:

[html] view plain copy
  1. <parent>  
  2. <span style="white-space:pre">  </span><groupId>org.springframework.boot</groupId>  
  3. <span style="white-space:pre">  </span><artifactId>spring-boot-starter-parent</artifactId>  
  4.     <version>1.3.8.RELEASE</version>  
  5.     <relativePath /> <!-- lookup parent from repository -->  
  6. </parent>  
  7.   
  8. <dependencies>  
  9.     <dependency>  
  10.         <groupId>org.springframework.boot</groupId>  
  11.         <artifactId>spring-boot-starter-test</artifactId>  
  12.         <scope>test</scope>  
  13.     </dependency>  
  14. <span style="white-space:pre">  </span><dependency>  
  15.         <groupId>org.springframework.cloud</groupId>  
  16.         <artifactId>spring-cloud-starter-eureka-server</artifactId>  
  17.     </dependency>  
  18. </dependencies>  
  19.   
  20. <dependencyManagement>  
  21.     <dependencies>  
  22.         <dependency>  
  23.             <groupId>org.springframework.cloud</groupId>  
  24.             <artifactId>spring-cloud-dependencies</artifactId>  
  25.             <version>Brixton.SR7</version>  
  26.             <type>pom</type>  
  27.             <scope>import</scope>  
  28.         </dependency>  
  29.     </dependencies>  
  30. </dependencyManagement>  
在Application文件中增加@EnableEurekaServer注解,表明这是服务端

[java] view plain copy
  1. @EnableEurekaServer  
  2. @SpringBootApplication  
  3. public class SpringcloudEurekaServerApplication {  
  4.   
  5.     public static void main(String[] args) {  
  6.         SpringApplication.run(SpringcloudEurekaServerApplication.class, args);  
  7.     }  
  8. }  
在默认设置下,该服务注册中心也会将自己作为客户端来尝试注册它自己,所以我们需要禁用它的客户端注册行为。在application.properties或yml中禁止客户端注册行为,否则会报错。

[html] view plain copy
  1. server.port=1111  
  2.   
  3. eureka.client.register-with-eureka=false  
  4. eureka.client.fetch-registry=false  
  5. eureka.client.serviceUrl.defaultZone=http://localhost:${server.port}/eureka/  

服务端就写好了,可以访问localhost:1111进行访问。可以看到,这时候是没有服务的。



接下来创建客户端

创建客户端,并在注册中心中注册自己。

还是首先添加依赖:这里和上面不同的地方只有对Eureka的依赖。

[html] view plain copy
  1. <parent>  
  2.     <groupId>org.springframework.boot</groupId>  
  3.     <artifactId>spring-boot-starter-parent</artifactId>  
  4.     <version>1.3.8.RELEASE</version>  
  5.     <relativePath /> <!-- lookup parent from repository -->  
  6. </parent>  
  7.   
  8.   
  9. <dependencies>  
  10.     <dependency>  
  11.         <groupId>org.springframework.cloud</groupId>  
  12.         <artifactId>spring-cloud-starter-eureka</artifactId>  
  13.     </dependency>  
  14. <span style="white-space:pre">  </span><dependency>  
  15.         <groupId>org.springframework.boot</groupId>  
  16.         <artifactId>spring-boot-starter-test</artifactId>  
  17.         <scope>test</scope>  
  18.     </dependency>  
  19. </dependencies>  
  20.   
  21. <dependencyManagement>  
  22.     <dependencies>  
  23.         <dependency>  
  24.             <groupId>org.springframework.cloud</groupId>  
  25.             <artifactId>spring-cloud-dependencies</artifactId>  
  26.             <version>Brixton.SR7</version>  
  27.             <type>pom</type>  
  28.             <scope>import</scope>  
  29.         </dependency>  
  30.     </dependencies>  
  31. </dependencyManagement>  
在Application文件中加入@EnableDiscoveryClient注解,表明这是一个客户端。

[java] view plain copy
  1. @EnableDiscoveryClient  
  2. @SpringBootApplication  
  3. public class SpringcloudEurekaServiceApplication {  
  4.   
  5.     public static void main(String[] args) {  
  6.         SpringApplication.run(SpringcloudEurekaServiceApplication.class, args);  
  7.     }  
  8. }  
然后我们需要向注册中心中注册自己,只需要在application.properties或yml文件中增加配置即可:

[html] view plain copy
  1. spring.application.name=compute-service  
  2. server.port=2222  
  3. eureka.client.serviceUrl.defaultZone=http://localhost:1111/eureka/  
defaultZone指定了服务注册中心的位置。

注册了之后我们就可以在客户端编写客户端提供的服务了。比如这里提供了add加法服务。

[java] view plain copy
  1. @RestController  
  2. public class ComputeController {  
  3.       
  4.     private final Logger logger = Logger.getLogger(getClass());  
  5.       
  6.     @Autowired  
  7.     private DiscoveryClient client;  
  8.       
  9.     @RequestMapping(value = "/add" ,method = RequestMethod.GET)  
  10.     public Integer add(@RequestParam Integer a, @RequestParam Integer b) {  
  11.         ServiceInstance instance = client.getLocalServiceInstance();  
  12.         Integer r = a + b;  
  13.         logger.info("/add, host:" + instance.getHost() + ", service_id:" + instance.getServiceId() + ", result:" + r);  
  14.         return r;  
  15.     }  
  16. }  
在提供的服务中,只需要使用DiscoveryClient就可以得到关于调用者的信息。

客户端也完成了,这个时候可以再次访问localhost:1111。


可以发现,客户端已经在服务端上注册了。


我们看一下架构图:


很显然,工作流程是这样的:Service Consumer -> Proxy Server -> Client(Load Balancer) -> Servie Discovery -> Target Service

我们编写好了上图的红色的部分,接下来应该对服务进行负载均衡了,也就是对客户端的负载均衡,我们使用Ribbon来完成这件事。

首先我们启动服务端和两个客户端,客户端分别开在2222和2223端口。即:


开启了两个服务,接下来我们使用Ribbon进行负载均衡。


新建一个项目。

在pom文件中添加如下依赖:

[html] view plain copy
  1. <parent>  
  2.     <groupId>org.springframework.boot</groupId>  
  3.     <artifactId>spring-boot-starter-parent</artifactId>  
  4.     <version>1.3.5.RELEASE</version>  
  5.     <relativePath/> <!-- lookup parent from repository -->  
  6. </parent>  
  7. <dependencies>  
  8.     <dependency>  
  9.         <groupId>org.springframework.cloud</groupId>  
  10.         <artifactId>spring-cloud-starter-ribbon</artifactId>  
  11.     </dependency>  
  12.     <dependency>  
  13.         <groupId>org.springframework.cloud</groupId>  
  14.         <artifactId>spring-cloud-starter-eureka</artifactId>  
  15.     </dependency>  
  16.     <dependency>  
  17.         <groupId>org.springframework.boot</groupId>  
  18.         <artifactId>spring-boot-starter-web</artifactId>  
  19.     </dependency>  
  20.     <dependency>  
  21.         <groupId>org.springframework.boot</groupId>  
  22.         <artifactId>spring-boot-starter-test</artifactId>  
  23.         <scope>test</scope>  
  24.     </dependency>  
  25. </dependencies>  
  26. <dependencyManagement>  
  27.     <dependencies>  
  28.         <dependency>  
  29.         <groupId>org.springframework.cloud</groupId>  
  30.         <artifactId>spring-cloud-dependencies</artifactId>  
  31.         <version>Brixton.RELEASE</version>  
  32.         <type>pom</type>  
  33.         <scope>import</scope>  
  34.     </dependency>  
  35.     </dependencies>  
  36. </dependencyManagement>  
使用@EnableDiscoveryClient注解在将其注册在注册中心。并且提供一个返回RestTemplate的bean实例,使用@LoadBalanced注解对这个实例进行负载均衡这样,使用这个实例去获取服务的时候,就会帮我们进行负载均衡了。
[java] view plain copy
  1. @SpringBootApplication  
  2. @EnableDiscoveryClient  
  3. public class RibbonApplication {  
  4.       
  5.     @Bean  
  6.     @LoadBalanced  
  7.     RestTemplate restTemplate() {  
  8.         return new RestTemplate();  
  9.     }  
  10.       
  11.     public static void main(String[] args) {  
  12.         SpringApplication.run(RibbonApplication.class, args);  
  13.     }  
  14. }  

在application.properties中注册:

[html] view plain copy
  1. spring.application.name=ribbon-consumer  
  2. server.port=3333  
  3. eureka.client.serviceUrl.defaultZone=http://localhost:1111/eureka/  

创建了bean实例,我们就可以通过@Autowired来获取这个RestTemplate了,并且使用这个实例去调用服务。
[java] view plain copy
  1. @RestController  
  2. public class ConsumerController {  
  3.       
  4.     @Autowired  
  5.     RestTemplate restTemplate;  
  6.       
  7.     @RequestMapping(value = "/add", method = RequestMethod.GET)  
  8.     public String add() {  
  9.         return restTemplate.getForEntity("http://COMPUTE-SERVICE/add?a=10&b=20", String.class).getBody();  
  10.     }  
  11. }  
启动这个项目,并且访问多次localhost:3333/add可以发现确实进行了负载均衡。


微服务架构中,服务被拆分成一个一个的单元,各个单元之间相互依赖调用。如果某个单元由于网络原因或者别的单元故障奔溃,那么会直接导致调用方对外的服务也发生延迟。若此时调用方的请求不断增加,最后就会出现因等待出现故障的依赖方响应而形成任务积压,最终导致自身服务的瘫痪,这样的结构相对于传统的web开发模式来说更加可怕,为了解决这个问题,我们可以采用断路器。

在分布式架构中,当某个服务单元发生故障,使用断路器返回一个错误的相应,而不是进行长时间的等待,这样就不会使得线程被长时间占用,导致服务器的瘫痪。

Spring Cloud提供了Hystrix这么一个组件来实现断路器的功能。


首先启动Eureka服务端和客户端。

对Ribbon的项目进行以下修改:

首先在pom文件中增加以下依赖:

[html] view plain copy
  1. <dependency>  
  2.     <groupId>org.springframework.cloud</groupId>  
  3.     <artifactId>spring-cloud-starter-hystrix</artifactId>  
  4. </dependency>  
在application中增加@EnableCircuitBreaker注解,表明使用断路器。

[java] view plain copy
  1. @SpringBootApplication  
  2. @EnableDiscoveryClient  
  3. @EnableCircuitBreaker  
  4. public class RibbonApplication {  
  5.       
  6.     @Bean  
  7.     @LoadBalanced  
  8.     RestTemplate restTemplate() {  
  9.         return new RestTemplate();  
  10.     }  
  11.       
  12.     public static void main(String[] args) {  
  13.         SpringApplication.run(RibbonApplication.class, args);  
  14.     }  
  15. }  
Hystrix使用消息队列的方式,如果连接的服务崩溃,则异步回调某个方法进行处理。

新增一个Service类,在这个类中定义好如何访问,以及失败之后的返回等。

[java] view plain copy
  1. @Service  
  2. public class ComputeService {  
  3.       
  4.     @Autowired  
  5.     RestTemplate restTemplate;  
  6.       
  7.     @HystrixCommand(fallbackMethod = "addServiceFallback")  
  8.     public String addService() {  
  9.         return restTemplate.getForEntity("http://COMPUTE-SERVICE/add?a=10&b=20", String.class).getBody();  
  10.     }  
  11.       
  12.     public String addServiceFallback() {  
  13.         return "error";  
  14.     }  
  15. }  
这里重点是@HystrixCommand注解:表明该方法为hystrix包裹,可以对依赖服务进行隔离、降级、快速失败、快速重试等等hystrix相关功能

列举几个属性:
1. fallbackMethod 降级方法
2. commandProperties 普通配置属性,可以配置HystrixCommand对应属性,例如采用线程池还是信号量隔离、熔断器熔断规则等等
3. ignoreExceptions 忽略的异常,默认HystrixBadRequestException不计入失败
4. groupKey() 组名称,默认使用类名称
5. commandKey 命令名称,默认使用方法名

最后修改一下Controller即可:

[java] view plain copy
  1. @RestController  
  2. public class ConsumerController {  
  3.       
  4.     @Autowired  
  5.     private ComputeService computeService;  
  6.       
  7.     @RequestMapping(value = "/add", method = RequestMethod.GET)  
  8.     public String add() {  
  9.         return computeService.addService();  
  10.     }  
  11. }  
对于断路器,针对生产环境,,Netflix还给我们准备了一个非常好用的运维工具, 那就是Hystrix Dashboard和Turbine.可以帮助我们更好的观察。


当客户端关闭时访问:


客户端启动时访问:


成功!


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章