# grpc-running **Repository Path**: coderwing/grpc-running ## Basic Information - **Project Name**: grpc-running - **Description**: grpc+springboot 集成学习 - **Primary Language**: Unknown - **License**: Not specified - **Default Branch**: master - **Homepage**: None - **GVP Project**: No ## Statistics - **Stars**: 0 - **Forks**: 0 - **Created**: 2025-10-25 - **Last Updated**: 2025-10-25 ## Categories & Tags **Categories**: Uncategorized **Tags**: None ## README # gRPC + Java 学习项目 - 用户管理系统 ## 📚 项目简介 这是一个完整的 gRPC + Java 学习项目,实现了一个用户管理系统,包含: - ✅ 完整的 Protocol Buffers 定义 - ✅ gRPC 服务端实现(支持四种 RPC 模式) - ✅ gRPC 客户端实现(同步和异步调用) - ✅ 详细的代码注释和学习文档 - ✅ 生产级别的项目结构 ## 🎯 学习目标 通过本项目,你将学习到: 1. **Protocol Buffers(protobuf)**:数据序列化格式和 IDL(接口定义语言) 2. **gRPC 核心概念**:RPC 框架、服务定义、四种 RPC 模式 3. **Java gRPC 实现**:服务端和客户端开发 4. **Maven 构建配置**:protobuf 编译、依赖管理 5. **最佳实践**:错误处理、日志、资源管理 --- ## 📋 目录 - [技术栈](#-技术栈) - [项目结构](#-项目结构) - [快速开始](#-快速开始) - [核心概念详解](#-核心概念详解) - [四种 RPC 模式详解](#-四种-rpc-模式详解) - [代码解析](#-代码解析) - [常见问题](#-常见问题) - [学习资源](#-学习资源) --- ## 🛠 技术栈 | 技术 | 版本 | 说明 | |-----|------|-----| | Java | 11+ | 编程语言 | | gRPC | 1.58.0 | RPC 框架 | | Protocol Buffers | 3.24.0 | 序列化格式 | | Maven | 3.6+ | 构建工具 | | SLF4J + Logback | 2.x | 日志框架 | --- ## 📁 项目结构 ``` grpc-stu/ ├── pom.xml # Maven 配置文件 ├── src/ │ ├── main/ │ │ ├── proto/ │ │ │ └── user_service.proto # Protocol Buffers 定义 │ │ ├── java/ │ │ │ └── com/study/grpc/ │ │ │ ├── server/ │ │ │ │ ├── UserServiceImpl.java # 服务端实现 │ │ │ │ └── UserServer.java # 服务端启动类 │ │ │ └── client/ │ │ │ └── UserClient.java # 客户端实现 │ │ └── resources/ │ │ └── logback.xml # 日志配置 │ └── test/ # 测试代码(可扩展) ├── README.md # 主学习文档 ├── CONCEPTS.md # 技术概念详解 └── .gitignore # Git 忽略文件 ``` --- ## 🚀 快速开始 ### 1. 环境准备 确保已安装: - **JDK 11+**:`java -version` - **Maven 3.6+**:`mvn -version` ### 2. 编译项目 ```bash # 克隆或进入项目目录 cd grpc-stu # 编译 protobuf 文件并构建项目 mvn clean compile # 如果需要打包 mvn clean package ``` **编译过程说明:** 1. `protobuf-maven-plugin` 会自动下载 `protoc` 编译器 2. 编译 `src/main/proto/user_service.proto` 文件 3. 生成 Java 代码到 `target/generated-sources/protobuf/` 4. 生成的代码包括: - `User.java`、`UserStatus.java` 等消息类 - `UserServiceGrpc.java` gRPC 服务类 ### 3. 运行服务端 **方式一:使用 Maven** ```bash mvn exec:java -Dexec.mainClass="com.study.grpc.server.UserServer" ``` **方式二:使用 IDE** - 在 IDE 中打开 `UserServer.java` - 右键运行 `main` 方法 **成功启动日志:** ``` ================================================= gRPC 服务器启动成功! 监听端口:50051 服务列表: - UserService(用户管理服务) ================================================= ``` ### 4. 运行客户端 **打开新的终端窗口** **方式一:使用 Maven** ```bash mvn exec:java -Dexec.mainClass="com.study.grpc.client.UserClient" ``` **方式二:使用 IDE** - 在 IDE 中打开 `UserClient.java` - 右键运行 `main` 方法 **预期输出:** 客户端会自动执行所有示例,包括: 1. 创建用户(一元 RPC) 2. 获取用户(一元 RPC) 3. 更新用户(一元 RPC) 4. 列表用户(一元 RPC + 分页) 5. 流式获取用户(服务端流式 RPC) 6. 批量创建用户(客户端流式 RPC) 7. 用户操作流(双向流式 RPC) --- ## 💡 核心概念详解 ### 1. 什么是 gRPC? **gRPC** = **g**oogle **R**emote **P**rocedure **C**all gRPC 是 Google 开发的高性能、开源的 RPC 框架,具有以下特点: #### 1.1 核心特性 | 特性 | 说明 | 优势 | |-----|------|------| | **基于 HTTP/2** | 使用 HTTP/2 作为传输协议 | 多路复用、头部压缩、双向流 | | **Protocol Buffers** | 默认使用 protobuf 序列化 | 体积小、速度快、强类型 | | **多语言支持** | 支持 10+ 种编程语言 | 跨语言通信、微服务架构 | | **流式支持** | 原生支持流式数据传输 | 实时通信、大数据传输 | | **代码生成** | 自动生成客户端和服务端代码 | 减少样板代码、类型安全 | #### 1.2 gRPC vs REST API | 对比项 | gRPC | REST API | |-------|------|----------| | **协议** | HTTP/2 | HTTP/1.1 | | **数据格式** | Protocol Buffers(二进制) | JSON(文本) | | **性能** | 更快(二进制、压缩) | 较慢(文本、解析) | | **浏览器支持** | 需要 grpc-web | 原生支持 | | **流式支持** | 原生支持 | 需要额外处理 | | **代码生成** | 自动生成 | 需要手动编写 | | **学习曲线** | 较陡 | 较平缓 | **何时选择 gRPC?** - ✅ 微服务之间的通信 - ✅ 需要高性能、低延迟 - ✅ 需要流式数据传输 - ✅ 多语言环境 - ✅ 强类型的 API 接口 **何时选择 REST?** - ✅ 浏览器直接访问 - ✅ 公开的 Web API - ✅ 简单的 CRUD 操作 - ✅ 需要人类可读的数据 ### 2. 什么是 Protocol Buffers? **Protocol Buffers(protobuf)** 是 Google 开发的一种数据序列化格式和接口定义语言(IDL)。 #### 2.1 核心概念 ```protobuf // 这是一个 .proto 文件示例 syntax = "proto3"; // 使用 proto3 语法 // 消息定义(类似于 class) message User { int64 id = 1; // 字段编号 1 string username = 2; // 字段编号 2 string email = 3; // 字段编号 3 } ``` **关键点:** 1. **字段编号(Field Number)**:每个字段都有唯一编号,用于二进制编码 2. **向后兼容**:可以添加新字段,不会破坏旧代码 3. **强类型**:编译时类型检查 4. **小体积**:二进制格式比 JSON 小 3-10 倍 #### 2.2 数据类型映射 | Proto 类型 | Java 类型 | 说明 | |-----------|----------|------| | `int32` | `int` | 32 位整数 | | `int64` | `long` | 64 位整数 | | `string` | `String` | UTF-8 字符串 | | `bool` | `boolean` | 布尔值 | | `bytes` | `ByteString` | 字节数组 | | `repeated` | `List` | 数组/列表 | | `enum` | `enum` | 枚举类型 | | `message` | `class` | 嵌套消息 | #### 2.3 为什么字段编号很重要? ```protobuf message User { int64 id = 1; // 编号 1 = 用户ID string username = 2; // 编号 2 = 用户名 } ``` **字段编号的作用:** - ✅ 用于二进制编码(不是字段名) - ✅ 一旦使用就不能改变 - ✅ 1-15 使用 1 字节编码(推荐常用字段) - ✅ 16-2047 使用 2 字节编码 **向后兼容示例:** ```protobuf // 旧版本 message User { int64 id = 1; string username = 2; } // 新版本(向后兼容) message User { int64 id = 1; string username = 2; string email = 3; // 新增字段,旧代码仍能工作 } ``` ### 3. gRPC 工作原理 #### 3.1 架构图 ``` ┌─────────────────┐ ┌─────────────────┐ │ gRPC Client │ │ gRPC Server │ │ │ │ │ │ ┌───────────┐ │ │ ┌───────────┐ │ │ │ Stub │ │ ──── RPC Request ────> │ │ Service │ │ │ │ (Generated)│ │ │ │ Impl │ │ │ └───────────┘ │ <─── RPC Response ──── │ └───────────┘ │ │ │ │ │ │ ┌───────────┐ │ │ ┌───────────┐ │ │ │ Channel │ │ <──── HTTP/2 ────────> │ │ Server │ │ │ └───────────┘ │ │ └───────────┘ │ └─────────────────┘ └─────────────────┘ ↓ ↓ Protobuf 序列化 Protobuf 反序列化 ``` #### 3.2 调用流程 1. **客户端**:调用 Stub 方法 2. **序列化**:将请求对象序列化为二进制数据(protobuf) 3. **HTTP/2 传输**:通过 HTTP/2 连接发送数据 4. **服务端接收**:反序列化请求数据 5. **业务处理**:调用实际的服务方法 6. **序列化响应**:将响应对象序列化 7. **HTTP/2 返回**:发送响应数据 8. **客户端接收**:反序列化响应数据 9. **返回结果**:Stub 返回结果对象 --- ## 🔄 四种 RPC 模式详解 gRPC 支持四种服务方法类型,每种适用于不同的场景。 ### 1. 一元 RPC(Unary RPC) **定义:** ```protobuf rpc CreateUser(CreateUserRequest) returns (CreateUserResponse) {} ``` **特点:** - 客户端发送 **一个** 请求 - 服务端返回 **一个** 响应 - 最简单、最常用的模式 **适用场景:** - 普通的 API 调用 - CRUD 操作 - 查询单个资源 **服务端实现:** ```java @Override public void createUser(CreateUserRequest request, StreamObserver responseObserver) { // 1. 处理业务逻辑 User user = processCreateUser(request); // 2. 构建响应 CreateUserResponse response = CreateUserResponse.newBuilder() .setSuccess(true) .setUser(user) .build(); // 3. 发送响应 responseObserver.onNext(response); // 4. 完成 responseObserver.onCompleted(); } ``` **客户端调用:** ```java // 同步调用 CreateUserResponse response = blockingStub.createUser(request); // 异步调用 asyncStub.createUser(request, new StreamObserver() { @Override public void onNext(CreateUserResponse response) { // 处理响应 } @Override public void onError(Throwable t) { // 处理错误 } @Override public void onCompleted() { // 完成 } }); ``` --- ### 2. 服务端流式 RPC(Server Streaming RPC) **定义:** ```protobuf rpc StreamUsers(StreamUsersRequest) returns (stream User) {} ``` **特点:** - 客户端发送 **一个** 请求 - 服务端返回 **多个** 响应(流) - 服务端可以持续发送数据 **适用场景:** - 返回大量数据(避免一次性加载到内存) - 实时数据推送 - 日志流、监控数据流 - 文件下载 **服务端实现:** ```java @Override public void streamUsers(StreamUsersRequest request, StreamObserver responseObserver) { try { // 逐个发送用户 for (User user : allUsers) { // 发送单个用户 responseObserver.onNext(user); // 可以控制发送速度 Thread.sleep(100); } // 流结束 responseObserver.onCompleted(); } catch (Exception e) { // 发送错误 responseObserver.onError(e); } } ``` **客户端调用:** ```java // 同步接收(使用迭代器) Iterator userStream = blockingStub.streamUsers(request); while (userStream.hasNext()) { User user = userStream.next(); // 处理每个用户 System.out.println("收到用户:" + user.getUsername()); } // 异步接收 asyncStub.streamUsers(request, new StreamObserver() { @Override public void onNext(User user) { // 处理每个用户 } @Override public void onError(Throwable t) { // 处理错误 } @Override public void onCompleted() { // 流结束 } }); ``` **优势:** - ✅ 内存效率高(不需要一次性加载所有数据) - ✅ 低延迟(边接收边处理) - ✅ 可以随时取消接收 --- ### 3. 客户端流式 RPC(Client Streaming RPC) **定义:** ```protobuf rpc BatchCreateUsers(stream BatchCreateUsersRequest) returns (BatchCreateUsersResponse) {} ``` **特点:** - 客户端发送 **多个** 请求(流) - 服务端返回 **一个** 响应 - 客户端可以持续发送数据 **适用场景:** - 批量操作(批量插入、批量更新) - 文件上传 - 日志收集 - 数据导入 **服务端实现:** ```java @Override public StreamObserver batchCreateUsers( StreamObserver responseObserver) { return new StreamObserver() { private int createdCount = 0; @Override public void onNext(BatchCreateUsersRequest request) { // 处理每个请求 User user = createUser(request); createdCount++; } @Override public void onError(Throwable t) { // 处理错误 } @Override public void onCompleted() { // 客户端流结束,发送最终响应 BatchCreateUsersResponse response = BatchCreateUsersResponse.newBuilder() .setCreatedCount(createdCount) .build(); responseObserver.onNext(response); responseObserver.onCompleted(); } }; } ``` **客户端调用:** ```java CountDownLatch finishLatch = new CountDownLatch(1); // 创建响应观察者 StreamObserver responseObserver = new StreamObserver() { @Override public void onNext(BatchCreateUsersResponse response) { // 接收最终响应 System.out.println("创建成功:" + response.getCreatedCount() + " 个用户"); } @Override public void onError(Throwable t) { finishLatch.countDown(); } @Override public void onCompleted() { finishLatch.countDown(); } }; // 获取请求流观察者 StreamObserver requestObserver = asyncStub.batchCreateUsers(responseObserver); // 发送多个请求 for (BatchCreateUsersRequest request : requests) { requestObserver.onNext(request); } // 完成发送 requestObserver.onCompleted(); // 等待响应 finishLatch.await(); ``` **优势:** - ✅ 减少网络往返次数 - ✅ 服务端可以批量处理(提高效率) - ✅ 适合大量数据上传 --- ### 4. 双向流式 RPC(Bidirectional Streaming RPC) **定义:** ```protobuf rpc UserActionStream(stream UserAction) returns (stream UserActionResult) {} ``` **特点:** - 客户端发送 **多个** 请求(流) - 服务端返回 **多个** 响应(流) - 两个方向的流是 **独立** 的 **适用场景:** - 聊天应用(双方都可以随时发送消息) - 实时游戏(玩家操作 ↔ 游戏事件) - 协作编辑(实时同步编辑内容) - 实时数据同步 **服务端实现:** ```java @Override public StreamObserver userActionStream( StreamObserver responseObserver) { return new StreamObserver() { @Override public void onNext(UserAction action) { // 处理每个操作 UserActionResult result = handleAction(action); // 立即返回结果(不需要等待所有请求) responseObserver.onNext(result); } @Override public void onError(Throwable t) { // 处理错误 } @Override public void onCompleted() { // 客户端流结束,关闭服务端流 responseObserver.onCompleted(); } }; } ``` **客户端调用:** ```java CountDownLatch finishLatch = new CountDownLatch(1); // 创建响应观察者 StreamObserver responseObserver = new StreamObserver() { @Override public void onNext(UserActionResult result) { // 接收每个响应(可能在任何时候到达) System.out.println("收到结果:" + result.getMessage()); } @Override public void onError(Throwable t) { finishLatch.countDown(); } @Override public void onCompleted() { finishLatch.countDown(); } }; // 获取请求流观察者 StreamObserver requestObserver = asyncStub.userActionStream(responseObserver); // 发送多个操作 for (UserAction action : actions) { requestObserver.onNext(action); // 可以在任何时候发送,不需要等待响应 Thread.sleep(200); } // 完成发送 requestObserver.onCompleted(); // 等待响应完成 finishLatch.await(); ``` **关键特性:** - ✅ 全双工通信(同时读写) - ✅ 独立的读写流(不需要一对一对应) - ✅ 低延迟(实时反馈) - ✅ 灵活的交互模式 --- ## 🔍 代码解析 ### 1. Protocol Buffers 定义解析 参见 `src/main/proto/user_service.proto` 文件,包含: #### 1.1 消息定义 ```protobuf message User { int64 id = 1; // 用户ID string username = 2; // 用户名 string email = 3; // 邮箱 UserStatus status = 4; // 状态(枚举) UserRole role = 5; // 角色(枚举) int64 created_at = 6; // 创建时间 } ``` #### 1.2 枚举定义 ```protobuf enum UserStatus { USER_STATUS_UNKNOWN = 0; // 默认值必须是 0 USER_STATUS_ACTIVE = 1; USER_STATUS_INACTIVE = 2; } ``` #### 1.3 服务定义 ```protobuf service UserService { // 一元 RPC rpc CreateUser(CreateUserRequest) returns (CreateUserResponse) {} // 服务端流式 RPC rpc StreamUsers(StreamUsersRequest) returns (stream User) {} // 客户端流式 RPC rpc BatchCreateUsers(stream BatchCreateUsersRequest) returns (BatchCreateUsersResponse) {} // 双向流式 RPC rpc UserActionStream(stream UserAction) returns (stream UserActionResult) {} } ``` ### 2. 服务端实现解析 参见 `src/main/java/com/study/grpc/server/UserServiceImpl.java` **关键点:** 1. 继承 `UserServiceGrpc.UserServiceImplBase` 2. 覆盖 RPC 方法 3. 使用 `StreamObserver` 发送响应 4. 错误处理和日志记录 ### 3. 客户端实现解析 参见 `src/main/java/com/study/grpc/client/UserClient.java` **关键点:** 1. 创建 `ManagedChannel` 连接服务器 2. 使用 `BlockingStub`(同步)或 `AsyncStub`(异步) 3. 调用 RPC 方法 4. 处理响应和错误 5. 正确关闭连接 --- ## ❓ 常见问题 ### Q1: 如何处理 gRPC 超时? ```java // 设置超时时间(5 秒) CreateUserResponse response = blockingStub .withDeadlineAfter(5, TimeUnit.SECONDS) .createUser(request); ``` ### Q2: 如何实现 gRPC 认证? 使用拦截器(Interceptor): ```java // 服务端 server = ServerBuilder.forPort(PORT) .addService(new UserServiceImpl()) .intercept(new AuthInterceptor()) // 添加认证拦截器 .build(); // 客户端 channel = ManagedChannelBuilder.forAddress(host, port) .intercept(new AuthClientInterceptor()) // 添加认证拦截器 .build(); ``` ### Q3: 如何处理大文件传输? 使用流式 RPC: ```protobuf // 文件上传(客户端流式) rpc UploadFile(stream FileChunk) returns (UploadResponse) {} // 文件下载(服务端流式) rpc DownloadFile(DownloadRequest) returns (stream FileChunk) {} message FileChunk { bytes data = 1; // 文件块数据 int32 offset = 2; // 偏移量 } ``` ### Q4: gRPC 如何实现负载均衡? ```java // 使用负载均衡策略 channel = ManagedChannelBuilder .forTarget("dns:///my-service.example.com") .defaultLoadBalancingPolicy("round_robin") // 轮询 .build(); ``` ### Q5: 如何在生产环境中使用 TLS? ```java // 服务端 server = ServerBuilder.forPort(PORT) .useTransportSecurity(certChainFile, privateKeyFile) .build(); // 客户端 channel = ManagedChannelBuilder.forAddress(host, port) .useTransportSecurity() // 启用 TLS .build(); ``` --- ## 📚 学习资源 ### 官方文档 - [gRPC 官方网站](https://grpc.io/) - [Protocol Buffers 文档](https://protobuf.dev/) - [gRPC Java 文档](https://grpc.io/docs/languages/java/) ### 推荐阅读 1. **gRPC 设计原理**:理解 HTTP/2、protobuf 编码 2. **微服务架构**:gRPC 在微服务中的应用 3. **性能优化**:连接池、流控、压缩 4. **生产实践**:监控、日志、错误处理 ### 下一步学习 1. ✅ 实现单元测试 2. ✅ 添加认证和授权 3. ✅ 实现健康检查 4. ✅ 添加监控和追踪 5. ✅ 部署到 Kubernetes --- ## 🚀 生产环境部署 ### 是否需要 Client 和 Server? 在生产环境中,**大多数微服务同时是 Server 和 Client**: ``` ┌─────────────────────────┐ │ 用户服务 │ │ │ │ ┌──────────┐ │ 对外提供 │ │ Server │◄──────────┼─ gRPC 服务 │ └──────────┘ │ │ │ │ ┌──────────┐ │ 调用其他 │ │ Client │───────────┼─► gRPC 服务 │ └──────────┘ │ └─────────────────────────┘ ``` ### 典型微服务架构 ``` API 网关 (Server + Client) │ ├─► 用户服务 (Server + Client) │ │ │ ├─► 订单服务 (Server + Client) │ │ │ │ │ └─► 支付服务 (Server) │ │ │ └─► 通知服务 (Server) │ └─► 商品服务 (Server) ``` ### Kubernetes 部署示例 **Deployment 配置:** ```yaml apiVersion: apps/v1 kind: Deployment metadata: name: user-service spec: replicas: 3 template: spec: containers: - name: user-service image: your-registry/user-service:1.0.0 ports: - containerPort: 50051 env: - name: JAVA_OPTS value: "-Denv=prod" --- apiVersion: v1 kind: Service metadata: name: user-service spec: selector: app: user-service ports: - port: 50051 type: ClusterIP ``` **生产环境配置(`application-prod.yml`):** ```yaml grpc: server: port: 50051 host: 0.0.0.0 client: order-service: host: order-service.default.svc.cluster.local port: 50052 usePlaintext: false ``` ### 详细说明 📖 完整的生产环境架构说明,请查看: - **[生产环境架构说明.md](./生产环境架构说明.md)**:详细的架构设计和最佳实践 --- ## 🎓 总结 通过本项目,你应该掌握了: 1. ✅ **Protocol Buffers**: - 定义消息和服务 - 字段编号和向后兼容 - 枚举和嵌套消息 2. ✅ **gRPC 核心概念**: - 四种 RPC 模式 - Channel 和 Stub - 同步和异步调用 3. ✅ **实践技能**: - Maven 项目配置 - 服务端实现 - 客户端调用 - 错误处理 4. ✅ **最佳实践**: - 资源管理(Channel 关闭) - 优雅关闭 - 日志记录 - 线程安全 --- ## 📞 联系方式 如有问题或建议,欢迎提出 Issue 或 Pull Request! --- **祝你学习愉快!🎉**