grpc基础
RPC 框架原理
RPC 框架的目标就是让远程服务调用更加简单、透明,RPC 框架负责屏蔽底层的传输方式(TCP 或者 UDP)、序列化方式(XML/Json/ 二进制)和通信细节。服务调用者可以像调用本地接口一样调用远程的服务提供者,而不需要关心底层通信细节和调用过程。

业界主流的 RPC 框架整体上分为三类:
- 支持多语言的 RPC 框架,比较成熟的有 Google 的 gRPC、facebook的Apache、Thrift;
- 只支持特定语言的 RPC 框架,例如新浪微博的 Motan;
- 支持服务治理等服务化特性的分布式服务框架,其底层内核仍然是 RPC 框架, 例如阿里的 Dubbo。
gRPC是什么
gRPC 是一个高性能、开源和通用的 RPC 框架,面向移动和 HTTP/2 设计。目前提供 C、Java 和 Go 语言版本,分别是:grpc, grpc-java, grpc-go. 其中 C 版本支持 C, C++, Node.js, Python, Ruby, Objective-C, PHP 和 C## 支持.
gRPC 基于 HTTP/2 标准设计,带来诸如双向流、流控、头部压缩、单 TCP 连接上的多复用请求等特。这些特性使得其在移动设备上表现更好,更省电和节省空间占用。
grc优点
- 多语言:语言中立,支持多种语言。
- 轻量级、高性能:序列化支持 PB(Protocol Buffer)和 JSON,PB 是一种语言无关的高性能序列化框架。
可插拔 - IDL:基于文件定义服务,通过 proto3 工具生成指定语言的数据结构、服务端接口以及客户端 Stub。
- 移动端:基于标准的 HTTP2 设计,支持双向流、消息头压缩、单 TCP 的多路复用、服务端推送等特性,这些特性使得 gRPC 在移动端设备上更加省电和节省网络流量。

安全
HTTP2 规范当使用 TLS 时强制使用 TLS 1.2 及以上的版本,并且在部署上对允许的密码施加一些额外的限制以避免已知的比如需要 SNI 支持的问题。并且期待 HTTP2 与专有的传输安全机制相结合,这些传输机制的规格说明不能提供有意义的建议。
gRPC使用
使用gRPC, 我们可以一次性的在一个.proto文件中定义服务并使用任何支持它的语言去实现客户端和服务端,反过来,它们可以应用在各种场景中,从Google的服务器到你自己的平板电脑—— gRPC帮你解决了不同语言及环境间通信的复杂性。使用protocol buffers还能获得其他好处,包括高效的序列号,简单的IDL以及容易进行接口更新。总之一句话,使用gRPC能让我们更容易编写跨语言的分布式代码。
- 通过一个 protocol buffers 模式,定义一个简单的带有 Hello World 方法的 RPC 服务。
- 用你最喜欢的语言(如果可用的话)来创建一个实现了这个接口的服务端。
- 用你最喜欢的(或者其他你愿意的)语言来访问你的服务端。
什么用grpc
- 服务而非对象、消息而非引用:促进微服务的系统间粗粒度消息交互设计理念。
- 负载无关的:不同的服务需要使用不同的消息类型和编码,例如 protocol buffers、JSON、XML 和 Thrift。
- 流:Streaming API。
- 阻塞式和非阻塞式:支持异步和同步处理在客户端和服务端间交互的消息序列。
- 元数据交换:常见的横切关注点,如认证或跟踪,依赖数据交换。
- 标准化状态码:客户端通常以有限的方式响应 API 调用返回的错误。
HealthCheck
gRPC 有一个标准的健康检测协议,在 gRPC 的所有语言实现中基本都提供了生成代码和用于设置运行状态的功能。
主动健康检查 health check,可以在服务提供者服务不稳定时,被消费者所感知,临时从负载均衡中摘除,减少错误请求。当服务提供者重新稳定后,health check 成功,重新加入到消费者的负载均衡,恢复请求。health check,同样也被用于外挂方式的容器健康检测,或者流量检测(k8s liveness & readiness)。


