当前位置: 首页 > news >正文

仿`gRPC`功能实现像调用本地方法一样调用其他服务器方法

文章目录

  • 仿`gRPC`功能实现像调用本地方法一样调用其他服务器方法
    • 简介
        • 单体架构
        • 微服务架构
        • `RPC`
        • `gPRC`
    • `gRPC`交互逻辑
        • 服务端逻辑
        • 客户端逻辑
        • 示例图
    • 原生实现仿`gRPC`框架
        • 编写客户端方法
        • 编写服务端方法
        • 综合演示

仿 gRPC功能实现像调用本地方法一样调用其他服务器方法

简介

在介绍gRPC简介之前我们先了解一写概念:

单体架构

单体架构简单理解就是所有的业务代码都在一台服务器上,一旦某个服务宕机,会引起整个应用不可用,隔离性差。只能整体应用进行伸缩,例如整体打包部署一台或多台服务器,浪费资源,可伸缩性差。代码耦合在一起,可维护性差。

微服务架构

解决了单体架构的弊端。可按需拆成多个服务,例如针对用户的请求非常多,针对支付的请求少,可以将用户业务功能拆为多个服务器,支付业务功能拆为单个服务器。

也有一些弊端,例如代码冗余,同样的代码在多个服务器上都要写,例如接口等。服务与服务之间存在调用关系,服务拆分之后,就是服务和服务之间发生是进程与进程之间的调用,服务器与服务器之间的调用。

这时候就需要发起网络调用, 网络调用一般使用HTTP,但是在微服务架构中,HTTP虽然方便,但性能较低,这时候就需要引入RPC(远程过程调用),通过自定义协议发起TCP调用,来加快传输效率。

RPC

RPC的全称是Remote Procedure Call,远程过程调用。这是一种协议,是用来屏蔽分布式计算中的各种调用细节使得你可以像是本地调用一样直接调用一个远程的函数。

gPRC

gRPC 是一个高性能、开源和通用的RPC 框架,面向移动和 HTTP/2 设计。目前提供 CJavaGo 语言版本,分别是:grpc, grpc-java, grpc-go. 其中 C 版本支持 C, C++, Node.js, Python, Ruby, Objective-C, PHPC# 支持。

中文文档:http://doc.oschina.net/grpc

gRPC中,我们称调用方为client,被调用方为server。跟其他的RPC框架一样,gRPC也是基于服务定义的思想。简单的来讲,就是我们通过某种方式来描述一个服务,这种描述方式是语言无关的。在这个服务定义的过程中,我们描述了我们提供的服务服务名是什么,有哪些方法可以被调用,这些方法有什么样的入参,有什么样的回参。

也就是说,在定义好了这些服务、这些方法之后,gRPC会屏蔽底层的细节,client只需要直接调用定义好的方法,就能拿到预期的返回结果。对于server端来说,还需要实现我们定义的方法。同样的,gRPC也会帮我们屏蔽底层的细节,我们只需要实现所定义的方法的具体逻辑即可。

可以发现,在上面的描述过程中,所谓的服务定义,就跟定义接口的语义是很接近的。我更愿意理解为这是一种"约定”,双方约定好接口,然后server实现这个接口,client调用这个接口的代理对象。到于其他的细节,交给gRPC

gRPC交互逻辑

服务端逻辑

  • 创建gRPC Server对象,可以理解为它是Server端的抽象对象。
  • server(其包含需要被调用的服务端接口)注册到gRPC Server的内部注册中心。
    • 这样可以在接受到请求时,通过内部的服务发现。发现该服务端接口并转接进行逻辑处理。
  • 创建Listen,监听TCP端口。
  • gRPC Server开始lis.Accept,直到Stop

客户端逻辑

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

示例图

如下图:业务服务器调用登录业务服务器,支付服务器,库存服务器。

在这里插入图片描述

原生实现仿gRPC框架

因为gRPC框架目前不支持IRIS/Caché,所以这里我们了解gRPC原理后,仿造gRPC框架实现类似的功能。通过正常编写代码无感知的情况下调用其他服务器上的代码方法。

注:为了显示这里使用Caché作为客户端,IRIS作为服务端。

编写客户端方法

  1. 首先在客户端也就是调用端创建客户端类Util.RPC.Client,代码如下:
    • %DispatchClassMethod - 动态派发方法是实现无感知的关键。
    • SERVERIP - 目标服务端的IP地址。
    • PORT - 目标服务端的端口号。
