行业资讯

微服务实践Spring Cloud

2017-09-06 eakun

背景

随着微服务的流行,基于Spring生态的Spring Cloud越来越被关注, SpringCloud专注于提供良好的开箱即用的典型用例和可扩展性覆盖机制。

特性

  • 分布式/版本化配置

  • 服务注册和发现

  • 路由

  • service - to - service调用

  • 负载均衡

  • 断路器

Spring cloud包含两个基本模块,spring cloud context和spring cloud commons。

Spring Cloud微服务实践

spring cloud context即springcloud应用上下文,包含引导上下文(加载bootstrap配置)、配置加密、配置刷新范围(RefreshScope)、控制端点(/env/reset,/refresh,/restart等)功能。

Spring cloud commons 提供服务注册发现,负载均衡,断路器等模式的一个共用抽象层,为具体现实提供统一抽象。

实际应用过程中,我们使用了

  • spring cloud consul作为服务注册和发现组件

  • spring cloud config作为分布式/版本化配置管理

  • spring cloud bus作为消息总线用于刷新分布式应用配置

  • spring boot admin作为统一的应用监控后台

  • spring cloud Netflix feign 作为rest服务调用client

  • spring cloud Netflix zuul 作为路由、过滤网关

  • spring cloud consul

Consul 是使用Go开发的开源的服务发现和健康检查的工具.Consul还提供K/V存储.可以很方便的使用Consul集群搭建高可用的微服务基础架构.Consul还包含web ui 可以查看各服务状态.

线上consul地址: http://consul.nidianwo.com/

如下截图:

Spring Cloud微服务实践

因为consul内置了服务注册发现功能,所以spring cloudconsul代码实现上比较简单,使用ConsulServiceRegistry进行服务注册操作,使用ConsulDiscoveryClient获取所有服务或者up的服务,内部则是使用ConsulClient请求consul集群进行操作。

在使用过程中出现了一个问题,一个服务多个机器注册的时候有时注册的服务会被覆盖,查看源码发现,应用servlet容器初始化事件被监听之后会进行consul应用的自动注册,注册使用ConsulAutoRegistration对象,内部会有一个NewService对象,通过NewService对象的id判断服务的唯一性,而NewService的id默认是ApplicationContext对象的id,也就是应用名称加port加profile,所以同一个应用这个id是相同的所以注册会被覆盖。找到问题了那么就来解决问题吧,增加配置bean通过覆盖ConsulAutoRegistration对象,设置id为ApplicationContext的id加机器的ip保证应用多台机器的id唯一。

@Bean @Primary public ConsulAutoRegistration consulRegistration(ConsulDiscoveryProperties properties, ApplicationContext applicationContext, ServletContext servletContext, HeartbeatProperties heartbeatProperties) {       properties.setInstanceId(applicationContext.getId()+"-"+ DigestUtils.sha1Hex(properties.getIpAddress()));     return ConsulAutoRegistration.registration(properties, applicationContext, servletContext, heartbeatProperties); }

ConsulDiscoveryProperties这个类是consul服务发现的配置类,其中一些配置需要注意,比如preferIpAddress默认为false,即默认是通过host来进行服务的地址进行注册和检查,但是当环境不支持host访问时就会出问题,比如我们线上的阿里云环境,也有机器不支持host访问,所以需要配置preferIpAddress=true。

spring cloud config

Spring CloudConfig提供服务端和客户端在分布式系统中扩展配置。支持不同环境的配置(开发、测试、生产)。使用Git做默认配置后端,可支持配置环境打版本标签。

spring cloud config架构图如下:

Spring Cloud微服务实践

Spring cloud config包含4部分

a)git配置仓库,存放应用各环境配置

b)config server提供了基于资源的HTTP接口 通过@EnableConfigServer开启配置服务端应用

# git config spring.cloud.config.server.git.uri=http://60.191.68.43:19090/config/{application}-config.git   spring.cloud.config.server.git.username=xxx   spring.cloud.config.server.git.password=xxx   spring.cloud.config.server.git.force-pull=true (这个配置可以在配置仓库冲突的时候强制拉取,而不会取不到最新的配置)   通过如上配置git仓库地址

通过如上配置git仓库地址

Config server以rest方式提供配置资源,如下所示:

Spring Cloud微服务实践

c)config client,通过配置的url或者服务发现拉取config server配置 Config server 开启服务发现后,configclient可以通过服务发现找到config server

我们的config client使用consul服务发现来找到configserver来拉取配置,默认ConsulDiscoveryClient获取服务的时候是根据服务id获取所有服务节点,即获取了down的服务,造成拉取配置失败,查看consul服务发现的配置类ConsulDiscoveryProperties发现默认queryPassing=false,通过配置改为true即可返回所有健康检查通过的服务。

d)spring cloud bus 分布式应用配置更新通知 Spring cloudbus支持rabbitmq和kafka,因为公司已经部署kafka,所以使用了kafka作为spring cloud bus的消息组件。

配置如下:

#spring cloud bus kafka  spring.cloud.bus.enabled=true  spring.cloud.bus.trace.enabled=false  spring.cloud.stream.kafka.binder.zk-nodes=192.168.11.30:2181,192.168.11.33:2181,192.168.11.35:2181  spring.cloud.stream.kafka.binder.brokers=192.168.11.30:9092,192.168.11.33:9092,192.168.11.35:9092

架构如下:

Spring Cloud微服务实践

