微服务使用RESTful时遇到的坑

本文涉及的产品
服务治理 MSE Sentinel/OpenSergo,Agent数量 不受限
注册配置 MSE Nacos/ZooKeeper,118元/月
云原生网关 MSE Higress,422元/月
简介: 微服务使用RESTful时遇到的坑

微服务架构

概念

一个大型复杂的业务系统由一个或多个微服务组成。系统中的各个微服务可被独立部署,各个微服务之间是松耦合的。每个微服务仅关注于完成一件任务并很好地完成该任务。每个任务代表着一个小的业务能力,组合或者复用这些微服务的能力,支撑上层大型复杂的业务系统。

解决方案

目前流行的微服务架构是基于开源的 Spring Cloud 实现,它提供了一整套的解决方案——服务注册与发现,服务消费,服务保护与熔断,网关,分布式调用追踪,分布式配置管理等。

Spring Boot 是 Spring 的一套快速配置脚手架,使用默认大于配置的理念,用于快速开发单个微服务。提供 HTTP 协议的 RESTful 接口。

Spring Cloud 组件架构

流程:

  1. 请求统一通过 API 网关(Zuul)来访问内部服务。
  2. 网关接收到请求后,从注册中心(Eureka)获取可用服务。
  3. 由 Ribbon 进行均衡负载后,分发到后端具体实例。
  4. 微服务之间通过 Feign 进行通信处理业务。
  5. Hystrix 负责处理服务超时熔断。
  6. Turbine 监控服务间的调用和熔断相关指标。

微服务间通信

基于 HTTP 的 REST 方式

Spring Cloud 采用的是基于 HTTP 的 REST 方式,相比于 Dubbo RPC,更加轻量化和灵活,有利于跨语言服务的实现,以及服务的发布部署,但是 REST 服务调用性能会比 RPC 低一些。

HTTP 序列化和反序列化

上篇文章中学习到,当我们需要将内存中的对象持久化到磁盘,数据库中时,当我们需要与浏览器进行交互时,当我们需要实现 RPC 时,这个时候就需要序列化和反序列化了。

在使用 Spring Boot 开发微服务时,通过 @RestController 注解进行 Json 的序列化和反序列化操作。这里实际上已经体现了 HTTP 序列化和反序列化的过程,而这里其实就是 HttpMessageConverter 发挥着作用。在报文到达 SpringMVC / SpringBoot 和从 SpringMVC / SpringBoot 出去,都存在一个字符串和 Java 对象间转化的问题。这一过程,在 SpringMVC / SpringBoot 中,是通过 HttpMessageConverter 来解决的。

FastJson 和 Jackson 的序列化和反序列化交叉使用

发现接口访问很慢

经过排查发现服务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

问题的原因分析

  1. 网络的问题可以基本排除,因为在同一台机器上进行联调测试的
  2. 服务之间的额外处理(序列化和反序列化),如下图

  • 在 Spring 的处理过程中,一次请求报文和一次响应报文,分别被抽象为一个请求消息 HttpInputMessage 和一个响应消息 HttpOutputMessage
  • 处理请求时,由合适的消息转换器将请求报文绑定为方法中的形参对象,在这里同一个对象就有可能出现多种不同的消息形式,如json、xml。同样响应请求也是同样道理。
  • 在 Spring 中,针对不同的消息形式,有不同的 HttpMessageConverter 实现类来处理各种消息形式,至于各种消息解析实现的不同,则在不同的 HttpMessageConverter 实现类中。

观察项目的配置发现两个服务配置的不一样

服务 A 配置如下:



@Beanpublic FastJsonHttpMessageConverter 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接口

Java几种常用JSON库性能比较

如果觉得还有帮助的话,你的关注和转发是对我最大的支持,O(∩_∩)O:

