《Go-micro微服务框架入门教程》学习笔记 | gRPC

学习视频来源:Golang微服务框架go-micro教程

个人在学习的同时,也验证了视频中的实验部分,现将授课笔记和实验笔记整理下来。

gRPC是一个高性能、开源和通用的RPC框架,面向移动和HTTP/2设计。gRPC基于HTTP/2标准设计,带来诸如双向流、流控、头部压缩、单TCP连接上的多复用请求等待。这些特性使得其在移动设备上表现更好,更省电和节省空间占用。

RPC

RPC(Remote Procedure Call Protocol)-- 远程过程调用协议,它是一种通过网络从远程计算机程序上请求服务,而不需要了解底层网络技术的协议。

简单来说,就是跟远程访问或者web请求差不多,都是一个client向远端服务器请求服务返回结果,但是web请求使用的网络协议是http高层协议,而rpc所使用的协议多是TCP,是网络测层协议,减少了信息的包装,加快了处理速度。

golang本身有rpc包,可以方便的使用,来构建自己的rpc服务,下边是一个简单实例,可以加深我们的理解

  • 1.调用客户端句柄执行传送参数
  • 2.调用本地系统内核发送网络消息
  • 3.消息传送到远程主机
  • 4.服务器句柄得到消息并取得参数
  • 5.执行远程过程
  • 6.执行的过程将结果返回服务器句柄
  • 7.服务器句柄返回结果,调用远程系统内核
  • 8.消息传回本地主机
  • 9.客户句柄由内核接收消息
  • 10.客户接收句柄返回的数据

服务端

package main
import (
	"fmt"
	"io"
	"net"
	"net/http"
	"net/rpc"
)
type Panda int
func (this *Panda)Getinfo(argType int, replyType *int)error{
	fmt.Println("Print peer send message:", argType)
	*replyType = argType + 12306
	return nil
}
func pandatext(w http.ResponseWriter, r *http.Request) {
	io.WriteString(w, "hello world hello panda")
}
func main() {
	http.HandleFunc("/panda", pandatext)
	pd := new(Panda)
	rpc.Register(pd)
	rpc.HandleHTTP()
	ln, err := net.Listen("tcp", ":10086")
	if err!=nil {
		fmt.Println("Network failure")
	}
	http.Serve(ln, nil)
}

客户端

package main
import (
	"fmt"
	"net/rpc"
)
func main() {
	cli, err := rpc.DialHTTP("tcp", "127.0.0.1:10086")
	if err != nil {
		fmt.Println("Network connect failure")
	}
	var pd int
	err = cli.Call("Panda.Getinfo", 10086, &pd)
	if err!=nil {
		fmt.Println("Call failure")
	}
	fmt.Println("Result is :", pd)
}

运行结果

服务端打印信息

客户端打印信息

GPRC是什么?

在gRPC里客户端应用可以像调用本地对象一样直接调用另一台不同的机器上服务端应用的方法,使得您能够更容易地创建分布式应用和服务。与许多RPC系统类似,gRPC也是基于以下理念:定义一个服务,指定能够被远程调用的方法(包含参数和返回类型)。在服务端实现这个接口,并运行一个gRPC服务器来处理客户端调用。在客户端拥有一个存根能够像服务端一样的方法。gRPC客户端和服务端可以在多种环境中运行和交互 - 从google内部的服务器到你自己的笔记本,并且可以用任何gRPC支持的语言来编写。所以,你可以很容易地用java创建一个gRPC服务端,用Go、Python、Ruby来创建客户端。此外,Google最新API将有gRPC版本的接口,使你很容易地将Google的功能集成到你的应用里。

GRPC使用protocol buffers

gRPC使用默认protobuf,这是Google开源的一套成熟的结构数据序列化机制(当然也可以使用其它数据格式如JSON)。正如你将在下方例子里所看到的,你用proto files创建gRPC服务,用protobuf消息类型来定义方法参数和返回类型。你可以在Protocol Buffers文档找到更多关于protoBuf的资料。虽然你可以使用proto2(当前默认的protocol buffers版本),我们通常建议你在gRPC里使用proto3,因为这样你可以使用gRPC支持全部范围的语言,并且能避免proto2客户端与proto3服务端交互时出现的兼容性问题,反之亦然。

环境搭建

git clone https://github.com/grpc/grpc-go.git

启动服务端

cd grpc/examples/helloworld/greeter_server
go run main.go

启动客户端

grpc/examples/helloworld/greeter_client
go run main.go

客户端代码介绍

/*
 *
 * Copyright 2015 gRPC authors.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
 */
