GRPC学习笔记

GRPC学习笔记

1 GRPC简介

1.1 定义

gRPC(Google Remote Procedure Call,Google远程过程调用)协议是谷歌发布的基于HTTP2协议承载的高性能、通用的RPC开源软件框架,提供了支持多种编程语言的、对网络设备进行配置和管理的方法。

1.2 目的

随着网络复杂化,服务之间远程调用的普遍使用,对远程调用工具的需求也越迫切,gRPC协议应运而生。基于gRPC协议实现对设备的管理已经应用在Telemetry订阅管理,且可以满足大规模、高性能的网络监控需求,逐渐在业界广泛使用。另外,基于gRPC协议实现对设备的查询和配置管理,以便获取设备的异常信息,及时进行网络收敛和业务切换,避免大量丢包导致的业务中断。于是设备提供了一种通过gRPC方式来管理设备的方法,包括配置、查询和能力获取三个方法。这些方法是通过设备和采集器对接,实现采集设备数据的功能。

2 GRPC原理

2.1 GRPC协议框架

2.1.1 gRPC协议栈分层

协议栈分层外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

各层详细说明

层次说明
TCP层底层通信协议,基于TCP连接。
TLS层该层是可选的,基于TLS加密通道。
HTTP2层gRPC承载在HTTP2协议上,利用了HTTP2的双向流、流控、头部压缩、单连接上的多路复用请求等特性。
gRPC层远程过程调用,定义了远程过程调用的协议交互格式。
编码层gRPC通过编码格式承载数据,包括GPB(Google Protocol Buffer)编码格式、JSON(JavaScript Object Notation)编码格式。
数据模型层业务模块的数据。通信双方需要了解彼此的数据模型,才能正确调用信息。当前设备提供了订阅、配置、查询业务模块。
2.2.2 GRPC网络架构

gRPC采用客户端和服务器模型,使用HTTP2协议传输报文。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

gRPC网络的工作机制如下:

  • 服务器通过监测指定服务端口来等待客户端的连接请求。
  • 用户通过执行客户端程序登录到服务器。
  • 客户端调用.proto文件提供的gRPC方法发送请求消息。
  • 服务器回复应答消息。
2.2.3 Dial-in模式和Dial-out模式

设备在网络架构里支持Dial-in和Dial-out两种对接模式。

  1. Dial-in模式:设备作为gRPC服务器,采集器作为gRPC客户端。由采集器主动向设备发起gRPC连接并获取需要采集的数据信息或下发配置。Dial-in模式适用于小规模网络和采集器需要向设备下发配置的场景。

    Dial-in模式支持以下操作:

    • Subscribe操作:高速采集设备的接口流量统计、CPU和内存等数据信息。当前仅支持基于Telemetry技术的Subscribe操作。
    • Get操作:获取设备运行状态和运行配置。当前仅支持基于gNMI(gRPC Network Management Interface)规范的Get操作。
    • Capabilities操作:获取设备能力数据。当前仅支持基于gNMI规范的Capabilities操作。
    • Set操作:向设备下发配置。当前仅支持基于gNMI规范的Set操作。
  2. Dial-out模式:设备作为gRPC客户端,采集器作为gRPC服务器。设备主动和采集器建立gRPC连接,将设备上配置的订阅数据推送给采集器。Dial-out模式适用于网络设备较多的情况下,由设备主动向采集器提供设备数据信息。Dial-out模式只支持基于Telemetry技术的Subscribe操作。

2.2 基于GRPC的订阅原理

2.3 基于gNMI的gRPC数据处理

gRPC支持通过gNMI(gRPC Network Management Interface)规范定义Capabilities、Set和Get、Subscribe方法,为用户提供基于gRPC协议的数据配置与查询功能。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

2.3.1 gNMI接口

gRPC支持Capabilities、Get、Set、Subscribe; gNMI的rpc接口如下

