目录
概念
Eureka服务注册中心的搭建(Eureka Server)
Eureka客户端的搭建(Eureka Client)
服务调用方式
Ribbon的搭建
Feign的搭建
断路器-Hystrix
什么是Spring Cloud
Spring Cloud带有“Cloud”这个单词,但它并不是云计算解决方案,而是一系列框架的有序集合。Spring Cloud内部包含了众多框架,这些框架相互协调构建分布式系统。Spring Cloud是在Spring Boot基础之上构建的,利用了Spring Boot的很多特性,简化了分布式系统基础设施的开发,使得开发人员很容易的开始工作,快速构建分布式系统的通用模式的工具集。
其次,使用Spring Cloud开发的应用程序非常适合在Docker和PaaS(比如Pivotal Cloud Foundry)上部署,所以又叫做云原生应用(Cloud Native Application)。云原生可以简单地理解为面向云环境的软件架构。
总的来说,Spring Cloud 提供了构建分布式系统所需的“全家桶”。
Spring Cloud特性
Spring Cloud核心特性如下:
- 分布式/版本化配置
- 服务注册和发现
- 服务网关
- 服务路由
- 服务与服务之间的调用
- 负载均衡
- 断路由
- 分布式消息
- 链路追踪
核心组件之间的配合
1.外部物联网设备、手机或者浏览器统一通过服务网关来访问内部服务,服务网管负责分发具体的服务。 2.服务运行过程中通过分布式配置中心获取相关配置信息。 3.多次调用失败服务会进入到断路器 4.服务与服务之间通过注册中心来相互调用 5.通过分布式链路来跟踪查看调用链 6.服务通过Message Broker来传递消息 7.服务运行过程中给的数据保存在数据库中 8.通过页面可以监控服务熔断、配置信息、服务调用和链路跟踪等信息 Spring Cloud优点
1.集大成者,Spring Cloud 包含了微服务架构的方方面面 2.约定优于配置,基于注解,没有配置文件 3.轻量级组件,Spring Cloud 整合的组件大多比较轻量级,且都是各自领域的佼佼者 4.开发简便,Spring Cloud 对各个组件进行了大量的封装,从而简化了开发 5.开发灵活,Spring Cloud 的组件都是解耦的,开发人员可以灵活按需选择组件 Spring Cloud缺点
1.项目结构复杂,每一个组件或者每一个服务都需要创建一个项目 2.部署门槛高,项目部署需要配合 Docker 等容器技术进行集群部署,而要想深入了解 Docker,学习成本高 Spring Cloud与Dubbo对比
Dubbo只是实现了服务治理,而Spring Cloud实现了微服务架构的方方面面。
核心要素 Dubbo Spring Cloud 服务注册中心 Zookeeper、Redis Spring Cloud Netflix Eureka 服务调用方式 RPC REST API 服务网关 无 Spring Cloud Netflix Zuul 断路器 不完善 Spring Cloud Netflix Hystrix 分布式配置 无 Spring Cloud Config 分布式追踪系统 无 Spring Cloud Sleuth 消息总线 无 Spring Cloud Bus 数据流 无 Spring Cloud Stream基于Redis,Rabbit,Kafkas实现的消息微服务 批量任务 无 Spring Cloud Task
服务注册中心是微服务架构的交通枢纽中心,用于管理各种服务功能包括服务的注册、发现、熔断、负载均衡、降级等等。所有的服务与服务之间的调用和被调用都需要服务注册中心。
为什么要使用注册中心
当拆分的服务达到一定规模时候,服务与服务之间的调用关系会很复杂,需要对其进行解耦。
什么是Eureka
Eureka是Nerflix公司的开源产品,提供了完整的服务注册和发现,也是Spring Cloud中最核心的组件之一。
Eureka组成
Eureka由两个组件组成:Eureka服务端和Eureka客户端。Eureka服务端就是注册中心,Eureka客户端就是一个Java的客户端,如下所示:
三种角色如下所示:
- Eureka Server
担任服务注册中心的角色,提供了服务的注册和发现的功能。
- Service Provider
服务提供者,将自身服务注册到服务注册中心Eureka Server
- Service Consumer
服务调用者,从Eureka获取注册服务列表,找到对应的服务地址再进行调用。
搭建Eureka Server
- 创建项目
创建Spring Boot项目,导入Eureka Server相关JAR包。如下所示:
- pom文件自动配置的依赖如下
org.springframework.cloud spring-cloud-starter-netflix-eureka-server org.springframework.boot spring-boot-starter-test test
- 配置application.properties
如下所示:
server.port=12000 #实例名称 eureka.instance.hostname=localhost #是否需要注册本项目到注册服务中心,默认为true eureka.client.register-with-eureka=false #是否要从注册服务中心查询本项目,默认为true eureka.client.fetch-registry=false #设置服务注册中心的url eureka.client.service-url.defalutZone=http://${eureka.instance.hostname}:${server.port}/eureka #应用名称 spring.application.name=letao-server
由于本项目是注册服务中心,故不需要注册和发现服务的功能,设置为false
- 在启动类上添加注解@EnableEurekaServer
@SpringBootApplication //启用Eureka服务 @EnableEurekaServer public class EurekaServerApplication { public static void main(String[] args) { SpringApplication.run(EurekaServerApplication.class, args); } }
- 运行
在启动类上点击运行,输入相应的地址:http://localhost:12000后,出现如下页面:
- 创建项目
创建Spring Boot项目,导入Eureka Discovery Client和Spring Web相关JAR包。如下所示:
- pom文件自动配置的依赖如下
org.springframework.boot spring-boot-starter-web org.springframework.cloud spring-cloud-starter-netflix-eureka-client org.springframework.boot spring-boot-starter-test test
- 配置application.properties
如下所示:
server.port=12001 #服务注册中心的URL eureka.client.service-url.defaultZone=http://localhost:12000/eureka #应用名称 spring.application.name=letao-client
- 在启动类上添加注解@EnableEurekaClient
@SpringBootApplication //启用Eureka客户端 @EnableEurekaClient @RestController public class EurekaServerApplication { public static void main(String[] args) { SpringApplication.run(EurekaServerApplication.class, args); } }
- 添加一个测试Controller控制器类
@Controller public class HelloController { @Value("${server.port}") String port; //获取客户端自己的端口号 @RequestMapping("/hello") public String hello(@RequestParam(value = "name", defaultValue = "Tom") String name) { return "hello " + name +", i am from port:" + port; } }
- 运行
在启动类上点击运行,输入相应的地址:http://localhost:12000后,出现如下页面:可以看出,客户端被添加进去了
Spring Cloud有两种调用服务的方式:Ribbon+restTemplate和Feign
Ribbon的搭建
什么是Ribbon?
Ribbon在客户端实现了负载均衡,能够自动的去帮助服务消费者去请求。
在Spring Cloud中,当Ribbon与Eureka配合使用时,Ribbon可自动从Eureka Server获取服务提供者地址列表,并基于负载均衡算法,请求其中一个服务提供者实例。如下所示:
使用Ribbon实例
- 创建多个Eureka Client
创建多个跟上面的Eureka Client一样的Eureka Client,除了每个Eureka Client使用不同的端口号,其他的都一样(包括一样的应用名称spring.application.name=letao-client和一样的hello()方法)。
- 创建项目
创建Spring Boot项目,导入Ribbon、Eureka Discovery Client和Spring Web相关JAR包。如下所示:
- pom文件自动配置的依赖如下
org.springframework.boot spring-boot-starter-web org.springframework.cloud spring-cloud-starter-netflix-eureka-client org.springframework.cloud spring-cloud-starter-netflix-ribbon org.springframework.boot spring-boot-starter-test test
- 配置application.properties
如下所示:
server.port=12003 #服务注册中心的URL eureka.client.service-url.defaultZone=http://localhost:12000/eureka #应用名称 spring.application.name=letao-ribbon
- 在启动类上添加注解
在启动类上向Spring注入一个bean:restTemplate,并添加@LoadBalanced注解,表明这个 restTemplate 开启负载均衡功能。Template表示模板的意思
@SpringBootApplication @EnableEurekaClient public class EurekaRibbonApplication { public static void main(String[] args) { SpringApplication.run(EurekaRibbonApplication.class, args); } @Bean @LoadBalanced RestTemplate restTemplate() { return new RestTemplate(); } }
- 创建一个Service服务类
@Service public class HelloService { @Autowired RestTemplate restTemplate; public String helloService(String name) { return restTemplate.getForObject("http://letao-client/hello?name="+name,String.class ); } }
这里使用Eureka Client的应用名称letao-client来代替地址和端口号
- 创建Controller控制器类
@RestController public class HelloController { @Autowired HelloService helloService; @RequestMapping("/hello") public String hello(@RequestParam String name) { String info = helloService.helloService(name); System.out.println(info); return info; } }
- 运行
输入地址:localhost:12003/hello?name="Jack",多次访问该地址效果如下:
可以看出,交替调用的不同的Eureka Client,说明实现了负载均衡,Ribbon 会在客户端发送请求时做一个负载均衡。
Ribbon负载均衡策略
Ribbon常见的负载均衡实现策略如下:
- 随机
- 轮询
- 一致性哈希
- 哈希
- 加权
Feign的搭建
什么是feign?
feign用于调用服务。整合了Ribbon,具有负载均衡的能力;整合了Hystrix,具有熔断的能力。
使用Feign实例
- 创建项目
创建Spring Boot项目,导入OpenFeign、Eureka Discovery Client和Spring Web相关JAR包。如下所示:
- pom文件自动配置的依赖如下
org.springframework.boot spring-boot-starter-web org.springframework.cloud spring-cloud-starter-netflix-eureka-client org.springframework.cloud spring-cloud-starter-openfeign org.springframework.boot spring-boot-starter-test test
- 配置application.properties
server.port=12004 #服务注册中心的URL eureka.client.service-url.defaultZone=http://localhost:12000/eureka #应用名称 spring.application.name=letao-feign
- 在启动类上添加注解@EnableEurekaClient、@EnableDiscoveryClient和@EnableFeignClients
@SpringBootApplication @EnableEurekaClient @EnableDiscoveryClient @EnableFeignClients public class EurekaFeignApplication { public static void main(String[] args) { SpringApplication.run(EurekaFeignApplication.class, args); } }
- 编写Service服务接口,添加注解
通过注解@FeignClient("服务应用名称"),来指定调用哪个服务;使用注解@GetMapping("接口名")来向接口发送Get请求;使用@RequestParam注解来指定请求参数。
@FeignClient("letao-client") public interface HelloService { @GetMapping("/hello") String hello(@RequestParam(value = "name") String name); }
- 编写Controller控制器类
@RestController public class HelloController { @Autowired HelloService helloService; @GetMapping("/hello") public String hello(@RequestParam String name) { String info = helloService.hello(name); System.out.println(info); return info; } }
- 运行
输入地址:localhost:12004/hello?name="Jack",多次刷新后,控制台打印如下:
可以看出,每次都调用了不同的Eureka Client,实现了负载均衡。
在链式调用服务时,如果其中一个服务发生异常,其他服务可能也会跟着发生异常。使用断路器后,当一个服务调用次数失败次数达到一定阈值的时候,断路器都会打开,执行服务调用失败时的处理方法,避免服务间连锁故障异常。
在Ribbon上使用Hystrix
- 在pom文件中添加Hystrix依赖
org.springframework.cloud spring-cloud-starter-netflix-hystrix
- 在程序启动类上添加@EnableHystrix注解,开启Hystrix
@SpringBootApplication @EnableEurekaClient @EnableHystrix public class EurekaRibbonApplication { public static void main(String[] args) { SpringApplication.run(EurekaRibbonApplication.class, args); } @Bean @LoadBalanced RestTemplate restTemplate() { return new RestTemplate(); } }
- 配置熔断方法和添加注解
在Service服务类上配置熔断方法,添加注解@HystrixComman,当服务方法不可用时,会执行熔断方法,如下:
@Service public class HelloService { @Autowired RestTemplate restTemplate; //添加注解,里面参数值是熔断方法名称 @HystrixCommand(fallbackMethod = "doError") public String helloService(String name) { return restTemplate.getForObject("http://letao-client/hello?name="+name,String.class ); } /** * 熔断方法 * @param name * @return */ public String doError(String name) { return "hello " + name + ", sorry some errors happened!"; } }
- 运行
启动项目,关闭eureka-client客户端,然后访问地址:http://localhost:12004/hello?name="Jack",控制台打印如下:
可以看出,当服务不可用时,断路器会执行熔断方法。
在Feign上使用Hystrix
- 打开断路器
Feign自带断路器,在D版本的Spring Cloud之后,它没有默认打开。需要在配置文件application.properties中打开:
server.port=12004 #服务注册中心的URL eureka.client.service-url.defaultZone=http://localhost:12000/eureka #应用名称 spring.application.name=letao-feign #打开断路器 feign.hystrix.enabled=true
- 定义熔断实现类
@Component public class HelloHystrix implements HelloService{ @Override public String hello(String name) { return "hello " + name + ", sorry some errors happened!"; } }
要在熔断实现类上添加注解@Component,不然出现如下错误:
No fallback instance of type class com.luckylqs.hystrix.HelloHystrix found for feign client letao-client
- 在Service服务接口类上指定熔断实现类
fallback指定熔断实现类名称
@FeignClient(value = "letao-client", fallback = HelloHystrix.class) public interface HelloService { @GetMapping("/hello") String hello(@RequestParam(value = "name") String name); }
- 运行
访问地址:http://localhost:12004/hello?name="Jack",控制台打印如下: