一、Eureka
eureka 是微服务的基础,不论是服务生产者,消费者,还是服务中心 都得依靠eureka。其中注册中心是Eureka作为服务端, 生产者和消费者是Eureka作为客户端。
服务生产者向注册中心进行注册,服务消费者向注册中心获取生产者列表以进行服务调用。
(注意:作为服务端和客户端引入的包是不一样的,
服务端:
spring-cloud-starter-netflix-eureka-server
客户端:
spring-cloud-starter-netflix-eureka-client
)
Eureka 作为服务提供者:
有‘心跳‘ 机制,与注册中心同步当前客户端的状态,即默认每隔30秒发送一次心跳给注册中心,告诉它自己正常运行
Eureka 作为服务端(注册中心)
注册中心如果在90秒内没有收到客户端的心跳,则会将其从注册表中删除。但是其有默认的自我保护机制(默认开启,可以手动关闭),
即在15分钟内超过85%客户端都没有心跳传送过来,则Eureka默认可能了网络异常,并不会移除服务的注册信心转而自动进入保护机制即:
1.不在移除因为长时间没有心跳的服务
2.Eureka Server仍然能够接受新服务的注册和查询请求,但是不会被同步到其它节点上,保证当前节点依然可用
3.当网络稳定时,当前Eureka Server新的注册信息会被同步到其它节点中。
当客户端心跳恢复时,Eureka会自动退出自我保护机制
Eureka 工作流程
1))Eureka Server 启动,等待服务注册,每个server都存者完整的服务注册表信息
2)Eureka Client 启动,去server注册服务
3)Eureka Client 每隔30s像server 发送一次心跳,证明客户端正常
4)当 Eureka Server 90s内没有收到client的心跳时,注册中心会注销该实例(server关闭自我保护机制的情况下)
5)server 默认开启自动保护机制,当15分钟内有大于85%的情况下没有收到心跳,则认为是网络异常导致,进入自我保护机制,不会剔除没有发送心跳的客户端
6)当client心跳恢复正常后,server退出自我保护模式
7)client 定时定量从server 中心获取服务注册表,并将其缓存到本地
8)client 调用服务时,先从本地缓存寻找服务列表,如果获取不到则从注册中心获取注册表缓存到本地
9)client 获取目标服务器信息发起服务调用
10)当所有的server挂掉时,client依然可以依靠本地缓存获取调用服务器信息,发起请求
二、 gateway
引入包:
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-gateway</artifactId>
</dependency>
如果前端发起一个请求时,而这个请求需要去客户服务调用客户信息,去订单服务调用订单信息,去产品服务调用产品信息时 要如何处理?可以先到客户服务获取客户信息,然后在客户服务去调用订单服务和产品服务获取信息 后返回,但是这样的话客户服务就得依赖于订单服务和产品服务,在一个项目中有很多类似这样的请求,这样服务之间的调用就会呈现网状,造成高度耦合。此时我们需要有一个中间层作为服务消费者 统一去调用多个服务,然后得到信息后封装成前端需要的数据格式统一进行返回。
如果前端发起一个请求,只需要去客户服务调用服务信息呢,那是通过中间层去调用客户服务吗,这个比较麻烦,因为中间层还需要发起请求,此时我们可以让中间层通过路由的方式直接让前端的请求去直接调用客户信息。
这个中间层就是网关,前端请求进来应该先进入网关,由网关统一进行处理。从Eureka 来说,这个就是Eureka client 客户端。被调用的服务也是Eureka client 不过他们是作为服务端
所以gateway 网关做完前端请求的统一入口有如下作用:
当前端请求进来时:
1.统一做身份校验(安全)
2.可以进行流量控制(限流)
3.记录请求响应数据,api耗时监控即性能监控(监控)
4.做数据缓存(缓存)
当前端请求进来后
1.如果请求只需要调用一个服务则做路由直接去请求相应的服务(路由)
当前端请求进来后去调用服务时
1.日志记录,全链路跟踪(日志)
2.记录请求响应数据,api耗时监控即性能监控(监控)
3.可以进行流量控制(限流)
三、Ribbon
客户端负载均衡
引入的jar包,引入spring-cloud-starter-netflix-eureka-client 包 时就会包含ribbon。
使用方式很简单,即用@LoadBalanced注解修饰RestTemplate,这样底层会用拦截器在调用RestTemplate时发现有@LoadBalanced标示的就会进行负载均衡的设置。可以手动设置负载均衡的规则
区别于Nginx,ribbon为什么称为客户端负载均衡,是因为Eureka client消费者 本地有缓存服务注册表信息,所以在调用服务时可以调用负载均衡策略。所谓的客户端是消费者相对于生产者而言的。
而Nginx称为服务端负载均衡,是因为请求先到了Nginx 服务器了,在由Nginx 策略进行调用,这时的服务端是相对于客户端请求。
四、feign
虽然使用了ribbon 实现了客户端负载均衡,但是我们每次调用还是要写restTemplate 去调用服务,代码很多很麻烦,所以feign出现了,它封装了ribbon,使得我们可以用调用接口方法的方式去调用服务。
底层用到的机制是动态代理:
1)首先会对有@FeignClient注解的接口创建一个动态代理
2)接着你调用这个接口,其实是调用它的动态代理
3)动态代理时会根据你接口上@RequestMapping等注解,去动态构造出你要请求的服务地址
4)最后针对这个地址发起请求,解析响应
feign 原理
feign + ribbon 原理:
五、Hystrix
在微服务里面,服务数量众多,他们之间有着代码耦合和业务耦合,如果一个服务出现问题,则后面调用者也会跟着出现问题,这就是雪崩现象,一个小问题引发后面一连串的问题
如订单服务调用完积分服务,要去调用库存服务和仓库服务,如果积分服务出现问题,无法返回则会影响后续服务的调用。
基本概念:
服务隔离:默认情况下Hystrix会为每个调用服务接口提供线程池,目的是为不同的服务分配一定的资源,当自己的资源用完直接返回失败而不是占用别人的资源
这样一个服务的线程池满了,也不会影响到其他服务。
反例: 当请求进来时,tomcat 将所有的请求都放在同一个线程池,这样同一个请求出现高并发时,则会影响到同一个线程池里面的其他请求,如下图(线程不隔离带来的问题):
用线程池进行隔离可以应对高并发情况,但是cpu资源占用大,所有hystrix 还提供了另外一种隔离策略:信号量
使用一个原子计数器(或信号量)来记录当前有多少个线程在运行,当请求进来时先判断计数 器的数值,若超过设置的最大线程个数则拒绝该请求,若不超过则通行,这时候计数器+1,请求返 回成功后计数器-1。
与线程池隔离最大不同在于执行依赖代码的线程依然是请求线程
服务熔断:
服务隔离后,如果出现高并发情况,我们可以设置阈值,当请求大于阈值时(限流),然后就让其不在去请求服务,而是去返回一个自己写好的方法,这个就叫做服务降级,熔断和降级一起使用。
@HystrixCommand(fallbackMethod = "getUserByTokenFb")
在调用服务方法上加注解@HystrixCommand,则默认在调用服务出现异常,或者响应超时(默认1秒)时会熔断,然后会去调用设置好的方法getUserByTokenFb,此方法参数要与调用服务的方法一致
服务降级:预先写好一个方法,当调用服务出现熔断时去调用这个方法进行处理。
springCloud基础组件完整调用流程: