当前位置: 首页 > news >正文

day7 使用 Protobuf 通信

文章目录

  • 1 为什么要使用 protobuf
  • 2 使用 protobuf 通信
  • 总结

本文代码地址: https://gitee.com/lymgoforIT/gee-cache/tree/master/day7-proto-buf

本文是7天用Go从零实现分布式缓存GeeCache的第七篇。

  • 为什么要使用 protobuf
  • 使用 protobuf 进行节点间通信,编码报文,提高效率。代码约50

1 为什么要使用 protobuf

protobufProtocol BuffersGoogle 开发的一种数据描述语言,是一种轻便高效的结构化数据存储格式,与语言、平台无关,可扩展可序列化。protobuf 以二进制方式存储,占用空间小。

protobuf 广泛地应用于远程过程调用(RPC) 的二进制传输,使用 protobuf 的目的非常简单,为了获得更高的性能。传输前使用 protobuf 编码,接收方再进行解码,可以显著地降低二进制传输的大小。另外一方面,protobuf 可非常适合传输结构化数据,便于通信字段的扩展。

使用 protobuf 一般分为以下 2 步:

  • 按照 protobuf 的语法,在 .proto 文件中定义数据结构,并使用 protoc 生成 Go 代码(.proto 文件是跨平台的,还可以生成 C、Java 等其他源码文件)。
  • 在项目代码中引用生成的Go代码。

2 使用 protobuf 通信

新建 package geecachepb,定义 geecachepb.proto

day7-proto-buf/geecache/geecachepb/geecachepb.proto

syntax = "proto3";package geecachepb;
option go_package = "./";message Request {string group = 1;string key = 2;
}message Response {bytes value = 1;
}service GroupCache {rpc Get(Request) returns (Response);
}
  • Request 包含 2 个字段, groupcache,这与我们之前定义的接口 /_geecache/<group>/<name> 所需的参数吻合。
  • Response 包含 1 个字段,bytes,类型为byte数组,与之前吻合。

生成 geecache.pb.go

$ protoc --go_out=. *.proto
$ ls
geecachepb.pb.go  geecachepb.proto

可以看到 geecachepb.pb.go 中有如下数据类型:

type Request struct {Group string   `protobuf:"bytes,1,opt,name=group,proto3" json:"group,omitempty"`Key   string   `protobuf:"bytes,2,opt,name=key,proto3" json:"key,omitempty"`...
}
type Response struct {Value []byte   `protobuf:"bytes,1,opt,name=value,proto3" json:"value,omitempty"`
}

接下来,修改 peers.go 中的 PeerGetter 接口,参数使用 geecachepb.pb.go 中的数据类型。

day7-proto-buf/geecache/peers.go

import pb "geecache/geecachepb"type PeerGetter interface {Get(in *pb.Request, out *pb.Response) error
}

最后,修改 geecache.gohttp.go 中使用了 PeerGetter 接口的地方。

day7-proto-buf/geecache/geecache.go

import (// ...pb "geecache/geecachepb"
)func (g *Group) getFromPeer(peer PeerGetter, key string) (ByteView, error) {req := &pb.Request{Group: g.name,Key:   key,}res := &pb.Response{}err := peer.Get(req, res)if err != nil {return ByteView{}, err}return ByteView{b: res.Value}, nil
}

day7-proto-buf/geecache/http.go

import (// ...pb "geecache/geecachepb""github.com/golang/protobuf/proto"
)func (p *HTTPPool) ServeHTTP(w http.ResponseWriter, r *http.Request) {// ...// Write the value to the response body as a proto message.body, err := proto.Marshal(&pb.Response{Value: view.ByteSlice()})if err != nil {http.Error(w, err.Error(), http.StatusInternalServerError)return}w.Header().Set("Content-Type", "application/octet-stream")w.Write(body)
}func (h *httpGetter) Get(in *pb.Request, out *pb.Response) error {u := fmt.Sprintf("%v/%v/%v",h.baseURL,url.QueryEscape(in.GetGroup()),url.QueryEscape(in.GetKey()),)res, err := http.Get(u)// ...if err = proto.Unmarshal(bytes, out); err != nil {return fmt.Errorf("decoding response body: %v", err)}return nil
}
  • ServeHTTP() 中使用 proto.Marshal() 编码 HTTP 响应。
  • Get() 中使用 proto.Unmarshal() 解码 HTTP 响应。

至此,我们已经将 HTTP 通信的中间载体替换成了 protobuf。运行 run.sh 即可以测试 GeeCache 能否正常工作。

