微服务通讯:gRPC入门教程

news2024/11/26 5:43:09

微服务通讯:个、RPC入门教程

gRPC是一个RPC框架,用于服务器之间服务的相互通讯,常见微服务项目开发中。市面上的RPC有很多,例如:dubbo、SpringCloud底层封装的等

1 概念

1.1 gRPC

  • gRPC是一个高性能、开源的通用RPC(远程过程调用remote procedure call)框架。
  • gRPC与语言无关,你可以用C++作为服务器,使用Go、Java等作为客户端
    在这里插入图片描述
  • gPRC会屏蔽底层的细节,client只需要直接定义好方法,就能拿到预期的返回结果,对于Server端来说,还需要实现我们定义的方法。【类比于Java中的Feign,但是feign不是RPC,feign是基于HTTP的,有7层】
  • 官网地址:https://grpc.io/docs/what-is-grpc/introduction/
  • 中文教程地址:http://doc.oschina.net/grpc
  • gRPC使用了Protocol Buffss(简称protobuf),这是谷歌开源的一套成熟的数据结构序列化机制

①服务端编写过程

  • 创建gRPC Server对象,你可以理解为它是Serverdaunt抽象的对象
  • 将server(其包含被调用的服务端接口)注册到gRPC Server的内部注册中心

    这样可以在接收到请求时,通过内部的服务发现,发现该服务端接口并转接进行逻辑处理

  • 创建Listen,监听TCP端口
  • gRPC Server开始Listen、Accept,直到Stop

②客户端编写

  • 创建与给定目标(服务端)的连接交互
  • 创建对应Client对象
  • 发送RPC请求,等待同步响应,得到回调后返回响应结果
  • 输出响应结果

1.2 protobuf

①介绍

  1. 谷歌开源的一种数据格式,适合高性能
  2. 二进制数据格式,需要编码和解码,数据本身不具有可读性,只能反序列化后才能得到真正可读的数据
  3. 序列化后体积比json和XML更小,适合网络传输
  4. 支持跨平台多语言
  5. 序列化、反序列化很快
  6. 消息格式升级和兼容性很不错

②安装protobuf

  1. 进入对应的GitHub
  • 根据自己操作系统下载对应版本:
    在这里插入图片描述
  1. 下载成功后解压并配置环境变量

配置为系统环境变量,因为配置为用户环境变量Goland可能不识别

# 打开cmd执行以下命令查看是否配置成功
protoc

在这里插入图片描述

2 gRPC安装及使用

2.1 安装

  1. 安装gRPC核心库
// 下载grpc
go get google.golang.org/grpc

//安装对应工具
go install google.golang.org/protobuf/cmd/protoc-gen-go@latest
go install google.golang.org/grpc/cmd/protoc-gen-go-grpc@latest

2.2 使用

①proto文件编写【定义接口】

  1. 编写proto文件

hello.proto:

//使用proto3的语法
syntax = "proto3";

//指明最后生成的go文件夹最后放在哪个目录的哪个包中
// . 表示当前目录; service表示包名为service
option go_package = ".;service";

//1. 定义一个服务【SayHello】,服务中可以有对应的方法【SayHello】
service SayHello {
  rpc SayHello(HelloRequest) returns (HelloResponse) {}
}

//关键字:message,可以理解为go中的结构体
message HelloRequest{
  string requestName = 1; //1表示消息顺序
//  int64 age = 2;
}

message HelloResponse {
  string responseMsg = 1;
}

  1. 执行以下命令,生成对应文件
 protoc --go_out=. .\hello.proto
 protoc --go-grpc_out=. hello.proto

在这里插入图片描述
3. 将server/proto文件下的hello.pb.go和hello_grpc.pb.go同时复制一份放在client/ptoro下

最终结构:

在这里插入图片描述

注意:

如果发现Goland识别不了protoc命令,

  • 报如下错误:protoc‘ 不是内部或外部命令,也不是可运行的程序 或批处理文件
  • 解决办法:将protoc配置为系统环境变量,然后重启Goland即可

②服务端编写

  • 编写服务端的启动代码
    main.go:
package main

import (
	"context"
	"fmt"
	"go_code/demo01/grpc/client/proto"
	"google.golang.org/grpc"
	"net"
)

// hello Server
type server struct {
	proto.UnimplementedSayHelloServer
}

func (s *server) SayHello(ctx context.Context, req *proto.HelloRequest) (*proto.HelloResponse, error) {
	//服务端实现接口【具体处理逻辑】
	fmt.Printf("client端远程调用成功..., 传入参数为=%v", req.GetRequestName())
	return &proto.HelloResponse{ResponseMsg: "hello," + req.RequestName}, nil
}

