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

gRPC之metadata

1、metadata

服务间使用 Http 相互调用时,经常会设置一些业务自定义 header 如时间戳、trace信息等,gRPC使用 HTTP/2

协议自然也是支持的,gRPC 通过 google.golang.org/grpc/metadata 包内的 MD 类型提供相关的功能接口。

1.1 类型定义

// MD is a mapping from metadata keys to values. Users should use the following
// two convenience functions New and Pairs to generate MD.
type MD map[string][]string

metadata.MD 类型的定义非常简单,可以像一个普通的 map 一样直接操作,同时 metadata 包里封装了很多工

具方法供我们使用。

// 使用 New 方法创建
md := metadata.New(map[string]string{"k1":"v1", "k2", "v2"})// 直接使用 make 创建
md := make(metadata.MD)// 使用 Pairs 方法创建
md := metadata.Pairs("k1", "v1-1", "k1", "v1-2")// 一些操作
md.Set("key", "v1", "v2")
md.Append("key", "v3")
md.Delete("key")
vals := md.Get("key")

1.2 发送与接收

1.2.1 客户端

客户端请求的 metadata 是通过设置 context 使用的,metadata 包提供了两个 context 相关的方法,设置好

context 后直接在调用 rpc 方法时传入即可:

md := metadata.New(map[string]string{"k1":"v1", "k2", "v2"})// 使用 NewOutgoingContext 初始化一个新的 context
ctx := metadata.NewOutgoingContext(context.Background(), md)// 使用 AppendToOutgoingContext 向 context 追加 metadata
ctx = metadata.AppendToOutgoingContext(ctx, "k3", "v3")

客户端接收响应中的 metadata 需要区分普通 rpc 和 stream rpc :

// 普通 rpc,使用 grpc.Header 方法包装为 CallOption
var md metadata.MD
res, err := client.Ping(ctx, &pb.PingRequest{Value: "ping"}, grpc.Header(&md))// stream rpc
stream, err := client.MultiPong(context.Background(), &pb.PingRequest{Value: "ping"})
if err != nil {log.Fatal(err)
}// 通过 stream 对象的 Header 方法获取
md, err := stream.Header()
if err != nil {log.Fatal(err)
}
1.2.2 服务端

对应客户端请求的 metadata 是使用 context 设置的,那么服务端在接收时自然也是从 context 中读取,

metadata 包中的 FromIncommingContext 方法就是用来读取 context 中的 metadata数据的:

