OpenFeign概念:
Feign是一个声明式的http客户端,使用Feign可以实现声明式REST调用,它的目的就是让Web Service调用更加简单。Feign整合了Ribbon和SpringMvc注解,这让Feign的客户端接口看起来就像一个Controller。Feign提供了HTTP请求的模板,通过编写简单的接口和插入注解,就可以定义好HTTP请求的参数、格式、地址等信息
。而Feign则会完全代理HTTP请求,我们只需要像调用方法一样调用它就可以完成服务请求及相关处理。同时Feign整合了Hystrix,可以很容易的实现服务熔断和降级.
为什么使用OpenFeign:
使用Ribbon作为客户端负载均衡完成通信,通过RestTemplate调用其它服务时,所需要的参数须在请求的URL中进行拼接,如果参数少的话或许我们还可以忍受,一旦有多个参数的话,这时拼接请求字符串就会效率低下,并且显得代码冗余
。而Feign的服务调用方式对于程序员来说更为友好,它基于Ribbon进行了封装,把一些负责的url和参数处理细节屏蔽起来,我们只需要简单编写Fiegn的客户端接口就可以像调用本地service去调用远程微服务.
如何使用OpenFeign:
第一步:导入依赖
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-openfeign</artifactId>
</dependency>
第二步:编写启动类
@SpringBootApplication
@EnableFeignClients // 开启Feign支持,会从当前包及子包扫描加上了@FeignClient注解的接口,通过反向代理实例化,交给spring管理
@EnableEurekaClient // 开启eurrka服务端支持
public class PayApplication {
public static void main(String[] args) {
SpringApplication.run(PayApplication.class);
}
}
第三步:准备配置文件
server:
port: 10040 #端口
eureka:
instance:
hostname: localhost #主机
client: #客户端配置
serviceUrl: #注册中心的注册地址
defaultZone: http://localhost:10010/eureka/ #http://${eureka.instance.hostname}:${server.port}/eureka/
instance-id: server-pay #实例ID
server:
enable-self-preservation: false #关闭自我保护警告
spring:
application:
name: server-pay #服务名
第四部:编写接口
// server-user是指定调用的服务名,会根据服务名找到指定的服务
@FeignClient("server-user")
public interface PayFeignClient {
@GetMapping("/user/{id}")
User getUserById(@PathVariable("id")Long id);
}
第五步:编写controller,调用接口
@RestController
public class PayController {
@Autowired
private PayFeignClient payFeignClient;
@GetMapping("/pay/{id}")
public User getById(@PathVariable("id") Long id){
return payFeignClient.getUserById(id);
}
}
Feign的工作原理
启动类上打上@EnableFeignClients开启feign支持,项目启动的时候会扫描当前包及其子包下面打了注解@FeignClient的接口,创建代理交给spring管理.Feign会为接口中的每个方法生成一个requestTemplate的request请求,交给http,http交给loadBalanceClient,使用ribbon的负载均衡算法发起调用
Feign可以根据@FeignClient("user-server")找到用户服务,根据方法上的@RequestMapping(value = "/user/{id}",method = RequestMethod.GET)找到目标服务的controller的方法 ,我们在使用Feign接口时传入的参数就会作为目标服务controller方法的参数,而返回值就是目标服务controller方法的返回值。
即:服务名要一致 , url路径要一致 , 参数要一致 , 返回值类型要一致。 建议 :服务名直接去目标服务配置中拷贝 , 方法直接从目标服务controller中拷贝
负载均衡配置:
Feign已经集成了Ribbon,所以它的负载均衡配置基于Ribbon配置即可,这里使用xml简单配置负载均衡策略如下:
user-server:
ribbon:
NFLoadBalancerRuleClassName: com.netflix.loadbalancer.RandomRule
Feign的超时配置:
如果服务调用出现“com.netflix.hystrix.exception.HystrixRuntimeException:.. timed - out and no fallback available” 错误日志,是因为Hystrix超时,默认Feign集成了Hystrix,但是高版本是关闭了Hystrix,我们可以配置Hystrix超时时间:
feign:
hystrix:
enabled: true #开启熔断支持
hystrix:
command:
default:
execution:
isolation:
thread:
timeoutInMilliseconds: 6000 #hystrix超时时间
Hystrix:
在了解hystrix之前,我们需要先了解什么是雪崩效应.在电影里面经常出现的场景,在冰山雪地不要大声呼喊,因为声音的震动会导致雪球的滑落,然后引起连锁反应导致整个雪山的崩塌这就是生活中的雪崩。在微服务里面也是一样,服务的调用非常复杂的 ,一个请求往往需要很多的微服务共同完成,可能会形成很长的服务调用链,在整个服务调用链中,某一个服务发生故障会导致调用它的服务跟着异常,然后导致整个调用链调用的异常,甚至导致整个微服务瘫痪 , --- 这就是雪崩效应.
而Hystrix能够完美的解决分布式系统架构中打造高可用服务面临的一系列技术难题.Hystrix将出现故障的服务通过熔断、降级等手段隔离开来
,这样不影响整个系统的主业务,同时也是可以帮我们做服务的治理和监控
Hystrix其设计原则:
-
防止单个服务异常导致整个微服务故障。
-
快速失败,如果服务出现故障,服务的请求快速失败,线程不会等待。
-
服务降级,请求故障可以返回设定好的二手方案数据(兜底数据)。
-
熔断机制,防止故障的扩散,导致整个服务瘫痪。
-
服务监控,提供了Hystrix Bashboard仪表盘,实时监控熔断器状态
Hystrix的功能:
资源隔离(流控,限流):
线程池隔离:使用一个线程池来存储当前请求,线程池对请求作处理,设置任务返回处理超时时间,堆积的请求先入线程池队列。这种方式要为每个依赖服务申请线程池,有一定的资源消耗,好处是可以应对突发流量(流量洪峰来临时,处理不完可将数据存储到线程池队里慢慢处理)
信号量隔离:
使用一个原子计数器(或信号量)记录当前有多少个线程在运行,请求来先判断计数器的数值,若超过设置的最大线程个数则丢弃该类型的新请求,若不超过则执行计数操作请求来计数器+1,请求返回计数器-1。这种方式是严格的控制线程且立即返回模式,无法应对突发流量(流量洪峰来临时,处理的线程超过数量,其他的请求会直接返回,不继续去请求依赖的服务)
服务熔断
熔断机制是对服务链路的保护机制,如果链路上的某个服务不可访问,调用超时,发生异常等,服务会触发降级返回托底数据,然后熔断服务的调用(失败率达到某个阀值服务标记为短路状态),当检查到该节点能正常使用时服务会快速恢复。
简单理解就是当服务不可访问了或者服务器报错了或者服务调用超过一定时间没返回结果,就立马触发熔断机制配合降级返回预先准备的兜底数据返回,不至于长时间的等待服务的相应造成大量的请求阻塞,也不至于返回一些错误信息给客户端,而是返回一些兜底数据。
降级机制
超时降级、资源不足时(线程或信号量)降级,降级后可以配合降级接口返回托底数据。
简单理解就是服务降级就是当服务因为网络故障,服务器故障,读取超时等原因造成服务不可达的情况下返回一些预先准备好的数据给客户端。
在生活中服务降级到处可见,如在系统故障我们会返回友好的提示“服务暂时不可用”,或者如淘宝双11期间退款服务,留言服务暂时不可用,这个就是为了保证正常的购物流程相关服务没问题,然后人为的关闭一些不重要的服务,配合降级返回一些托底数据返回给用户(比如返回友好的提示信息“暂时不能退款”)。
缓存
提供了请求缓存、请求合并实现 , 在高并发的场景之下,Hystrix请求缓存可以方便地开启和使用请求缓存来优化系统,达到减轻高并发时请求线程的消耗、降低请求响应时间的效果。
OpenFeign整合Hystrix
第一步:不需要导包了,OpenFeign整合了Hystrix的jar包,直接使用就可以
第二步:配置文件
feign:
hystrix:
enabled: true #开启熔断支持
第三步:修改接口,我采用的是fallbackFactory方式,因为FallbackFactory可以打印出异常日志
// @FeignClient("user-server") : user-server是用户服务的服务名字,Feign根据服务名能够在注册中心找到目标服务的通信地址
// FeignHystrixFallbackFactoory降级之后执行的业务
@FeignClient(value = "server-user",fallbackFactory = FeignHystrixFallbackFactory.class)
public interface PayFeignClient {
@GetMapping("/user/{id}")
User getUserById(@PathVariable("id")Long id);
}
第四步:编写兜底类,发生异常时,无法处理请求时,就启用兜底类,注意,这里托底类需要交给Spirng管理,类上需要打 @Component 注解 , 拖地类需要实现 Feign接口,复写接口中的方法作为托底方法返回拖地数据。当Fiegn调用失败就会以拖地方法返回的结果返回给用户
/**
*降级之后处理业务,可以实现FallbackFactory,实现这个接口可以打印错误信息,Fallback不能打印错误信息
*/
@Component
public class FeignHystrixFallbackFactory implements FallbackFactory<PayFeignClient> {
@Override
public PayFeignClient create(Throwable throwable) {
return new PayFeignClient() {
@Override
public User getUserById(Long id) {
// 走降级之后,打印错误信息
throwable.printStackTrace();
return new User(-1L,"","系统繁忙,请稍后重试");
}
};
}
}
Zuul服务网关:
什么是Zuul:
Zuul 是netflix开源的一个API Gateway 服务器, 本质上是一个web servlet(filter)应用。Zuul 在云平台上提供动态路由(请求分发),监控,弹性,安全等边缘服务的框架。Zuul 相当于是设备和 Netflix 流应用的 Web 网站后端所有请求的前门,也要注册入Eureka,用一张图来理解zuul在架构中的的角色
Zuul作用:
所有的请求都需要通过zuul将请求分发到其他微服务,根据这一特性我们就可以在zuul做统一的登录检查,下游的微服务不再处理登录检查逻辑
如何使用Zuul:
第一步:导入依赖
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-zuul</artifactId>
</dependency>
第二步:配置类
server:
port: 10050 #端口
eureka:
instance:
hostname: localhost #主机
client: #客户端配置
serviceUrl: #注册中心的注册地址
defaultZone: http://localhost:10010/eureka/ #http://${eureka.instance.hostname}:${server.port}/eureka/
instance-id: server-zuul #实例ID
server:
enable-self-preservation: false #关闭自我保护警告
spring:
application:
name: server-zuul
zuul:
prefix: "/server" #访问前缀
ignored-services: "*" #禁用使用服务名直接访问服务
routes:
server-pay: "/pay/**" #配置访问server-pay的别名
server-order: "/order/**" #配置访问server-order的别名
server-user: "/user/**" #配置访问server-user的别名
第三步:启动类
@SpringBootApplication
//@EnableZuulServer // 这里我们使用@EnableZuulProxy注解是@EnableZuulServer的加强注解
@EnableZuulProxy
@EnableEurekaClient
public class ZuulApplication {
public static void main(String[] args) {
SpringApplication.run(ZuulApplication.class);
}
}
完成以上三个步骤就集成了zuul了,可以开始使用了