// Package main implements a client for Greeter service.
package main
import (
        "context"
        "log"
        "os"
        "time"
        "google.golang.org/grpc"
        pb "google.golang.org/grpc/examples/helloworld/helloworld"
        //这是引用编译好的protobuf
)
const (
        address     = "localhost:50051"
        defaultName = "world"
)
func main() {
        // 建立到服务器的连接
        conn, err := grpc.Dial(address, grpc.WithInsecure(), grpc.WithBlock())
        if err != nil {
                log.Fatalf("did not connect: %v", err)
        }
        //延迟关闭连接
        defer conn.Close()
        //调用protobuf的函数创建客户端连接句柄
        c := pb.NewGreeterClient(conn)
        //联系服务器并打印它的响应
        name := defaultName
        if len(os.Args) > 1 {
                name = os.Args[1]
        }
        ctx, cancel := context.WithTimeout(context.Background(), time.Second)
        defer cancel()
        //调用protobuf的sayhello函数
        r, err := c.SayHello(ctx, &pb.HelloRequest{Name: name})
        if err != nil {
                log.Fatalf("could not greet: %v", err)
        }
        //打印结果
        log.Printf("Greeting: %s", r.GetMessage())
}

服务端代码介绍

/*
 *
 * Copyright 2015 gRPC authors.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
 */
// Package main implements a server for Greeter service.
package main
import (
        "context"
        "log"
        "net"
        "google.golang.org/grpc"
        pb "google.golang.org/grpc/examples/helloworld/helloworld"
)
const (
        port = ":50051"
)
//服务器用于实现hellow.GreeterServer
type server struct {
        pb.UnimplementedGreeterServer
}
//SayHello实现helloworld.GreeterServer
func (s *server) SayHello(ctx context.Context, in *pb.HelloRequest) (*pb.HelloReply, error) {
        log.Printf("Received: %v", in.GetName())
        return &pb.HelloReply{Message: "Hello " + in.GetName()}, nil
}
func main() {
        //监听
        lis, err := net.Listen("tcp", port)
        if err != nil {
                log.Fatalf("failed to listen: %v", err)
        }
        //new服务对象
        s := grpc.NewServer()
        //注册服务
        pb.RegisterGreeterServer(s, &server{})
        //在gRPC服务器上注册反射服务
        log.Printf("server listening at %v", lis.Addr())
        if err := s.Serve(lis); err != nil {
                log.Fatalf("failed to serve: %v", err)
        }
}

go语言实现GRPC远程调用

准备环境

cd /home/guoliang/go/src/google.golang.org/grpc-go/cmd/protoc-gen-go-grpc
go build
cp protoc-gen-go-grpc /usr/local/bin
mkdir /usr/local/go/src/github.com/golang
cd /home/guoliang
git clone https://github.com/golang/net.git
cp -R net/ /usr/local/go/src/golang.org/x/
git clone https://github.com/golang/protobuf.git
cp -R protobuf/ /usr/local/go/src/google.golang.org/
git clone https://github.com/golang/sys.git
cp -R sys/ /usr/local/go/src/golang.org/x/
git clone https://github.com/googleapis/go-genproto.git
cp -R go-genproto/ /usr/local/go/src/google.golang.org/
mv go-genproto/ genproto

protobuf协议定义

创建proto文件

syntax = "proto3";
package myproto;
option go_package = ".;myproto";
service Helloserver{
  rpc Sayhello(HelloReq)returns(HelloRsp){}
  rpc Sayname(NameReq)returns(NameRsp){}
}
message HelloReq{
  string name = 1;
}
message HelloRsp{
  string msg = 1;
}
message NameReq{
  string name = 1;
}
message NameRsp{
  string msg = 1;
}

编译生成pb.go文件

protoc --go-grpc_out=. *.proto

gRPC-Server编写

package main
import (
	pd "awesomeProject/myproto"
	"context"
	"fmt"
	"google.golang.org/grpc"
	"net"
)
type server struct {
	pd.UnimplementedHelloserverServer
}
func (this *server)Sayhello(ctx context.Context, in *pd.HelloReq) (out * pd.HelloRsp, err error){
	return &pd.HelloRsp{Msg: "hello"+in.Name}, nil
}
func (this *server)Sayname(ctx context.Context, in *pd.NameReq) (out *pd.NameRsp, err error){
	return &pd.NameRsp{Msg:in.Name+"morning"}, nil
}
func main() {
	ln, err := net.Listen("tcp", ":10086")
	if err != nil {
		fmt.Println("Network failure", err)
	}
	srv := grpc.NewServer()
	pd.RegisterHelloserverServer(srv, &server{})
	err=srv.Serve(ln)
	if err!=nil {
		fmt.Println("Network failure", err)
	}
}

