我正在将遗留应用程序(一些微服务和整体应用程序)迁移到使用 GRPC。目前整个代码库都在 GO 中。
我已经开始对我的消息进行建模,它们看起来与我在应用程序代码中使用的结构非常相似。我定义了两次相同的对象似乎很奇怪,但使用消息对象作为核心结构也似乎很奇怪。不过,似乎我会有大量的内存密集型数据整理。下面是消息和结构的示例以及它们的相似之处。
对于决定如何对我的消息进行建模,是否有任何建议/最佳实践?它们应该与我的核心结构保持一致吗?我是否应该不关心从 Golang 结构到消息的所有编组?
如果我问这样一个基本问题,请原谅我,因为我对协议缓冲区和 GRPC 非常陌生。
消息原型定义:
message Profile {
string UID = 1;
string ContactEmail = 2;
google.protobuf.Timestamp DateOfBirth = 3;
float WeightInKilos = 4;
string Gender = 5;
string Unit = 6;
string CurrentStatus = 7;
string Country = 8;
string ExperienceType = 9;
google.protobuf.Timestamp DateJoined = 10;
repeated Ability Abilities = 11;
repeated Role Roles = 12;
repeated TermsAndConditionsAcceptance TermsAndConditionsAcceptances = 13;
string TimeZone = 14;
repeated BaselineTestResults BaselineTests =15;
//Excluded UpdatedDate …Run Code Online (Sandbox Code Playgroud) 我最近一直在尝试 gRPC 错误处理,并希望将我自己的原始消息传递给客户端(定义我自己的错误详细信息和内部错误代码)。经过搜索后,发现了几个使用 gRPC 状态包中的 WithDetails() 来附加自定义元数据的示例。我开始实施相同的如下
gRPC 原型消息
message ErrorInfo {
int64 error_code = 1;
string error_message = 2;
string resource_name = 3;
}
Run Code Online (Sandbox Code Playgroud)
服务器端实现
// Frame the error message
st := status.New(codes.NotFound, "object not found")
errInfo := &api.ErrorInfo {
ErrorCode: 100,
ErrorMessage: "Fetching credential failed",
ResourceName: req.GetBackupLocation().GetCloudCredential(),
}
var err error
st, err = st.WithDetails(errInfo)
if err != nil {
// If this errored, it will always error
// here, so better panic so we can figure
// …Run Code Online (Sandbox Code Playgroud) 我正在尝试从 C# 客户端连接到 Go GRPC 服务器,但客户端通道无法连接到服务器。
我希望连接到由 Go 编写和托管的 GRPC 服务器以及用 C# 编写的客户端时应该没有问题。
我的 Go Server 连接是这样设置的:
lis, err := net.Listen("tcp", ":50051")
if err != nil {
log.Fatalf("Failed to listen: %v", err)
}
s := grpc.NewServer()
pb.Register**ServiceServer(s, &server{})
reflection.Register(s)
if err := s.Serve(lis); err != nil {
log.Fatalf("Failed to serve: %v", err)
}
Run Code Online (Sandbox Code Playgroud)
这是相当标准的,我知道我的服务器正在工作,因为我能够使用提供的端口与 Go 客户端连接:
conn, err := grpc.Dial("localhost:50051", grpc.WithInsecure(), grpc.WithBlock())
Run Code Online (Sandbox Code Playgroud)
但是当我尝试使用 C# 客户端使用Grpc.Net.Client包进行连接时:
var channel = GrpcChannel.ForAddress(@"http://localhost:50051", new GrpcChannelOptions
{
Credentials = ChannelCredentials.Insecure
});
Run Code Online (Sandbox Code Playgroud)
我得到一个Grpc.Core.RpcException: …
我读过这个答案:/sf/answers/3986064001/,它说无法使用grpc-nodepackage.json 在相同的地址和端口运行 gRPC 服务器和 HTTP 服务器。
但我可以使用 package.json 在相同的地址和端口(例如都使用localhost:3000)创建 gRPC 服务器和 HTTP 服务器grpc-go。这是一个示例: https: //github.com/mrdulin/grpc-go-cnode/blob/master/cmd/server/main.go#L79
那么,为什么 grpc-node 和 grpc-go 的行为不一致。这有道理吗?
我期望的结果是,无论grpc中实现什么语言,行为都应该是一致的。所以grpc服务器应该能够与同一系统进程中的Node标准库http创建的服务器共享相同的端口。
我对protoc-gen-govs有点困惑protoc-gen-go-grpc。我知道:
protoc-gen-go 包含用于 protobuf 消息序列化/反序列化的代码protoc-gen-go-grpc 包含 gRPC 服务器和客户端的代码但是,我正在使用以下命令
protoc -I $protodir --go_out=plugins=grpc:./genproto/ $protodir/v1/foo.proto
Run Code Online (Sandbox Code Playgroud)
并且生成的foo.pb.go包含用于消息序列化和gRPC 服务器/客户端的代码。另外,我只protoc-gen-go安装在我的系统上。
我有一种感觉,这是在 GO 中进行 gRPC的旧方法,而新方法是protoc --go_out=. --go-grpc_out=.
问题:
protoc --go_out=.(为什么它还生成 gRPC 客户端/服务器代码?)谢谢,直流
我试图了解 Go 上下文取消在客户端服务通信(例如任何 gRPC API 调用)中是如何工作的。
假设客户端取消了上下文。这是否会导致向服务器发出新的 HTTP 请求,并取消先前/正在进行的 gRPC 请求的上下文?服务器如何知道客户端是否取消了上下文?
我设置了一系列 gRPC 请求和响应,它们都可以正常工作,但是当我尝试获取客户端 IP 地址和调用我的 gRPC API 的用户代理时,我卡住了。
我阅读了 Go gRPC 文档和其他来源,但没有找到太多有价值的信息。他们中很少有人谈论 Golang 中的 gRPC。
在设置 gRPC API 时,我应该设置一个键值来在上下文中存储 IP 地址吗?
我正在使用 gRPC 构建 API,并且在服务器端,我想在客户端断开连接时收到通知,识别它并基于此执行一些任务。
到目前为止,我能够使用grpc.StatsHandlermethod检测客户端断开连接HandleConn。我尝试使用上下文传递值,但无法从服务器端访问它们。
客户端:
conn, err := grpc.DialContext(
context.WithValue(context.Background(), "user_id", 1234),
address,
grpc.WithInsecure(),
)
Run Code Online (Sandbox Code Playgroud)
服务器端:
// Build stats handler
type serverStats struct {}
func (h *serverStats) TagRPC(ctx context.Context, info *stats.RPCTagInfo) context.Context {
return ctx
}
func (h *serverStats) HandleRPC(ctx context.Context, s stats.RPCStats) {}
func (h *serverStats) TagConn(ctx context.Context, info *stats.ConnTagInfo) context.Context {
return context.TODO()
}
func (h *serverStats) HandleConn(ctx context.Context, s stats.ConnStats) {
fmt.Println(ctx.Value("user_id")) // Returns nil, can't access the value
switch s.(type) { …Run Code Online (Sandbox Code Playgroud) 在下面的gRPC-client代码中,第二个是if必要的吗?
status, err := cli.GetStatus(ctx, &empty.Empty{})
if err != nil {
return err
}
if status == nil {
// this should NEVER happen - right?
return fmt.Errorf("nil Status result returned")
}
Run Code Online (Sandbox Code Playgroud)
go 直觉上,为了以防万一,应该始终检查 nil 。但是,有一个运行时检查来捕获任何客户端到服务器的nil使用情况,例如
status, err := cli.GetStatus(ctx, nil) // <- runtime error
if err != nil {
// "rpc error: code = Internal desc = grpc: error while marshaling: proto: Marshal called with nil"
return err
}
Run Code Online (Sandbox Code Playgroud)
那么是否存在类似的服务器到客户端运行时保证,从而消除检查的需要status == …
我们正在开发一个高频交易平台,并且在我们的一个组件中,我们已经使用 golang 实现了 grpc。我们需要在我们的一个用例中使用双向流,我们制作了一个示例实现,如下面的代码,但是当我们通过检查日志时间戳之间的差异来测试代码的性能时
Recv Time %v Index: %v Num: %v
Send Time %v, Index: %v, Num: %v
Run Code Online (Sandbox Code Playgroud)
我们发现从客户端调用流的.Send方法并通过在服务器端调用.Recv接收相同的数据大约需要 400-800 微秒,这对我们来说太低了。我们需要最大 10-50 微秒的性能,当我们阅读指南时,我们看到如果客户端和服务器在同一台计算机上,grpc 可以达到纳秒(这正是我们的情况)
所以我认为我们缺少一些选项或一些关于它的性能技巧。有谁知道我们可以做些什么来增加这个性能问题
客户代码:
package main
import (
"context"
"log"
"math/rand"
pb "github.com/pahanini/go-grpc-bidirectional-streaming-example/src/proto"
"time"
"google.golang.org/grpc"
)
func main() {
rand.Seed(time.Now().Unix())
// dail server
conn, err := grpc.Dial(":50005", grpc.WithInsecure())
if err != nil {
log.Fatalf("can not connect with server %v", err)
}
// create stream
client := pb.NewMathClient(conn)
stream, err := client.Max(context.Background())
if err != …Run Code Online (Sandbox Code Playgroud)