service gNMI {
  // Capabilities allows the client to retrieve the set of capabilities that
  // is supported by the target. This allows the target to validate the
  // service version that is implemented and retrieve the set of models that
  // the target supports. The models can then be specified in subsequent RPCs
  // to restrict the set of data that is utilized.
  // Reference: gNMI Specification Section 3.2
  rpc Capabilities(CapabilityRequest) returns (CapabilityResponse);
  // Retrieve a snapshot of data from the target. A Get RPC requests that the
  // target snapshots a subset of the data tree as specified by the paths
  // included in the message and serializes this to be returned to the
  // client using the specified encoding.
  // Reference: gNMI Specification Section 3.3
  rpc Get(GetRequest) returns (GetResponse);
  // Set allows the client to modify the state of data on the target. The
  // paths to modified along with the new values that the client wishes
  // to set the value to.
  // Reference: gNMI Specification Section 3.4
  rpc Set(SetRequest) returns (SetResponse);
  // Subscribe allows a client to request the target to send it values
  // of particular paths within the data tree. These values may be streamed
  // at a particular cadence (STREAM), sent one off on a long-lived channel
  // (POLL), or sent as a one-off retrieval (ONCE).
  // Reference: gNMI Specification Section 3.5
  rpc Subscribe(stream SubscribeRequest) returns (stream SubscribeResponse);
}

gnmi.proto文件链接:gnmi/proto/gnmi/gnmi.proto at master · openconfig/gnmi · GitHub

2.4 参考博客

CloudEngine 16800系列交换机 产品文档 (huawei.com)

3 gRPC的四种通信模式

  • RPC有四种通信⽅式,分别是:简单 RPC(Unary RPC)、服务端流式 RPC (Server streaming RPC)、客户端流式 RPC (Clientstreaming RPC)、双向流式 RPC(Bi-directional streaming RPC)。它们主要有以下特点:
服务类型特点
简单 RPC⼀般的rpc调⽤,传⼊⼀个请求对象,返回⼀个返回对象
服务端流式 RPC传⼊⼀个请求对象,服务端可以返回多个结果对象
客户端流式 RPC客户端传⼊多个请求对象,服务端返回⼀个结果对象
双向流式 RPC结合客户端流式RPC和服务端流式RPC,可以传⼊多个请求对象,返回多个结果对象

3.1 简单RPC

  • 简单rpc 这就是⼀般的rpc调⽤,⼀个请求对象对应⼀个返回对象
  • 客户端发起⼀次请求,服务端响应⼀个数据,即标准RPC通信。
  • 这种模式,⼀个每⼀次都是发起⼀个独⽴的tcp连接,⾛⼀次三次握⼿和四次挥⼿!
  • 这个就是我们基础案例的示例,模式图如下