// unary rpc
func (s *PingPongServer) Ping(ctx context.Context, req *pb.PingRequest) (*pb.PongResponse, error) {// 读取请求metadatamd, ok := metadata.FromIncomingContext(ctx)if ok {log.Printf("Got md: %v", md)}// stream rpc
func (s *PingPongServer) MultiPingPong(stream pb.PingPong_MultiPingPongServer) error {md, ok := metadata.FromIncomingContext(stream.Context())if ok {log.Printf("Got md: %v", md)}

服务端设置响应的 metadata 也非常简单,只需要调用封装好的 SetHeaderSendHeader 方法即可:

// unary rpc
func (s *PingPongServer) Ping(ctx context.Context, req *pb.PingRequest) (*pb.PongResponse, error) {// 读取请求metadatamd, ok := metadata.FromIncomingContext(ctx)if ok {log.Printf("Got md: %v", md)}// SetHeader设置响应 metadatagrpc.SetHeader(ctx, metadata.New(map[string]string{"rkey": "rval"}))// 注意 SendHeader 只能调用一次// grpc.SendHeader(ctx, metadata.New(map[string]string{"rkey": "rval"}))// stream rpc, 调用 stream 的 SetHeader 方法
func (s *PingPongServer) MultiPong(req *pb.PingRequest, stream pb.PingPong_MultiPongServer) error {stream.SetHeader(metadata.New(map[string]string{"rkey": "rval"}))// 注意 SendHeader 只能调用一次// stream.SendHeader(metadata.New(map[string]string{"rkey": "rval"}))

1.3 使用案例

1.3.1 proto 文件编写和编译

demo.proto文件内容:

syntax="proto3";
package protos;
option go_package = "./protos;protos";service Greeter {rpc SayHello(HelloRequest) returns(HelloReply){}
}message HelloRequest {string name = 1;
}message HelloReply {string message = 1;
}

编译生成demo.pb.go 文件:

$ protoc --go_out=plugins=grpc:. demo.proto
1.3.2 server端

server.go文件的内容:

package mainimport ("context""flag""fmt""demo/protos""google.golang.org/grpc""google.golang.org/grpc/metadata""log""net"
)var host = "127.0.0.1"var (ServiceName = flag.String("ServiceName", "hello_service", "service name")Port        = flag.Int("Port", 50001, "listening port")
)type server struct {
}func main() {flag.Parse()lis, err := net.Listen("tcp", fmt.Sprintf("127.0.0.1:%d", *Port))if err != nil {log.Fatalf("failed to listen:%s", err)} else {fmt.Printf("listen at :%d\n", *Port)}defer lis.Close()s := grpc.NewServer()defer s.GracefulStop()protos.RegisterGreeterServer(s, &server{})addr := fmt.Sprintf("%s:%d", host, *Port)fmt.Printf("server add:%s\n", addr)if err := s.Serve(lis); err != nil {fmt.Printf("failed to server: %s", err)}
}func (s *server) SayHello(ctx context.Context, in *protos.HelloRequest) (*protos.HelloReply, error) {md, ok := metadata.FromIncomingContext(ctx)if !ok {fmt.Printf("get metadata error")}else{fmt.Println("get metadata success: ",md)}if t, ok := md["timestamp"]; ok {fmt.Printf("timestamp from metadata:\n")for i, e := range t {fmt.Printf(" %d. %s\n", i, e)}}if t1, ok1 := md["key1"]; ok1 {fmt.Printf("key1 from metadata:\n")for i, e := range t1 {fmt.Printf(" %d . %s\n", i, e)}}if len(md) > 0 {for k, v := range md {fmt.Printf("%v:%v\n", k, v)}}return &protos.HelloReply{Message: "server: " + in.Name}, nil
}
1.3.3 client端

client.go文件的内容:

package mainimport ("context""fmt""demo/protos""google.golang.org/grpc""google.golang.org/grpc/metadata""time"
)const (timestampFormat = time.StampNano
)func main() {conn, err := grpc.Dial("127.0.0.1:50001", grpc.WithInsecure())if err != nil {panic(err)}client := protos.NewGreeterClient(conn)md := metadata.Pairs("timestamp", time.Now().Format(timestampFormat))md = metadata.New(map[string]string{"key1": "val1", "key2": "val2"})ctx := metadata.NewOutgoingContext(context.Background(), md)resp, err := client.SayHello(ctx, &protos.HelloRequest{Name: "Hello"})if err == nil {fmt.Printf("Reply is : %s\n", resp.Message)} else {fmt.Printf("call server error:%s\n", err)}
}
1.3.4 运行
[root@zsx demo]# go run server.go
listen at :50001
server add:127.0.0.1:50001
get metadata success:  map[:authority:[127.0.0.1:50001] content-type:[application/grpc] key1:[val1] key2:[val2] user-agent:[grpc-go/1.53.0]]
key1 from metadata:0 . val1
:authority:[127.0.0.1:50001]
content-type:[application/grpc]
user-agent:[grpc-go/1.53.0]
key2:[val2]
key1:[val1]
[root@zsx demo]# go run client.go
Reply is : server: Hello
# 项目结构
[root@zsx protoc]# tree demo/
demo/
├── client.go
├── demo.proto
├── go.mod
├── go.sum
├── protos
│   └── demo.pb.go
└── server.go1 directory, 6 files

相关文章:

gRPC之metadata

1、metadata 服务间使用 Http 相互调用时,经常会设置一些业务自定义 header 如时间戳、trace信息等,gRPC使用 HTTP/2 协议自然也是支持的,gRPC 通过 google.golang.org/grpc/metadata 包内的 MD 类型提供相关的功能接口。 1.1 类型定义 /…...

【OpenCV实现图像:OpenCV进行OCR字符分割】

文章目录 概要基本概念读入图像图像二值化小结 概要 在处理OCR(Optical Character Recognition,光学字符识别)时,利用传统的图像处理方法进行字符切分仍然是一种有效的途径。即便当前计算机视觉领域主导的是卷积神经网络&#xf…...

景联文科技入选量子位智库《中国AIGC数据标注产业全景报告》数据标注行业代表机构

量子位智库《中国AIGC数据标注产业全景报告》中指出,数据标注处于重新洗牌时期,更高质量、专业化的数据标注成为刚需。未来五年,国内AI基础数据服务将达到百亿规模,年复合增长率在27%左右。 基于数据基础设施建设、大模型/AI技术理…...

ClickHouse SQL操作

基本上来说传统关系型数据库(以MySQL为例)的SQL语句,ClickHouse基本都支持,这里不会从头讲解SQL语法只介绍ClickHouse与标准SQL(MySQL)不一致的地方。 1 Insert 基本与标准SQL(MySQL&#xff09…...

Ubuntu安装Python环境(使用VSCode)

想在Ubuntu上安装Python环境,选择了VSCode,而不想多装Anaconda等环境,最后参考了这篇博客: python入门开发:ubuntu下搭建python开发环境(vscode)...

QTcpSocket发送结构体的做法

作者:朱金灿 来源:clever101的专栏 为什么大多数人学不会人工智能编程?>>> QTcpSocket发送结构体其实很简单:使用QByteArray类对象进行封装发送,示例代码如下: /* 消息结构体 */ struct stMsg {int m_A…...

微服务学习 | Ribbon负载均衡、Nacos注册中心、微服务技术对比

Ribbon负载均衡 负载均衡流程 负载均衡策略 通过定义IRule实现可以修改负载均衡规则,有两种方式: 1. 代码方式:在服务消费者order-service中的OrderApplication类中,定义一个新的IRule: 2.配置文件方式: 在order-service的application.yml…...

【FPGA】zynq 单端口RAM 双端口RAM 读写冲突 写写冲突

RAMRAM读写分类RAM原理及实现RAM三种读写模式不变模式写优先读优先 单端口 RAM伪双端口 RAM真双端口 RAM读写冲突和写写冲突读写冲突写写冲突总结: RAM RAM 的英文全称是 Random Access Memory,即随机存取存储器,简称随机存储器,…...

【备忘】websocket学习之挖坑埋自己

背景故事 以前没有好好学习过websocket,只知道它有什么用途,也知道是个好东西,平时在工作中没用过,所以对它并不知所以然。如今要做个自己的项目,要在付款的时候实时播报声音。自己是个开发者,也不想用别人…...

大数据研发工程师面试

文章目录 面试1.AUC,ROC,准确率与召回率都是怎么计算的?2.数据清洗是如何清洗的,要做哪些清洗的工作?3.什么是数据的完整性?4.数仓是怎么设计的?5.linux查看进程的命令是什么,如何查看具体某一行的内容(查看第n至m行&#xff0…...

【星海出品】云存储 ceph

https://ceph.com/en/ ceph组件介绍 Monitor 一个Ceph集群需要多个Monitor组成的小集群,它们通过Paxos同步数据,用来保存OSD的元数据。 OSD OSD全称Object Storage Device,也就是负责响应客户端请求返回具体数据的进程。一个Ceph集群一般都有…...

[nlp] grad norm先降后升再降

grad norm先降后升再降正常嘛 在深度学习中,梯度的范数通常被用来衡量模型参数的更新程度,也就是模型的学习进度。在训练初期,由于模型参数的初始值比较随机,梯度的范数可能会比较大,这是正常现象。随着模型的训练&…...

云积天赫AI全域营销系统,为品牌营销注入新活力

AIGC(生成式人工智能)的出现,标志着人工智能已经进入了一个全新的时代,它与传统的人工智能不同,可以更好地理解品牌的需求,并提供更精准的答案。目前,AIGC已经深入到各个领域,其中营…...

Arthas在线修改Java代码

Arthas在线修改Java代码 jad --source-only com.example.demo.arthas.user.UserController > /tmp/UserController.javamc /tmp/UserController.java -d /tmpretransform /tmp/com/example/demo/arthas/user/UserController.class参考链接: arthas retransform...

mapbox支持的坐标系

mapbox 中只支持 web墨卡托坐标系,不支持经纬度坐标系。 栅格数据 基于经纬度坐标系的栅格数据没有办法渲染。矢量数据 矢量数据代码中会自动转换成墨卡托投影坐标系再渲染。 输出坐标时候还是经纬度。...

腾讯云新客户优惠服务器88元/年,540元/3年,另有5年优惠服务器

在选择云服务器时,首先需要考虑的是性能与配置是否与自己的需求相匹配。对于小型网站或者个人博客,轻量应用服务器是一个不错的选择。腾讯云双十一活动中,2核2G轻量应用服务器的活动优惠价为88元/年,2核4G轻量应用服务器的活动优惠…...

伦敦银和美白银的关系

与黄金相似,世界上白银交易的基础就是伦敦白银市场,人们利用设立在伦敦的专们负责清算银行(与黄金的清算银行相同)所开设的账户进行白银保证金交易。在伦敦市场,以美元清算的伦敦白银价格,是以美元买进1金衡…...

Matplotlib的使用方法

Matplotlib是Python最著名的绘图库,它提供了一整套和Matlab相似的命令API,十分适合交互式地进行制图。而且也可以方便地将它作为绘图控件,嵌入到GUI应用程序中。Matplotlib能够创建多数类型的图表,如条形图、散点图、条形图、饼图…...

【入门篇】1.7 Redis 之 codis 入门介绍

文章目录 1. 简介2. Codis的安装与配置下载编译源码安装1. 安装 Go 运行环境2. 设置编译环境3. 下载 Codis 源代码4. 编译 Codis 源代码 Docker 部署 3. Codis的架构Codis的架构图和组件Codis的工作流程 4. Codis的核心特性自动数据分片数据迁移高可用性全面支持Redis命令分布式…...

【JavaEE】Servlet API 详解(HttpServlet类)

一、HttpServlet 写 Servlet 代码的时候, 首先第一步就是先创建类, 继承自HttpServlet, 并重写其中的某些方法 1.1 HttpServlet核心方法 1.2 Servlet生命周期 这些方法的调用时机, 就称为 “Servlet 生命周期”. (也就是描述了一个 Servlet 实例从生到死的过程) 1.3 处理G…...

(LeetCode 每日一题) 3442. 奇偶频次间的最大差值 I (哈希、字符串)

题目:3442. 奇偶频次间的最大差值 I 思路 :哈希,时间复杂度0(n)。 用哈希表来记录每个字符串中字符的分布情况,哈希表这里用数组即可实现。 C版本: class Solution { public:int maxDifference(string s) {int a[26]…...

k8s从入门到放弃之Ingress七层负载

k8s从入门到放弃之Ingress七层负载 在Kubernetes(简称K8s)中,Ingress是一个API对象,它允许你定义如何从集群外部访问集群内部的服务。Ingress可以提供负载均衡、SSL终结和基于名称的虚拟主机等功能。通过Ingress,你可…...

【SpringBoot】100、SpringBoot中使用自定义注解+AOP实现参数自动解密

在实际项目中,用户注册、登录、修改密码等操作,都涉及到参数传输安全问题。所以我们需要在前端对账户、密码等敏感信息加密传输,在后端接收到数据后能自动解密。 1、引入依赖 <dependency><groupId>org.springframework.boot</groupId><artifactId...

江苏艾立泰跨国资源接力:废料变黄金的绿色供应链革命

在华东塑料包装行业面临限塑令深度调整的背景下&#xff0c;江苏艾立泰以一场跨国资源接力的创新实践&#xff0c;重新定义了绿色供应链的边界。 跨国回收网络&#xff1a;废料变黄金的全球棋局 艾立泰在欧洲、东南亚建立再生塑料回收点&#xff0c;将海外废弃包装箱通过标准…...

python如何将word的doc另存为docx

将 DOCX 文件另存为 DOCX 格式&#xff08;Python 实现&#xff09; 在 Python 中&#xff0c;你可以使用 python-docx 库来操作 Word 文档。不过需要注意的是&#xff0c;.doc 是旧的 Word 格式&#xff0c;而 .docx 是新的基于 XML 的格式。python-docx 只能处理 .docx 格式…...

解决本地部署 SmolVLM2 大语言模型运行 flash-attn 报错

出现的问题 安装 flash-attn 会一直卡在 build 那一步或者运行报错 解决办法 是因为你安装的 flash-attn 版本没有对应上&#xff0c;所以报错&#xff0c;到 https://github.com/Dao-AILab/flash-attention/releases 下载对应版本&#xff0c;cu、torch、cp 的版本一定要对…...

如何理解 IP 数据报中的 TTL?

目录 前言理解 前言 面试灵魂一问&#xff1a;说说对 IP 数据报中 TTL 的理解&#xff1f;我们都知道&#xff0c;IP 数据报由首部和数据两部分组成&#xff0c;首部又分为两部分&#xff1a;固定部分和可变部分&#xff0c;共占 20 字节&#xff0c;而即将讨论的 TTL 就位于首…...

【HarmonyOS 5 开发速记】如何获取用户信息(头像/昵称/手机号)

1.获取 authorizationCode&#xff1a; 2.利用 authorizationCode 获取 accessToken&#xff1a;文档中心 3.获取手机&#xff1a;文档中心 4.获取昵称头像&#xff1a;文档中心 首先创建 request 若要获取手机号&#xff0c;scope必填 phone&#xff0c;permissions 必填 …...

Web 架构之 CDN 加速原理与落地实践

文章目录 一、思维导图二、正文内容&#xff08;一&#xff09;CDN 基础概念1. 定义2. 组成部分 &#xff08;二&#xff09;CDN 加速原理1. 请求路由2. 内容缓存3. 内容更新 &#xff08;三&#xff09;CDN 落地实践1. 选择 CDN 服务商2. 配置 CDN3. 集成到 Web 架构 &#xf…...

QT开发技术【ffmpeg + QAudioOutput】音乐播放器

一、 介绍 使用ffmpeg 4.2.2 在数字化浪潮席卷全球的当下&#xff0c;音视频内容犹如璀璨繁星&#xff0c;点亮了人们的生活与工作。从短视频平台上令人捧腹的搞笑视频&#xff0c;到在线课堂中知识渊博的专家授课&#xff0c;再到影视平台上扣人心弦的高清大片&#xff0c;音…...