当前位置: 首页 > 科技观察

面试不再慌张!跟着老司机一起了解SpringCloud

时间:2023-03-19 16:46:06 科技观察

【.com原稿】最近和一个朋友聊天提到前几天面试的时候被问到:“你能描述一下SpringCloud吗?”他当场就愣住了,不知道从何说起。图片来自Unsplash是的,SpringCloud是一个众所周知的微服务架构,它包含了很多组件,每个组件都有自己的分工。我们如何理解SpringCloud架构并解释它的作用?今天我们就来看看吧。从一个例子开始对于这样一个“大”问题,通常需要拆解成小问题来回答。要解释SpringCloud是干什么的,有必要弄清楚它包含的组件是干什么的?如果一一罗列,显得过于独立,无关紧要,缺乏逻辑感。让我们从一个简单的示例开始,将这些组件像一串珍珠一样串起来。假设有一个项目有两个服务,分别是“A”和“B”:“A”和“B”之间的关系是“A”调用“B”。然后,有一个客户端“C”调用“A”。客户端“C”调用服务“A”,服务“A”调用服务“B”Eureka服务相互了解在服务器端我们已经有两个服务,“A”和“B”。他们的关系是“A”呼唤“B”,“B”被“A”呼唤。当只有两个服务时我们知道这个关系,我们可以记录这个关系,但是如果有多个服务,我们怎么记录这个关系呢?于是,Eureka登场了,它负责“服务注册、服务发现”的工作。Eureka分为EurekaServer和EurekaClient。每个微服务架构都会有一个或多个EurekaServer,用于存储注册服务信息。每个服务都会包含一个EurekaClient,它会配置EurekaServer的信息,这样当服务启动的时候,可以向EurekaServer注册自己。同时,各个服务还可以通过EurekaClient从EurekaServer获取其他服务信息(GetRegistry)。“A”服务和“B”服务的调用关系“A”服务和“B”服务首先通过自己集成的EurekaClient在EurekaServer上注册自己的信息,包括:服务名称、地址、端口号等。之后注册完成,“A”服务通过EurekaClient从EurekaServer获取(GetRegistry)服务“B”信息。由于“A”服务调用“B”服务,因此“A”服务称为“消费者”,“B”服务称为“生产者”。Feign服务之间的信息传递既然“A”和“B”这两个服务相互了解,就轮到“A”服务调用“B”服务了。由于两者是独立的服务,并且两个服务都在一个网络中,因此通常通过HTTP请求进行调用。传统的方法是“A”服务写入请求的消息,序列化成二进制字符串传递给“B”服务。“B”服务收到消息后,对消息进行反序列化分析,然后以同样的方式响应给“A”。”Serve。传统意义上完成这些代码需要做大量的工作和大量的编码考虑。为了简化上述过程,Feign组件诞生了,方便了服务之间的调用。引入Feign后,你只需要在“A”服务中填写一个简单的URL、参数和请求方法,就可以调用“B”服务了,调用“B”服务就像调用本地方法一样简单。通过Feign调用服务的代码片段。我们需要做的就是在“A”服务(消费者)中创建一个FeignClient,填写我们需要调用的URL、参数和方法,其他的就交给Feign来完成。FeignClient工作流程从上图可以看出,“消费者”一开始只需要提供“生产者”的URL、参数等信息即可。FeignClient会根据这些信息生成相应的HTTP请求头和数据包,然后发送给生产者。生产者返回信息后,FeignClient也会返回“消费者”能够理解的JavaBean信息。Ribbon已经完成了负载平衡。现在“A”和“B”服务相互了解,“A”服务可以调用“B”服务。假设“B”服务业务量增加,一个“B”服务不能满足当前需求,复制两个“B”服务,加上原来的“B”服务,现在一共三个“B”服务即成。虽然三者提供的服务相同,但是“A”服务应该调用“B”服务的哪个副本呢?这时候Ribbon就派上用场了,它是用来做负载均衡的。“A”服务不需要知道调用三个副本中的哪个,它只需要告诉Ribbon我要调用“B”服务,Ribbon就会根据策略调用三个副本中的一个。Ribbon充当负载均衡器。在Ribbon的几种负载均衡策略中,使用较多的是随机策略。例如:“B1”、“B2”、“B3”分别是“B”服务的三个副本。服务“A”第一次调用服务“B1”。根据随机策略,第二次调用服务“B2”,第三次调用服务“B3”,第四次调用服务“B1”。以此类推,循环往复。下面列出其他服务仅供参考,限于篇幅不再赘述:随机(Random)轮询(RoundRobin)一致性哈希(ConsistentHash)哈希(Hash)加权(Weighted)Hystrix服务宕机和现在“A”服务知道如何调用“B”服务的“B1”、“B2”、“B3”三个副本。如果“B2”服务失败,“A”服务还能访问吗?为了防止单个服务失效影响其他服务,Hystrix应运而生。未能调用“B1”服务Hystrix俗称熔断器(断路器)。当服务不可用或失败时,提供响应处理机制。在微服务架构中,每个服务可能依赖其他服务,也可能多个服务同时依赖一个服务,也可能服务之间存在链式依赖(A依赖B,B依赖D)。一旦依赖的服务失效,Hystrix可以通过预设的处理机制调整服务的响应。例如:返回错误信息,将服务返回的信息替换为缓存的或自下而上的信息。单个服务依赖多个服务,其中一个依赖的服务出现问题,影响到整体。多个服务依赖于一个服务,一个服务的故障会影响多个服务。应用Hystrix只需要两步:第一步在“A”服务(消费者)上定义,调用“B”服务(生产者)失败时的处理方法。调用“B”服务故障处理方法,代码片段。第二步,在“A”服务(消费者)调用“B”服务的方法的Annotation上标记调用失败时需要执行的“第一步”方法。声明调用失败方法,将代码片段添加到“A”服务中并添加HystrixZuul如何访问微服务上面和服务端差不多。如果“C”客户端需要访问“A”服务,系统将如何告诉它是哪一个?服务“A”怎么样?这里实际上缺少一个网关,连接“C”客户端和“A”服务的网关。Zuul就是这个网关,它的职责就是过滤和路由。Zuul是连接客户端和服务端的网关。还记得上面提到的Eureka服务注册和服务发现吗?Zuul可以配合Eureka完成服务路由。首先向Eureka注册“A”服务,然后“C”客户端向Zuul发起请求访问“A”服务。Zuul从Eureka获取“A”服务的地址,然后访问“A”服务。Zuul和Eureka一起工作。Zuul不仅可以做路由,还可以做过滤器。可用于权限验证和金丝雀测试。这里简单介绍一下Zuul的内部运行机制。Zuul收到HTTP请求后,会通知ZuulServlet进行处理。同时会生成一个RequestContext记录请求的上下文信息,该信息会一直保留到路由结束。ZuulFilterRunner收到ZuulServlet的通知后,会从RequestContext中取出请求的信息,传递给FilterProcesser进行处理。它会维护一套过滤和路由规则,并根据这些规则将请求发送到目标服务。Zuul内部工作原理图SpringCloud微服务架构总结看完上面的内容,是不是对SpringCloud有了更深入的了解呢?回顾一下,SpringCloud是一个微服务架构,为微服务开发提供了丰富的组件。五个重要的组件是:Eureka:服务发现和服务注册。Feign:服务调用请求。Ribbon:服务之间的负载均衡。Hystrix:保险丝。Zuul:服务网关。如果,用我们上面的ABC例子来记,A调用B(Eureka),A发送请求(Feign),B做横向扩展后,A通过(Ribbon)找到B,B通过熔断机制(Hystrix)保证服务调用正常,C通过Zuul找到A。用一张大图总结一下:通过ABC了解SpringCloud的五大组件并总结整个流程,客户端请求→Zuul→Eureka获取服务→Feign通信→Ribbon负载均衡→Hystrix熔断:用户请求会优先发送给Zuul,Zuul作为API网关使用。同时它也可以用作过滤器。微服务注册操作需要通过Eureka作为服务发现和注册中心。一方面记录服务的注册和健康,另一方面配合Zuul做好服务接入。微服务之间的通信,需要将数据打包发送,接收后还需要解包读取信息。这里可以使用Feign作为服务通信的组件,配合Ribbon完成通信工作。Robbin,负责微服务集群的负载均衡。服务出现故障,例如:业务异常、网络异常等。具体的处理操作需要通过断路器Hystrix来实现,比如服务异常通知注册中心,比如将服务降级。此时服务注册发现中心会将服务标记为异常,如果有请求,则不会发送到异常服务。同时,服务发现注册中心也会定期检查服务的状态,一旦服务恢复,就会被放入访问队列中。作者:崔浩简介:十六年开发架构经验。曾在惠普武汉交付中心担任技术专家、需求分析师、项目经理,后在一家初创公司担任技术/产品经理。善于学习,乐于分享。目前专注于技术架构和研发管理。【原创稿件,合作网站转载请注明原作者和出处为.com】