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@latest
go 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里,如果仅仅是用来做后端微服务,可以考虑不加密.本文太长,先给个大纲. ...
随机推荐
- 关于GPIO口的一些概念性问题
一.什么是GPIO? GPIO的英文全称是General-Purpose IO ports,也就是通用输入输出口. 在嵌入式系统中,经常需要控制许多结构简单的外部设备或者电路,这些设备有的需要通过CP ...
- Tomcat PUT方法任意写文件漏洞(CVE-2017-12615)
Apache Tomcat 7.0.0~7.0.79 直接发送以下数据包即可在Web根目录写入shell: PUT /1.jsp/ HTTP/1.1 Host: 192.168.49.2:8080 A ...
- 论文笔记:(2019CVPR)PointConv: Deep Convolutional Networks on 3D Point Clouds
目录 摘要 一.前言 1.1直接获取3D数据的传感器 1.2为什么用3D数据 1.3目前遇到的困难 1.4现有的解决方法及存在的问题 二.本文idea 2.1 idea来源 2.2 初始思路 2.3 ...
- 云服务器是什么?ECS、BCC、CVM...
什么是云服务器?云服务器有哪些优势?能用来干什么? 很多人不太了解云服务器的定义和用途. 云服务器是一种简单高效.处理能力可弹性伸缩的计算服务,帮助用户快速构建更稳定.安全的应用,提升运维效率,降低 ...
- 浅析php环境配置
PHP作为开源的服务器端脚本语言,在web应用方面非常广泛.如果你想下载某些开源应用,github上php开源软件选择往往比Java还多.最近,研究了linux下php的安装,主要有以下体会. PHP ...
- Java8 Lambda表达式(一)
目录 一.应用场景引入 优化一:使用策略模式 优化二:使用匿名内部类 优化三:使用Lambda表达式 优化四:使用Stream API 二.Lambda运算符和对应语法 语法格式 Lambda表达式需 ...
- 获取浏览器中url的参数
例如: 浏览器的地址是:http://localhost:8080/src/views/moneyDetail?id=10 vue 获取浏览器的参数 获取id的参数:this.$route.query ...
- Springboot通过拦截器拦截请求信息收集到日志
1.需求 最近在工作中遇到的一个需求,将请求中的客户端类型.操作系统类型.ip.port.请求方式.URI以及请求参数值收集到日志中,网上找资料说用拦截器拦截所有请求然后收集信息,于是就开始了操作: ...
- Salesforce Integration 概览(六) UI Update Based on Data Changes(UI自动更新基于数据变更)
Salesforce用户界面必须由于Salesforce数据的更改而自动更新.这个场景其实在我所经历的项目中用到的不是特别多,因为客户可能直接点击刷新按钮就直接看到了最新的数据,而不是那种一直不刷新然 ...
- let 及const
ES5中的块级作用域 ES5中只有全局作用域和函数作用域,这样带来了很多的不便利,会出现内层变量被外层变量覆盖,循环体中的变量会暴露在全局,很多情况下需要自执行函数来私有化变量. ES6块级的作用域 ...