Class Util.RPC.Client Extends %RegisteredObject
{Parameter SERVERIP = "127.0.0.1";Parameter PORT = 7788;ClassMethod %DispatchClassMethod(class As %String, method As %String, args...) [ ServerOnly = 1 ]
{#; 客户端通信、客户端需要设置服务器IP与端口号#dim clientSocket As %IO.Socket = ##class(%IO.Socket).%New()s host = ..#SERVERIPs port = ..#PORTs clientSocket.TranslationTable = "UTF8"d clientSocket.Open(host, port, .sc)s obj = {}	//注释1s obj.class = classs obj.method = methods params = []s i = ""for {s i = $o(args(i))q:(i = "")d params.%Push(args(i))}s obj.params = paramsd clientSocket.WriteLine(obj.%ToJSON())	//注释2while (1) {s data = clientSocket.ReadLine() if (data '= "" ){	//注释3ret data}}q $$$OK
}}
  1. 创建空类M.LoginM.PayM.Stock分别继承Util.RPC.Client
    • 目的是模拟交互接口,因为要调用其他服务器方法,首先要确定要调用的服务器接口名称。

在这里插入图片描述

  1. 按照常规调用方法的模式,来编写方法。

    • 这里实际上是没有LoginPayStock方法的,因为上一步创建的类为空类。

    • 如果按照常规直接调用方法肯定会提示方法不存在的错误,这里实际上我们调用的是服务端的方法。

    • 可以观察到,这里是按照正常调用类方法的方式编写的代码,并没有其他额外的操作。

Class M.RPC Extends %RegisteredObject
{/// d ##class(M.RPC).Biz()
ClassMethod Biz()
{w ##class(M.Login).Login("yx","123456"),!w ##class(M.Pay).Pay(100),!w ##class(M.Stock).Stock(3),!
}}

编写服务端方法

  1. 创建服务端监听Util.RPC.Server类,这里模拟的是gRPC 创建Server对象,创建Listen,监听TCP端口。代码如下:
    • 参数PORT为服务端监听和开启的接口。
Class Util.RPC.Server Extends %RegisteredObject
{Parameter PORT = 7788;/// d ##class(Util.RPC.Server).ServerRPC()
ClassMethod ServerRPC()
{#; 服务端通信、服务端需要打开端口,等待客户端通信#dim severSocket As %IO.ServerSocket = ##class(%IO.ServerSocket).%New()s port = ..#PORTs severSocket.TranslationTable="UTF8"s severSocket.ConnectionQueueSize = 2d severSocket.Open(port, 10, .sc)q:($$$ISERR(sc)) "Open:" _ $System.Status.GetOneErrorText(sc)d severSocket.Listen(10, .sc)q:($$$ISERR(sc)) "Listen:" _ $System.Status.GetOneErrorText(sc)while (1) {s data =  severSocket.ReadLine()if (data '= "") {s obj = {}.%FromJSON(data)	//注释1s arg = obj.params.%Size()for i = 1 : 1 : arg{s arg(i) = obj.params.%Get(i - 1)}s ret = $classmethod(obj.class, obj.method, arg...)	//注释2d severSocket.WriteLine(ret)	//注释3}}q $$$OK
}}
  1. 编写服务端M.LoginLogin方法,M.PayPay方法,M.StockStock方法。

    • 这里使用IRIS当服务端,实现的方法都在服务端,客户端是没有该方法的。

    • 客户端调用的方法实际上是服务端的上的方法。

在这里插入图片描述

综合演示

  1. IRIS服务端开启监听方法。

  2. 客户端Caché调用无感知业务逻辑业务员Biz()方法。

    • 可观察到客户端直接调用到了服务端的方法,并且编码方式跟正常编写代码并无差别。

    • 客户端不需要了解底层的细节,client只需要直接调用定义好的方法。

在这里插入图片描述

通过这种方式我们就实现了类似gRPC的功能,像正常编写代码一样调用服务端的程序。

创造价值,分享学习,一起成长,相伴前行,欢迎大家提出意见,共同交流。

相关文章:

仿`gRPC`功能实现像调用本地方法一样调用其他服务器方法

文章目录 仿gRPC功能实现像调用本地方法一样调用其他服务器方法 简介单体架构微服务架构RPCgPRC gRPC交互逻辑服务端逻辑客户端逻辑示例图 原生实现仿gRPC框架编写客户端方法编写服务端方法综合演示 仿 gRPC功能实现像调用本地方法一样调用其他服务器方法 简介 在介绍gRPC简介…...

分布式环境下的数据同步

一般而言elasticsearch负责搜索(查询),而sql数据负责记录(增删改),elasticsearch中的数据来自于sql数据库,因此sql数据发生改变时,elasticsearch也必须跟着改变,这个就是…...

无涯教程-Flutter - 数据库

