百度360必应搜狗淘宝本站头条
当前位置:网站首页 > 技术文章 > 正文

大白话 golang 教程-21-分布式服务框架 gRPC

ccwgpt 2024-10-02 12:04 29 浏览 0 评论

gRPC 是谷歌开发的高性能、通用的开源 RPC 框架,使用 http/2 协议设计,默认基于 protobuf 序列化,gRPC 支持众多的编程语言互调。使用之前需要安装 protoc 的编译器。Protocol Buffers 是用 C++ 语言编写的,直接去 https://github.com/protocolbuffers/protobuf/releases 下载二进制版本到本地解压后,移动到系统的 bin 目录,比如 /usr/local/bin 就用了。


Desktop  protoc --version
libprotoc 3.14.0

查看 protoc 的版本则安装成功,要生成对应语言的 proto 代码,还需要安装对应的语言的插件。执行下面的命令安装 go 语言的 protobuf 插件:

GO111MODULE=off go get github.com/golang/protobuf/protoc-gen-go

使用 which 确认一下:

Desktop  which protoc-gen-go
/Users/wangbo/.go/bin/protoc-gen-go

protobuf 最基本的数据单元叫 message,类似于结构体,不同的语言通过这个 message 定义来生成可以互相调用的代码。

看一个最简单的 hello.proto 的定义:

syntax = "proto3";

package hello; // 包名

// 定义一种 String 的类型/结构
message String {
  // 成员  
  string value = 1; // 1 是编码时的编号
}

使用 protoc 命令生成 go 的代码:

hello[master*]  protoc --go_out=. hello.proto
hello[master*]  ll
total 8.0K
-rw-r--r-- 1 wangbo staff 2.4K  1 15 11:42 hello.pb.go
-rw-r--r-- 1 wangbo staff   72  1 15 11:42 hello.proto

--go_out 表示生成 go 语言的代码,hello.pb.go 就是其生成的文件,里面定义了 String 这个结构体,还增加了一些方法。HellService 现在可以这样写了:

type HelloService struct{}

func (hs *HelloService) Hello(name *String, reply *String) error {
  reply.Value = "hi, " + name.GetValue()
  return nil
}

func startHelloProtoRpcServer() {
  rpc.RegisterName("HelloService", new(HelloService))
  listener, _ := net.Listen("tcp", ":3000")
  conn, _ := listener.Accept()
  rpc.ServeConn(conn)
}

服务端和 net/rpc 版本的代码相同,客户端的代码也差不多,换成了 String 类型:

func startHelloProtoRpcClient() {
  var reply String
  client, _ := rpc.Dial("tcp", "127.0.0.1:3000")
  client.Call("HelloService.Say", String{Value: "zhangsan"}, &reply)
  fmt.Println(reply.Value)
}

这好像和自己定义一个 String 结构体没有什么区别啊? 确实,上个章节说到如果不需要跨语言用 net/rpc 就很好了,不过它演示了 protobuf 的基本用法。


下面实现一个跨语言版本的 hellorpc,对 hello.proto 增加 Say 方法的定义:

syntax = "proto3";

package grpchello;

// 调用参数 
message Person {    
  string name = 1;
}

// 调用结果
message Result {    
  string text = 1;
}

// 调用方法
service HelloService {    
  rpc Say (Person) returns (Result);
}

生成 go 语言的定义:

protoc --go_out=plugins=grpc:. hello.go.proto

打开生成的 hello.pb.go 文件,发现除了定义 Person 和 Result 结构体外,还定义了服务端和客户端的接口:

type HelloServiceServer interface { 
  Say(context.Context, *Person) (*Result, error)
}

type HelloServiceClient interface { 
  Say(ctx context.Context, in *Person, opts ...grpc.CallOption) (*Result, error)
}

rpc 的服务方被抽象成了 grpc.Server,客户端其实是包装了 grpc.ClientConn 的对象,还提供了 rpc 的注册函数 RegisterHelloServiceServer,构造一个 grpc.Server 对象,提供一个 HelloServiceServer 的结构体实现 Say 方法就可以启动一个 grpc 的服务端了:

