Spring Boot微服务中集成gRPC实践经验分享

cover

Spring Boot微服务中集成gRPC实践经验分享

一、业务场景描述

在某电商系统中,推荐服务、库存服务、订单服务等微服务需要高效、双向流式通信,REST+HTTP已无法满足低延迟、高并发和严格类型安全的需求。为此,我们选择在Spring Boot微服务中集成gRPC,提升服务间调用性能,并充分利用protobuf带来的强类型和跨语言支持。

二、技术选型过程

常见方案对比:

  1. REST+JSON:简单易用,但网络开销大、序列化性能受限;
  2. WebSocket:支持双向通信,但消息协议需自定义,开发成本高;
  3. gRPC:基于HTTP/2、支持双向流和流控,性能优越,自动生成服务、客户端代码。

最终选型:gRPC。主要理由:

  • 基于HTTP/2,多路复用和二进制压缩;
  • protobuf自动生成Java代码,强类型校验;
  • 支持流式RPC,便于实时数据处理;
  • 社区成熟,Spring生态已有starter。

三、实现方案详解

3.1 构建项目结构

spring-grpc-demo/
├── proto/
│   └── order.proto
├── service-provider/
│   ├── src/main/java/...
│   └── build.gradle
├── service-consumer/
│   ├── src/main/java/...
│   └── build.gradle
└── common/└── build.gradle

3.2 Protobuf定义(order.proto)

syntax = "proto3";
package com.example.order;option java_multiple_files = true;
option java_package = "com.example.order.proto";
option java_outer_classname = "OrderProto";service OrderService {// 下单RPCrpc CreateOrder (OrderRequest) returns (OrderReply);// 实时订单状态流rpc WatchOrderStatus (OrderRequest) returns (stream OrderStatus);
}message OrderRequest {int64 userId = 1;repeated int64 productIds = 2;
}message OrderReply {int64 orderId = 1;string status = 2;
}message OrderStatus {int64 orderId = 1;string status = 2;int64 timestamp = 3;
}

3.3 Service-Provider配置

build.gradle
plugins {id 'java'id 'com.google.protobuf' version '0.8.18'id 'org.springframework.boot' version '2.7.5'
}dependencies {implementation 'org.springframework.boot:spring-boot-starter'implementation 'net.devh:grpc-server-spring-boot-starter:2.13.1.RELEASE'compile project(':common')
}protobuf {protoc { artifact = "com.google.protobuf:protoc:3.19.4" }generatedFilesBaseDir = "$projectDir/src/main/java"
} 
Spring Boot启动类
@SpringBootApplication
public class OrderServiceProviderApplication {public static void main(String[] args) {SpringApplication.run(OrderServiceProviderApplication.class, args);}
}
OrderServiceImpl
@GRpcService
public class OrderServiceImpl extends OrderServiceGrpc.OrderServiceImplBase {@Overridepublic void createOrder(OrderRequest req, StreamObserver<OrderReply> responseObserver) {// 模拟下单逻辑long orderId = IdGenerator.nextId();OrderReply reply = OrderReply.newBuilder().setOrderId(orderId).setStatus("CREATED").build();responseObserver.onNext(reply);responseObserver.onCompleted();}@Overridepublic void watchOrderStatus(OrderRequest req, StreamObserver<OrderStatus> responseObserver) {// 模拟订单状态推送long orderId = 12345L;for (String status : Arrays.asList("CREATED","PROCESSING","SHIPPED","DELIVERED")) {OrderStatus os = OrderStatus.newBuilder().setOrderId(orderId).setStatus(status).setTimestamp(System.currentTimeMillis()).build();responseObserver.onNext(os);try { Thread.sleep(1000); } catch (InterruptedException ignored) {}}responseObserver.onCompleted();}
}
application.yml
server:port: 9090
grpc:server:port: 9090enable-tls: false

3.4 Service-Consumer配置

build.gradle
plugins {id 'java'id 'com.google.protobuf' version '0.8.18'id 'org.springframework.boot' version '2.7.5'
}dependencies {implementation 'org.springframework.boot:spring-boot-starter'implementation 'net.devh:grpc-client-spring-boot-starter:2.13.1.RELEASE'compile project(':common')
}protobuf {protoc { artifact = "com.google.protobuf:protoc:3.19.4" }generatedFilesBaseDir = "$projectDir/src/main/java"
}
gRPC客户端调用示例
@Service
public class OrderClient {@GrpcClient("order-service")private OrderServiceGrpc.OrderServiceBlockingStub blockingStub;public void createAndWatch() {OrderRequest req = OrderRequest.newBuilder().setUserId(1001).addProductIds(2001).build();OrderReply reply = blockingStub.createOrder(req);System.out.println("Order Created: " + reply.getOrderId());// 订阅状态流blockingStub.withDeadlineAfter(10, TimeUnit.SECONDS).watchOrderStatus(req).forEachRemaining(status -> System.out.println("Status: " + status.getStatus()));}
}
application.yml
grpc:client:order-service:address: static://localhost:9090enable-tls: false

四、踩过的坑与解决方案

  1. Protobuf版本冲突:

    • 问题:不同模块依赖的protobuf版本不一致,生成代码不兼容。
    • 解决:统一使用com.google.protobuf:protoc:3.19.4,在根build.gradle中强制版本管理。
  2. gRPC端口冲突:

    • 问题:Spring Boot默认端口与gRPC服务端口共用导致冲突。
    • 解决:在application.yml中分别配置server.portgrpc.server.port
  3. Deadline超时异常:

    • 问题:默认无超时时间,生产环境下客户端无限等待。
    • 解决:使用withDeadlineAfterwithDeadline设置合理超时。
  4. 流式RPC卡顿:

    • 问题:无流控或心跳时长连接容易被防火墙中断。
    • 解决:配置HTTP/2 keepAlive(grpc.server.keepAliveTime)或底层TCP心跳。

五、总结与最佳实践

  • 充分利用protobuf定义协议,保持向前兼容性。
  • 在生产环境中开启TLS加密,保障通信安全。
  • 合理设置Deadline,避免资源长时间被占用。
  • 对重要RPC接口添加链路追踪(Spring Cloud Sleuth或OpenTelemetry)。
  • 根据QPS和机器性能调整gRPC线程池和流控参数。
  • 在Kubernetes环境下,可结合gRPC Load Balancer(DNS、Envoy等)实现灰度发布与高可用。
  • 定期分析堆栈与日志,提前发现长尾请求和性能瓶颈。

通过上述实践,我们将Spring Boot微服务与gRPC集成后,服务间调用延迟降低了40%,并成功支撑了千万级日调用量,满足了高并发低延迟场景的业务需求。希望本文对您的gRPC之旅有所帮助。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。
如若转载,请注明出处:http://www.pswp.cn/diannao/90414.shtml
繁体地址,请注明出处:http://hk.pswp.cn/diannao/90414.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

springboot项目编写测试类,乱码问题解决

​MockMvc 的默认行为​ MockMvc ​默认使用 ISO-8859-1 解码响应&#xff0c;而服务端实际返回 UTF-8 编码数据 。 Postman 无乱码是因浏览器自动识别编码&#xff0c;但 MockMvc 需显式配置。 ​过滤器失效场景​ Spring 的 CharacterEncodingFilter ​默认只对 POST 请求生效…

打破传统,开启 AR 智慧课堂​

在教育领域&#xff0c;AR 智慧课堂宛如一场及时雨&#xff0c;为传统教育模式带来了革命性的变革&#xff0c;让学习变得更加生动有趣、高效互动。通过 AR 技术&#xff0c;抽象的知识瞬间变得鲜活起来&#xff0c;学生们可以在虚拟与现实交织的世界中&#xff0c;探索历史的长…

热烈祝贺 Flink 2.0 存算分离入选 VLDB 2025

VLDB 2025 论文热烈祝贺 Apache Flink 2.0 的重磅研究成果《Disaggregated State Management in Apache Flink 2.0 》被数据库领域顶级会议 VLDB 2025 正式接收&#xff01;这项工作由 Apache Flink 社区 联合 阿里巴巴实时计算 Flink 团队 以及多位学术界研究人员共同完成&…

蓄电池能量管理matlab的simulink仿真

蓄电池能量管理matlab的simulink仿真模型 AlternatorTableData.mat , 7395 Battery_Management_Lib.mdl , 577258 Readme.txt , 1293 license.txt , 1551 ssc_battery_management.mdl , 221248 ssc_lead_acid_battery_50Ah_ini.m , 1760 ssc_lead_acid_battery_80Ah_ini.m , 1…

MyBatisPlus-03-扩展功能

文章目录【README】【1】基于MyBatisPlus的代码生成器【2】MyBatisPlus-DB静态工具【2.1】使用MyBatisPlus的DB静态工具查询单个及多个用户地址【查询单个用户的访问效果】【查询多个用户的访问效果】【3】逻辑删除【3.1】代码实现【4】枚举处理器【4.1】代码实现【5】JSON处理…

初识Neo4j之Cypher(三)

目录 一、介绍 二、语法 1、节点 2、关系 3、属性 4、模式 一、介绍 Cypher 是 Neo4j 的声明式查询语言&#xff0c;兼容 GQL 标准。通过 openCypher 项目&#xff0c;Cypher 以开源方式提供。它类似于 SQL&#xff0c;但专为图数据优化。 Cypher 直观且接近自然语言&…

19-C#静态方法与静态类

C#静态方法与静态类 1.static-静态方法animal.eat&#xff08;&#xff09;;//直接调用 public class animal {public static void eat()//定义静态方法{messagebox.show("animal eat");} }2.static-静态类animal.eat&#xff08;&#xff09;;//直接调用public stat…

基于YOLO的足球检测Web应用:从训练到部署的完整实战

用Python和深度学习技术打造一个完整的足球检测系统&#xff0c;支持图片检测、视频分析和实时监控。本文带你从零开始构建一个专业的Web应用。&#x1f3af; 项目背景 在体育赛事分析和足球训练中&#xff0c;准确识别和定位足球是一个重要需求。本项目利用YOLO深度学习算法&a…

npm 切换 node 版本 和npm的源

在开发过程中&#xff0c;不同项目可能需要不同版本的 Node.js&#xff0c;同时 于由XX原因&#xff0c;我们需要切换npm的源。这时如果需要切换node版本或者npm的源&#xff0c;我们可以使用以下方法。 使用 nvm 切换 Node 版本 1、安装 npm install nvm -g2、使用 # 列出所有…

Java学习第二十部分——EasyMock

目录 一.概述 二.作用 三.工作原理 四.使用示例 五.主要特点 六.适用场景 七.其他模拟框架比较 八.idea简单项目实战 1.打开idea创建Java项目&#xff0c;注意构建系统选“Maven” 2.为pom.xml文件添加如下依赖&#xff0c;并重新加载Maven依赖&#xff0c;直至不报错…

机器学习模型在C++平台的部署

一、概述机器学习模型的训练通常在Python环境下完成&#xff0c;而现实生产环境的复杂性和多样性使得模型的部署成为一个值得关注的重点。不同应用场景下有不同适应的实现方式&#xff0c;这里主要介绍通过一种通用中间格式——ONNX&#xff08;Open Neural Network Exchange&a…

保姆级安装 Ruby 环境下载及安装教程, RubyInstaller下载及安装教程

一、下载安装 RubyInstaller 1.打开 RubyInstaller 官网&#xff1a;https://rubyinstaller.org/ 点击跳转, 官网界面如下图&#xff1a; 点击下载最新的 RubyDevkit 版本&#xff08;如 RubyDevkit 3.4.X (x64) &#xff09;。如下图所示&#xff1a; 注意点&#xff1a;如果…

SQL 一键生成 Go Struct!支持字段注释、类型映射、结构体命名规范

SQL 一键生成 Go Struct&#xff01;支持字段注释、类型映射、结构体命名规范 在 Golang 开发中&#xff0c;尤其是操作数据库时&#xff0c;我们经常会遇到这种场景&#xff1a; ✅ 拿到数据库建表 SQL&#xff0c;却要手动写 Go struct✅ 字段几十个、类型复杂&#xff0c;…

Web 前端框架选型:React、Vue 和 Angular 的对比与实践

Web 前端框架选型&#xff1a;React、Vue 和 Angular 的对比与实践 选择前端框架就像选择一个长期合作伙伴。错误的选择可能会让你的项目在未来几年内背负沉重的技术债务&#xff0c;而正确的选择则能让开发效率飞速提升。 经过多年的项目实践&#xff0c;我发现很多新人在框架…

C# 值拷贝、引用拷贝、浅拷贝、深拷贝

值拷贝定义&#xff1a;直接复制变量的值&#xff0c;适用于基本数据类型&#xff08;如int, float, char等&#xff09;。在 C# 中&#xff0c;值类型&#xff08;基本数据类型和结构体&#xff09;默认使用值拷贝。特点&#xff1a;创建原始值的完全独立副本&#xff0c;修改…

深度学习图像分类数据集—百种鸟类识别分类

该数据集为图像分类数据集&#xff0c;适用于ResNet、VGG等卷积神经网络&#xff0c;SENet、CBAM等注意力机制相关算法&#xff0c;Vision Transformer等Transformer相关算法。 数据集信息介绍&#xff1a;525种鸟类识别分类 训练数据集总共有84635张图片&#xff0c;每个文件夹…

零基础 “入坑” Java--- 八、类和对象(一)

文章目录一、初识面向对象二、类的定义和使用1.认识类2.类的定义格式三、类的实例化四、this引用五、对象的构造及初始化1.有关初始化2.构造方法3.就地初始化一、初识面向对象 Java是一门纯面向对象的语言&#xff08;OOP&#xff09;&#xff0c;在面向对象的世界里&#xff…

数字孪生技术引领UI前端设计新篇章:智能物联网的深度集成

hello宝子们...我们是艾斯视觉擅长ui设计、前端开发、数字孪生、大数据、三维建模、三维动画10年经验!希望我的分享能帮助到您!如需帮助可以评论关注私信我们一起探讨!致敬感谢感恩!一、引言&#xff1a;数字孪生与物联网的共生革命在智能设备爆发式增长的今天&#xff0c;传统…

代码审计-shiro漏洞分析

一、关于shiro介绍 简单讲&#xff0c;shiro是apache旗下的一个Java安全框架&#xff0c;轻量级简单易上手&#xff0c;框架提供很多功能接口&#xff0c;常见的身份认证 、权限认证、会话管理、Remember 记住功能、加密等等。 二、漏洞分析 1.CVE-2019-12422-shiro550 漏洞原理…

EF提高性能(查询禁用追踪)(关闭延迟加载)

EF默认是支持延迟加载的&#xff0c;在加载一个表的数据时&#xff0c;会把关联表的数据一并加载&#xff0c;这样会影响性能。 一般建议关闭延迟加载可以提高EF加载的性能。还有其他方法提高性能&#xff08;查询禁用追踪&#xff09; 如果要实现延迟加载&#xff0c;必须满足…