protubuf文件编写
syntax = "proto3";
package hello;
// option go_package = "hello";
option go_package = "/hello";
// The greeting service definition.
service Greeter {
// Sends a greeting
rpc SayHello (HelloRequest) returns (HelloReply) {}
}
// The request message containing the user's name.
message HelloRequest {
string name = 1;
}
// The response message containing the greetings
message HelloReply {
string message = 1;
}
golang创建grpc server
安装工具包:
- 下载protoc 链接
go install google.golang.org/protobuf/cmd/protoc-gen-go@latestgo install google.golang.org/grpc/cmd/protoc-gen-go-grpc@latest
执行:
protoc --go_out=./ --go-grpc_out=./ hello.proto
- --proto_path: 指定了要去哪个目录中搜索import中导入的和要编译为.go的proto文件 (在这没有使用,需要的话可以加上)
- --go_out:指定了生成的go文件的目录,我在这里把go文件放到本目录中
- --go-grpc_out: 指定了生成的go grpc文件的目录,我在这里把go grpc文件放到本目录中
- hello.proto, 定义了我要编译的文件是哪个文件。
go server代码
package main
import (
"context"
"errors"
"fmt"
"github.com/zhaohaiyu1996/akit/example/grpc/hello"
"google.golang.org/grpc"
"net"
)
type Server struct {
hello.UnimplementedGreeterServer
}
// SayHello implements helloworld.GreeterServer
func (s *Server) SayHello(ctx context.Context, in *hello.HelloRequest) (*hello.HelloReply, error) {
if in.Name == "error" {
return nil, errors.New("123")
}
if in.Name == "panic" {
panic("grpc panic")
}
return &hello.HelloReply{Message: fmt.Sprintf("Hello %+v", in.Name)}, nil
}
type Ss struct {
*grpc.Server
}
func main() {
// 监听本地的8848端口
s := Ss{grpc.NewServer()}
hello.RegisterGreeterServer(s, &Server{}) // 在gRPC服务端注册服务
lis, err := net.Listen("tcp", "127.0.0.1:8808")
if err != nil {
fmt.Printf("listen failed: %v", err)
return
}
//reflection.Register(s.Server) //在给定的gRPC服务器上注册服务器反射服务
// Serve方法在lis上接受传入连接,为每个连接创建一个ServerTransport和server的goroutine。
// 该goroutine读取gRPC请求,然后调用已注册的处理程序来响应它们。
err = s.Serve(lis)
if err != nil {
fmt.Printf("failed to serve: %v", err)
return
}
}
golang创建grpc client
执行:
protoc --go_out=./ --go-grpc_out=./ hello.proto
go client代码
package main
import (
"context"
"fmt"
"github.com/zhaohaiyu1996/akit/example/grpc/hello"
"google.golang.org/grpc"
)
func main() {
// 连接服务器
conn, err := grpc.Dial("localhost:8808", grpc.WithInsecure())
if err != nil {
fmt.Printf("connect faild: %v", err)
}
defer conn.Close()
c := hello.NewGreeterClient(conn)
// 调用SayHello
r, err := c.SayHello(context.Background(), &hello.HelloRequest{Name: "zhaohaiyu"})
if err != nil {
fmt.Printf("sayHello failed: %v", err)
}
fmt.Println(r)
}
结果:
SayHello: hello ---> zhaohaiyu
python创建grpc client
使用python客户端调用golang服务端的方法
下载依赖:
pip install grpcio
pip install protobuf
pip install grpcio_tools
执行:
python -m grpc_tools.protoc -I ./ --python_out=./ --grpc_python_out=./ hello.proto
python client代码
import grpc
import hello_pb2
import hello_pb2_grpc
def run():
with grpc.insecure_channel('localhost:8848') as channel:
stub = hello_pb2_grpc.HelloStub(channel)
res = stub.SayHello(hello_pb2.HelloRequest(name="赵海宇"))
print(res.message)
if __name__ == '__main__':
run()
结果:
python ./main.go
hello ---> 赵海宇
gprc的haeder
- grpc是基于http2.0的rpc框架 -
- grpc对于http头部传递数据进行了封装 metadata,单独抽象了一个包google.golang.org/grpc/metadata-
- type ***p[string][]string其实就是一个map
客户端发送方式一:
// 创建md 并加入ctx
md := metadata.Pairs("key1","value1","key2","value2")
ctx := metadata.NewOutgoingContext(context.Background(),md)
// 从ctx中拿出md
md,_ = metadata.FromOutgoingContext(ctx)
newMd := metadata.Pairs("key3","value3")
ctx = metadata.NewOutgoingContext(ctx,metadata.Join(md,newMd))
客户端发送方式二:
ctx := context.Background()
ctx = metadata.AppendToOutgoingContext(ctx,"key1","value1","key2","value2")
ctx = metadata.AppendToOutgoingContext(ctx,"key3","value3")
服务端接收:
md,ok := metadata.FromIncomingContext(ctx)
实例:
- server:
package main
import (
"fmt"
"net"
pb "test/demo13/server/hello"
"github.com/grpc-ecosystem/grpc-gateway/examples/clients/responsebody"
"github.com/uber/jaeger-client-go/crossdock/client"
"golang.org/x/net/context"
"google.golang.org/grpc"
"google.golang.org/grpc/metadata"
"google.golang.org/grpc/reflection"
)
type server struct{}
func (s *server) SayHello(ctx context.Context, in *pb.HelloRequest) (*pb.HelloResponse, error) {
md,ok := metadata.FromIncomingContext(ctx)
if ok {
fmt.Println(md)
}
return &pb.HelloResponse{Message: "hello ---> " + in.Name}, nil
}
func main() {
// 监听本地的8848端口
lis, err := net.Listen("tcp", "localhost:8848")
if err != nil {
fmt.Printf("listen failed: %v", err)
return
}
s := grpc.NewServer() // 创建gRPC服务器
pb.RegisterHelloServer(s, &server{}) // 在gRPC服务端注册服务
reflection.Register(s) //在给定的gRPC服务器上注册服务器反射服务
// Serve方法在lis上接受传入连接,为每个连接创建一个ServerTransport和server的goroutine。
// 该goroutine读取gRPC请求,然后调用已注册的处理程序来响应它们。
err = s.Serve(lis)
if err != nil {
fmt.Printf("failed to serve: %v", err)
return
}
}
- client
package main
import (
"context"
"fmt"
pb "test/demo13/client/hello"
"google.golang.org/grpc"
"google.golang.org/grpc/metadata"
)
func main() {
// 连接服务器
conn, err := grpc.Dial("localhost:8848", grpc.WithInsecure())
if err != nil {
fmt.Printf("faild to connect: %v", err)
}
defer conn.Close()
c := pb.NewHelloClient(conn)
// 调用服务端的SayHello
ctx := context.Background()
ctx = metadata.AppendToOutgoingContext(ctx,"zhyyz","961119")
r, err := c.SayHello(ctx, &pb.HelloRequest{Name: "zhaohaiyu"})
if err != nil {
fmt.Printf("sayHello failed: %v", err)
}
fmt.Printf("SayHello: %s \n", r.Message)
}
grpc基础的更多相关文章
- gRPC官方文档(gRPC基础:C++)
文章来自gRPC 官方文档中文版 本教程提供了C++程序员如何使用gRPC的指南. 通过学习教程中例子,你可以学会如何: 在一个 .proto 文件内定义服务. 用 protocol buffer 编 ...
- grpc基础讲解和golang实现grpc通信小案例
grpc简介 gRPC由google开发,是一款语言中立.平台中立.开源的远程过程调用系统 gRPC客户端和服务端可以在多种环境中运行和交互,例如用java写一个服务端,可以用go语言写客户端调用 g ...
- gRPC官方文档(异步基础: C++)
文章来自gRPC 官方文档中文版 异步基础: C++ 本教程介绍如何使用 C++ 的 gRPC 异步/非阻塞 API 去实现简单的服务器和客户端.假设你已经熟悉实现同步 gRPC 代码,如gRPC 基 ...
- 【Networking】gRPC golang 相关资料
参考资料: Golang gRPC 示例: http://www.cnblogs.com/YaoDD/p/5504881.html grpc golang学习心得(1)----安装与测试: ht ...
- 编写一个go gRPC的服务
前置条件: 获取 gRPC-go 源码 $ go get google.golang.org/grpc 简单例子的源码位置: $ cd $GOPATH/src/google.golang.org/gr ...
- ASP.NET Core 3.0 上的gRPC服务模板初体验(多图)
早就听说ASP.NET Core 3.0中引入了gRPC的服务模板,正好趁着家里电脑刚做了新系统,然后装了VS2019的功夫来体验一把.同时记录体验的过程.如果你也想按照本文的步骤体验的话,那你得先安 ...
- .net core 3.0中可以使用gRPC了
今天发现.net core下有gRPC模板了,这个可是补全了.net core下高性能RPC框架缺失这一大短板了. 使用模板创建了工程后,发现连客户端的示例也创建了. 更加给力的是,IDE是能直接识别 ...
- 【.NET6】gRPC服务端和客户端开发案例,以及minimal API服务、gRPC服务和传统webapi服务的访问效率大对决
前言:随着.Net6的发布,Minimal API成了当下受人追捧的角儿.而这之前,程序之间通信效率的王者也许可以算得上是gRPC了.那么以下咱们先通过开发一个gRPC服务的教程,然后顺势而为,再接着 ...
- gRPC源码分析1-SSL/TLS
引子 前几天看到微信后台团队分享了TLS相关文章,正好gRPC里TLS数据加密是很重要的一块,于是整理出了这篇文章. 在gRPC里,如果仅仅是用来做后端微服务,可以考虑不加密.本文太长,先给个大纲. ...
随机推荐
- vulnhub-DC:4靶机渗透记录
准备工作 在vulnhub官网下载DC:4靶机https://www.vulnhub.com/entry/dc-4,313/ 导入到vmware,设置成NAT模式 打开kali准备进行渗透(ip:19 ...
- 17Java进阶——反射、进程、Java11新特性
1.Java反射机制 Java反射(Reflection)概念:在运行时动态获取类的信息以及动态调用对象方法的功能. 1.1反射的应用--通过全类名获取类对象及其方法 package two.refl ...
- 【LeetCode】841. 钥匙和房间
841. 钥匙和房间 知识点:图:递归 题目描述 有 N 个房间,开始时你位于 0 号房间.每个房间有不同的号码:0,1,2,...,N-1,并且房间里可能有一些钥匙能使你进入下一个房间. 在形式上, ...
- fastjson 1.2.24 反序列化导致任意命令执行漏洞
漏洞检测 区分 Fastjson 和 Jackson {"name":"S","age":21} 和 {"name":& ...
- 电脑软件安装过程文档.BA
MD 01-打印并阅读-电脑软件安装过程文档.BAT-即此批处理脚本文档MD 02-阅读-电脑软件安装经验教训文档.DOCX-MD 03-制作-杏雨梨云USB维护系统2019中秋版之国庆更新-可启动U ...
- VIM的跨行查找和匹配数量
跨行用\n表示,例如 用4\n56可以匹配到: 4 56 中,查询一段文本中pattern出现的次数,类似于UltraEdit中的"Count All"功能,用:%s/patter ...
- tomcat及springboot实现Filter、Servlet、Listener
tomcat实现: 核心类org.apache.catalina.startup.ContextConfig //支持注解 see:org.apache.catalina.deploy.WebXml ...
- vue 快速入门 系列 —— vue-cli 下
其他章节请看: vue 快速入门 系列 Vue CLI 4.x 下 在 vue loader 一文中我们已经学会从零搭建一个简单的,用于单文件组件开发的脚手架:本篇,我们将全面学习 vue-cli 这 ...
- Java基础技术多线程与并发面试【笔记】
Java基础技术多线程与并发 什么是线程死锁? 死锁是指两个或两个以上的进程(线程)在执行过程中,由于竞争资源或者由于彼此通信而造成的一种阻塞的现象,若无外力作用,它们都将无法推进下去,我们就可以称 ...
- 【原创】Java内存攻击技术漫谈
前言 Java技术栈漏洞目前业已是web安全领域的主流战场,随着IPS.RASP等防御系统的更新迭代,Java攻防交战阵地已经从磁盘升级到了内存里面. 在今年7月份上海银针安全沙龙上,我分享了< ...