认识GO--gRPC的metadata
参考:
写给go开发者的gRPC教程-metadata-CSDN博客
https://blog.csdn.net/kevin_tech/article/details/129395177?ops_request_misc=%257B%2522request%255Fid%2522%253A%25221f2f2e26f48c755c33344ccb171a49fc%2522%252C%2522scm%2522%253A%252220140713.130102334..%2522%257D&request_id=1f2f2e26f48c755c33344ccb171a49fc&biz_id=0&utm_medium=distribute.pc_search_result.none-task-blog-2~all~sobaiduend~default-1-129395177-null-null.142^v100^pc_search_result_base6&utm_term=go%E7%9A%84metadata&spm=1018.2226.3001.4187
什么是metadata?
元数据。他就是我们的对数据进行封装的一个单位化数据。在某些理解上,他是一个。他们是一个整体。这么说有点抽象,举例说明吧:目前我们有一个请求,请求的数据是:用户名+密码。这就是我们常说的”数据“。那么请求的方法是什么?编码是什么?token呢?cookie呢?他们提供了有关其他数据的信息,用于描述数据的特征、来源、用途、关系等诸多方面。因此,我们将他们也封装到一起,打包成我们的metadata,一起发送,一起接收......
那么在go语言中,metadata又是什么?具体的说,应该是在go的grpc中,请求和响应携带的“元数据”,他们就叫做 metadata。grpc基于http2.0,那么metadata在grpc的一次调用就是一个生命周期。
简单的理解:metadata是context中负责数据打包的载体,配合context实现服务端和客户端之间的互相传递信息。
metadata的创建
我们先了解一个东西:在grpc中,metadata的本质其实是一个map[string][]string。
New()
md := metadata.New(map[string]string{"key1":"value1","key2":"value2"})
Pairs()
要注意如果有相同的 key 会自动合并
md := metadata.Pairs(
"key1", "value1",
"key1", "value1.2",
"key2", "value2",
)
"key1" will have map value []string{"value1", "value1.2"}
Join()
md1 := metadata.Pairs("k1", "v1", "k2", "v2")
md2 := metadata.New(map[string]string{"key1":"value1","key2":"value2"})
md := metadata.Join(md1, md2)
合并md1和md2为md
存储二进制数据(-bin)
在 metadata 中,key 永远是 string 类型,但是 value 可以是 string 也可以是二进制数据。为了在 metadata 中存储二进制数据,我们仅仅需要在 key 的后面加上一个 - bin 后缀。具有 - bin 后缀的 key 所对应的 value 在创建 metadata 时会被编码(base64),收到的时候会被解码:
md := metadata.Pairs(
"key", "string value",
"key-bin", string([]byte{96, 102},
)
关于其他metadata的操作:https://pkg.go.dev/google.golang.org/grpc@v1.44.0/metadata
metadata的发送
由于,他是为了配合context传递上下文信息的,所以,metadata的传递可以是双向的。
Client----->Server
Client发送
覆盖式发送NewOutgoingContext
ctx := metadata.NewOutgoingContext(context.Background(), md)
追加式发送AppendToOutgoingContext
// 如果对应的 context 没有 metadata,那么就会创建一个
ctx := metadata.AppendToOutgoingContext(ctx, "k1", "v1", "k1", "v2", "k2", "v3")
// 如果已有 metadata 了,那么就将数据添加到原来的 metadata (例如在拦截器中)
ctx := metadata.AppendToOutgoingContext(ctx, "k3", "v4")
Server接收
使用FromIncomingContext
这里不管是普通调用还是流式调用,都是从contex.Context
中读取metadata
核心的代码:
// 普通调用
md, ok := metadata.FromIncomingContext(ctx)
// 流式调用
md, ok := metadata.FromIncomingContext(stream.Context())
Server----->Client
服务端发送的metadata
被分成了header
和 trailer
两者,因而客户端也可以读取两者。
trailer:服务端在处理完一个请求后,除了正常的响应消息主体外,可能还需要传递一些不能在响应头部(header
)中发送的信息。这些信息可能是在处理请求过程中才生成的,或者因为某些协议规定、性能考虑等因素而适合放在消息结尾发送。
Server发送
对于普通RPC(unary RPC)server可以使用grpc包中提供的函数向client发送 header
和trailer
-
grpc.SendHeader()
-
grpc.SetHeader()
-
grpc.SetTrailer()
对于流式RPC(streaming RPC)server可以使用ServerStream[1]接口中定义的函数向client发送header
和 trailer
-
ServerStream.SendHeader()
-
ServerStream.SetHeader()
-
ServerStream.SetTrailer()
其中:
sendHeader是立即发送
setHeader是追加设置header,自动合并到一个header中,等到合适的机会发送
setTrailer一般设置一次,防止信息设置混乱,因此也是 发送 tailer 信息
流式的差不多
Client接收
普通RPC使用grpc.Header()
和grpc.Trailer()
流式RPC使用
ClientStream接口的返回对象调用
Header
和Trailer
区别
根本区别:发送的时机不同!
✨ headers
会在下面三种场景下被发送
-
SendHeader()
被调用时(包含grpc.SendHeader
和stream.SendHeader
) -
第一个响应被发送时
-
RPC结束时(包含成功或失败)
✨ trailer
会在rpc返回的时候,即这个请求结束的时候被发送
差异在流式RPC(streaming RPC)中比较明显:
因为trailer
是在服务端发送完请求之后才发送的,所以client获取trailer
的时候需要在stream.CloseAndRecv
或者stream.Recv
返回非nil错误 (包含 io.EOF)之后
如果stream.CloseAndRecv
之前调用stream.Trailer()
获取的是空
stream, err := client.SomeStreamingRPC(ctx)// retrieve header
header, err := stream.Header()// retrieve trailer
// `trailer`会在rpc返回的时候,即这个请求结束的时候被发送
// 因此此时调用`stream.Trailer()`获取的是空
trailer := stream.Trailer()stream.CloseAndRecv()// retrieve trailer
// `trailer`会在rpc返回的时候,即这个请求结束的时候被发送
// 因此此时调用`stream.Trailer()`才可以获取到值
trailer := stream.Trailer()
使用场景
当我们把metadata
类比成HTTP Header的时候
,那么metadata
的使用场景也可以借鉴HTTP
的Header
。如传递用户token
进行用户认证,传递trace
进行链路追踪等
相关文章:

认识GO--gRPC的metadata
参考: 写给go开发者的gRPC教程-metadata-CSDN博客https://blog.csdn.net/kevin_tech/article/details/129395177?ops_request_misc%257B%2522request%255Fid%2522%253A%25221f2f2e26f48c755c33344ccb171a49fc%2522%252C%2522scm%2522%253A%252220140713.130102334…...

2024年安徽省职业院校技能大赛信息安全管理与评估
一、赛项名称 赛项名称:信息安全管理与评估 英文名称:Information Security Management and Evaluation 赛项组别:高职组 赛项归属:电子信息大类 二、竞赛目标 通过赛项检验参赛选手熟悉信息安全行业标准规范和信息 安全测试员新职…...

Perl 引用
Perl 引用 Perl,作为一种灵活而强大的编程语言,广泛用于系统管理、网络编程、GUI开发等领域。在Perl编程中,引用(References)是一个核心概念,它允许变量引用其他数据,从而创建复杂的数据结构&a…...

RT-Thread启动过程 :从汇编开始的启动流程
这个系列参考了《嵌入式实时操作系统RT-Thread设计与实现》,会详细介绍RT-Thread的启动流程,即是如何从零开始在开发板上运行起一个RTOS内核的。本文将会以 ch32v307VCT6 开发板为例展开进行详细介绍。主要包括:startup.S、初始化与系统相关的…...

Scala—“==“和“equals“用法(附与Java对比)
Scala 字符串比较—""和"equals"用法 Scala 的 在 Scala 中, 是一个方法调用,实际上等价于调用 equals 方法。不仅适用于字符串,还可以用于任何类型,并且自动处理 null。 Demo: Java 的 在 J…...

$route和$router的区别
在 Vue.js 中,$route 和 $router 都是 Vue Router 提供的对象,但它们有不同的用途和功能。 1. $router $router 是 Vue Router 实例的引用,它允许你通过 JavaScript 进行路由的控制和导航。你可以通过 $router 来执行路由的操作,…...

[工具升级问题] 钉钉(linux版)升级带来的小麻烦
本文由Markdown语法编辑器编辑完成。 1. 背景: 今日钉钉又发布了新的升级版本。由于我工作时使用的是Ubuntu 20.04版本,收到的升级推送信息是,可以升级到最新的7.6.25-Release版本。根据钉钉官方给出的历次更新版说明,这个新的版本…...

Leetcode经典题13--接雨水
题目描述 给定 n 个非负整数表示每个宽度为 1 的柱子的高度图,计算按此排列的柱子,下雨之后能接多少雨水。 输入输出示例 输入:height [0,1,0,2,1,0,1,3,2,1,2,1] 输出:6 解释:上面是由数组 [0,1,0,2,1,0,1,3,2,1,2,1…...

yarn修改缓存位置
查看缓存位置 以下三个命令分别为:bin是yarn存储命令的二进制文件,global存储全局node_modules ,cache存储用下下载缓存,查看本机目前的目录: 查看bin目录命令:yarn global bin 查看global目录命令&…...

OpenHarmony-3.HDF input子系统(5)
HDF input 子系统OpenHarmony-4.0-Release 1.Input 概述 输入设备是用户与计算机系统进行人机交互的主要装置之一,是用户与计算机或者其他设备通信的桥梁。常见的输入设备有键盘、鼠标、游戏杆、触摸屏等。本文档将介绍基于 HDF_Input 模型的触摸屏器件 IC 为 GT91…...

RabbitMQ 消息持久化/镜像队列/lazy对时延影响
测试背景: 不同条件下RabbitMQ不同队列类型的生产时延测试: 测试环境: 机型:rabbimtq.2u4g.cluster 背景流量:1000 TPS 测试条件: 消息大小 4k,消息条数为1000条,时延取值为平均…...

【深度学习】深刻理解Swin Transformer
Swin Transformer 是一种基于 Transformer 的视觉模型,由 Microsoft 研究团队提出,旨在解决传统 Transformer 模型在计算机视觉任务中的高计算复杂度问题。其全称是 Shifted Window Transformer,通过引入分层架构和滑动窗口机制,S…...

[2015~2024]SmartMediaKit音视频直播技术演进之路
技术背景 2015年,因应急指挥项目需求,我们实现了RTMP推送音视频采集推送(采集摄像头和麦克风数据)模块,在我们做好了RTMP推送模块后,苦于没有一个满足我们毫秒级延迟诉求的RTMP播放器,于是第一…...

redis 使用Lettuce 当redis挂掉重启之后 网络是怎么重新连接
Lettuce是一个高性能的Java Redis客户端,支持同步、异步和反应式编程模式 Lettuce的核心功能包括: 高性能:通过使用Netty作为底层网络通信框架,实现了非阻塞IO,提高了性能。丰富的API:提供了丰富…...

【IntelliJ IDEA 集成工具】TalkX - AI编程助手
前言 在数字化时代,技术的迅猛发展给软件开发者带来了更多的挑战和机遇。为了提高技术开发群体在繁多项目中的编码效率和质量,他们需要一个强大而专业的工具来辅助开发过程,而正是为了满足这一需求,TalkX 应运而生。 一、概述 1…...

二叉搜索树Ⅲ【东北大学oj数据结构8-3】C++
二叉搜索树 III B:在二叉搜索树II中加入delete指令,创建程序对二叉搜索树T执行如下指令。 插入 k:将key k 插入到 T 中。 find k:报告T中是否存在key k。 delete k:删除key为 k 的节点。 打印:使用中序树遍…...

【面试笔记】CPU 缓存机制
CPU 缓存机制 1. CPU Cache 与 MMU1.1 MMU 是什么?TLB 又是什么?他们是怎么工作的?2.2 简述 Cache 与 MMU 的协作关系?2.3 简述 Cache 与 MMU 的协作工作流程? 2. CPU 多层次缓存2.1 什么是 CPU 的多层次缓存结构&…...

MySQL基础函数使用
目录 简介 1. 单行函数 1.1 字符串函数 1.2 日期函数 1.3 数值函数 1.4 转换函数 1.5 其他函数 2. 多行函数 示例: 3. 数据分组 示例: 4. DQL单表关键字执行顺序 示例: 5. 多表查询 示例: 6. 表与表的外连接 示例…...

解决docker环境下aspose-words转换word成pdf后乱码问题
描述 环境:docker 部署工具:Jenkins 需求:本地上传的word文档需要转换成pdf 问题:转换之后的pdf文档出现小框框(乱码) 转换成PDF的操作 pom: <dependency><groupId>org.apach…...

C# 生成随机数的方法
C# 提供了一种强大而方便的工具类 Random ,用于生成随机数。这里将分类讨论如何通过 C# 实现随机数生成,以及应用于实际情况中的一些具体方案。 一、Random 类概述 Random 类表示一个伪随机数生成器,用于生成满足随机性统计要求的数字序列。…...

ip_done
文章目录 路由结论 IP分片 数据链路层重谈Mac地址MAC帧报头局域网的通信原理MSS,以及MAC帧对上层的影响ARP协议 1.公司是不是这样呢? 类似的要给运营商交钱,构建公司的子网,具有公司级别的入口路由器 2.为什么要这样呢?? IP地…...

3D可视化引擎HOOPS Visualize与HOOPS Luminate Bridge的功能与应用
HOOPS Visualize HPS / HOOPS Luminate Bridge为开发者提供了强大的工具,用于在CAD应用中集成逼真的渲染能力。本文旨在梳理该桥接产品的核心功能、使用方法及应用场景,为用户快速上手并充分利用产品特性提供指导。 桥接产品的核心功能概述 HOOPS Lumi…...

Docder 搭建Redis分片集群 散片插槽 数据分片 故障转移 Java连接
介绍 使多个 Redis 实例共同工作,实现数据的水平扩展。通过将数据分片到多个节点上,Redis 集群能够在不牺牲性能的前提下扩展存储容量和处理能力,从而支持更高并发的请求。Redis 集群不仅支持数据分片,还提供了自动故障转移和高可…...

校园交友app/校园资源共享小程序/校园圈子集合二手物品交易论坛、交友等综合型生活服务社交论坛
多客校园社交圈子系统搭建 校园交友多功能系统源码: 1、更改学校为独立的模块。整体UI改为绿色,青春色,更贴近校园风格。2、圈子归纳到学校去进行运营。每个学校可建立多个圈子。和其他学校圈子互不干扰。3、增加用户绑定学校,以后进入将默认…...

Chaos Mesh云原生的混沌测试平台搭建
Chaos Mesh云原生的混沌测试平台搭建 一.环境准备 确认已经安装helm,如要查看 Helm 是否已经安装,请执行如下命令: helm version二.使用helm安装 1.添加 Chaos Mesh 仓库 在 Helm 仓库中添加 Chaos Mesh 仓库: helm re…...

Vue3之组合式API详解
Vue 3引入了一种新的API风格——组合式API(Composition API),旨在提升组件的逻辑复用性和可维护性。本文将详细阐述Vue 3中的组合式API,包括其定义、特点、使用场景、优势等,并给出具体的示例代码。 一、定义 组合式…...

大模型的构建与部署(3)——数据标注
版权声明 本文原创作者:谷哥的小弟作者博客地址:http://blog.csdn.net/lfdfhl1. 数据标注的重要性 1.1 增强数据可解释性 数据标注通过为原始数据添加标签或注释,显著增强了数据的可解释性。在机器学习和深度学习领域,模型的训练依赖于大量带标签的数据。这些标签不仅帮助…...

AI发展与LabVIEW程序员就业
人工智能(AI)技术的快速发展确实对许多行业带来了变革,包括自动化、数据分析、软件开发等领域。对于LabVIEW程序员来说,AI的崛起确实引发了一个值得关注的问题:AI会不会取代他们的工作,导致大量失业&#x…...

本地事务 + 消息队列事务方案设计
Spring Boot 和 RocketMQ 在Spring Boot项目中实现“本地事务 消息队列事务”的方案,可以按照以下步骤实现: 先执行MySQL本地事务操作(未提交)随后发送消息到消息队列(如RocketMQ事务消息)等待消息队列确…...

pinctrl子系统学习笔记
一、背景 cpu的gpio引脚可以复用成多个功能,如可以配置成I2C或者普通GPIO模式。配置方式一般是通过写引脚复用的配置寄存器,但是不同芯片厂商配置寄存器格式内容各不相同,设置引脚复用无法做到通用且自由的配置,只能在启动初始化…...