func startGrpcHelloServer() { 
  grpcServer := grpc.NewServer() 
  RegisterHelloServiceServer(grpcServer, new(HelloServiceServerImpl)) 
  conn, _ := net.Listen("tcp", ":3000") 
  grpcServer.Serve(conn)
}

接下来做一个java 的客户端来访问它,首先也得根据 proto 文件生成 java 的代码,和 go 不同的时候,指定了 java 的 package 包名,引入依赖 protobuf-java、grpc-protobuf、grpc-stub,记得要先安装 protoc-gen-grpc-java 插件(编译参考 https://github.com/grpc/grpc-java/blob/master/compiler/README.md,下载参考 https://repo1.maven.org/maven2/io/grpc/protoc-gen-grpc-java/1.35.0/)。

mkdir -p src/main/java
protoc --java_out=src/main/java hello.java.proto
protoc --plugin=/usr/local/bin/protoc-gen-grpc-java --grpc-java_out=src/main/java hello.java.proto

生成的文件:

src/main/java
└── com
    └── wangbo
        └── proto
            ├── HelloProto.java
            ├── HelloService.java
            ├── HelloServiceGrpc.java
            ├── Person.java
            ├── PersonOrBuilder.java
            ├── Result.java
            ├── ResultOrBuilder.java

启动 java 的客户端访问 go 的服务端:

public class ClientApplication {
    public static void main(String[] args) {
        ManagedChannel channel = ManagedChannelBuilder
                .forAddress("127.0.0.1", 3000)
                .usePlaintext()
                .build();
        HelloServiceGrpc.HelloServiceBlockingStub stub = HelloServiceGrpc.newBlockingStub(channel);
        Person person = Person.newBuilder().setName("zhangsan").build();
        Result result = stub.say(person);
        System.out.println(result.getText());
    }
}

调用成功,如果把 go 作为客户端代码也很简单:

func startGrpcHelloClient() { 
  conn, _ := grpc.Dial("127.0.0.1:3000", grpc.WithInsecure()) 
  defer conn.Close()
  stub := NewHelloServiceClient(conn) 
  result, _ := stub.Say(context.Background(), &Person{Name: "zhangsan"}, grpc.EmptyCallOption{}) 
  fmt.Println(result.Text)
}

对应的 java 服务端的代码,继承 HelloServiceImplBase 重载 say 方法:

public class ServerApplication {
    public static void main(String[] args) throws InterruptedException, IOException {
        Server server = ServerBuilder.forPort(3000)
                .addService(new HelloServiceGrpc.HelloServiceImplBase() {
                    @Override
                    public void say(com.wangbo.proto.Person person, StreamObserver<com.wangbo.proto.Result> responseObserver) {
                        Result result = Result.newBuilder().setText("hi, " + person.getName()).build();
                        responseObserver.onNext(result);
                        responseObserver.onCompleted();
                    }
                }).build().start();
        server.awaitTermination();
    }
}


这两个例子只使用 string 类型,为了跨语言,protobuf 定义了很多种数据类型,更多的用法和例子访问 https://developers.google.com/protocol-buffers/docs/reference/google.protobuf,其他语言的 grpc 参考 https://grpc.io/docs/languages,grpc 还提供了 tls 安全的通讯方案。


本章节的代码 https://github.com/developdeveloper/go-demo/tree/master/21-distibuted-os-issue

相关推荐

用Steam启动Epic游戏会更快吗?(epic怎么用steam启动)

Epic商店很香,但也有不少抱怨,其中一条是启动游戏太慢。那么,如果让Steam启动Epic游戏,会不会速度更快?众所周知,Steam可以启动非Steam游戏,方法是在客户端左下方点击“添加游戏”,然...

Docker看这一篇入门就够了(dockerl)

安装DockerLinux:$curl-fsSLhttps://get.docker.com-oget-docker.sh$sudoshget-docker.sh注意:如果安装了旧版...

AYUI 炫丽PC开发UI框架2016年6月15日对外免费开发使用 [1]

2016年6月15日,我AY对外发布AYUI(WPF4.0开发)的UI框架,开发时候,你可以无任何影响的去开发PC电脑上的软件exe程序。AYUI兼容XP操作系统,在Win7/8/8.1/10上都顺利...

别再说C#/C++套壳方案多了!Tauri这“借壳生蛋”你可能没看懂!

浏览器套壳方案,C#和C++有更多,你说的没错,从数量和历史积淀来看,C#和C++确实有不少方式来套壳浏览器,让Web内容在桌面应用里跑起来。但咱们得把这套壳二字掰扯清楚,因为这里面学问可大了!不同的...

OneCode 核心概念解析——Page(页面)

在接触到OneCode最先接触到的就是,Page页面,在低代码引擎中,页面(Page)设计的灵活性是平衡“快速开发”与“复杂需求适配”的关键。以下从架构设计、组件系统、配置能力等维度,解析确...

React是最后的前端框架吗,为什么这么说的?

油管上有一位叫Theo的博主说,React是终极前端框架,为什么这么说呢?让我们来看看其逻辑:这个标题看起来像假的,对吧?React之后明明有无数新框架诞生,凭什么说它是最后一个?我说的“最后一个”不...

面试辅导(二):2025前端面试密码:用3个底层逻辑征服技术官

面试官放下简历,手指在桌上敲了三下:"你上次解决的技术难题,现在回头看有什么不足?"眼前的候选人瞬间僵住——这是上周真实发生在蚂蚁金服终面的场景。2025年的前端战场早已不是框架熟练...

前端新星崛起!Astro框架能否终结React的霸主地位?

引言:当"背着背包的全能选手"遇上"轻装上阵的短跑冠军"如果你是一名前端开发者,2024年的框架之争绝对让你眼花缭乱——一边是React这位"背着全家桶的全能选...

基于函数计算的 BFF 架构(基于函数计算的 bff 架构是什么)

什么是BFFBFF全称是BackendsForFrontends(服务于前端的后端),起源于2015年SamNewman一篇博客文章《Pattern:BackendsFor...

谷歌 Prompt Engineering 白皮书:2025年 AI 提示词工程的 10 个技巧

在AI技术飞速发展的当下,如何更高效地与大语言模型(LLM)沟通,以获取更准确、更有价值的输出,成为了一个备受关注的问题。谷歌最新发布的《PromptEngineering》白皮书,为这一问题提供了...

光的艺术:灯具创意设计(灯光艺术作品展示)

本文转自|艺术与设计微信号|artdesign_org_cn“光”是文明的起源,是思维的开端,同样也是人类睁眼的开始。每个人在出生一刻,便接受了光的照耀和洗礼。远古时候,人们将光奉为神明,用火来...

MoE模型已成新风口,AI基础设施竞速升级

机器之心报道编辑:Panda因为基准测试成绩与实际表现相差较大,近期开源的Llama4系列模型正陷入争议的漩涡之中,但有一点却毫无疑问:MoE(混合专家)定然是未来AI大模型的主流范式之一。...

Meta Spatial SDK重大改进:重塑Horizon OS应用开发格局

由文心大模型生成的文章摘要Meta持续深耕SpatialSDK技术生态,提供开自去年9月正式推出以来,Meta持续深耕其SpatialSDK技术生态,通过一系列重大迭代与功能增强,不断革新H...

&quot;上云&quot;到底是个啥?用&quot;租房&quot;给你讲明白IaaS/PaaS/SaaS的区别

半夜三点被机房报警电话惊醒,顶着黑眼圈排查服务器故障——这是十年前互联网公司运维的日常。而现在,程序员小王正敷着面膜刷剧,因为公司的系统全"搬"到了云上。"部署到云上"...

php宝塔搭建部署thinkphp机械设备响应式企业网站php源码

大家好啊,欢迎来到web测评。本期给大家带来一套php开发的机械设备响应式企业网站php源码,上次是谁要的系统项目啊,帮你找到了,还说不会搭建,让我帮忙录制一期教程,趁着今天有空,简单的录制测试了一下...

取消回复欢迎 发表评论: