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

【tRPC-go】message、context相关源码设计思路

codec 包基础设计

package:trpc-go/codec

  1. Msg接口的定义: 后续实际的消息msg结构体实现该接口,可以方便地获取一些值(如Context),也可以方便地进行一些值地设置(如设置SerializationType)
// message.go 文件下 

// Msg defines core message data for multi protocol, business protocol
// should set this message when packing and unpacking data.
type Msg interface {
	// Context returns rpc context
	Context() context.Context

	// WithRemoteAddr sets upstream address for server,
	// or downstream address for client.
	WithRemoteAddr(addr net.Addr)

	// WithLocalAddr sets server local address.
	WithLocalAddr(addr net.Addr)

	// RemoteAddr returns upstream address for server,
	// or downstream address for client.
	RemoteAddr() net.Addr

	// LocalAddr returns server local address.
	LocalAddr() net.Addr

	// WithNamespace sets server namespace.
	WithNamespace(string)

	// Namespace returns server namespace.
	Namespace() string

	// WithEnvName sets server environment.
	WithEnvName(string)
		// SerializationType returns serialization type.
	SerializationType() int

	// WithCompressType sets compress type.
	WithCompressType(int)
	....
  1. msg 整个rpc的上下文,先看接口体的设计,以及实现上面Msg接口定义的方法
// message_impl.go 文件

// msg is the context of rpc.
type msg struct {
	context             context.Context
	frameHead           interface{}
	requestTimeout      time.Duration
	serializationType   int
	compressType        int
	streamID            uint32
	dyeing              bool
	dyeingKey           string
	serverRPCName       string
	clientRPCName       string
	serverMetaData      MetaData
	clientMetaData      MetaData
	callerServiceName   string
	calleeServiceName   string
	calleeContainerName string
	serverRspErr        error
	clientRspErr        error
	serverReqHead       interface{}
	serverRspHead       interface{}
	clientReqHead       interface{}
	clientRspHead       interface{}
	localAddr           net.Addr
	remoteAddr          net.Addr
	logger              interface{}
	callerApp           string
	callerServer        string
	callerService       string
	callerMethod        string
	calleeApp           string
	calleeServer        string
	calleeService       string
	calleeMethod        string
	namespace           string
	setName             string
	envName             string
	envTransfer         string
	requestID           uint32
	calleeSetName       string
	streamFrame         interface{}
	commonMeta          CommonMeta
	callType            RequestType
}

// 实现了 Msg接口所有方法
// Context restores old context when create new msg.
func (m *msg) Context() context.Context {
	return m.context
}

// WithNamespace set server's namespace.
func (m *msg) WithNamespace(namespace string) {
	m.namespace = namespace
}
....

msg在后续:会被写入trpc协议的帧头中,进行网络传输,以达到下游
在这里插入图片描述

客户端调用 使用message:GreeterClientProxyImpl

  1. 客户端调用具体rpc方法桩代码:
func (c *GreeterClientProxyImpl) Hello(ctx context.Context, req *HelloRequest, opts ...client.Option) (*HelloReply, error) {
	// 派生出新的消息,以实现整个调用链路的context消息传递
	ctx, msg := codec.WithCloneMessage(ctx)
	
	defer codec.PutBackMessage(msg)
	msg.WithClientRPCName("/trpc.helloworld.Greeter/Hello")
	msg.WithCalleeServiceName(GreeterServer_ServiceDesc.ServiceName)
	msg.WithCalleeApp("")
	msg.WithCalleeServer("")
	msg.WithCalleeService("Greeter")
	msg.WithCalleeMethod("Hello")
	msg.WithSerializationType(codec.SerializationTypePB)
	callopts := make([]client.Option, 0, len(c.opts)+len(opts))
	callopts = append(callopts, c.opts...)
	callopts = append(callopts, opts...)
	rsp := &HelloReply{}
	if err := c.client.Invoke(ctx, req, rsp, callopts...); err != nil {
		return nil, err
	}
	return rsp, nil
}

先看WithCloneMessage方法:主要实现一组新的 ctx 和 msg 的派生

  • 首先可以看到第二个返回值Msg就是之前的接口类型
  • val.(*msg)是因为context中存储的不是实际结构体,而是结构体的指针
  • 所以上面桩代码中:msg.WithClientRPCName(“/trpc.helloworld.Greeter/Hello”),WithClientRPCName这些方法都是指针类型的实现:func (m *msg) xxx(namespace string) {
// message_impl.go 文件

// WithCloneMessage copy a new message and put into context, each rpc call should
// create a new message, this method will be called by client stub.
func WithCloneMessage(ctx context.Context) (context.Context, Msg) {
	newMsg := msgPool.Get().(*msg)
	val := ctx.Value(ContextKeyMessage)
	m, ok := val.(*msg)
	if !ok {
		ctx = context.WithValue(ctx, ContextKeyMessage, newMsg)
		newMsg.context = ctx
		return ctx, newMsg
	}
	ctx = context.WithValue(ctx, ContextKeyMessage, newMsg)
	newMsg.context = ctx
	copyCommonMessage(m, newMsg)
	copyServerToClientMessage(m, newMsg)
	return ctx, newMsg
}

到这里,一个派生的消息就从一个现有消息中拷贝了框架定义的一些上下文信息了,并且也设置了主调信息为自身服务,但是,被调信息呢?你回到开头看 tRPC 的桩代码就会知道了,桩代码里会负责进一步重写被调信息。

参考文献:

https://cloud.tencent.com/developer/article/2417507

相关文章:

  • vue 入门:生命周期
  • 【第16届蓝桥杯C++C组】--- 数位倍数
  • Leetcode:二叉树
  • 简述一下Unity的UnityWebRequest
  • 第二届电气技术与自动化工程国际学术会议 (ETAE 2025)
  • STM32 低功耗模式下 RTC唤醒 和 PA0唤醒 的配合使用
  • HTML — 定位
  • leetcode精选合集(更新中)
  • Istio常用命令
  • kafka4.0浅尝辄止
  • 使用uv管理python项目环境
  • STM32单片机入门学习——第34节: [10-4] I2C通信外设
  • Mysql -- 基础
  • 数据库表的操作
  • Ethers.js 开发入门:核心功能、最佳实践与避坑指南
  • TP8 PHP 支付宝-通用版-V3 SDK 接口加签方式为证书方式
  • 手撕TCP内网穿透及配置树莓派
  • 【DDR 内存学习专栏 1.2 -- DDR Channel 介绍】
  • 【webSocket协议】进阶实战案例(Spring 原生低层 API)
  • Python基础语法1
  • 马克思主义理论研究教学名师系列访谈|丁晓强:马克思主义学者要更关注社会现实的需要
  • 马上评|科学谋划“十五五”,坚定不移办好自己的事
  • 赵乐际主持十四届全国人大常委会第十五次会议闭幕会并作讲话
  • 80后共青团云南省委副书记许思思已任迪庆州委副书记
  • 中信银行一季度净利195.09亿增1.66%,不良率持平
  • 秦洪看盘|上市公司业绩“排雷”近尾声,A股下行压力趋缓