公众号springcloudAlibaba实战和源码分析正在火热更新中,更有17种Java生态技术面试宝典
组成:
服务注册与发现组件:Eureka,Zookeeper,Consul,Nacos等。Eureka基于REST风格的。
服务调用组件:Hystrix(熔断降级,在出现依赖服务失效的情况下,通过隔离 系统依赖服务 的方式,防止服务级联失败,同时提供失败回滚机制,使系统能够更快地从异常中恢复),Ribbon(客户端负载均衡,用于提供客户端的软件负载均衡算法,提供了一系列完善的配置项:连接超时、重试等),OpenFeign(优雅的封装Ribbon,是一个声明式RESTful网络请求客户端,它使编写Web服务客户端变得更加方便和快捷)。
网关:路由和过滤。Zuul,Gateway。
配置中心:提供了配置集中管理,动态刷新配置的功能;配置通过Git或者其他方式来存储。
消息组件:Spring Cloud Stream(对分布式消息进行抽象,包括发布订阅、分组消费等功能,实现了微服务之间的异步通信)和Spring Cloud Bus(主要提供服务间的事件通信,如刷新配置)
安全控制组件:Spring Cloud Security 基于OAuth2.0开放网络的安全标准,提供了单点登录、资源授权和令牌管理等功能。
链路追踪组件:Spring Cloud Sleuth(收集调用链路上的数据),Zipkin(对Sleuth收集的信息,进行存储,统计,展示)。
组件概述:
Eureka:服务注册与发现,用于服务管理。
Feign:web调用客户端,能够简化HTTP接口的调用。
Ribbon:基于客户端的负载均衡。
Hystrix:熔断降级,防止服务雪崩。
Zuul:网关路由,提供路由转发、请求过滤、限流降级等功能。
Config:配置中心,分布式配置管理。
Sleuth:服务链路追踪
Admin:健康管理
RestTemplate + Eureka
@Bean
RestTemplate restTemplate() {
return new RestTemplate();
}
@Bean
RestTemplate restTemplate() {
RestTemplate restTemplate = new RestTemplate();
//自定义过滤器
restTemplate.getInterceptors().add(new LoggingClientHttpRequestInterceptor());
return restTemplate;
}
调用http服务
String url ="http://provider/sayHello";
String respStr = restTemplate.getForObject(url, String.class);
Ribbon + Eureka
当系统面临大量的用户访问,负载过高的时候,通常会增加服务器数量来进行横向扩展(集群),多个服务器的负载需要均衡,以免出现服务器负载不均衡,部分服务器负载较大,部分服务器负载较小的情况。通过负载均衡,使得集群中服务器的负载保持在稳定高效的状态,从而提高整个系统的处理能力。
@Bean
// 开启负载均衡
@LoadBalanced
RestTemplate restTemplate() {
return new RestTemplate();
}
Ribbon作为Spring Cloud的负载均衡机制的实现,
Ribbon可以单独使用,作为一个独立的负载均衡组件。只是需要我们手动配置 服务地址列表。
Ribbon与Eureka配合使用时,Ribbon可自动从Eureka Server获取服务提供者地址列表(DiscoveryClient),并基于负载均衡算法,请求其中一个服务提供者实例。
Ribbon与OpenFeign和RestTemplate进行无缝对接,让二者具有负载均衡的能力。OpenFeign默认集成了ribbon。
负载均衡算法
ZoneAvoidanceRule(区域权衡策略):复合判断Server所在区域的性能和Server的可用性,轮询选择服务器。
其他规则:
BestAvailableRule(最低并发策略):会先过滤掉由于多次访问故障而处于断路器跳闸状态的服务,然后选择一个并发量最小的服务。逐个找服务,如果断路器打开,则忽略。
RoundRobinRule(轮询策略):以简单轮询选择一个服务器。按顺序循环选择一个server。
RandomRule(随机策略):随机选择一个服务器。
AvailabilityFilteringRule(可用过滤策略):会先过滤掉多次访问故障而处于断路器跳闸状态的服务和过滤并发的连接数量超过阀值得服务,然后对剩余的服务列表安装轮询策略进行访问。
WeightedResponseTimeRule(响应时间加权策略):据平均响应时间计算所有的服务的权重,响应时间越快服务权重越大,容易被选中的概率就越高。刚启动时,如果统计信息不中,则使用RoundRobinRule(轮询)策略,等统计的信息足够了会自动的切换到WeightedResponseTimeRule。响应时间长,权重低,被选择的概率低。反之,同样道理。此策略综合了各种因素(网络,磁盘,IO等),这些因素直接影响响应时间。
RetryRule(重试策略):先按照RoundRobinRule(轮询)的策略获取服务,如果获取的服务失败则在指定的时间会进行重试,进行获取可用的服务。如多次获取某个服务失败,就不会再次获取该服务。主要是在一个时间段内,如果选择一个服务不成功,就继续找可用的服务,直到超时。
Feign
OpenFeign是Netflix 开发的声明式、模板化的HTTP请求客户端。可以更加便捷、优雅地调用http api。
OpenFeign会根据带有注解的函数信息构建出网络请求的模板,在发送网络请求之前,OpenFeign会将函数的参数值设置到这些请求模板中。
feign主要是构建微服务消费端。只要使用OpenFeign提供的注解修饰定义网络请求的接口类,就可以使用该接口的实例发送RESTful的网络请求。还可以集成Ribbon和Hystrix,提供负载均衡和断路器。
是一个 Http 请求调用的轻量级框架,可以以 Java 接口注解的方式调用 Http 请求,而不用像 Java 中通过封装 HTTP 请求报文的方式直接调用。通过处理注解,将请求模板化,当实际调用的时候,传入参数,根据参数再应用到请求上,进而转化成真正的请求,这种请求相对而言比较直观。Feign 封装 了HTTP 调用流程,面向接口编程。
Feign和OpenFeign的关系
Feign本身不支持Spring MVC的注解,它有一套自己的注解
OpenFeign是Spring Cloud 在Feign的基础上支持了Spring MVC的注解,如@RequesMapping等等。OpenFeign的@FeignClient
可以解析SpringMVC的@RequestMapping注解下的接口, 并通过动态代理的方式产生实现类,实现类中做负载均衡并调用其他服务。
@RequestMapping("/User")
public interface RegisterApi {
@GetMapping("/isAlive")
public String isAlive();
}
//provider实现当前接口并实现
package com.mashibing.UserProvider;
import com.mashibing.UserAPI.RegisterApi;
@RestController
public class UserController implements RegisterApi {
@Override
public String isAlive() {
return "ok";
}
}
consumer调用
@FeignClient(name = "user-provider")
public interface UserConsumerService extends RegisterApi {
}
@RestController
public class ConsumerController {
@Autowired
UserConsumerService consumerSrv;
@GetMapping("/alive")
public String alive() {
return consumerSrv.isAlive();
}
}
Get和Post
Feign默认所有带参数的请求都是Post,想要使用指定的提交方式需引入依赖
<dependency>
<groupId>io.github.openfeign</groupId>
<artifactId>feign-httpclient</artifactId>
</dependency>
并指明提交方式
@RequestMapping(value = "/alived", method = RequestMethod.POST)
@GetMapping("/findById")
带参请求
@GetMapping("/findById")
public Map findById(@RequestParam("id") Integer id);
@PostMapping("/register")
public Map<String, String> reg(@RequestBody User user);
原理
主程序入口添加@EnableFeignClients注解开启对Feign Client扫描加载处理。根据Feign Client的开发规范,定义接口并加@FeignClient注解。
当程序启动时,会进行包扫描,扫描所有@FeignClient注解的类,并将这些信息注入Spring IoC容器中。当定义的Feign接口中的方法被调用时,通过JDK的代理方式,来生成具体的RequestTemplate。当生成代理时,Feign会为每个接口方法创建一个RequestTemplate对象,该对象封装了HTTP请求需要的全部信息,如请求参数名、请求方法等信息都在这个过程中确定。
然后由RequestTemplate生成Request,然后把这个Request交给client处理,这里指的Client可以是JDK原生的URLConnection、Apache的Http Client,也可以是Okhttp。最后Client被封装到LoadBalanceClient类,这个类结合Ribbon负载均衡发起服务之间的调用。
超时
Feign默认支持Ribbon;Ribbon的重试机制和Feign的重试机制有冲突,所以源码中默认关闭Feign的重试机制,使用Ribbon的重试机制
#连接超时时间(ms)
ribbon.ConnectTimeout=1000
#业务逻辑超时时间(ms)
ribbon.ReadTimeout=6000
重试
#同一台实例最大重试次数,不包括首次调用
ribbon.MaxAutoRetries=1
#重试负载均衡其他的实例最大重试次数,不包括首次调用
ribbon.MaxAutoRetriesNextServer=1
#是否所有操作都重试
ribbon.OkToRetryOnAllOperations=false
使用ribbon重试机制,请求失败后,每个6秒会重新尝试
Hystrix
spring cloud 用的是 hystrix,是一个容错组件。
Hystrix实现了 超时机制和断路器模式。
Hystrix是Netflix开源的一个类库,用于隔离远程系统、服务或者第三方库,防止级联失败,从而提升系统的可用性与容错性。主要有以下几点功能:
为系统提供保护机制。在依赖的服务出现高延迟或失败时,为系统提供保护和控制。
防止雪崩。
包裹请求:使用HystrixCommand(或HystrixObservableCommand)包裹对依赖的调用逻辑,每个命令在独立线程中运行。
跳闸机制:当某服务失败率达到一定的阈值时,Hystrix可以自动跳闸,停止请求该服务一段时间。
资源隔离:Hystrix为每个请求都的依赖都维护了一个小型线程池,如果该线程池已满,发往该依赖的请求就被立即拒绝,而不是排队等候,从而加速失败判定。防止级联失败。
快速失败:Fail Fast。同时能快速恢复。侧重点是:(不去真正的请求服务,发生异常再返回),而是直接失败。
监控:Hystrix可以实时监控运行指标和配置的变化,提供近实时的监控、报警、运维控制。
回退机制:fallback,当请求失败、超时、被拒绝,或当断路器被打开时,执行回退逻辑。回退逻辑我们自定义,提供优雅的服务降级。
自我修复:断路器打开一段时间后,会自动进入“半开”状态,可以进行打开,关闭,半开状态的转换。
整合Feign
配置
feign.hystrix.enabled=true
@FeignClient(name = "user-provider",fallback = AliveBack.class)
public interface ConsumerApi {
@RequestMapping(value = "/User/alive",method = RequestMethod.GET)
public String alive();
@RequestMapping(value = "/User/getById",method = RequestMethod.GET)
public String getById(Integer id);
}
@Component
public class AliveBack implements ConsumerApi{
@Override
public String alive() {
// TODO Auto-generated method stub
return "aaa";
}
@Override
public String getById(Integer id) {
// TODO Auto-generated method stub
return null;
}
}
使用fallbackFactory检查具体错误
@Component
public class WebError implements FallbackFactory<ConsumerApi> {
@Override
public ConsumerApi create(Throwable cause) {
// TODO Auto-generated method stub
return new ConsumerApi() {
@Override
public Person postPserson(Person person) {
// TODO Auto-generated method stub
return null;
}
@Override
public String getById(Integer id) {
// TODO Auto-generated method stub
return null;
}
@Override
public String alive() {
// TODO Auto-generated method stub
System.out.println(cause.getLocalizedMessage());
cause.printStackTrace();
return ToStringBuilder.reflectionToString(cause);
}
@Override
public Map<Integer, String> postMap(Map<String, Object> map) {
// TODO Auto-generated method stub
return null;
}
@Override
public Map<Integer, String> getMap3(Map<String, Object> map) {
// TODO Auto-generated method stub
return null;
}
@Override
public Map<Integer, String> getMap2(Integer id, String name) {
// TODO Auto-generated method stub
return null;
}
@Override
public Map<Integer, String> getMap(Integer id) {
// TODO Auto-generated method stub
return null;
}
};
}
}
针对不同异常返回响应
@Override
public String alive() {
// TODO Auto-generated method stub
System.out.println(cause);
if(cause instanceof InternalServerError) {
System.out.println("InternalServerError");
return "远程服务报错";
}else if(cause instanceof RuntimeException) {
return "请求时异常:" + cause;
}else {
return "都算不上";
}
}
信号量隔离与线程隔离
默认情况下hystrix使用线程池控制请求隔离
线程池隔离技术,是用 Hystrix 自己的线程去执行调用;而信号量隔离技术,是直接让 tomcat 线程去调用依赖服务。信号量隔离,只是一道关卡,信号量有多少,就允许多少个 tomcat 线程通过它,然后去执行。
信号量隔离主要维护的是Tomcat的线程,不需要内部线程池,更加轻量级。
hystrix.command.default.execution.isolation.strategy 隔离策略,默认是Thread, 可选Thread|Semaphore
thread 通过线程数量来限制并发请求数,可以提供额外的保护,但有一定的延迟。一般用于网络调用
semaphore 通过semaphore count来限制并发请求数,适用于无网络的高并发请求
hystrix.command.default.execution.isolation.thread.timeoutInMilliseconds 命令执行超时时间,默认1000ms
hystrix.command.default.execution.timeout.enabled 执行是否启用超时,默认启用true
hystrix.command.default.execution.isolation.thread.interruptOnTimeout 发生超时是是否中断,默认true
hystrix.command.default.execution.isolation.semaphore.maxConcurrentRequests 最大并发请求数,默认10,该参数当使用ExecutionIsolationStrategy.SEMAPHORE策略时才有效。如果达到最大并发请求数,请求会被拒绝。理论上选择semaphore size的原则和选择thread size一致,但选用semaphore时每次执行的单元要比较小且执行速度快(ms级别),否则的话应该用thread。
semaphore应该占整个容器(tomcat)的线程池的一小部分。
开启dashboard
启动类
@EnableHystrixDashboard
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>
spring-cloud-starter-netflix-hystrix-dashboard
</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
健康上报
http://localhost:90/actuator/hystrix.stream
图形化
http://localhost:90/hystrix