func main() {
	//1. 开启端口
	listen, _ := net.Listen("tcp", ":9090")
	//2. 创建grpc服务
	grpcServer := grpc.NewServer()
	//3. 将我们自己编写好的服务注册到grpc
	proto.RegisterSayHelloServer(grpcServer, &server{})

	//4. 启动服务
	err := grpcServer.Serve(listen)
	if err != nil {
		fmt.Printf("failed to server: %v", err)
		return
	}
}

整体结构:
在这里插入图片描述

③客户端编写

main.go:

package main

import (
	"context"
	"fmt"
	pb "go_code/demo01/grpc/server/proto"
	"google.golang.org/grpc"
	"google.golang.org/grpc/credentials/insecure"
	"log"
)

func main() {
	//1. 与Server建立连接[案例中:此处禁用安全传输,我们这里没有使用加密验证]
	conn, err := grpc.Dial("127.0.0.1:9090", grpc.WithTransportCredentials(insecure.NewCredentials()))
	if err != nil {
		log.Fatalf("did not connect: %v", err)
	}
	defer conn.Close() //延时关闭连接

	//2. 与对应服务建立连接
	client := pb.NewSayHelloClient(conn)
	//3. 执行grpc调用[对应方法已经在对应的Server端实现了]
	resp, _ := client.SayHello(context.Background(), &pb.HelloRequest{RequestName: "curry"})
	fmt.Println(resp.GetResponseMsg())

}

④测试结果

  • 配置goland同时启动多个实例
    在这里插入图片描述
  • 启动server和client,查看结果
    在这里插入图片描述

3 https及实现grpc加密通信

3.1 加密相关知识

3.2 实现grpc加密通信【基于TLS】

1. 安装openssl并配置环境变量

在github上找到对应版本并安装:https://github.com/openssl/openssl/releases

# 在cmd窗口输入以下命令,查看是否配置成功
openssl

在这里插入图片描述

2. 生成对应key和证书

在上面入门的基础上新建文件夹key,通过cmd来到key目录下,执行下面命令

# 1. 生成私钥
openssl genrsa -out server.key 2048

# 2. 生成证书,全部回车即可,可以不填[就是一些基本信息:国家、地区什么的]
openssl req -new -x509 -key server.key -out server.crt -days 36500

# 3. 生成csr[同样可以全部回车,不填写任何信息]
openssl req -new -key server.key -out server.csr

最终效果:
在这里插入图片描述

3. 配置openssl.cnf

