2. gRPC 基础回顾:核心概念与通信模式
在深入缓存一致性方案之前,必须牢固掌握 gRPC 的基础构件。本章将快速回顾 gRPC 的定位、Protocol Buffers 的契约定义方式,以及四种 RPC 模式的适用场景。这些知识是后续实现缓存失效广播、分布式锁、一致性哈希通信的底层支撑。
2.1 gRPC 简介
gRPC 是 Google 开源的高性能、跨语言 RPC 框架,基于 HTTP/2 协议传输,默认使用 Protocol Buffers 作为接口定义语言(IDL)和序列化工具。其核心优势包括:
- HTTP/2 多路复用:单一 TCP 连接可并发处理多个请求/响应,降低连接开销。
- 双向流式通信:服务端与客户端可同时发送数据流,适合缓存订阅/推送场景。
- 强类型契约:通过 .proto 文件定义服务与消息,生成各语言客户端/服务端桩代码。
- 负载均衡与健康检查:原生支持 gRPC 负载均衡策略,适配缓存节点动态扩缩。
缓存场景提示:gRPC 的双向流和 HTTP/2 头部压缩特性,特别适合缓存节点间频繁、小数据量的失效通知与元数据同步。
2.2 Protocol Buffers 定义
Protocol Buffers(proto3)是 gRPC 的契约语言。一个典型的 .proto 文件包含消息类型和服务定义。以下是与缓存一致性相关的示例:
syntax = "proto3";
package cache.v1;
// 缓存键值对消息
message CacheEntry {
string key = 1;
bytes value = 2;
int64 ttl_seconds = 3; // 过期时间(秒)
int64 version = 4; // 版本号,用于冲突检测
}
// 缓存失效通知
message InvalidationEvent {
string cache_key = 1;
string region = 2; // 缓存区域标识
int64 timestamp = 3; // 失效发生时间戳
enum Reason {
UNKNOWN = 0;
UPDATE = 1;
DELETE = 2;
EVICTION = 3;
}
Reason reason = 4;
}
// 缓存一致性服务
service CacheConsistency {
// 单向失效通知
rpc Invalidate(InvalidationEvent) returns (InvalidationAck);
// 双向流订阅失效事件
rpc SubscribeInvalidations(SubscriptionRequest) returns (stream InvalidationEvent);
}
| 元素 | 说明 | 缓存一致性用途 |
|---|---|---|
| message | 定义结构化数据字段 | 封装缓存条目、失效事件、订阅请求 |
| service | 定义 RPC 方法签名 | 声明失效通知、订阅、批量同步接口 |
| enum | 枚举常量 | 区分失效原因(更新/删除/驱逐) |
| stream | 标记流式返回 | 实现持续推送缓存失效事件 |
2.3 四种 RPC 模式
gRPC 定义了四种通信模式,每种模式在缓存一致性架构中有不同的适用位置。下面通过对比表格和一张架构图来理解它们的差异。
| 模式 | 客户端请求 | 服务端响应 | 缓存一致性典型场景 |
|---|---|---|---|
| Unary | 单条 | 单条 | 查询缓存条目、单次失效确认 |
| Server Streaming | 单条 | 多条(流) | 订阅某个缓存区域的批量失效事件 |
| Client Streaming | 多条(流) | 单条 | 批量上报缓存命中/未命中统计 |
| Bidirectional Streaming | 多条(流) | 多条(流) | 缓存节点间双向同步、分布式锁协商 |
2.4 模式选择与缓存一致性映射
在实际的缓存一致性系统中,四种模式并非孤立使用,而是根据通信方向和数据量组合出现。下面通过第二个 SVG 图展示一个典型的缓存节点间通信架构,其中标注了每种模式的使用位置。
2.5 关键代码片段:Unary 与 Server Streaming 实现
以下代码展示在 Go 语言中如何实现 Unary 模式的缓存查询和 Server Streaming 模式的失效事件订阅。注意流式上下文的处理方式。
// Unary 模式:查询缓存条目
func (s *CacheServer) GetCacheEntry(ctx context.Context, req *pb.GetRequest) (*pb.CacheEntry, error) {
entry, err := s.store.Get(req.Key)
if err != nil {
return nil, status.Errorf(codes.NotFound, "key not found: %v", err)
}
return entry, nil
}
// Server Streaming 模式:订阅失效事件
func (s *CacheServer) SubscribeInvalidations(req *pb.SubscriptionRequest, stream pb.CacheConsistency_SubscribeInvalidationsServer) error {
// 注册订阅者
ch := s.broker.Subscribe(req.Region)
defer s.broker.Unsubscribe(req.Region, ch)
for {
select {
case <-stream.Context().Done():
// 客户端断开连接
return nil
case event := <-ch:
// 向客户端推送失效事件
if err := stream.Send(event); err != nil {
return err
}
}
}
}
流式连接管理要点:Server Streaming 和 Bidirectional Streaming 中,必须监听
stream.Context().Done() 以检测客户端断开,避免 goroutine 泄漏。同时建议在服务端设置流超时和最大并发流数,防止资源耗尽。
2.6 本章小结
- gRPC 基于 HTTP/2 和 Protocol Buffers,提供四种通信模式,覆盖缓存一致性中的查询、订阅、上报和双向同步需求。
- Protocol Buffers 的 message、service、enum、stream 关键字是定义缓存一致性契约的核心工具。
- Unary 适合单次请求/响应;Server Streaming 适合事件推送;Client Streaming 适合批量上报;Bidirectional Streaming 适合节点间对等同步。
- 在后续章节中,将基于这些模式构建缓存失效广播、分布式锁协商、一致性哈希通信等高级机制。