gRPC + Spring Boot实战:微服务高性能通讯从入门到落地 [复制链接]
发表于 5 天前 | 显示全部楼层 |阅读模式

马上注册,结交更多好友,享用更多功能,让你轻松玩转社区。

您需要 登录 才可以下载或查看,没有账号?立即注册

×
一、gRPC简介

gRPC是Google开源的高性能RPC框架,基于HTTP/2和Protocol Buffers,支持双向流、多语言代码天生。相比REST JSON,gRPC序列化体积小3-5倍,耽误低沉30%以上,是微服务间通讯的首选方案。
二、项目布局
  1. grpc-demo/
  2. ├── grpc-api/          # Proto定义 + 生成代码
  3. │   └── src/main/proto/
  4. │       └── user.proto
  5. ├── grpc-server/       # 服务端
  6. └── grpc-client/       # 客户端
复制代码
三、Proto文件界说
  1. syntax = "proto3";
  2. package com.example.grpc;
  3. option java_package = "com.example.grpc.user";
  4. option java_outer_classname = "UserProto";
  5. service UserService {
  6.   rpc GetUser (GetUserRequest) returns (GetUserResponse);
  7.   rpc ListUsers (ListUsersRequest) returns (stream GetUserResponse);
  8.   rpc CreateUser (stream CreateUserRequest) returns (CreateUserBatchResponse);
  9.   rpc Chat (stream ChatMessage) returns (stream ChatMessage);
  10. }
  11. message GetUserRequest {
  12.   int32 id = 1;
  13. }
  14. message GetUserResponse {
  15.   int32 id = 1;
  16.   string name = 2;
  17.   string email = 3;
  18.   int32 age = 4;
  19. }
  20. message ListUsersRequest {
  21.   int32 page = 1;
  22.   int32 size = 2;
  23. }
  24. message CreateUserRequest {
  25.   string name = 1;
  26.   string email = 2;
  27.   int32 age = 3;
  28. }
  29. message CreateUserBatchResponse {
  30.   int32 count = 1;
  31.   repeated GetUserResponse users = 2;
  32. }
  33. message ChatMessage {
  34.   string from = 1;
  35.   string message = 2;
  36. }
复制代码
四、Maven依赖设置
  1. <dependencies>
  2.     <dependency>
  3.         <groupId>net.devh</groupId>
  4.         grpc-spring-boot-starter</artifactId>
  5.         <version>3.1.0.RELEASE</version>
  6.     </dependency>
  7.     <dependency>
  8.         <groupId>io.grpc</groupId>
  9.         grpc-protobuf</artifactId>
  10.         <version>1.62.2</version>
  11.     </dependency>
  12.     <dependency>
  13.         <groupId>io.grpc</groupId>
  14.         grpc-stub</artifactId>
  15.         <version>1.62.2</version>
  16.     </dependency>
  17. </dependencies>
  18. <build>
  19.     <extensions>
  20.         <extension>
  21.             <groupId>kr.motd.maven</groupId>
  22.             os-maven-plugin</artifactId>
  23.             <version>1.7.1</version>
  24.         </extension>
  25.     </extensions>
  26.     <plugins>
  27.         <plugin>
  28.             <groupId>org.xolstice.maven.plugins</groupId>
  29.             protobuf-maven-plugin</artifactId>
  30.             <version>0.6.1</version>
  31.             <configuration>
  32.                 <protocArtifact>com.google.protobuf:protoc:3.25.3:exe:${os.detected.classifier}</protocArtifact>
  33.                 <pluginId>grpc-java</pluginId>
  34.                 <pluginArtifact>io.grpc:protoc-gen-grpc-java:1.62.2:exe:${os.detected.classifier}</pluginArtifact>
  35.             </configuration>
  36.             <executions>
  37.                 <execution>
  38.                     <goals><goal>compile</goal><goal>compile-custom</goal></goals>
  39.                 </execution>
  40.             </executions>
  41.         </plugin>
  42.     </plugins>
  43. </build>
复制代码
五、服务端实现
  1. @GrpcService
  2. public class UserGrpcService extends UserServiceGrpc.UserServiceImplBase {
  3.     @Autowired
  4.     private UserRepository userRepository;
  5.     @Override
  6.     public void getUser(GetUserRequest request, StreamObserver<GetUserResponse> responseObserver) {
  7.         User user = userRepository.findById(request.getId())
  8.             .orElseThrow(() -> new StatusRuntimeException(
  9.                 Status.NOT_FOUND.withDescription("User not found")));
  10.         responseObserver.onNext(toResponse(user));
  11.         responseObserver.onCompleted();
  12.     }
  13.     @Override
  14.     public void listUsers(ListUsersRequest request,
  15.             StreamObserver<GetUserResponse> responseObserver) {
  16.         List<User> users = userRepository.findAll(
  17.             PageRequest.of(request.getPage(), request.getSize())).getContent();
  18.         for (User user : users) {
  19.             responseObserver.onNext(toResponse(user));
  20.         }
  21.         responseObserver.onCompleted();
  22.     }
  23.     @Override
  24.     public StreamObserver<CreateUserRequest> createUser(
  25.             StreamObserver<CreateUserBatchResponse> responseObserver) {
  26.         return new StreamObserver<CreateUserRequest>() {
  27.             List<User> created = new ArrayList<>();
  28.             public void onNext(CreateUserRequest req) {
  29.                 User user = new User(req.getName(), req.getEmail(), req.getAge());
  30.                 created.add(userRepository.save(user));
  31.             }
  32.             public void onError(Throwable t) { }
  33.             public void onCompleted() {
  34.                 CreateUserBatchResponse resp = CreateUserBatchResponse.newBuilder()
  35.                     .setCount(created.size())
  36.                     .addAllUsers(created.stream().map(u -> toResponse(u)).collect(Collectors.toList()))
  37.                     .build();
  38.                 responseObserver.onNext(resp);
  39.                 responseObserver.onCompleted();
  40.             }
  41.         };
  42.     }
  43.     private GetUserResponse toResponse(User user) {
  44.         return GetUserResponse.newBuilder()
  45.             .setId(user.getId()).setName(user.getName())
  46.             .setEmail(user.getEmail()).setAge(user.getAge()).build();
  47.     }
  48. }
