中国领先的IT技术网站
|
|

Spring Cloud微服务实践

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

作者:佚名来源:点我达技术|2017-09-05 14:05

沙龙活动 | 去哪儿、陌陌、ThoughtWorks在自动化运维中的实践!10.28不见不散!


背景

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

特性

  • 分布式/版本化配置
  • 服务注册和发现
  • 路由
  • service - to - service调用
  • 负载均衡
  • 断路器

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

Spring Cloud微服务实践

spring cloud context即spring cloud应用上下文,包含引导上下文(加载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 cloud consul代码实现上比较简单,使用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唯一。

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

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

spring cloud config

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

spring cloud config架构图如下:

Spring Cloud微服务实践

Spring cloud config包含4部分

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

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

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

通过如上配置git仓库地址

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

Spring Cloud微服务实践

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

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

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

配置如下:

  1. #spring cloud bus kafka  
  2. spring.cloud.bus.enabled=true  
  3. spring.cloud.bus.trace.enabled=false  
  4. spring.cloud.stream.kafka.binder.zk-nodes=192.168.11.30:2181,192.168.11.33:2181,192.168.11.35:2181  
  5. 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是spring boot应用的监控管理服务,通过服务发现拉取服务列表,通过ApplicationRegistry注册到内部的map或者使用Hazelcast分布式存储。通过扩展zuul的RouteLocator对各个应用的spring boot actuator endpoint进行路由请求,返回各个应用的各项指标数据,通过angular js展现。地址: http://middleware.nidianwo.com/

界面如下:

Spring Cloud微服务实践

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

Spring Cloud微服务实践

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

spring cloud netfix feign

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

feign的使用非常简单

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

添加服务调用接口类:

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

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

  1. Decoder feignDecoder: ResponseEntityDecoder(这是对SpringDecoder的封装)  
  2. Encoder feignEncoder: SpringEncoder  
  3. Logger feignLogger: Slf4jLogger  
  4. Contract feignContract: SpringMvcContract  
  5. 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/**
  1. zuul.routes.express.serviceId=express-open-api 
  2.  
  3. zuul.routes.express.stripPrefix=false 

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

一些体会

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

【编辑推荐】

  1. 技术主管一直做微服务 程序员不干了
  2. Netflix如何在上万台机器中管理微服务?
  3. 看来微服务就是一把双刃剑
  4. Apache发布支持Java EE微服务的Meecrowave服务器
  5. 实例解读:基于Java构建实际可用的微服务
【责任编辑:未丽燕 TEL:(010)68476606】

点赞 0
分享:
大家都在看
猜你喜欢

视频课程+更多

热门职位+更多

读 书 +更多

高质量程序设计指南:C++/C语言(第3版)

本书以轻松幽默的笔调向读者论述了高质量软件开发方法与C++/C编程规范。它是作者多年从事软件开发工作的经验总结。本书共17章,第1章到第4...

订阅51CTO邮刊

点击这里查看样刊

订阅51CTO邮刊
× Python最火的编程语言