SQLite" class"css-1occaib">SQLite数据库是基于事实和标准SQL的嵌入式数据库引擎,它是小型且经过时间考验的数据库引擎,sqflite软件包提供了许多函数,可以有效地与SQLite数据库一起使用,它提供了操作SQLite数据…...

算法笔记:平衡二叉树

1 介绍 平衡二叉树(AVL树)是一种特殊的二叉搜索树(BST),它自动确保树保持低高度,以便实现各种基本操作(如添加、删除和查找)的高效性能。 ——>时间都维持在了O(logN)它是一棵空…...

redis 通用命令

目录 通用命令是什么 SET & GET keys EXISTS DEL EXPIRE TTL redis 的过期策略 定时器策略 基于优先级队列定时器 基于时间轮的定时器 TYPE 通过 redis 客户端和 redis 服务器交互。 所以需要使用 redis 的命令,但是 redis 的命令非常多。 通用命令…...

Pycharm配置及使用Git教程

文章目录 1. 安装PyCharm2. 安装Git3. 在PyCharm中配置Git插件4. 连接远程Gtilab仓库5. Clone项目代码6. 将本地文件提交到远程仓库6.1 git add6.2 git commit6.3 git push6.4 git pull 平时习惯在windows下开发,但是我们又需要实时将远方仓库的代码clone到本地&…...

CSS transition 过渡

1 前言 水平居中、垂直居中是前端面试百问不厌的问题。 其实现方案也是多种多样,常叫人头昏眼花。 水平方向可以认为是内联方向,垂直方向认为是块级方向。 下面介绍一些常见的方法。 2 内联元素的水平垂直居中 首先,常见内联元素有&…...

Unity中Shader的UV扭曲效果的实现

文章目录 前言一、实现的思路1、在属性面板暴露一个 扭曲贴图的属性2、在片元结构体中,新增一个float2类型的变量,用于独立存储将用于扭曲的纹理的信息3、在顶点着色器中,根据需要使用TRANSFORM_TEX对Tilling 和 Offset 插值;以及…...

Automotive 添加一个特权APP

