Eureka
注册中心,负责每个服务的注册和发现。
每个微服务中都有一个Euraka client组件,专门负责将这个服务的服务id(serviceId)、ip、端口等信息注册到Eureka server 中。
Euraka Server 是一个注册中心,该组件内部维护了一个表,保存了各个服务所在的机器ip和端口号等信息。
服务发现,默认是30S 一次,实际上当服务在拉取服务注册表的时候,其实客户端不是直接从 Eureka 中的 服务注册表中获取数据的。
Eureka 做了二级缓存,第一级叫做 ReadOnly 缓存,二级叫做 ReadWrite 缓存。
客户端会直接从ReadOnly 缓存中读取注册表信息。服务在进行注册的时候,先往服务注册表中写入注册信息,服务注册表更新了,立马会同步一份数据到 ReadWrite 缓存中去。
有一个定时任务会定时去检查 ReadWrite 是否跟 ReadOnly 不一致,不一致就把数据同步到 ReadOnly 中去,定时任务也默认是 30S。
为什么做二级缓存?
优化并发读写的冲突。如果服务进行注册的时候,同时有服务来读去注册表信息,就会存在频繁的读写加锁的操作,写的时候就不能读,导致性能下降,所以我们需要避免大量的读写都去操作一个表
服务注册中心还有一个很重要的功能就是 心跳与故障检查。心跳跟故障检测其实就是为了知道注册上来的这些服务是不是还活着的。
Eureka 会开启一个定时任务定时去检查心跳,默认也是30秒。当出现机器故障没有在约定的时间间隔内上报自己的状态,那么Eureka 就会把这台机器剔除注册表,同时更新到 ReadWrite 缓存中去。如图:
但是把数据从ReadWrite 缓存同步到 ReadOnly 缓存是有时间间隔的。当服务消费者A 也只有等待下一次请求更新的时候才会把自己列表里面的服务给更新掉。
有时候会出现你注册上去的服务经过及时秒才被服务消费者发现,或者服务的某个节点出现故障,没有及时剔除掉。这里就是同步机制的时间差问题。
Feign
远程服务调用组件
主要负责与其他服务建立连接,构造请求,然后发起请求来调用其他服务来获取数据。
Ribbon
主要负责负载均衡的组件
一个服务可能会部署很多台机器,那么我们使用Feign 去调用这个服务的时候,到底把请求发送到哪台机器上去呢?此时我们就需要一个组件来根据一定的策略来选择一台机器。不管怎么选的,总之得选一台机器给 Feign 去调用就好了。
Ribbon 主要负责就是负载均衡。Ribbon 会定期去从Eureka 注册中心拉取注册表信息,缓存到本地,每次发起远程调用的时候,Ribbon 就会从 Eureka 注册表拉取下来的数据中挑选一个机器让 Feign 来发起远程调用。
Zuul
负责网络路由
很多微服务,如果一个服务一个IP,使用方都需要进行调用的话,是不是得知道每一个服务的IP地址才行呢?那得记住多少才行呀,多不好管理。
如果有一个统一的地址,然后根据不同的请求路径来跟我进行转发多少是不,比如 /user/* 是转发到用户服务 ,/product/* 是转向到商品服务等等。我使用的时候,只需要访问同一个IP ,只是路径不一样,就行了。
Zuul ,他是一个网关,就是负责网络的路由的。每个请求都经过这个网关,我们还可以做统一鉴权等等很多事情。
Zuul 配置请求路径与服务的对应关系,你的请求到网关,他就直接查找到匹配的服务,然后就直接把请求转发给那个服务的某台机器。
Hystrix
解决服务出错或超时问题
Hystrix,它是一个隔离、熔断以及降级的一个框架 。
在微服务的相互调用过程中,可能会出现被调用服务错误或者超时的情况,从而导致整个系统崩溃不可用,也就是我们常说的服务雪崩问题,Hystrix 的存在就是为了解决这种问题的。
它提供了服务降级、服务熔断、线程和信号隔离、请求缓存、请求合并以及服务监控等强大功能。
Hystrix使用舱壁模式实现线程池的隔离,它会为每一个依赖服务创建一个独立的线程池,这样就算某个依赖服务出现延迟过高的情况,也只是对该依赖服务的调用产生影响,而不会拖慢其他的依赖服务。
模拟下单买东西
整个调用流程:
- 首先每个服务启动的时候都需要往注册中心进行注册。
- 用户先对网管发起下单请求,网管收到请求后发现是下单操作要到订单系统,然后把请求路由到订单系统。
- 订单系统一系列操作后,然后通过Feign去调用库存系统减库存,通知仓储服务发货,调用积分系统加积分。
- 在发起调用之前,订单系统还得通过Ribbon去注册中心拉取各系统的注册表信息,并且挑一台机器给Feign来发起网络调用。