总结

到这一篇为止,7天用 Go 从零实现分布式缓存 GeeCache 这个系列就完成了。简单回顾下。

  • 第一天:为了解决资源限制的问题,实现了 LRU 缓存淘汰算法
  • 第二天:实现了单机并发,并给用户提供了自定义数据源的回调函数
  • 第三天:新增了HTTPPool,为其实现了 HTTP 服务端
  • 第四天:实现了一致性哈希算法,解决远程节点的挑选问题
  • 第五天:为HTTPPool增加了 HTTP 客户端功能,实现了多节点间的通信
  • 第六天:实现了 singleflight 解决缓存击穿的问题
  • 第七天:使用 protobuf 库,优化了节点间通信的性能

原文地址:https://geektutu.com/post/geecache-day7.html

相关文章:

  • 北京网站建设多少钱?
  • 辽宁网页制作哪家好_网站建设
  • 高端品牌网站建设_汉中网站制作
  • 层次特征的尺度艺术:sklearn中的缩放技术
  • 【语音识别和生成】语音识别和语音合成技术
  • 基于SpringBoot+Vue前后端分离的高校实验室预约管理系统的设计与实现
  • 细说MCU的DAC改变输出信号频率的方法
  • AUTOSAR BSW OBD Config 配置
  • 第09课 Scratch入门篇:小鸡啄米-自制积木实现
  • 随堂测小程序的设计
  • Git安装流程以及如何将本地代码推送到新建的git仓库(IDEA操作简单易学)
  • 【LLM开源模型】LLMs-Llama3.1-240723通关攻略笔记
  • 具身智能又进一步!卡内基梅隆Meta苏黎世联邦实现虚拟人超灵活抓取
  • 微软:警惕利用VMware ESXi进行身份验证绕过攻击
  • 搭建自己的金融数据源和量化分析平台(二):读取上交所股票列表
  • 最后一个单词的长度-string
  • A Survey on Multimodal Large Language Models(from gpt-4o)
  • Redis的分布式锁
  • [Vue CLI 3] 配置解析之 css.extract
  • django开发-定时任务的使用
  • ECMAScript 6 学习之路 ( 四 ) String 字符串扩展
  • Eureka 2.0 开源流产,真的对你影响很大吗?
  • Redis字符串类型内部编码剖析
  • SQLServer之索引简介
  • ViewService——一种保证客户端与服务端同步的方法
  • vue-router 实现分析
  • web标准化(下)
  • 更好理解的面向对象的Javascript 1 —— 动态类型和多态
  • 记录:CentOS7.2配置LNMP环境记录
  • 区块链共识机制优缺点对比都是什么
  • 深入体验bash on windows,在windows上搭建原生的linux开发环境,酷!
  • 算法-插入排序
  • Hibernate主键生成策略及选择
  • ​【经验分享】微机原理、指令判断、判断指令是否正确判断指令是否正确​
  • ​第20课 在Android Native开发中加入新的C++类
  • $nextTick的使用场景介绍
  • (4)事件处理——(7)简单事件(Simple events)
  • (C++17) std算法之执行策略 execution
  • (C语言)求出1,2,5三个数不同个数组合为100的组合个数
  • (day18) leetcode 204.计数质数
  • (MonoGame从入门到放弃-1) MonoGame环境搭建
  • (简单有案例)前端实现主题切换、动态换肤的两种简单方式
  • (每日一问)设计模式:设计模式的原则与分类——如何提升代码质量?
  • (全注解开发)学习Spring-MVC的第三天
  • (三) diretfbrc详解
  • (十六)Flask之蓝图
  • (顺序)容器的好伴侣 --- 容器适配器
  • (转)IIS6 ASP 0251超过响应缓冲区限制错误的解决方法
  • (转载)从 Java 代码到 Java 堆
  • ./configure、make、make install 命令
  • .java 9 找不到符号_java找不到符号
  • .NET Core Web APi类库如何内嵌运行?
  • .net core 控制台应用程序读取配置文件app.config
  • .NET LINQ 通常分 Syntax Query 和Syntax Method
  • .NET 事件模型教程(二)
  • .NET/C# 如何获取当前进程的 CPU 和内存占用?如何获取全局 CPU 和内存占用?
  • .net6 core Worker Service项目,使用Exchange Web Services (EWS) 分页获取电子邮件收件箱列表,邮件信息字段
  • .NET程序集编辑器/调试器 dnSpy 使用介绍