首页 > 数据库 > 数据库开发技术 > 微服务使用RESTful时遇到的坑
一个大型复杂的业务系统由一个或多个微服务组成。系统中的各个微服务可被独立部署,各个微服务之间是松耦合的。每个微服务仅关注于完成一件任务并很好地完成该任务。每个任务代表着一个小的业务能力,组合或者复用这些微服务的能力,支撑上层大型复杂的业务系统。
目前流行的微服务架构是基于开源的 Spring Cloud 实现,它提供了一整套的解决方案——服务注册与发现,服务消费,服务保护与熔断,网关,分布式调用追踪,分布式配置管理等。
Spring Boot 是 Spring 的一套快速配置脚手架,使用默认大于配置的理念,用于快速开发单个微服务。提供 HTTP 协议的 RESTful 接口。
流程:
Spring Cloud 采用的是基于 HTTP 的 REST 方式,相比于 Dubbo RPC,更加轻量化和灵活,有利于跨语言服务的实现,以及服务的发布部署,但是 REST 服务调用性能会比 RPC 低一些。
上篇文章中学习到,当我们需要将内存中的对象持久化到磁盘,数据库中时,当我们需要与浏览器进行交互时,当我们需要实现 RPC 时,这个时候就需要序列化和反序列化了。
在使用 Spring Boot 开发微服务时,通过 @RestController 注解进行 Json 的序列化和反序列化操作。这里实际上已经体现了 HTTP 序列化和反序列化的过程,而这里其实就是 HttpMessageConverter 发挥着作用。在报文到达 SpringMVC / SpringBoot 和从 SpringMVC / SpringBoot 出去,都存在一个字符串和 Java 对象间转化的问题。这一过程,在 SpringMVC / SpringBoot 中,是通过 HttpMessageConverter 来解决的。
经过排查发现服务A的接口调用另一个服务B的接口,接口调用关系如下图
1、在服务A中检测到的searchNotices()方法的请求慢时间(511.2513ms)如下:
com.gemantic.semantic.datacenter.controller.CompanyProceedingController:searchNotices()---[1452.6121ms] com.gemantic.semantic.datacenter.controller.CompanyProceedingController:searchNotices()+---[50.4082ms] com.gemantic.semantic.datacenter.repository.TqOaStcodeRepository:findBySetypeAndEnddateAndSymbol() #93+---[461.2263ms] com.gemantic.semantic.datacenter.repository.CompanyProceedingRepository:findAll() #148+---[251.5718ms] com.gemantic.semantic.datacenter.repository.ComProceedingDetailRepository:findAllByIdIn() #158+---[511.2513ms] com.gemantic.semantic.datacenter.rest.repository.GreatWisdomDocRepository:existByCaseNumbers() #226
2、在服务B中检测到被调用的方法existByCaseNumbersPost()方法的请求时间(77.0756ms)如下:
---[77.0756ms] com.gemantic.greatwisdom.controller.LegalProceedingDetailController:existByCaseNumbersPost()
+---[0.1424ms] org.apache.commons.logging.Log:info() #73
+---[71.7306ms] com.gemantic.greatwisdom.repository.LegalProceedingDetailRepository:findAllByCrIdIn() #74
`---[0.4626ms] com.gemantic.springcloud.model.Responses:ok() #76
网络的问题可以基本排除,因为在同一台机器上进行联调测试的
服务之间的额外处理(序列化和反序列化),如下图
HttpInputMessage 和一个响应消息 HttpOutputMessage。HttpMessageConverter 实现类来处理各种消息形式,至于各种消息解析实现的不同,则在不同的 HttpMessageConverter 实现类中。服务 A 配置如下:
@BeanpublicFastJsonHttpMessageConverter fastJsonpHttpMessageConverter() {FastJsonHttpMessageConverter fastJsonHttpMessageConverter = new FastJsonHttpMessageConverter();FastJsonConfig fastJsonConfig = new FastJsonConfig();fastJsonConfig.setSerializerFeatures(SerializerFeature.DisableCircularReferenceDetect,SerializerFeature.BrowserSecure);fastJsonHttpMessageConverter.setFastJsonConfig(fastJsonConfig);List<MediaType> supportedMediaTypes = new ArrayList<>();supportedMediaTypes.add(MediaType.APPLICATION_JSON);supportedMediaTypes.add(MediaType.APPLICATION_JSON_UTF8);supportedMediaTypes.add(MediaType.APPLICATION_ATOM_XML);supportedMediaTypes.add(MediaType.APPLICATION_FORM_URLENCODED);supportedMediaTypes.add(MediaType.APPLICATION_OCTET_STREAM);supportedMediaTypes.add(MediaType.APPLICATION_PDF);supportedMediaTypes.add(MediaType.APPLICATION_XHTML_XML);supportedMediaTypes.add(MediaType.APPLICATION_XML);supportedMediaTypes.add(MediaType.IMAGE_GIF);supportedMediaTypes.add(MediaType.IMAGE_JPEG);supportedMediaTypes.add(MediaType.IMAGE_PNG);supportedMediaTypes.add(MediaType.TEXT_HTML);supportedMediaTypes.add(MediaType.TEXT_MARKDOWN);supportedMediaTypes.add(MediaType.TEXT_PLAIN);supportedMediaTypes.add(MediaType.TEXT_XML);fastJsonHttpMessageConverter.setSupportedMediaTypes(supportedMediaTypes);return fastJsonHttpMessageConverter;}
服务 B 配置如下:
@Beanpublic HttpMessageConverters jsonHttpMessageConverters() {return new HttpMessageConverters(false, Collections.singleton(new MappingJackson2HttpMessageConverter()));}
将两个服务的 Json 序列化和反序列化进行统一配置再次测试,请求的时间大幅缩减了,所以可以将大部分的时间消耗原因确定为序列化的问题
推荐阅读:
Java的POJO类为什么要实现Serializable接口
如果觉得还有帮助的话,你的关注和转发是对我最大的支持,O(∩_∩)O:
原文作者:HelloTech技术派;如有侵权,请联系管理员删除。