更改openssl.cnf (Linux上是openssl.cfg)

  1. 复制一份你安装的openssl的bin目录里面的openssl.cnf文件到你项目所在目录
  2. 找到[CA_default],打开copy_extensions = copy (就是把前面的#去掉)
  3. 找到[req],打开req_extensions = v3_req # The extensions to add to a certificate request
  4. 找到[ v3_req ],添加subjectAltName = @alt_names
  5. 添加新的标签[alt_names]和标签字段
    DNS.1 = *.ziyi.com

在这里插入图片描述

# 1. 生成证书私钥test.key
openssl genpkey -algorithm RSA -out test.key

# 2. 通过私钥test.key生成证书请求文件test.csr(注意cfg和cnf,linux上是cfg)
openssl req -new -nodes -key test.key -out test.csr -days 3650 -subj "/C=cn/OU=myorg/O=mycomp/CN=myname" -config ./openssl.cnf -extensions v3_req
#test.csr是上面生成的证书请求文件。ca.crt/server.key是CA证书文件和key,用来对test.csr进行签名认证,这两个文件在第2大部分已经生成

# 3. 生成SAN证书 pem
openssl x509 -req -days 365 -in test.csr -out test.pem -CA server.crt -CAkey server.key -CAcreateserial -extfile ./openssl.cnf -extensions v3_req

4. 编写main.go代码(客户端、服务端)

  • 服务端
package main

import (
	"context"
	"fmt"
	"go_code/demo01/grpc/client/proto"
	"google.golang.org/grpc"
	"google.golang.org/grpc/credentials"
	"net"
)

// hello Server
type server struct {
	proto.UnimplementedSayHelloServer
}

func (s *server) SayHello(ctx context.Context, req *proto.HelloRequest) (*proto.HelloResponse, error) {
	//服务端实现接口【具体处理逻辑】
	fmt.Printf("client端远程调用成功..., 传入参数为=%v", req.GetRequestName())
	return &proto.HelloResponse{ResponseMsg: "hello," + req.RequestName}, nil
}

func main() {
	//TSL认证
	//两个参数分别是crtFile、keyFile
	//自带签名证书文件和私钥文件
	//0. 配置证书和私钥文件
	creds, _ := credentials.NewServerTLSFromFile("E:\\Go\\GoPro\\src\\go_code\\demo01\\grpc\\key\\test.pem",
		"E:\\Go\\GoPro\\src\\go_code\\demo01\\grpc\\key\\test.key")
	//1. 开启端口
	listen, _ := net.Listen("tcp", ":9090")
	2. 创建grpc服务
	//grpcServer := grpc.NewServer()
	
	//2. 创建带证书的服务
	grpcServer := grpc.NewServer(grpc.Creds(creds))
	//3. 将我们自己编写好的服务注册到grpc
	proto.RegisterSayHelloServer(grpcServer, &server{})

	//4. 启动服务
	err := grpcServer.Serve(listen)
	if err != nil {
		fmt.Printf("failed to server: %v", err)
		return
	}
}

结果:
在这里插入图片描述

3.3 实现grpc加密通信【基于Token】

1. 认识对应接口

gRPC提供给我们了一个接口,接口中有两个方法,接口位于credentials包下,这个接口需要客户端来实现

type PerRPCCredentials interface {
	/*
	获取元数据信息,也就是客户端提供了k-v对,
	context用于控制超时和取消,uri是请求入口处的uri
	*/
	GetRequestMetadata(ctx context.Context, uri ...string) (map[string]string, error)

	/*
	用于设置是否需要TLS认证进行安全传入,如果返回true则必须加上TLS验证
	*/
	RequireTransportSecurity() bool
}

token是可以和TLS结合的

2. 编写服务端代码

package main

import (
	"context"
	"errors"
	"fmt"
	"go_code/demo01/grpc/client/proto"
	"google.golang.org/grpc"
	"google.golang.org/grpc/credentials/insecure"
	"google.golang.org/grpc/metadata"
	"net"
)

// hello Server
type server struct {
	proto.UnimplementedSayHelloServer
}

// 业务
func (s *server) SayHello(ctx context.Context, req *proto.HelloRequest) (*proto.HelloResponse, error) {
	fmt.Printf("---------------")
	//【校验token】
	//获取客户端传入的元数据信息
	md, ok := metadata.FromIncomingContext(ctx)
	if !ok {
		return nil, errors.New("未传输token")
	}
	var appId string
	var appKey string
	if v, ok := md["appId"]; ok {
		appId = v[0]
	}
	if v, ok := md["appKey"]; ok {
		appKey = v[0]
	}

	if appId != "ziyi" || appKey != "123456" {
		return nil, errors.New("token 不正确")
	}

	//服务端实现接口【具体处理逻辑】
	fmt.Printf("client端远程调用成功..., 传入参数为=%v", req.GetRequestName())
	return &proto.HelloResponse{ResponseMsg: "hello," + req.RequestName}, nil
}

func main() {
	TSL认证
	两个参数分别是crtFile、keyFile
	自带签名证书文件和私钥文件
	0. 配置证书和私钥文件
	//creds, _ := credentials.NewServerTLSFromFile("E:\\Go\\GoPro\\src\\go_code\\demo01\\grpc\\key\\test.pem",
	//	"E:\\Go\\GoPro\\src\\go_code\\demo01\\grpc\\key\\test.key")

	//1. 开启端口
	listen, _ := net.Listen("tcp", ":9090")
	2. 创建grpc服务
	//grpcServer := grpc.NewServer()

	//2. 创建带证书的服务
	grpcServer := grpc.NewServer(grpc.Creds(insecure.NewCredentials()))
	//3. 将我们自己编写好的服务注册到grpc
	proto.RegisterSayHelloServer(grpcServer, &server{})

	//4. 启动服务
	err := grpcServer.Serve(listen)
	if err != nil {
		fmt.Printf("failed to server: %v", err)
		return
	}
}

3. 客户端代码

package main

import (
	"context"
	"fmt"
	pb "go_code/demo01/grpc/server/proto"
	"google.golang.org/grpc"
	"google.golang.org/grpc/credentials/insecure"
	"log"
)

type ClientTokenAuth struct {

}

func (c ClientTokenAuth) GetRequestMetadata(ctx context.Context, uri ...string) (map[string]string, error){
	return map[string]string{
		"appId": "ziyi",
		"appKey": "123456",
	}, nil
}

func (c ClientTokenAuth) RequireTransportSecurity() bool {
	return false
}

func main() {
	0. 设置证书文件test.pem 【因为是测试,故:域名此处写死:*.ziyi.com】,线上应该通过浏览器去获取
	//creds, _ := credentials.NewClientTLSFromFile("E:\\Go\\GoPro\\src\\go_code\\demo01\\grpc\\key\\test.pem",
	//	"*.ziyi2.com")

	//1. 与Server建立连接[案例中:此处禁用安全传输,我们这里没有使用加密验证]
	var opts []grpc.DialOption
	opts = append(opts, grpc.WithTransportCredentials(insecure.NewCredentials())) //这里我们不使用TLS,因此这里传入空
	opts = append(opts, grpc.WithPerRPCCredentials(new(ClientTokenAuth))) //传入我们自定义的验证方式【Token】
	conn, err := grpc.Dial("127.0.0.1:9090", opts...)

	1. 与Server建立带加密的连接
	//conn, err := grpc.Dial("127.0.0.1", grpc.WithTransportCredentials(creds))
	if err != nil {
		log.Fatalf("did not connect: %v", err)
	}
	defer conn.Close() //延时关闭连接

	//2. 与对应服务建立连接
	client := pb.NewSayHelloClient(conn)
	//3. 执行grpc调用[对应方法已经在对应的Server端实现了]
	resp, _ := client.SayHello(context.Background(), &pb.HelloRequest{RequestName: "curry"})
	fmt.Println(resp.GetResponseMsg())

}

总结:gRPC将各种认证方式浓缩到一个凭证(credentials)上,可以单独使用一种拼争,比如只使用TLS或者只使用自定义凭证,也可以多种凭证组合,gRPC提供统一的gRPC验证机制,使得研发人员使用方便,这也是gRPC设计的巧妙之处

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/529563.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

计算机组成原理主要问题汇总(五)

一、定点数的原码、补码、反码和移码的表示和相互转换方法 1、原码(true form)是一种计算机中对数字的二进制定点表示方法。原码表示法在数值前面增加了一位符号位(即最高位为符号位):正数该位为0,负数该位为1(0有两种…

JavaEE(系列5) -- 多线程带来的风险(线程安全)

我们直接给出含有一个bug的例子 创建两个线程,各执行5w次自增。正常情况,结果是10w。 初始代码如下: package threading; //线程不安全 class Counter{private int count0;public void add(){count;}public int get(){return count;} } public class Th…

【项目实训】ATM自助取款系统

文章目录 1. 课程设计目的2. 课程设计任务与要求3. 课程设计说明书3.1 需求分析3.1.1 功能分析3.1.2 性能要求分析 3.2 概要设计3.2.1 功能模块图 3.3 详细设计3.3.1 实体类的设计3.3.2 实现数据库处理 3.4 主要程序功能流程图 4. 课程设计成果4.1 完整代码4.2 运行结果4.2.1 精…

最常用的开源免费自动化测试工具整理汇总 ,总有一款适合你

目录 1、Selenium 2、JMeter 3、Appium 4、Soapui 5、Postman 6、Robot Framework 7、Monkey 8、GT 9、Appscan 10、Jenkins 1、Selenium 官网: WebUI自动化测试 Selenium是一个用于Web应用程序测试的工具,Selenium已经成为Web自动化测试工程…

SpringCloud源码探析(六)-消息队列RabbitMQ

1.概述 RabbitMQ是一个开源的消息代理和队列服务器,它是基于Erlang语言开发,并且是基于AMQP协议的。由于Erlang语言最初使用与交换机领域架构,因此使得RabbitMQ在Broker之间的数据交互具有良好的性能。AMQP(Advanced Message Queuing Protoc…

路径规划算法:基于多元宇宙算法的路径规划算法- 附代码

路径规划算法:基于多元宇宙优化的路径规划算法- 附代码 文章目录 路径规划算法:基于多元宇宙优化的路径规划算法- 附代码1.算法原理1.1 环境设定1.2 约束条件1.3 适应度函数 2.算法结果3.MATLAB代码4.参考文献 摘要:本文主要介绍利用智能优化…

【Unity Optimize】使用对象池(Object Pooling)优化项目

目录 1 对象池(Object Pooling)介绍2 实现对象池脚本3 使用对象池生成Cube4 效果展示5 Unity资源商店的对象池插件 1 对象池(Object Pooling)介绍 Unity中的对象池(Object Pooling)是一种用于提高游戏性能…

教程详解|如何在PICO眼镜中接入VR全景?

伴随着《万人狂欢泼水节》首场VR直播开启,PICO视频正式推出《跟着PICO去旅行》系列VR文旅直播节目,通过PICO眼镜结合VR技术向众多观众展现更多祖国的大好山河,通过PICO眼镜身临其境地感受云游世界的美妙。 经历了十余年的发展,VR…

esp32环境安装教程---arduino IDE

前言 (1)最近突然对esp32感兴趣了,源于逛油管的时候,总是看到很多大佬使用esp32cam进行网络图传,做摄像头。个人比较感兴趣,在环境安装过程遇到了很多坑,所以在此跟大家分享一下。 (…

了解ChatGPT的最便捷有效方式是跟对人

毕业后,工作原因,我自己的CSND就没有更新过。现在更新一篇有关chatGPT的快速入门指南。 一、什么是chatGPT 2022年12月底,你问我这个问题,我还真得好好跟你解释一下。目前这个阶段的火热程度,这里不再啰嗦了。基于GPT…

AI时代的赚钱思路:23岁女网红如何利用AI技术年入4亿?

一、AI技术为网红赚钱创造新途径 23岁美国网红Caryn Marjorie(卡琳玛乔丽)正同时交往1000多个男朋友。 作为一个在Snapchat上坐拥180万粉丝的美女,她利用人工智能(AI)技术,打造了一个AI版本的自己&#x…

鲲鹏昇腾开发者峰会开幕 星辰天合发布新一代天合翔宇一体机

近日,主题为“创未来 享非凡”的鲲鹏昇腾开发者峰会 2023 在东莞松山湖开幕,此次大会旨在帮助开发者深入了解鲲鹏、昇腾全栈技术,加速行业数智化的技术、产品和解决方案创新。 作为鲲鹏生态重要合作伙伴,XSKY星辰天合获邀参加此次…

【利用AI让知识体系化】入门Koa框架

思维导图 文章目录 思维导图一、介绍Koa什么是KoaKoa的历史Koa的特点 二、基本使用安装KoaHello World中间件路由错误处理 三、进阶使用静态资源管理Session管理文件上传表单处理HTTPS支持 四、Koa中间件中间件的概念Koa的洋葱模型常用中间件的介绍自定义中间件的编写 五、异步…

这个水平来面试也敢要20K?还是3年经验的测试工程师....

起因 老板觉得现在公司部门里都是男的,缺少一点阴柔之气,想平衡一下,正巧当时互联网公司倒了一大批,大批简历投到公司,老板以为自己也是技术出身,就想着要招了一个三年工作经验的女测试员,要价…

ANR实战案例1 - Google广告导致ANR解决

系列文章目录 提示:这里可以添加系列文章的所有文章的目录,目录需要自己手动添加 例如:第一章 Python 机器学习入门之pandas的使用 文章目录 系列文章目录前言一、AdLoader$Builder广告构建ANR二、AdView布局动态创建案例总结 前言 一、AdLoa…

Linux 安装JDK详解

安装步骤 1. 从官网下载安装包保存到 /home/download 下面 2.下载后解压到指定目录,例如:/usr/java/jdk11 3. 解压压缩包 [rootlocalhost linux-x86-64]# cd /usr/java/jdk11 [rootlocalhost jdk11]# [rootlocalhost jdk11]# [rootlocalhost jdk11]…

【换模型更简单】如何用 Serverless 一键部署 Stable Diffusion?

作者:寒斜 本篇章是阿里云函数计算部署 Stable Diffusion 系列的第三篇,如果说第一篇是尝试使用云服务来解决用户本地部署 Stable Diffusion 的问题(显卡成本,部署技术复杂),第二篇是面向技术同学解决云服…

Wijmo 2023 v1 Crack

改进了 FlexGrid,支持 React 18 严格模式和可访问性。 5月 15, 2023 - 10:51 新版本 特征 改进了对 React 18 的支持 - 添加了对 React 18 严格模式的支持,可帮助开发人员在开发过程中查找常见错误。辅助功能改进 - 以下是此版本中…

postman工具使用中,遇到的简单疑问

post请求和get请求有什么区别? GET请求和POST请求都是HTTP协议中的两种常见请求方式,主要区别如下: GET请求在请求URL的后面附带参数,而POST请求则将参数包含在请求体中。 GET请求的数据是以查询字符串的形式传递的,而…

JavaEE(系列4) -- 多线程(线程的状态)

目录 观察线程的所有状态 1. new状态 2. TERMINATED 状态 3. RUNNABLE 就绪状态,运行状态 4. TIMED_WAITNG 休眠状态 5. BLOCKED 表示等待锁出现的状态 6. WAITING 使用wait方法出现的状态 观察线程的所有状态 线程的状态是一个枚举类型 public class test2 {public static v…