Automotive 添加一个特权APP platform: android-13.0.0_r32 一. 添加一个自定义空调的app为例 路径:packages/apps/Car/MyHvac app内容可以自己定义,目录结构如下: 1.1 Android.bp package {default_applicable_licenses: ["Andr…...

自定义TimeLine

自定义TimeLine 什么是TimeLineData(数据)Clip(片段)Track(轨道)Mixer(混合) 什么是TimeLine 在 Unity 中,TimeLine(时间轴)是一种用于创建和管理…...

如何使用SQL系列 之 如何在SQL中使用WHERE条件语句

引言 在结构化查询语言 (SQL)语句中,WHERE子句限制了给定操作会影响哪些行。它们通过定义特定的条件(称为搜索条件)来实现这一点,每一行都必须满足这些条件才能受到操作的影响。 本指南将介绍WHERE子句中使用的通用语法。它还将概述如何在单个WHERE子句…...

leetcode:1941. 检查是否所有字符出现次数相同(python3解法)

难度:简单 给你一个字符串 s ,如果 s 是一个 好 字符串,请你返回 true ,否则请返回 false 。 如果 s 中出现过的 所有 字符的出现次数 相同 ,那么我们称字符串 s 是 好 字符串。 示例 1: 输入:s…...

Echarts 各种点击事件监听

目录 一、鼠标事件1.1、左击1.2、双击1.3、右击1.4、右键双击1.5、中轴滚动二、时间轴2.1、时间轴监听三、拖动3.1、拖动事件一、鼠标事件 1.1、左击 chart.on(click, function(params)...

《智能网联汽车自动驾驶功能测试规程》

一、 编制背景 2018 年4 月12 日,工业和信息化部、公安部、交通运输部联合发布《智能网联汽车道路测试管理规范(试行)》(以下简称《管理规范》),对智能网联汽车道路测试申请、审核、管理以及测试主体、测试驾驶人和测试车辆要求等…...

NVIDIA CUDA Win10安装步骤

前言 windows10 版本安装 CUDA ,首先需要下载两个安装包 CUDA toolkit(toolkit就是指工具包)cuDNN 1. 安装前准备 在安装CUDA之前,需要完成以下准备工作: 确认你的显卡已经正确安装,在设备管理器中可以看…...

Elasticsearch、Kibana以及Java操作ES 的快速使用

docker 安装elastic search 、 kibana(可视化管理elastic search) docker pull elasticsearch:7.12.1 docker pull kibana:7.12.1创建docker自定义网络 docker自定义网络可以使得容器之间使用容器名网络互连,默认的网络不会有这功能。 一定…...

逐鹿人形机器人,百度、腾讯、小米卷起来

长期不温不火的人形机器人产业迎来新风口,技术显著提升、新品层出不穷、资本投资态度也逐渐好转。 8月18日,2023世界机器人大会博览会正式开放,全面展示了机器人行业的新技术、新产品和新应用。据悉,此次展会展览总面积达4.5万平…...

AndroidStudio推荐下载和配置

1、推荐下载链接 Download Android Studio & App Tools - Android Developers 2、gradle配置案例 // Top-level build file where you can add configuration options common to all sub-projects/modules.buildscript {repositories {maven { url https://maven.aliyun.…...

mysql异常占用资源排查

通过执行日志与连接信息排查 查看是否开启日志记录 mysql> show global variables like %general%; --------------------------------- | Variable_name | Value | --------------------------------- | general_log | OFF | | general_log_file…...

requests 库:发送 form-data 格式的 http 请求 (python)

安装 requests-toolbelt !pip install requests-toolbeltdemo from requests_toolbelt import MultipartEncoder import requestsm MultipartEncoder(fields{query: """第一,向量化匹配是有能力上限的。搜索引擎实现语义搜索已经是好几年的事情了…...

C++初阶-list的底层

目录 1.std::list实现的所有代码 2.list的简单介绍 2.1实现list的类 2.2_list_iterator的实现 2.2.1_list_iterator实现的原因和好处 2.2.2_list_iterator实现 2.3_list_node的实现 2.3.1. 避免递归的模板依赖 2.3.2. 内存布局一致性 2.3.3. 类型安全的替代方案 2.3.…...

python打卡day49

知识点回顾: 通道注意力模块复习空间注意力模块CBAM的定义 作业:尝试对今天的模型检查参数数目,并用tensorboard查看训练过程 import torch import torch.nn as nn# 定义通道注意力 class ChannelAttention(nn.Module):def __init__(self,…...

Oracle查询表空间大小

1 查询数据库中所有的表空间以及表空间所占空间的大小 SELECTtablespace_name,sum( bytes ) / 1024 / 1024 FROMdba_data_files GROUP BYtablespace_name; 2 Oracle查询表空间大小及每个表所占空间的大小 SELECTtablespace_name,file_id,file_name,round( bytes / ( 1024 …...

镜像里切换为普通用户

如果你登录远程虚拟机默认就是 root 用户,但你不希望用 root 权限运行 ns-3(这是对的,ns3 工具会拒绝 root),你可以按以下方法创建一个 非 root 用户账号 并切换到它运行 ns-3。 一次性解决方案:创建非 roo…...

拉力测试cuda pytorch 把 4070显卡拉满

import torch import timedef stress_test_gpu(matrix_size16384, duration300):"""对GPU进行压力测试,通过持续的矩阵乘法来最大化GPU利用率参数:matrix_size: 矩阵维度大小,增大可提高计算复杂度duration: 测试持续时间(秒&…...

IT供电系统绝缘监测及故障定位解决方案

随着新能源的快速发展,光伏电站、储能系统及充电设备已广泛应用于现代能源网络。在光伏领域,IT供电系统凭借其持续供电性好、安全性高等优势成为光伏首选,但在长期运行中,例如老化、潮湿、隐裂、机械损伤等问题会影响光伏板绝缘层…...

成都鼎讯硬核科技!雷达目标与干扰模拟器,以卓越性能制胜电磁频谱战

在现代战争中,电磁频谱已成为继陆、海、空、天之后的 “第五维战场”,雷达作为电磁频谱领域的关键装备,其干扰与抗干扰能力的较量,直接影响着战争的胜负走向。由成都鼎讯科技匠心打造的雷达目标与干扰模拟器,凭借数字射…...

QT: `long long` 类型转换为 `QString` 2025.6.5

在 Qt 中,将 long long 类型转换为 QString 可以通过以下两种常用方法实现: 方法 1:使用 QString::number() 直接调用 QString 的静态方法 number(),将数值转换为字符串: long long value 1234567890123456789LL; …...

蓝桥杯 冶炼金属

原题目链接 🔧 冶炼金属转换率推测题解 📜 原题描述 小蓝有一个神奇的炉子用于将普通金属 O O O 冶炼成为一种特殊金属 X X X。这个炉子有一个属性叫转换率 V V V,是一个正整数,表示每 V V V 个普通金属 O O O 可以冶炼出 …...

vulnyx Blogger writeup

信息收集 arp-scan nmap 获取userFlag 上web看看 一个默认的页面,gobuster扫一下目录 可以看到扫出的目录中得到了一个有价值的目录/wordpress,说明目标所使用的cms是wordpress,访问http://192.168.43.213/wordpress/然后查看源码能看到 这…...