这时Spring Cloud Bus做配置更新步骤如下:

  • 提交代码,利用 git 的 webhook 触发post请求给 bus/refresh

  • server端接收到请求并发送给Spring Cloud Bus

  • Spring Cloud bus接到消息并通知给其它客户端

  • 其它客户端接收到通知,请求Server端获取最新配置

  • 全部客户端均获取到最新的配置

spring boot admin

spring boot admin是springboot应用的监控管理服务,通过服务发现拉取服务列表,通过ApplicationRegistry注册到内部的map或者使用Hazelcast分布式存储。通过扩展zuul的RouteLocator对各个应用的springboot actuator endpoint进行路由请求,返回各个应用的各项指标数据,通过angular js展现。地址:http://middleware.nidianwo.com/

界面如下:

Spring Cloud微服务实践

可以通过界面查看应用的健康状况,内存磁盘使用,java gc情况,配置,日志,thread dump heapdump等各项应用数据。 界面如下:

Spring Cloud微服务实践

通过日志的实时监控,可以方便观察应用启动状况,以及实时请求的日志,方便调试。

spring cloud netfix feign

spring cloudnetflix包含了很多非常有用的微服务组件,比如服务发现(Eureka),断路器(Hystrix),智能路由(Zuul)和客户端负载均衡(Ribbon),声明式服务调用client(feign)

feign的使用非常简单

应用main类增加注解@EnableFeignClients(basePackages ="com.dianwoba.open.express.service"),

添加服务调用接口类:

@FeignClient(name = "heimdall", url="${express.open.url}",         configuration = RemoteConfiguration.class) public interface RemoteExpressService {      //@Headers({"Content-Type: application/x-www-form-urlencoded","Accept: application/x-www-form-urlencoded"})     @RequestMapping(method = RequestMethod.POST, value = "/express/api/v1/addModifySite")     @ResponseBody     ApiResponse addModifySite(SiteDTO siteDTO); }

Feign内部通过几个组件进行请求的封装、调用和响应的解析。Contract实现上面接口方法的注解的解析以及请求的包装,Encoder实现上面接口方法参数的解析以及请求的组装,Feign.Builder实现核心类feign对象的建造器,Decoder实现响应的解析生成返回对象,Logger实现日志记录方式。这些接口都有默认实现,通过一个配置类配置了默认实现,默认实现为:

Decoder feignDecoder: ResponseEntityDecoder(这是对SpringDecoder的封装)  Encoder feignEncoder: SpringEncoder  Logger feignLogger: Slf4jLogger  Contract feignContract: SpringMvcContract  Feign.Builder feignBuilder: HystrixFeign.Builder

程序实现过程如下:

  • 首先通过@EnableFeignCleints注解开启FeignCleint

  • 根据Feign的规则实现接口,并加@FeignCleint注解

  • 程序启动后,会进行包扫描,扫描所有的@ FeignCleint的注解的类,并将这些信息注入到ioc容器中。

  • 当接口的方法被调用,通过jdk的代理,来生成具体的RequesTemplate

  • RequesTemplate在生成Request

  • Request交给Client去处理,其中Client可以是HttpUrlConnection、HttpClient也可以是Okhttp

  • 最后Client被封装到LoadBalanceClient类,这个类结合类Ribbon做到了负载均衡。

spring cloud netfix zuul

zuul作为微服务网关,具有动态路由和过滤器链功能,基于zuul可以实现:

  • 认证&鉴权

  • 数据统计

  • 服务路由

  • 协助单点压测

  • 限流

  • 静态响应

Zuul通过ZuulhanderMapping实现了SrpingMVC的AbstractUrlHandlerMapping,通过RouteLocator获取Route列表,映射对应route的fullPath到ZuulController,ZuulController继承了ServletWrappingController,会把对应请求代理到ZuulServlet,而ZuulServlet是zuul过滤器链的入口,过滤器链分三种类型,分别是pre、route、post分别对应请求执行前,请求路由执行,请求执行返回的操作,可以自定义各种过滤器实现特定需求。

使用非常简单

  • Spring boot启动类增加注解@EnableZuulProxy开启zuul代理功能。

  • 配置 zuul.routes.express.path=/express/**

zuul.routes.express.serviceId=express-open-api  zuul.routes.express.stripPrefix=false

请求的不同path会路由到不同的服务。

一些体会

spring cloud微服务组件使用感觉比较简单方便,通常是增加starter依赖,开启开关配置,启动类开启注解就能使用,使用过程中可能会遇到一些小问题,不过springboot以及spring cloud社区非常活跃,版本迭代非常快,问题应该比较好解决,自己也可以看看源码通过解决问题来学习相关设计思想。

【编辑推荐】

  1. 技术主管一直做微服务 程序员不干了

  2. Netflix如何在上万台机器中管理微服务?

  3. 看来微服务就是一把双刃剑

  4. Apache发布支持Java EE微服务的Meecrowave服务器

  5. 实例解读:基于Java构建实际可用的微服务

【责任编辑:未丽燕 TEL:(010)68476606】

关于我们

深圳市宜坤网络科技有限公司(宜坤网络),EAKUN(宜坤)品牌的所有者,专业的机房控制产品及解决方案提供商, 提供包括KVM切换器、延长器、视频分配器、智能PDU、智能机柜、动环监控设备在内的全系列机房管控产品及解决方案。


产品秀秀

联系我们

深圳市宜坤网络科技有限公司

深圳市宝安区新安街道安乐社区44区物业大厦503

4000163005

粤ICP备2024247455号

宜坤KVM切换器

Powered by EAKUN