复制代码
六、客户端调用
  1. @Service
  2. public class UserGrpcClient {
  3.     @GrpcClient("user-service")
  4.     private UserServiceGrpc.UserServiceBlockingStub blockingStub;
  5.     @GrpcClient("user-service")
  6.     private UserServiceGrpc.UserServiceStub asyncStub;
  7.     public GetUserResponse getUser(int id) {
  8.         return blockingStub.getUser(GetUserRequest.newBuilder().setId(id).build());
  9.     }
  10.     public List<GetUserResponse> listUsers(int page, int size) {
  11.         List<GetUserResponse> result = new ArrayList<>();
  12.         Iterator<GetUserResponse> it = blockingStub.listUsers(
  13.             ListUsersRequest.newBuilder().setPage(page).setSize(size).build());
  14.         while (it.hasNext()) { result.add(it.next()); }
  15.         return result;
  16.     }
  17.     public void createUserBatch(List<CreateUserRequest> requests) {
  18.         StreamObserver<CreateUserBatchResponse> observer = new StreamObserver<CreateUserBatchResponse>() {
  19.             public void onNext(CreateUserBatchResponse resp) {
  20.                 System.out.println("Created " + resp.getCount() + " users");
  21.             }
  22.             public void onError(Throwable t) { t.printStackTrace(); }
  23.             public void onCompleted() { System.out.println("Batch done"); }
  24.         };
  25.         StreamObserver<CreateUserRequest> requestObserver = asyncStub.createUser(observer);
  26.         for (CreateUserRequest req : requests) { requestObserver.onNext(req); }
  27.         requestObserver.onCompleted();
  28.     }
  29. }
复制代码
七、客户端设置
  1. # application.yml
  2. grpc:
  3.   client:
  4.     user-service:
  5.       address: static://localhost:9090
  6.       negotiationType: plaintext
  7.       enableKeepAlive: true
  8.       keepAliveTime: 30s
  9.       keepAliveTimeout: 10s
  10. server:
  11.   port: 8081
复制代码
八、REST网关集成
  1. @RestController
  2. @RequestMapping("/api/users")
  3. public class UserRestController {
  4.     @Autowired
  5.     private UserGrpcClient grpcClient;
  6.     @GetMapping("/{id}")
  7.     public Map<String, Object> getUser(@PathVariable int id) {
  8.         GetUserResponse resp = grpcClient.getUser(id);
  9.         return Map.of("id", resp.getId(), "name", resp.getName(),
  10.             "email", resp.getEmail(), "age", resp.getAge());
  11.     }
  12.     @GetMapping
  13.     public List<Map<String, Object>> listUsers(
  14.             @RequestParam(defaultValue = "0") int page,
  15.             @RequestParam(defaultValue = "10") int size) {
  16.         return grpcClient.listUsers(page, size).stream()
  17.             .map(r -> Map.of("id", r.getId(), "name", r.getName(),
  18.                 "email", r.getEmail(), "age", r.getAge()))
  19.             .collect(Collectors.toList());
  20.     }
  21. }
复制代码
九、性能对比
  1. 指标              REST/JSON      gRPC/Protobuf
  2. -----------------------------------------------
  3. 序列化体积        ~2.1KB         ~0.4KB
  4. 平均延迟          45ms           12ms
  5. QPS (单连接)      ~3,200         ~9,500
  6. CPU占用           高             低
  7. 代码生成          无             自动
  8. 流式支持          SSE(单向)      双向流
复制代码
十、最佳实践


  • Proto版本管理:利用buf工具管理Proto文件和Breaking Change检测
  • 错误处置处罚:用gRPC Status Code更换业务非常,保持语义划一
  • 超时设置:Deadline流传,克制级联超时
  • 负载平衡:团结Nacos/Consul实现服务发现+客户端负载平衡
  • 拦截器:用gRPC Interceptor实现认证、日记、链路追踪
十一、总结

gRPC + Spring Boot是微服务性能通讯的最佳实践。通过grpc-spring-boot-starter,Spring Boot开发者可以像写平凡Service一样实现gRPC服务。四种通讯模式(Unary、Server Stream、Client Stream、Bidirectional Stream)覆盖了险些全部微服务交互场景。

免责声明:如果侵犯了您的权益,请联系站长及时删除侵权内容,谢谢合作!qidao123.com:ToB企服之家,中国第一个企服评测及软件市场,开放入驻,技术点评得现金.
回复

使用道具 举报

登录后关闭弹窗

登录参与点评抽奖  加入IT实名职场社区
去登录
快速回复 返回顶部 返回列表