一、什么是SpringCloud?
Spring Cloud是一个基于Spring Boot实现的,为开发者提供了快速构建分布式系统的工具集。
包括配置管理、服务发现、断路器、路由、微代理、事件总线、全局锁、决策竞选、分布式会话等等。
二、服务的注册和发现
1、要想SpringCloud中包含Eureka服务器,需要加入Eureka的依赖。
Spring Cloud Netflix的Eureka ,eureka是一个服务注册和发现模块。
2、eureka是一个高可用的组件,它没有后端缓存,每一个实例注册之后需要向注册中心发送心跳,
在默认情况下erureka server也是一个eureka client ,如果只作为一个服务注册中心,则必须要在(yml)配置文件
中指定是一个 server。
通过eureka.client.registerWithEureka:false和fetchRegistry:false来表明自己是一个eureka server。
3、在SpringBoot的主配置类上添加@EnableEurekaServer注解,启动一个服务注册中心。
eureka server 是有界面的,端口默认为8761
4、服务提供者 (eureka client):服务的被调用方
当client向server注册时,它会提供一些元数据,例如主机和端口,URL,主页等。
Eureka server 从每个client实例接收心跳消息。 如果心跳超时,则通常将该实例从注册server中删除。
5、@EnableDiscoveryClient 与 @EnableEurekaClient 的区别:
● spring cloud中discovery service有许多种实现(eureka、consul、zookeeper等等),
@EnableDiscoveryClient基于spring-cloud-commons, @EnableEurekaClient基于spring-cloud-netflix。
● 其实用更简单的话来说,就是如果选用的注册中心是eureka,那么就推荐@EnableEurekaClient,
如果是其他的注册中心,那么推荐使用@EnableDiscoveryClient。
● @EnableEurekaClient注解只能用在服务采用的是eureka作为注册中心,
如果服务采用的是其它的注册中心,则不能使用,只能使用@EnableDiscoveryClient 。
三、服务消费者(服务调用方)
在微服务架构中,业务都会被拆分成一个独立的服务,服务与服务的通讯是基于http restful的。
★ Spring cloud有两种服务调用方式:
一种是:ribbon + restTemplate;
另一种是:feign
★ ribbon是一个负载均衡客户端,可以很好的控制htt和tcp的一些行为。Feign默认集成了ribbon。
1、服务消费者(restTemplate + ribbon)
①、在Springboot的主配置类上,添加@EnableDiscoveryClient注解,通过此注解向服务注册中心注册;
②、并且在主配置类中通过@Bean注解注入一个RestTemplate bean,返回值是注册的bean,
方法名是容器中该bean的id;
③、在注入的RestTemplate bean上添加 @LoadBalanced 注解表明这个RestTemplate 开启了负载均衡的功能;
④、写一个测试类,使用 @Autowired 注入RestTemplate,然后使用RestTemplate调用服务提供者提供的服务接
口,可以使用程序名代替具体的Url地址,在Ribben中会根据服务名来选择具体的服务实例,根据服务实例在请求
的时候会用具体的url替换服务名。
通过以上步骤编写完之后,多次调用方法,会发现已经实现了负载均衡,默认是使用的轮询机制。
此外还有随机访问、响应时间加权等机制实现负载均衡。
2、服务消费者(Feign)
● Feign是一个声明式的伪Http客户端,它使得写Http客户端变得更简单。Feign 采用的是基于接口的注解;
● Feign默认集成了Ribbon,并和Eureka结合,默认实现了负载均衡的效果。
①、导入spring-cloud-starter-feign、spring-cloud-starter-eureka、spring-boot-starter-web依赖;
②、在配置文件application.yml文件中,指定程序名,端口号,服务注册地址;
③、在SpringBoot的主配置类上添加@EnableFeignClients注解开启Feign的功能;
④、定义一个接口,接口上添加@ FeignClient(“服务名”)注解,来指定调用哪个服务;
在接口中写一个方法,指定调用指定服务的哪个方法;
⑤、在web层的controller层,写一个controller,用于外界访问
启动程序,多次访问,发现也实现负载均衡的效果,不同端口轮询显示
四、断路器(Hystrix)
● 在微服务架构中,根据业务需求把一个复杂的软件应用拆分成一个个的微小服务,服务与服务之间可以相互调用
【RPC:远程过程调用(Remote Procedure Call)】,在Spring Cloud 中可以使用RestTemplate + Ribbon 或
Feign来调用。为了保证其高可用,单个服务通常会集群部署。由于网络原因或者自身的原因,服务并不能保证100%
可用,如果单个服务出现问题,调用这个服务就会出现线程阻塞,此时若有大量的请求涌入,Servlet容器的线程资源
会被消耗完毕,导致服务瘫痪。服务与服务之间的依赖性,故障会传播,会对整个微服务系统造成灾难性的严重后果,
这就是服务故障的“雪崩”效应。
● 解决这个问题的方法:断路器
● Netflix开源了Hystrix组件,实现了断路器模式,SpringCloud对这一组件进行了整合。
在微服务架构中,一个请求需要调用多个服务是非常常见的,较底层的服务如果出现故障,会导致连锁故障。
当对特定的服务的调用,其不可用达到一个阀值(Hystrix 默认是5秒内出现20次), 断路器将会被打开。
断路打开后,可用避免连锁故障,fallback方法可以直接返回一个固定值。
▲ 在ribbon中使用断路器
①、首先在pom.xml 添加 spring-cloud-starter-hystrix 依赖;
②、在SpringBoot的主配置类上添加@EnableHystrix注解开启Hystrix;
③、在服务消费者调用服务提供者接口的方法上添加@HystrixCommand(fallbackMethod = "方法名")注解,
该注解对该方法创建了断路器的功能,并指定了fallbackMethod ,fallbackMethod 中的方法返回一个固定值。
@Service
public class HelloService {
@Autowired
RestTemplate restTemplate;
@HystrixCommand(fallbackMethod = "hiError")
public String hiService(String name) {
return restTemplate.getForObject("http://SERVICE-HI/hi?name="+name,String.class);
}
public String hiError(String name) {
return "hi,"+name+",sorry,error!";
}
}
如果出现故障,直接返回指定的值,而不是等待响应超时,很好的控制了容器的线程阻塞。
▲ 在Feign中使用断路器
①、在接口上的@FeignClient注解中添加fallback 属性
@FeignClient(value = "service-hi",fallback = SchedualServiceHiHystric.class)
public interface SchedualServiceHi {
@RequestMapping(value = "/hi",method = RequestMethod.GET)
String sayHiFromClientOne(@RequestParam(value = "name") String name);
}
②、fallback 属性指定的类实现接口,并注入到Ioc容器中
@Component
public class SchedualServiceHiHystric implements SchedualServiceHi {
@Override
public String sayHiFromClientOne(String name) {
return "sorry "+name;
}
}
③、在配置文件中添加:
feign:
hystrix:
enabled: true
▲ Hystrix Dashboard (断路器:Hystrix 仪表盘)
①、需要在pom.xml 中添加spring-cloud-starter-hystrix、spring-cloud-starter-hystrix-dashboard、
spring-boot-starter-actuator依赖;
②、在SpringBoot的主配置类上添加@EnableHystrix 和 @EnableHystrixDashboard 注解,
@EnableHystrixDashboard注解是开启hystrixDashboard;
③、打开浏览器:访问[http://localhost:端口/hystrix,界面如下:
④、点击monitor stream,进入下一个界面,然后新开窗口访问:http://localhost:8764/hi?name=forezp
然后返回之前的窗口,此时会出现监控界面:
五、路由网关(zuul)
1、在Spring Cloud微服务系统中,一种常见的负载均衡方式是,客户端的请求首先经过负载均衡(zuul、Ngnix),再到达服务网关(zuul集群),
然后再到具体的服。服务统一注册到高可用的服务注册中心Eureka集群,服务的所有的配置文件由配置服务管理,配置服务的配置文件放在git仓库,
方便开发人员随时改配置。
2、Zuul的主要功能是路由转发和过滤器。路由功能是微服务的一部分,比如/api/user转发到到user服务,/api/shop转发到到shop服务。
zuul默认和Ribbon结合实现了负载均衡的功能。
▲ 3、zuul的路由转发功能的实现:
①、在pom.xml 中导入spring-cloud-starter-zuul依赖;
②、在SpringBoot的主配置类上添加@EnableZuulProxy,开启zuul的功能;
③、在配置文件application.yml中加上以下的配置代码:
eureka:
client:
serviceUrl:
#指定服务注册中心的地址
defaultZone: http://localhost:8761/eureka/
server:
#指定服务的端口
port: 8768
#指定服务名
spring:
application:
name: service-zuul
#指定zuul的路由转发功能
zuul:
routes:
#以/to-ribbon/ 开头的请求都转发给service-ribbon服务;
api-a:
path: /to-ribbon/**
serviceId: service-ribbon
#以/to-feign/开头的请求都转发给service-feign服务;
api-b:
path: /to-feign/**
serviceId: service-feign
④、依次运行工程;打开浏览器访问:http://localhost:8768/to-ribbon/hi?name=tom;浏览器显示:
hi tom ,i am from port:8763
▲ 4、zuul的服务过滤功能,可以做一些安全验证,写一个filter extends ZuulFilter
六、分布式配置中心(Spring cloud Config)
1、在分布式系统中,由于服务数量巨多,为了方便服务配置文件统一管理,实时更新,所以需要分布式配置中心组件。
在Spring Cloud中,有分布式配置中心组件spring cloud config ,它支持配置服务放在配置服务的内存中(即本地),
也支持放在远程Git仓库中。
在spring cloud config 组件中,分两个角色,一是config server,二是config client。
2、配置服务中心可以从远程程序获取配置信息。【config-server 从git仓库读取配置文件信息】
①、在pom.xml 中 导入 spring-cloud-config-server依赖;
②、在SpringBoot的主配置类上添加@EnableConfigServer注解,开启配置服务器的功能;
③、在配置文件application.properties中进行相关配置:
spring.application.name=服务名
server.port=端口必须是8888
spring.cloud.config.server.git.uri=配置git仓库地址
spring.cloud.config.server.git.searchPaths=配置仓库路径
spring.cloud.config.label=配置仓库的分支
spring.cloud.config.server.git.username=用户名 (如果Git仓库为公开仓库,可以不填写用户名和密码,如果是私有仓库需要填写)
spring.cloud.config.server.git.password=密码
④、 启动程序访问里面的配置文件,http请求地址和资源文件映射如下:
/{application}/{profile}[/{label}]
/{application}-{profile}.yml
/{label}/{application}-{profile}.yml
/{application}-{profile}.properties
/{label}/{application}-{profile}.properties
【注意:】{application}是git仓库中配置文件的文件名,该文件名与config-client的项目中配置文件中的spring.application.name值相同
4、本地从配置中心读取值
①、在pom.xml 中 导入 spring-cloud-starter-config 依赖;
②、在配置文件application.properties中进行相关配置:
spring.application.name=服务名
server.port=端口任意
spring.cloud.config.label=指明远程仓库的分支
spring.cloud.config.profile=激活什么环境
spring.cloud.config.uri= 指明配置服务中心的网址
③、写一个controller,可以获取从配置中心读取的值
5、config-client可以从config-server 中获取属性,而config-server是从git仓库读取的
【注意:】
● config-server 中的配置文件的端口必须是8888
● spring.application.name 设置的值必须和git仓库中要读取的配置文件的名字一样
否则config-client 从配置中心读取值时就会报错:Could not resolve placeholder '要读取的值' in value "${要读取的值}"