[image-20220514155737224](https://images.cnblogs.com/cnblogs_com/Mcoming/2385829/o_240318095709_20220514-image-20220514155737224 .png)

3.2 服务端流式RPC

  • 服务端流式rpc ⼀个请求对象,服务端可以传回多个结果对象

  • 服务端流 RPC 下,客户端发出⼀个请求,但不会⽴即得到⼀个响应,⽽是在服务端与客户端之间建⽴⼀个单向的流,服务端可以随时向流
    中写⼊多个响应消息,最后主动关闭流,⽽客户端需要监听这个流,不断获取响应直到流关闭

  • 应⽤场景举例:

    • 典型的例⼦是客户端向服务端发送⼀个股票代码,服务端就把该股票的实时数据源源不断的返回给客户端

[image-20220514155832935](https://images.cnblogs.com/cnblogs_com/Mcoming/2385829/o_240318095709_20220514-image-20220514155832935 .png)

3.3 客户端流RPC

  • 客户端流式rpc 客户端传⼊多个请求对象,服务端返回⼀个响应结果
  • 应用场景如:物联⽹终端向服务器报送数据

[image-20220514155907457](https://images.cnblogs.com/cnblogs_com/Mcoming/2385829/o_240318095709_20220514-image-20220514155907457 .png)

3.4 双向流RPC

  • 双向流式rpc 结合客户端流式rpc和服务端流式rpc,可以传⼊多个对象,返回多个响应对象
  • 应⽤场景:聊天应⽤

[image-20220514194549273](https://images.cnblogs.com/cnblogs_com/Mcoming/2385829/o_240318095709_20220514-image-20220514194549273 .png)

3.5 实战

stream_grpc.proto 定义

syntax = "proto3";
 
package example;
 
service StreamService {
  rpc BidirectionalStream(stream ExampleMessage) returns (stream ExampleMessage);   // 双向流模式
  rpc ClientStream(stream ExampleMessage) returns (ExampleMessage);                 // 客户端流模式
  rpc ServerStream(ExampleMessage) returns (stream ExampleMessage);                 // 服务端流模式
}
 
message ExampleMessage {
  string data = 1;
}

客户端代码

import time
import grpc
import pb.stream_grpc_pb2 as service_pb2
import pb.stream_grpc_pb2_grpc as service_pb2_grpc
 
def run():
    with grpc.insecure_channel('localhost:50051') as channel:
        stub = service_pb2_grpc.StreamServiceStub(channel)
        response_iterator = stub.BidirectionalStream(iter([service_pb2.ExampleMessage(data='Hello'),
            service_pb2.ExampleMessage(data='Hello2'), service_pb2.ExampleMessage(data='Hello2'), 
            service_pb2.ExampleMessage(data='Hello4'), service_pb2.ExampleMessage(data='Hello5')
        ]))
        for response in response_iterator:
            print(response.data)
def send_stream_data():
    for i in range(10) :
        yield service_pb2.ExampleMessage(data=f'client send data {i}')
        time.sleep(1)

def ClientStream():
    with grpc.insecure_channel('localhost:50051') as channel:
        stub = service_pb2_grpc.StreamServiceStub(channel)
        response = stub.ClientStream(send_stream_data())
    print('返回结果', response.data)

def ServerSteam():
    with grpc.insecure_channel('localhost:50051') as channel:
        stub = service_pb2_grpc.StreamServiceStub(channel)
        response = stub.ServerStream(service_pb2.ExampleMessage(data='Start'))
        for msg in response:
            print('返回结果', msg.data)


def BothStream():
    with grpc.insecure_channel('localhost:50051') as channel:
        stub = service_pb2_grpc.StreamServiceStub(channel)
        response = stub.BidirectionalStream(send_stream_data())
        for msg in response:
            print('客户端收到:', msg.data)
 
if __name__ == '__main__':
    # run()
    # ClientStream()
    # ServerSteam()
    BothStream()

服务端代码

import time
from concurrent import futures
import grpc
import pb.stream_grpc_pb2 as service_pb2
import pb.stream_grpc_pb2_grpc as service_pb2_grpc
 
class StreamService(service_pb2_grpc.StreamServiceServicer):
    def BidirectionalStream(self, request_iterator, context):
        for message in request_iterator:
            print('服务端收到:',message.data)
            # 处理接收到的消息
            # yield service_pb2.ExampleMessage(data=message.data + " response")
        
        for i in range(10):
            time.sleep(1)
            yield service_pb2.ExampleMessage(data=f'服务端响应给客户端 {i}')

    def ClientStream(self, request_iterator, context):
        for message in request_iterator:
            print(message.data)
        return service_pb2.ExampleMessage(data=message.data + " client stream,server not stream")
    
    def ServerStream(self, request, context):
        print(request)
        for i in range(10):
            print(context.is_active())
            time.sleep(1)
            print('给客户端发送数据:', i)
            yield service_pb2.ExampleMessage(data=f'服务端响应 {i}')
        print(context.is_active())
    
 
def serve():
    server = grpc.server(futures.ThreadPoolExecutor(max_workers=10))
    service_pb2_grpc.add_StreamServiceServicer_to_server(StreamService(), server)
    server.add_insecure_port('[::]:50051')
    server.start()
    try:
        server.wait_for_termination()
    except KeyboardInterrupt:
        server.stop(0)
 
if __name__ == '__main__':
    serve()

3.6 参考博客

grpc python 实战 python grpc stream_mob64ca13faa4e6的技术博客_51CTO博客

gRPC的四种通信模式 - BigSun丶 - 博客园 (cnblogs.com)

server.stop(0)

if name == ‘main’:
serve()


### 3.6 参考博客

[grpc python 实战 python grpc stream_mob64ca13faa4e6的技术博客_51CTO博客](https://blog.51cto.com/u_16213593/7315989)

[gRPC的四种通信模式 - BigSun丶 - 博客园 (cnblogs.com)](https://www.cnblogs.com/Mcoming/p/18080564)



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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

更新至2022年上市公司数字化转型数据合集(四份数据合集)

更新至2022年上市公司数字化转型数据合集(四份数据合集) 一、2000-2022年上市公司数字化转型数据(年报词频、文本统计) 二、2007-2022年上市公司数字化转型数据(年报和管理层讨论)(含原始数据…

Java中的运算符

运算符是用于数学函数、一些特殊的赋值语句和逻辑比较方面的特殊符号。 赋值运算符(“”) 赋值运算符是一个二元运算符(即对两个操作数进行处理),功能是将右侧的操作数赋值给左侧的操作数。 int a 100; 该表达式就…

prometheus配置监控Java应用服务

程序员的公众号:源1024,获取更多资料,无加密无套路! 最近整理了一份大厂面试资料《史上最全大厂面试题》,Springboot、微服务、算法、数据结构、Zookeeper、Mybatis、Dubbo、linux、Kafka、Elasticsearch、数据库等等 …

从底层分析并详解SpringAOP底层实现

首先分析AOP的实现 首先切面(Advisor)由通知(Advice)和切点(Pointcut)组成 包括前置通知后置通知等等最终都会被转化为实现 MethodInterceptor 接口的环绕通知 先看一段代码了解一下是aop是怎么运作的 首先定义了两个类实现了MethodInterceptor接口&…

XiaodiSec day017 Learn Note 小迪安全学习笔记

XiaodiSec day017 Learn Note 小迪安全学习笔记 记录得比较凌乱,不尽详细 day 17 主要内容: php 框架 thinkPHPyiilaravel 使用 fofa 搜索 thinkphp 市面上 thinkphp5 版本较多 url 结构 域名/.php(文件名)/index(目录)/index(函数名)模块名-控…

oracle 12c+ max_string_size参数

一个客户的数据库版本是19.3,在做数据库复制的时候,目标端报错了,查看了一下问题发现表的字段长度有不对,在12c以前我们都知道varchar的长度最大是4000,但是客户这里居然有32767: 把客户的建表语句弄出来,放到我的一个19c的测试环境进行测试: 发现报错了: 这里报错很明显了,是M…

不可思议!我的AI有道英语字典助手竟然与百度千帆AI应用创意挑战赛K12教育主题赛榜首作品差之毫厘

目录 一、前言二、效果对比三、优化《AI英语词典》提示词四、其他获奖作品链接 一、前言 今天看百度千帆AI原生应用创意挑战赛——K12教育主题赛,发现第一名的《我爱记单词》和我早两天发布的一篇《AI英语词典》的想法不谋而合。当时我们应该都是互相不知道对方的&a…

Day1--什么是网络安全?网络安全常用术语

目录 1. 什么是网络安全? 信息系统(Information System) 信息系统安全三要素(CIA) 网络空间安全管理流程 网络安全管理 2. 网络安全的常用术语 3. 网络安全形势 4. 中国网络安全产业现状 1. 什么是网络安全&am…

使用IOPaint实现图片擦除路人

IOPaint 是一个免费的开源的 inpainting/outpainting 工具,由最先进的 AI 模型提供支持。 IOPaint 中使用各种模型来修改图像: 擦除:删除任何不需要的物体、缺陷、水印、人物。修复:对图像的特定部分进行修改、添加新对象或替换…

第二期书生浦语大模型训练营第四次笔记

大模型微调技术 大模型微调是一种通过在预训练模型的基础上,有针对性地微调部分参数以适应特定任务需求的方法。 微调预训练模型的方法 微调所有层:将预训练模型的所有层都参与微调,以适应新的任务。 微调顶层:只微调预训练模型…

ACL的知识点和实验

1.ACL的组成 ACL由若干条permit或deny语句组成。每条语句就是该ACL的一条规则,每条语句中的permit或deny就是与这条规则相对应的处理动作。 2.规则编号 (1)一个ACL中的每一条规则都有一个相应的编号。 (2)步长是系…

本地CPU搭建知识库大模型来体验学习Prompt Engineering/RAG/Agent/Text2sql

目录 1.环境 2.效果 3.概念解析 4.架构图 5. AI畅想 6.涉及到的技术方案 7. db-gpt的提示词 1.环境 基于一台16c 32G的纯CPU的机器来搭建 纯docker 打造 2.效果 3.概念解析 Prompt Engineering : 提示词工程 RAG: 检索增强生成; …

PDE求格林函数

求Green函数 通俗地解释拉普拉斯方程的基本解的意义 拉普拉斯方程的基本解是一个非常有用的数学概念,它帮助我们理解在某一个点施加一个非常小的影响(比如一个微小的推动、热源或电荷)时,这种影响是如何在整个空间中扩散和影响其…

业内PMP考试哪家机构通过率高?

选择培训机构时,通过率并不是唯一的标准。PMP培训机构避坑指南,如何选择可靠的机构?哪些是虚假误导?哪些是真正的优质培训机构? 20家业内PMP机构测评 干扰项总结(一)【各种虚假排行榜】 这个行业首先不存在官方的机构…

会议文字记录工具【钉钉闪记】

当开会时,需要文字记录会议内容,但是打字又慢,可以使用钉钉闪记。 钉钉工作台直接搜索-钉钉闪记

【注释和反射】类加载的过程

继上一篇博客【注释和反射】获取class类实例的方法-CSDN博客 目录 三、类加载的过程 例子 三、类加载的过程 在Java虚拟机(JVM)中,类加载是一个将类的字节码文件从文件系统或其他来源加载到JVM的内存中,并将其转换为类或接口的…

napi —— linux 网卡驱动收包机制

linux 操作系统一般指 linux 内核。在 linux 上开发应用的时候,可以使用 linux 提供的系统调用。linux 内核管理着机器上的硬件资源:内存,磁盘,网卡等。开发应用的时候不能直接操作这些硬件,而只能通过系统调用来使用…

初识C++ · 类和对象(中)(2)

前言:上篇文章已经介绍了6个默认成员函数中的3个函数,分别是构造函数,析构函数,拷贝构造函数,本文介绍的是后三个,赋值运算符重载,const成员函数,取地址操纵符重载。 目录​​​​​…

全世界IT人苦竞业久矣!美国FTC宣布全面废除员工竞业协议

2023 年 1 月,美国联邦贸易委员会(FTC)发布声明称,拟在全国范围禁止用人单位与雇员签订竞业禁止性条款。当地时间 4 月 23 日,FTC 宣布全面禁止所有员工(包括高级管理人员)签署新的竞业禁止协议…

Vue3+Echarts: 浏览器缩小后,图表内容发生重叠

一、问题 Vue3Echarts项目:浏览器缩小后,图表内容发生重叠。本文将提供几个解决上述问题的思路,后续有新的解决思路将在此处进行补充。 二、解决思路 1、动态调整ECharts配置 如果图表容器的尺寸没有随着浏览器窗口的缩小而进行相应地调整…