请先阅读分布式架构相关概念介绍
Spring Cloud
Spring Cloud是快速构建微服务项目的java框架,为解决微服务架构的各种问题提供了一整套方案和实现。
Spring Cloud是基于Spring Boot来开发的,核心配置文件为bootstrap.properties和application.properties,其中application.properties是Spring Boot本来就有的,bootstrap.properties是Spring Cloud项目才有的。
bootstrap.properties先于application.properties加载,主要应用于Spring Cloud Config Server项目和Spring Cloud Config Client项目中,其他项目不需要使用bootstrap.properties。
SpringCloud的基础功能
服务注册与发现: Spring Cloud Eurek
声明式服务调用: Spring Cloud Feign,Spring Cloud OpenFeign
服务熔断保护: Spring Cloud Hystrix
客户端负载均衡: Spring Cloud Ribbon
服务网关:Spring Cloud Zuul,Spring Cloud Gateway
分布式配置中心: Spring Cloud Config
SpringCloud的高级功能
消息总线: Spring Cloud Bus
消息驱动的微服务: Spring Cloud Stream
分布式服务跟踪: Spring Cloud Sleuth
服务定时任务调度
自动化构建部署
版本选择
spring cloud和spring boot版本对应关系
粗略版本对应关系:https://spring.io/projects/spring-cloud#overview
详细版本对应关系,访问然后将结果格式化看版本对应关系:https://start.spring.io/actuator/info
已经成熟的版本选择
cloud:Hoxton.SR1
boot:2.2.2.RELEASE
cloud alibaba:2.1.0.RELEASE
java:Java8
maven:3.5及以上
mysql:5.7及以上
Spring Cloud组件升级
Eureka
是SpringCloud对服务治理的实现,根据功能角色可分为:Eureka Server(服务注册中心)和Eureka Client(服务客户端)。Eureka Client又分为服务提供者(Provider)和服务消费者(Consumer)。
服务一般既可以是服务提供者又可以是服务消费者,也可以作为单纯的服务消费者(单纯的服务消费者可以不用在Eureka Server注册)
Eureka Server(服务注册中心)
失效剔除:默认每隔一段时间(默认为60秒) 将当前清单中超时(默认为90秒)没有续约的服务剔除出去。
自我保护:。EurekaServer 在运行期间,会统计心跳失败的比例在15分钟之内是否低于85%(通常由于网络不稳定导致)。 Eureka Server会将当前的实例注册信息保护起来, 让这些实例不会过期,尽可能保护这些注册信息。
EurekaServer可以配置多个(集群)相互注册,从而达到EurekaServer稳定高可用,避免EurekaServer宕机所有服务都无法使用。
单个EurekaServer配置示例:
server.port=8761
eureka.instance.hostname=localhost
eureka.client.service-url.defaultZone=http://${eureka.instance.hostname}:${server.port}/eureka/
##禁止自己向自己注册
eureka.client.register-with-eureka=false
eureka.client.fetch-registry=false
EurekaServer集群配置示例:
项目springcloud_eureka_server1(8761):
server.port=8761
eureka.instance.hostname=server1
eureka.client.service-url.defaultZone=http://server2:8762/eureka/
spring.application.name=server1
项目springcloud_eureka_server2(8762)
server.port=8762
eureka.instance.hostname=server2
eureka.client.service-url.defaultZone=http://server1:8761/eureka/
spring.application.name=server2
启动类注解:
@EnableEurekaServer
maven依赖:
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-server</artifactId>
</dependency>
可以在浏览器访问EurekaServer的项目根路径查看服务注册情况。
Eureka Client(服务客户端)
服务提供者:
服务注册:启动的时候会通过发送REST请求的方式将自己注册到Eureka Server上,同时带上了自身服务的一些元数据信息。
**服务续约:**在注册完服务之后,服务提供者会维护一个心跳用来持续告诉Eureka Server: "我还活着 ” 、
服务下线:当服务实例进行正常的关闭操作时,它会触发一个服务下线的REST请求给Eureka Server, 告诉服务注册中心:“我要下线了 ”。
服务消费者:
获取服务:当我们启动服务消费者的时候,它会发送一个REST请求给服务注册中心,来获取上面注册的服务清单
服务调用:服务消费者在获取服务清单后,通过服务名可以获得具体提供服务的实例名和该实例的元数据信息。在进行服务调用的时候,优先访问同处一个Zone中的服务提供方。
启动类注解:
@EnableDiscoveryClient或@EnableEurekaClient注解。
这两者的区别在于:spring cloud中discovery service有许多种实现(eureka、consul、zookeeper等等),@EnableDiscoveryClient基于spring-cloud-commons, @EnableEurekaClient基于spring-cloud-netflix。
其实用更简单的话来说,就是如果选用的注册中心是eureka,那么就推荐@EnableEurekaClient,如果是其他的注册中心,那么推荐使用@EnableDiscoveryClient。
maven依赖:
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>
eureka自我保护
什么是自我保护模式?
默认情况下,如果 EurekaServer在一定时间内没有接收到某个微服务实例的心跳, EurekaServer将会注销该实例(默认90秒)。但是当网络分区故障发生(延时、卡顿、拥挤)时,微服务与 EurekaServer之间无法正常通信,以上行为可能变得非常危险了一一因为微服务本身其实是健康的,此时本不应该注销这个微服务。 Eurekai通过“自我保护模式”来解决这个问题一一当EurekaServer节点在短时间内丢失过多客户端时(可能发生了网络分区故障),那么这个节点就会进入自我保护模式。
在自我保护模式中, Eureka Server会保护服务注册表中的信息,不再注销任何服务实例。
它的设计哲学就是宁可保留错误的服务注册信息,也不盲目注销任何可能健康的服务实例。一句话讲解:好死不如赖活着。
综上,自我保护模式是一种应对网络异常的安全保护措施。它的架构哲学是宁可同时保留所有微服务(健康的微服务和不健康的微服务都会保留)也不盲目注销任何健康的微服务。使用自我保护模式,可以让 Eureka集群更加的健壮、稳定。
RestTemplate
RestTemplate是SpringCloud提供的访问restful接口的工具类,可以直接传入在EurekaServer注册的服务实例名进行调用,也可以直接使用ip地址进行调用。
主要方法有:
postForObject(接口地址, 参数, 返回值类型)
getForEntity(接口地址, 返回值类型)
示例:
ResponseEntity<Integer> result = restTemplate.postForObject("http://service1/add", new User("张三","男"), Integer.class);
Integer resultValue=result.getBody();
ResponseEntity<String> result = restTemplate.getForEntity("http://service2/query?name=张三", String.class);
String resultValue=result.getBody();
Spring Cloud使用RestTemplate请求其他服务时,内部使用的就是常规的http请求实例发送请求。
为RestTemplate增加了@LoanBalanced 注解后,实际上通过配置,为RestTemplate注入负载均衡拦截器,让负载均衡器选择根据其对应的策略选择合适的服务后,再发送请求。
Spring Cloud Ribbon
Ribbon是Spring Cloud客户端负载均衡的实现,Ribbon自带了一系列不同负载均衡策略的实现,我们也可以根据需要自定义负载均衡策略。
使用java config配置所有服务的均衡策略:
@Configuration
public class RuleConfig{
@Bean
public IRule ribbonRule() {
return new RandomRule();
}
}
使用application.properties设置单个服务的均衡策略:
服务名.ribbon.NFLoadBalancerRuleClassName: com.netflix.loadbalancer.RandomRule
启动类注解:
不需要也没有启动类注解。
maven依赖:
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-eureka</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-ribbon</artifactId>
</dependency>
Spring Cloud Ribbon负载均衡策略类关系图
Ribbon负载均衡策略规则实现
内置负载均衡规则类 | 规则描述 |
---|---|
RoundRobinRule | 简单轮询服务列表来选择服务器。它是Ribbon默认的负载均衡规则。 |
AvailabilityFilteringRule | 对以下两种服务器进行忽略:(1)在默认情况下,这台服务器如果3次连接失败,这台服务器就会被设置为“短路”状态。短路状态将持续30秒,如果再次连接失败,短路的持续时间就会几何级地增加。注意:可以通过修改配置loadbalancer..connectionFailureCountThreshold来修改连接失败多少次之后被设置为短路状态。默认是3次。(2)并发数过高的服务器。如果一个服务器的并发连接数过高,配置了AvailabilityFilteringRule规则的客户端也会将其忽略。并发连接数的上线,可以由客户端的..ActiveConnectionsLimit属性进行配置。 |
WeightedResponseTimeRule | 随机选择,但服务器响应时间越长,这个服务器的被选中的权重就越小。 |
ZoneAvoidanceRule | 从可用区域中选择服务器,并过滤掉连接数过多服务器。 |
BestAvailableRule | 忽略短路的(tripped)服务器,并选择并发数最低(连接数量最小)的服务器。 |
RandomRule | 随机选择一个可用的服务器。 |
RetryRule | 重试机制的选择逻辑 |
Hystrix
Spring Cloud Hystrix实现了断路器、线程隔离等一系列服务保护功能。
核心功能:服务降级,服务熔断,服务限流,服务监控。
Fallback(失败快速返回):当某个服务单元发生故障(类似用电器发生短路)之后,通过断路器的故障监控(类似熔断保险丝), 向调用方返回一个错误响应, 而不是长时间的等待。这样就不会使得线程因调用故障服务被长时间占用不释放,避免了故障在分布式系统中的蔓延。
资源/依赖隔离(线程池隔离):它会为每一个依赖服务创建一个独立的线程池,这样就算某个依赖服务出现延迟过高的情况,也只是对该依赖服务的调用产生影响, 而不会拖慢其他的依赖服务。
Hystrix提供几个熔断关键参数:滑动窗口大小(20)、 熔断器开关间隔(5s)、错误率(50%)
每当20个请求中,有50%失败时,熔断器就会打开,此时再调用此服务,将会直接返回失败,不再调远程服务。
直到5s钟之后,重新检测该触发条件,判断是否把熔断器关闭,或者继续打开。
Hystrix还有请求合并、请求缓存这样强大的功能。
hystrix原理介绍:
https://zhuanlan.zhihu.com/p/34304136
服务降级,fallback
服务器忙,请稍后再试,不让客户端等待并立刻返回一个友好提示。
哪些情况会出发降级
- 程序运行异常
- 超时
- 服务熔断触发服务降级
- 线程池/信号量打满也会导致服务降级
服务熔断,break
类比保险丝达到最大服务访问后,直接拒绝访问,拉闸限电,然后调用服务降级的方法并返回友好提示。
服务限流,flowlimit
秒杀高并发等操作,严禁一窝蜂的过来拥挤,大家排队,一秒钟一个,有序进行。
服务监控,Hystrix Dashboard
它主要用来实时监控Hystrix的各项指标信息。通过Hystrix Dashboard反馈的实时信息,可以帮助我们快速发现系统中存在的问题,从而及时地采取应对措施。
Spring Cloud Feign
基于 Netflix Feign 实现,整合了 Spring Cloud Ribbon 与 Spring Cloud Hystrix, 除了整合这两者的强大功能之外,它还提 供了声明式的服务调用(不再通过RestTemplate)。
声明式服务调用:
使用HTTP请求远程服务时能与调用本地方法一样的编码体验,开发者完全感知不到这是远程方法,更感知不到这是个HTTP请求。
启动类注解:
@EnableFeignClients
maven依赖:
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-eureka</artifactId><!--不能去掉-->
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-feign</artifactId>
</dependency>
Feign简单示例:
服务绑定:
// value --->指定调用哪个服务
// fallbackFactory--->熔断器的降级提示
@FeignClient(value = "要调用的服务名", fallbackFactory = UserServiceFallback.class)
public interface UserService {
// 使用springmvc注解,将方法绑定到远程服务具体的url
@RequestMapping(value = "/user/query/{id}", method = RequestMethod.GET)
public User query(@PathVariable("id") Integer id);
@RequestMapping(value = "/user/add", method = RequestMethod.POST)
public Integer add(User user);
}
/**
* Feign中使用断路器
* 这里主要是处理服务调用异常时的情况(降级/熔断时服务不可用)
*/
@Component//必须要注册到Spring容器中去
public class UserServiceFallback implements FallbackFactory<UserService> {
@Override
public UserService create(Throwable throwable) {
return new UserService() {
@Override
public User query(Integer id) {
return null;
}
@Override
public Integer add(User user) {
return 0;
}
};
}
}
zuul
SpringCloud Zuul通过与SpringCloud Eureka进行整合,将zuul自身注册为Eureka服务治理下的应用,同时从Eureka中获得了所有其他微服务的实例信息。外层调用都必须通过API网关,使得将维护服务实例的工作交给了服务治理框架自动完成。
在API网关服务上进行统一调用来对微服务接口做前置过滤,以实现对微服务接口的拦截和校验。
启动类注解:
@EnableZuulProxy
zuul作用
在服务集群时,对外部统一服务地址,调用者只需要知道一个服务地址即可,而不用维护服务的所有服务地址。
在服务集群时,实现服务端对外部调用者的负载均衡,也就是说,服务端自行负载均衡,调用者不用管(有点像nginx反向代理)。
统一服务的权限验证处理,避免冗余的代码。
Zuul还有很多知识点:
路由匹配(动态路由)
过滤器实现(动态过滤器)
默认会过滤掉Cookie与敏感的HTTP头信息(额外配置)
zuul与Ribbon、Hystrix
只要引入了spring-cloud-starter-zuul就会间接引入Ribbon、Hystrix
路由信息可能是从配置文件中加载的,也可能是通过DiscoveryClient从注册中心加载的
zuul是通过前置过滤器PreDecorationFilter找到与当前requestURI匹配的路由信息,并在RequestContext中设置相关属性的,后续的Route Filter会根据RequestContext中的这些属性判断如何路由转发
Route Filter主要使用 SimpleHostRoutingFilter 和 RibbonRoutingFilter
当RequestContext请求上下文中存在routeHost,即URL直连信息时,使用SimpleHostRoutingFilter简单Host路由
当RequestContext请求上下文中存在serviceId,即服务id时(可能会与注册中心关联获取服务列表,或者读取配置文件中serviceId.ribbon.listOfServers的服务列表),使用RibbonRoutingFilter,会使用Ribbon、Hystrix
个人理解:zuul在对外提供服务时,不会使用到Ribbon、Hystrix,只有在转发url包含serviceId的路由时,才会使用到Ribbon、Hystrix。也就是说,zuul本身和Ribbon、Hystrix没有半毛钱关系,但因为zuul要做转发内部服务请求的工作,所以被迫使用了Ribbon、Hystrix。
Zuul和Nginx反向代理
有了zuul,一般来说可以不需要使用nginx反向代理了,因为zuul相当于已经做了反向代理了,除非需要将Zuul自己搭成集群来实现高可用,那么zuul和nginx反向代理可以一起使用。
SpringCloud Config
在分布式系统中,由于服务数量巨多(服务越多配置文件越多),为了方便服务配置文件统一管理,实时更新,所以需要分布式配置中心组件。
SpringCloud Config有两个角色,一是config server,二是config client。
server提供配置文件的存储、以接口的形式将配置文件的内容提供出去,client通过接口获取数据、并依据此数据初始化自己的应用。
Sentinel
https://github.com/alibaba/Sentinel/wiki/介绍
简而言之就是替代Hystrix的断路器。
Hystrix的缺陷:
1 需要我们程序员自己手工搭建监控平台
2 没有一套web界面可以给我们进行更加细粒度化得配置,如流控、速率控制、服务熔断、服务降级等等。
Sentinel主要功能:
Sentinel主要构成:
Sentinel本身是一个微服务。
Sentinel Dashboard是一个可视化的控制台(web网站)。
Sentinel Dashboard介绍:https://github.com/alibaba/Sentinel/tree/master/sentinel-dashboard
https://github.com/alibaba/Sentinel/wiki/%E5%90%AF%E5%8A%A8%E9%85%8D%E7%BD%AE%E9%A1%B9
https://github.com/alibaba/Sentinel/blob/master/sentinel-dashboard/Sentinel_Dashboard_Feature.md
Sentinel Dashboard下载:https://github.com/alibaba/Sentinel/releases
下载这个sentinel-dashboard-1.8.5.jar
Sentinel Dashboard运行:
java -Dserver.port=8080 \
-Dcsp.sentinel.dashboard.server=localhost:8080 \
-Dproject.name=sentinel-dashboard \
-jar target/sentinel-dashboard.jar
Sentinel Dashboard访问:
http://127.0.0.1:8080/
账号:sentinel
密码:sentinel
京东微服务架构图