相关文章
|
3月前
|
监控 负载均衡 API
Web、RESTful API 在微服务中有哪些作用?
在微服务架构中,Web 和 RESTful API 扮演着至关重要的角色。它们帮助实现服务之间的通信、数据交换和系统的可扩展性。
76 2
|
3月前
|
缓存 监控 API
微服务架构下RESTful风格api实践中,我为何抛弃了路由参数 - 用简单设计来提速
本文探讨了 RESTful API 设计中的两种路径方案:动态路径和固定路径。动态路径通过路径参数实现资源的 CRUD 操作,而固定路径则通过查询参数和不同的 HTTP 方法实现相同功能。固定路径设计提高了安全性、路由匹配速度和 API 的可维护性,但也可能增加 URL 长度并降低表达灵活性。通过对比测试,固定路径在性能上表现更优,适合微服务架构下的 API 设计。
|
4月前
|
缓存 Java 应用服务中间件
随着微服务架构的兴起,Spring Boot凭借其快速开发和易部署的特点,成为构建RESTful API的首选框架
【9月更文挑战第6天】随着微服务架构的兴起,Spring Boot凭借其快速开发和易部署的特点,成为构建RESTful API的首选框架。Nginx作为高性能的HTTP反向代理服务器,常用于前端负载均衡,提升应用的可用性和响应速度。本文详细介绍如何通过合理配置实现Spring Boot与Nginx的高效协同工作,包括负载均衡策略、静态资源缓存、数据压缩传输及Spring Boot内部优化(如线程池配置、缓存策略等)。通过这些方法,开发者可以显著提升系统的整体性能,打造高性能、高可用的Web应用。
87 2
|
5月前
|
数据库 Java 数据库连接
Hibernate 实体监听器竟如魔法精灵,在 CRUD 操作中掀起自动化风暴!
【8月更文挑战第31天】在软件开发中,效率与自动化至关重要。Hibernate 通过其强大的持久化框架提供了实体监听器这一利器,自动处理 CRUD 操作中的重复任务,如生成唯一标识符、记录更新时间和执行清理操作,从而大幅提升开发效率并减少错误。下面通过示例代码展示了如何定义监听器类,并在实体类中使用 `@EntityListeners` 注解来指定监听器,实现自动化任务。这不仅简化了开发流程,还能根据具体需求灵活应用,满足各种业务场景。
51 0
|
5月前
|
NoSQL API 数据库
揭秘!Flask如何一键解锁RESTful API高效微服务?打造未来互联网架构的隐形力量!
【8月更文挑战第31天】本文介绍如何使用 Flask 构建高效且易维护的 RESTful 微服务,涵盖环境搭建、基本应用创建及代码详解。通过示例展示用户管理系统的 CRUD 操作,并讨论数据库集成、错误处理、认证授权、性能优化及文档生成等高级主题,助力开发者打造强大的后端支持。
84 0
|
6月前
|
消息中间件 API 数据库
在微服务架构中,每个服务通常都是一个独立运行、独立部署、独立扩展的组件,它们之间通过轻量级的通信机制(如HTTP/RESTful API、gRPC等)进行通信。
在微服务架构中,每个服务通常都是一个独立运行、独立部署、独立扩展的组件,它们之间通过轻量级的通信机制(如HTTP/RESTful API、gRPC等)进行通信。
|
7月前
|
JSON Java Spring
实战SpringCloud响应式微服务系列教程(第八章)构建响应式RESTful服务
实战SpringCloud响应式微服务系列教程(第八章)构建响应式RESTful服务
|
8月前
|
缓存 Shell API
作者推荐 | 一文深度解读 — 彻底认识与理解微服务技术之Rest与Restful架构精髓
作者推荐 | 一文深度解读 — 彻底认识与理解微服务技术之Rest与Restful架构精髓
476 0
|
XML JSON Java
07-微服务技术栈(扩展):什么是RESTful
对于http接口的调用,其历程经历过原始servlet,到后面的struts,SpringMVC,对于后端的参数封装也逐渐从单个属性演变成对象封装,那么什么是RESTful,工作中又如何使用呢?
178 0
|
2月前
|
JSON 缓存 JavaScript
深入浅出:使用Node.js构建RESTful API
在这个数字时代,API已成为软件开发的基石之一。本文旨在引导初学者通过Node.js和Express框架快速搭建一个功能完备的RESTful API。我们将从零开始,逐步深入,不仅涉及代码编写,还包括设计原则、最佳实践及调试技巧。无论你是初探后端开发,还是希望扩展你的技术栈,这篇文章都将是你的理想指南。