赞
踩
SpringCloud是微服务架构中很重要的技术,通过对这方面技术点的学习,现将SpringCoud底层原理做出总结,主要是从五大基本组件入手,结合业务场景表达出自己的看法,如有不当之处,还希望读者做出评论,一起进步。
业务场景:我自己所写小项目 “宠物智慧平台“ 中有实现订单支付这样一个功能; 用户在购买商品时创建一个订单,当该用户立即支付了这个订单,我们就要将订单的状态更新为“已支付”。 并且此时在商品库存中也要相应的减去此商品。 并且还要去通知存储中心,进行货物的补充。 成功支付后还要给此用户的积分表上增加相应的积分。
针对上述的业务描述,整体思路如下:
1)首先我们在项目中需要有订单服务,库存服务,仓储服务,积分服务。
2)用户支付完成之后,首先寻找订单服务,及时的更新其订单的状态。
3)订单服务调用库存服务,在库存中减去对应的商品。
4)订单服务调用仓储服务,及时发货补充货源。
5)订单服务调用积分服务,给用户增加相应的积分。
结合以上的业务场景,在使用微服务架构中来说明其组件之间如何的进行协调工作如下:
1,当用户支付成功之后,订单服务想要去调用库存服务,或者是仓储服务,再或者是积分服务,这个过程他显然是没有办法直接完成的,得要通过中间的组件去协助它进行完成。 这时就要用到Spring Cloud Eureka,它是微服务架构中的注册中心,主要的功能就是负责 服务的注册与发现。如下图:
每一个服务中都会有一个Eureka Client组件,此组件就是负责将服务的信息注册到Eureka Server中。通俗点讲就是可以告诉Eureka Server自己的这个服务在那一台机器上,监听着哪一个端口,而Eureka Server就是一个注册中心,里面会有一张注册表,表中保存了每一个注册过的服务所在的机器和端口号。
在订单服务中也会有一个Eureka Client 组件,它在工作时就会去寻找Eureka Server问一下:他将要调用的服务在哪一台机器上?监听的端口是哪一个?Eureka Server就会将相应的信息给它,之后它就可以将这些重要的信息从Eureka Server注册表中拉取过来保存到自己的本地缓存中。
在这之后订单服务想要调用其他的服务就可以在自己的本地缓存中找到对应的信息,然后发送请求过去,调用操作接口就可以实现其需求。
Eureka Client:负责将服务的信息注册到Eureka Server中。
Eureka Server:注册中心,其中有一个注册表,记录的有各个服务所在的机器和端口号。
Zuul,就是微服务网关,主要是负责网络路由的。
假设我在后台部署了几百个服务,现在有请求直接从浏览器那边发过来,举例子:如果他要请求一下积分服务,难道我们还要让他记住我们给这个积分服务器的名字吗?部署在哪一台机器上?这样就会很不方便,几百个服务还要记住几百个服务对应的名字。
所以微服务架构中都会设计一个网关在里面,这样我们就不用去关心后端有多少个服务了,知道一个网关后,所有的请求都会走到网关上,网关就会根据请求中的特征将请求转发后端的各个服务中。
并且有了网关后还可以做同一的降级,限流,认证授权…
问题:对于库存服务,我们将这一服务部署在了10台机器上,如果有请求过来调用库存服务,那么这个请求最终应该去那一台机器上进行调用呢?
Spring Cloud Ribbon的作用就是负载均衡。它会在请求过来时选择机器,均匀的把请求分发到各个机器上。
1)Ribbon 的负载均衡在默认情况下使用的 Round Robin轮询算法。 指的就是当订单服务对积分服务发起了6次请求,那就会先请求第一台机器,接着是第二台…,不断的循环。
2)Ribbon和Feign以及Eureka是紧密协作来完成工作的:
a,首先Ribbon会从Eureka Client中获取对应的服务注册表,就会知道服务部署的机器记忆监听的端口号。
b,之后Ribbon就会使用默认的轮询算法,去选择机器进行操作。
c,Feign就会针对这些机器发起请求。
问题:订单服务在调用其他的几种服务时是怎么进行调用的呢?是要自己写很多的代码和其他的网络建立连接,然后去构造请求将其发送过去,最后对返回的响应在写一堆代码来进行处理吗?
针对这一问题,又一高明的组件出现了,那就是Feign,指的就是服务调用。
1)Feign没有去写建立连接,构造请求,解析响应的代码,他直接就是通过注解定义FeignClient接口,然后去调用此接口就可以了。Feign Client会在底层根据我们的注解去跟指定的服务建立连接,构造请求,发起请求,获取响应,解析响应…等等的操作。
2)Feign它是使用了动态代理的方式来进行实现的,如图所示:
a,如果我们在操作中对某个接口定义了@FeignClient注解,那么Feign就会针对这个接口创建一个动态代理。
b,当我们调用此接口时,本质上就是调用Feign创建的动态代理
c,Feign的动态代理就会根据接口上的@RequestMapping…等注解,动态的构造出要请求的服务地址。
d,最后会针对这个地址,发起请求,解析响应。
场景:订单服务在一个业务流程中需要调用其他三个服务,现在假设订单服务自己最多只有90个线程可以处理请求,但是积分服务挂掉了,每次订单服务调用积分服务的时候,就会卡主几秒钟,接着抛出异常。
如果系统处于高并发的场景下,大量的请求打过来时,订单服务的90个线程就会都卡在积分服务的这一点上,导致订单服务没有一个线程可以成功处理请求。这样就会导致别人在请求订单服务的时候,发现订单服务也挂掉了,没有任何的请求响应。 这就是服务雪崩的问题。
如上图,服务相互调用,如果不做任何保护,当其中某一个服务挂掉就会引起连锁反应,导致别的服务也会挂掉。结合业务场景,就算积分服务挂掉了,订单服务也可以不用挂,在支付订单时,只要把库存减了,然后通知仓库发货就行了;如果积分服务挂掉,那就等他恢复之后再用人工进行恢复数据就可以了。
这时就要用到Hystrix,熔断器,它是一个隔离,熔断以及降级的框架。它会为每个服务弄很多个小小的线程池,比如当订单服务请求库存服务弄一个线程池,请求仓储服务也弄一个线程池…,这样每个线程池里的线程就仅仅用于特定的那个服务。当积分服务挂掉了,那订单服务中用来调用积分服务的线程就会卡死不工作,但是对于其他服务是没有影响的。其他的服务还是可以正常的工作被调用。当有人请求订单服务,他还是可以正常的减库存和通知发货,但是在调用积分服务时每次都会报错,还是会卡几秒,那我们就对它进行熔断,比如在5分钟内请求积分服务直接就返回,不去走网络请求卡主的几秒,这个过程就是熔断。
也可以去给积分服务进行降级,每次在调用积分服务时就在数据库中记录一条消息,给某某用户增加多少积分,因为积分服务挂了,没有增加成功,等其恢复了在通过记录手工的进行添加,这个过程就是降级。
下图为Hystrix隔离,熔断和降级的全过程:
五个核心组件分别在微服务架构中扮演的角色:
1.Eureka:各个服务启动时,Eureka Client就会将服务注册到Eureka Server中,并且Eureka Client还可以反过来从Eureka Server中拉取注册表,从而知道服务的具体信息。
2.Ribbon:服务发起请求时,基于Ribbon做负载均衡,从一个服务的多台机器中选择一台
3.Feign:基于Feign的动态代理机制,根据注解和选择的机器,拼接请求URL地址,发起请求。
4.Hystrix:发起请求就通过Hystrix的线程池来走,不同的服务走不同线程池,实现了不同服务调用的隔离,避免了服务雪崩的问题。
5.Zuul:当前端调用后端系统时,同一从Zuul网关进入,由Zuul网关转发请求给对应的服务。
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。