gRPC-Client编写

package main
import (
	pd "awesomeProject/myproto"
	"context"
	"fmt"
	"google.golang.org/grpc"
)
func main() {
	conn, err := grpc.Dial("127.0.0.1:10086", grpc.WithInsecure())
	if err!=nil {
		fmt.Println("Network failure", err)
	}
	defer conn.Close()
	c := pd.NewHelloserverClient(conn)
	re, err := c.Sayhello(context.Background(), &pd.HelloReq{Name: "Panda"})
	if err != nil {
		fmt.Println("sayhello service call failure")
	}
	fmt.Println("call sayhello returns", re.Msg)
	re1, err := c.Sayname(context.Background(), &pd.NameReq{Name: "Tony"})
	if err != nil{
		fmt.Println("sayname call failure")
	}
	fmt.Println("call sayname returns", re1.Msg)
}

运行结果

先运行server.go,再运行client.go

  • 3
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
### 回答1: 很高兴为您提供帮助!关于Go语言中的GRPC教程,您可以参考Go官方文档中的GRPC教程:https://grpc.io/docs/tutorials/basic/go/,也可以参考GitHub上的一些开源项目,如https://github.com/grpc/grpc-go。 ### 回答2: Golang的GRPC教程是关于如何使用Google开发的gRPC框架来构建高效的分布式系统的指南。GRPC是一种远程过程调用(RPC)框架,主要用于在客户端和服务器之间进行通信。 Golang的GRPC教程首先介绍了GRPC的基本概念和原理,例如客户端和服务器之间的通信方式以及如何定义服务和消息。然后,教程详细介绍了如何在Golang中安装和配置GRPC的软件开发工具包,并提供了一些示例代码来说明如何创建GRPC服务器和客户端。 接下来,教程会教你如何使用protobuf(Protocol Buffers)作为GRPC的数据格式,protobuf是一种轻量级且语言无关的数据序列化机制。你将学会如何定义消息和服务接口,以及如何使用protobuf生成Golang的代码。 在教程的后半部分,你将学习如何使用GRPC的不同功能,如流式传输、服务器端流式和客户端流式,以及双向流式。这些功能可以让你更灵活地设计和实现你的分布式系统。 此外,教程还涉及了如何使用拦截器(interceptors)来实现自定义的认证、日志记录和错误处理等功能。你将了解如何在GRPC中实现服务端和客户端的拦截器,并掌握如何在应用程序中使用它们。 最后,教程还会介绍一些关于GRPC的最佳实践,例如如何处理错误、优化性能和处理并发等问题。这些实践可以帮助你在开发和维护GRPC应用程序时更高效和可靠。 总之,Golang的GRPC教程提供了一种简单且强大的方式来构建分布式系统,并为你提供了充足的示例代码和实践经验来帮助你理解和应用GRPC框架。无论是初学者还是有经验的开发者,都能受益于这个教程。 ### 回答3: Golang的GRPC教程是介绍Go语言中的GRPC框架的教程。GRPC是一种高性能、开源的远程过程调用(RPC)框架,支持多种编程语言,包括Go语言。 在GRPC教程中,首先会介绍GRPC的基本概念和架构。GRPC使用Protocol Buffers(简称Protobuf)作为接口定义语言(IDL),用于定义服务接口和消息格式。它提供了强类型的接口定义和支持多种语言的代码生成工具。通过IDL的定义,可以自动生成客户端和服务器端代码,大大简化了跨服务通信的开发工作。 接下来的教程将详细介绍如何使用GRPC构建客户端和服务器端。通过定义GRPC服务的接口和消息格式,可以方便地在不同的服务之间进行通信。教程会演示如何编写服务器端代码,实现服务接口的具体逻辑,并将其注册到GRPC框架中。同时,还会演示如何编写客户端代码,通过GRPC调用服务器端提供的服务,并处理返回的结果。 GRPC教程还会介绍一些高级特性,例如流式处理、认证和安全性等。流式处理支持客户端流、服务器端流和双向流,可以实现更复杂的通信模式。认证和安全性可以通过TLS/SSL等机制来保护通信的安全性。 在学习GRPC教程时,你将会了解到GRPC的优势和如何使用GRPC来构建可扩展和高性能的分布式系统。通过GRPC,你可以轻松地实现跨语言的服务调用,并利用其丰富的特性来满足不同的业务需求。 总之,Golang的GRPC教程是一个很好的学习资源,能够帮助你掌握GRPC框架的基本概念和使用方法,并在实际项目中应用它来构建高效可靠的分布式系统。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值