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

SpringCloudNetflix概述及架构设计

时间:2023-03-14 01:07:18 科技观察

SpringCloud介绍SpringCloud是一套基于SpringBoot实现微服务的框架。他提供微服务开发所需的配置管理、服务发现、断路器、智能路由、微代理、控制总线、全局锁、决策竞选、分布式会话和集群状态管理等组件。最重要的是,配合springboot框架使用,可以非常方便的开发微服务架构的云服务。SpringCloud包含很多子框架。其中,SpringCloudNetflix就是框架之一。它由Netflix开发,后来并入SpringCloud家族。它提供的主要模块包括:服务发现、熔断与监控、智能路由、客户端负载均衡等。SpringCloudNetflix项目成立时间不长,两年前被并入SpringCloud大家庭,所以相关的使用文档还是比较少的。除了官方文件,中国还有一个华人社区。但是,如果你是新手,想用它来搭建微服务应用架构,你总会觉得无从下手。因此,这篇文章是从整体上看一下框架的各个组件,它们的用途是什么,它们是如何交互的。最后,结合实际体验,介绍可能出现的问题以及部分问题的解决方案。微服务架构首先我们来看一下一般的微服务架构需要的功能或者使用场景:我们把整个系统按照业务拆分成几个子系统。每个子系统可以部署多个应用,多个应用之间采用负载均衡。需要有一个服务注册中心,所有的服务都注册到注册中心,通过注册到注册中心的服务也是通过一定的策略来实现负载均衡的。所有客户端通过同一个网关地址访问后台服务。通过路由配置,网关确定哪个服务处理URL请求。将请求转发到服务时也使用负载平衡。服务有时需要相互访问。例如,有一个用户模块。其他服务在处理一些业务时,需要获取用户服务的用户数据。需要一个断路器来及时处理服务调用的超时和错误,以防止由于其中一个服务出现问题而导致整个系统瘫痪。还需要一个监控功能,监控每次服务调用花费的时间等。SpringCloudNetflix组件和SpringCloudNetflix框架的部署恰好满足了以上所有需求,最重要的是使用起来非常简单。SpringCloudNetflix的组件和主要功能大致如下:Eureka,服务注册与发现,它提供服务注册中心,服务发现的客户端,以及方便查看所有已注册服务的接口。所有服务都使用Eureka的服务发现客户端向Eureka服务器注册自己。Zuul,网关,所有客户端请求通过这个网关访问后台服务。他可以使用某种路由配置来确定哪个服务处理某个URL。并从Eureka获取注册服务来转发请求。Ribbon,即负载均衡。当Zuul网关向某个服务应用发送请求时,如果某个服务启动了多个实例,则通过一定的负载均衡策略,通过Ribbon发送给某个服务实例。Feign,服务客户端,如果服务之间需要互相访问,可以使用RestTemplate或者Feign客户端访问。它默认会使用Ribbon来实现负载均衡。Hystrix,监控和断路器。我们只需要在服务接口上添加Hystrix标签,就可以实现该接口的监控和熔断功能。HystrixDashboard,一个监控面板,提供了一个接口来监控各种服务的服务调用所消耗的时间。Turbine,监控聚合,使用Hystrix监控,我们需要打开各个服务实例的监控信息进行查看。而Turbine可以帮我们把所有服务实例的监控信息聚合到一个地方,统一查看。这样就不用一个一个打开页面一个一个查看了。下面是使用上述子框架实现的服务架构组架构图:在上图中,有几点需要说明:Zuul网关也是在注册中心注册的,也被看作是一项服务。负载均衡不是一个独立的组件。它运行在网关、服务调用等上面,每当需要访问一个服务时,就会通过Ribbon获取该服务的一个实例。Ribbon每次发送请求时,都是从Eureka注册中心获取服务和实例列表,而不是从注册中心获取。我们可以使用RestTemplate进行服务间调用,或者配置FeignClient来使用它。不管是什么方法,只要你使用了服务注册,默认都会使用Ribbon负载均衡。(RestTemplate需要加@LoadBalanced)每个服务都可以开启监控功能,监控服务会提供一个servlet接口/hystrix.stream。如果需要监控该服务某个方法的运行统计,在该方法中添加一个@HystrixCommand标签。查看监控信息,在HystrixDashboard输入该服务的监控url:http://serviceIp:port/hystrix.stream,可以以图表的形式查看运行中的监控信息。如果想把所有服务的监控信息聚合在一起统一查看,就需要使用Turbine来聚合需要服务的监控信息。从上图我们也可以看出该架构的部署方式:独立部署一个网关应用服务注册中心和监控可以配置在一个应用中,也可以配置在两个应用中。也可以部署多个服务注册中心,以区域区分,实现高可用。对于每项服务,根据负载和高可用性要求部署一个或多个实例。SpringCloudNetflix组件开发上面提到,基于SpringCloudNetflix开发微服务非常简单。一般我们配合SpringBoot使用。如果你想在你原来的Javaweb应用中使用它,你也可以通过添加相关配置来练习。详细开发可以参考SpringCloud中文社区的该系列文章,里面详细介绍了各个组件的开发。这里,只看服务注册和监控模块的开发,以及服务调用的开发。其他的可以直接参考上面的系列文章。注册监控中心的开发很简单,就是下面的类://省略import@SpringBootApplication@EnableEurekaServer@EnableHystrixDashboardpublicclassApplicationRegistry{publicstaticvoidmain(String[]args){newSpringApplicationBuilder(Application.class).web(true).run(args);}}@SpringBootApplication这里使用SpringBoot标签表示当前应用是SpringBoot应用。这样我可以直接在IDE中使用main函数启动应用,也可以打包后用命令行启动。当然也可以用Tomcat等服务器启动打包好的war包。使用@EnableEurekaServer标签,可以在启动过程中启动Eureka服务注册中心的组件。它将监听一个端口,默认为8761,以接收服务注册。并提供一个网页,打开后可以看到注册的服务。添加@EnableHystrixDashboard将提供一个监控页面。我们可以在上面输入需要监控的服务的地址,然后就可以查看启用了Hystrix监控的接口的调用情况。当然,为了使用以上组件,我们需要在Maven的POM文件中添加相应的依赖,比如使用spring-boot-starter-parent,依赖spring-cloud-starter-eureka-server和spring-cloud-starter-hystrix-dashboard等服务间调用网上的各种文档中,服务间调用都没有明确说明,所以这里特地说明一下如何开发这个。服务调用有两种方式,RestTemplate和FeignClient。不管是什么方法,都是通过REST接口调用服务的http接口,参数和结果默认由Jackson进行序列化和反序列化。由于SpringMVC的RestController定义的接口,返回的数据通过Jackson序列化成JSON数据。RestTemplate使用这个方法,你只需要定义一个RestTemplateBean,并设置为LoadBalanced:@ConfigurationpublicclassSomeCloudConfiguration{@LoadBalanced@BeanRestTemplaterestTemplate(){returnnewRestTemplate();}}这样我们就可以在需要注入的地方使用它这个bean使用:publicclassSomeServiceClass{@AutowiredprivateRestTemplaterestTemplate;publicStringgetUserById(LonguserId){UserDTO结果=restTemplate.getForObject("http://users/getUserDetail/"+userId,UserDTO.class);返回结果;其中users为服务ID,Ribbon会从服务实例列表中获取该服务的一个实例,发送请求,获取结果。对象UserDTO需要一个序列号,它的反序列化是自动完成的。FeignClient除了上面的方法,我们还可以使用FeignClient。或者直接看代码:@FeignClient(value="users",path="/users")publicinterfaceUserCompositeService{@RequestMapping(value="/getUserDetail/{id}",method=RequestMethod.GET,produces=MediaType.APPLICATION_JSON_VALUE)UserDTOgetUserById(@PathVariableLongid);}我们只需要使用@FeignClient定义一个接口,SpringCloudFeign会帮我们生成一个实现,从对应的用户服务中获取数据。其中@FeignClient(value="users",path="/users/getUserDetail")中的value为服务ID,path为这组接口的路径前缀。在下面的方法定义中,就像设置了SpringMVC的接口一样。该方法对应的URL为/users/getUserDetail/{id}。然后在使用的时候,像注入一般服务一样注入:publicclassSomeOtherServiceClass{@AutowiredprivateUserCompositeServiceuserService;publicvoiddoSomething(){//.....UserDTO结果=userService.getUserById(userId);//其他操作...}}遇到的问题由于SpringCloud文档较少,微服务的架构相对复杂。在开发过程中,难免会遇到很多问题。有的是如何更好的使用这个框架来搭建架构,还有一些是如何配置的问题。下面是我在构建微服务架构时遇到的一些问题的一些方法。请求超时问题Zuul网关默认的超时时间很短,这是为了保证调用服务时能够快速响应。但是,我们会有一些业务方法运行很长时间,尤其是在测试服务器上。这时候就需要调整超时时间了。这个超时有几个地方:LoadbalancingRibbon,负载均衡有超时设置,包括连接时间和读取时间Hystrix断路器也有超时设置,需要在合适的时间返回,而不是等待请求。对应配置如下:hystrix.command.default.execution.isolation.thread.timeoutInMilliseconds=30000ribbon:ReadTimeout:30000ConnectTimeout:15000ServiceID问题服务ID,也就是服务名,可以在application.yml或者Bootstrap中传入.ymlSettings:spring:application:name:users管理路径问题SpringBoot应用默认开启一些管理接口,比如/info、/health和metrics监控接口/metrics等,如果使用默认路径,会有使用Hystrix监控和监控服务注册中心的服务状态没问题,但是如果要用其他路径,比如/management/info,/management/health,会涉及很多而且每个版本都可能或多或少有问题,这会导致你遇到的问题不一样。我遇到的问题是:注册成功但是找不到服务。首先可以注册成功,在Eureka服务器页面也可以看到各个服务。但是通过网关调用,总是提示找不到服务。这时候可能需要在各个服务的application.yml中配置如下:eureka:instance:nonSecurePort:${server.port}appname:${spring.application.name}statusPageUrlPath:${management.context-path}/infohealthCheckUrlPath:${management.context-path}/health简单的说,这个就是在注册的时候告诉Eureka服务器,服务的端口是什么,用来监控状态的路径是什么.这是因为我们使用了不同的管理接口路径,而Eureka服务器没有使用相应的路径。如果一切正常,您应该能够通过单击Eureka服务器上的已注册服务来打开信息页面。可能是空白,但至少Eureka服务器可以通过这个知道服务是正常运行的。并不是所有版本都存在这个问题,只有部分SpringCloud版本存在。设置了管理路径的Hystrix监控刚才说了Hystrix监控的路径是http://serviceIp:port/hystrix.stream,如果你设置了管理界面的路径,那么这个监控路径也会变成:http://serviceIp:port/${management.context-path}/hystrix.stream这时候如果要使用Turbine聚合,Turbine是找不到的,因为它默认使用Eureka服务器上的服务器地址和端口,在hystrix之后添加/。溪流。这时候需要设置Turbine:turbine:aggregator:clusterConfig:USERappConfig:USERinstanceUrlSuffix:USER:/user/hystrix.stream管理路径安全对于微服务部署的几台机器,可以通过开启防火墙来控制谁可以访问管理接口,不过即便如此,为了安全等,我一般还是用SpringSecurity来保护管理接口。这样就无法直接访问监控界面了。服务间调用的授权验证一般我们的API接口都需要某种授权才能访问。登录成功后,可以通过token或cookie调用接口。如果你使用SpringCloudNetfix框架,当你登录时,登录请求被转发到相应的用户服务。登录成功后,会设置一个cookie或headertoken。那么客户端的下一次请求就会携带这些验证信息,从Zuul网关传给相应的服务进行验证。Zuul网关在向后台服务转发请求时,默认会向服务器发送一些Header,如:Cookie、Set-Cookie、Authorization。这样就可以将客户端请求的相关header传递给服务器,同时也可以将服务器设置的cookie传递给客户端。但是,如果要禁止某些header透传给服务端,可以在Zuul网关的application.yml配置中禁用,方法如下:zuul:routes:users:path:/users/**sensitiveHeaders:Cookie,Set-Cookie,AuthorizationserviceId:刚才用户说我们的一个服务有时候需要调用另一个服务。这个时候这个请求不是客户端发起的,他的请求头中不会有认证信息。这时候要么通过防火墙等设置,保证服务之间调用的接口只能被某些地址访问;或者,以某种方式设置标题。同时,如果想在某个服务中获取本次请求的真实IP(因为请求是通过网关转发的,直接通过请求获取网关的IP),可以从headerX中获取-转发主机。如果你想禁用这个header,你也可以:zuul.addProxyHeaders=false如果你使用RestTemplate调用,你可以在请求中添加一个Optionswithheader。它也可以由以下拦截器设置,它适用于RestTemplate和FeignClient:模板。标头(AUTH_TOKEN_HEADER,authToken);}};}