仿`gRPC`功能实现像调用本地方法一样调用其他服务器方法
文章目录
仿 gRPC
功能实现像调用本地方法一样调用其他服务器方法
gRPC
功能实现像调用本地方法一样调用其他服务器方法 简介
在介绍gRPC
简介之前我们先了解一写概念:
单体架构
单体架构简单理解就是所有的业务代码都在一台服务器上,一旦某个服务宕机,会引起整个应用不可用,隔离性差。只能整体应用进行伸缩,例如整体打包部署一台或多台服务器,浪费资源,可伸缩性差。代码耦合在一起,可维护性差。
微服务架构
解决了单体架构的弊端。可按需拆成多个服务,例如针对用户的请求非常多,针对支付的请求少,可以将用户业务功能拆为多个服务器,支付业务功能拆为单个服务器。
也有一些弊端,例如代码冗余,同样的代码在多个服务器上都要写,例如接口等。服务与服务之间存在调用关系,服务拆分之后,就是服务和服务之间发生是进程与进程之间的调用,服务器与服务器之间的调用。
这时候就需要发起网络调用, 网络调用一般使用HTTP
,但是在微服务架构中,HTTP
虽然方便,但性能较低,这时候就需要引入RPC
(远程过程调用),通过自定义协议发起TCP
调用,来加快传输效率。
RPC
RPC
的全称是Remote Procedure Call
,远程过程调用。这是一种协议,是用来屏蔽分布式计算中的各种调用细节,使得你可以像是本地调用一样直接调用一个远程的函数。
gPRC
gRPC
是一个高性能、开源和通用的RPC
框架,面向移动和 HTTP/2
设计。目前提供 C
、Java
和 Go
语言版本,分别是:grpc
, grpc-java
, grpc-go.
其中 C
版本支持 C
, C++
, Node.js
, Python
, Ruby
, Objective-C
, PHP
和 C#
支持。
中文文档: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
作为服务端。
编写客户端方法
- 首先在客户端也就是调用端创建客户端类
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
}}
- 创建空类
M.Login
,M.Pay
,M.Stock
分别继承Util.RPC.Client
。- 目的是模拟交互接口,因为要调用其他服务器方法,首先要确定要调用的服务器接口名称。
-
按照常规调用方法的模式,来编写方法。
-
这里实际上是没有
Login
,Pay
,Stock
方法的,因为上一步创建的类为空类。 -
如果按照常规直接调用方法肯定会提示方法不存在的错误,这里实际上我们调用的是服务端的方法。
-
可以观察到,这里是按照正常调用类方法的方式编写的代码,并没有其他额外的操作。
-
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),!
}}
编写服务端方法
- 创建服务端监听
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
}}
-
编写服务端
M.Login
的Login
方法,M.Pay
的Pay
方法,M.Stock
的Stock
方法。-
这里使用
IRIS
当服务端,实现的方法都在服务端,客户端是没有该方法的。 -
客户端调用的方法实际上是服务端的上的方法。
-
综合演示
-
IRIS
服务端开启监听方法。 -
客户端
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: """第一,向量化匹配是有能力上限的。搜索引擎实现语义搜索已经是好几年的事情了…...
论文解读:交大港大上海AI Lab开源论文 | 宇树机器人多姿态起立控制强化学习框架(二)
HoST框架核心实现方法详解 - 论文深度解读(第二部分) 《Learning Humanoid Standing-up Control across Diverse Postures》 系列文章: 论文深度解读 + 算法与代码分析(二) 作者机构: 上海AI Lab, 上海交通大学, 香港大学, 浙江大学, 香港中文大学 论文主题: 人形机器人…...

Docker 运行 Kafka 带 SASL 认证教程
Docker 运行 Kafka 带 SASL 认证教程 Docker 运行 Kafka 带 SASL 认证教程一、说明二、环境准备三、编写 Docker Compose 和 jaas文件docker-compose.yml代码说明:server_jaas.conf 四、启动服务五、验证服务六、连接kafka服务七、总结 Docker 运行 Kafka 带 SASL 认…...
Auto-Coder使用GPT-4o完成:在用TabPFN这个模型构建一个预测未来3天涨跌的分类任务
通过akshare库,获取股票数据,并生成TabPFN这个模型 可以识别、处理的格式,写一个完整的预处理示例,并构建一个预测未来 3 天股价涨跌的分类任务 用TabPFN这个模型构建一个预测未来 3 天股价涨跌的分类任务,进行预测并输…...
数据链路层的主要功能是什么
数据链路层(OSI模型第2层)的核心功能是在相邻网络节点(如交换机、主机)间提供可靠的数据帧传输服务,主要职责包括: 🔑 核心功能详解: 帧封装与解封装 封装: 将网络层下发…...
Python如何给视频添加音频和字幕
在Python中,给视频添加音频和字幕可以使用电影文件处理库MoviePy和字幕处理库Subtitles。下面将详细介绍如何使用这些库来实现视频的音频和字幕添加,包括必要的代码示例和详细解释。 环境准备 在开始之前,需要安装以下Python库:…...
【C语言练习】080. 使用C语言实现简单的数据库操作
080. 使用C语言实现简单的数据库操作 080. 使用C语言实现简单的数据库操作使用原生APIODBC接口第三方库ORM框架文件模拟1. 安装SQLite2. 示例代码:使用SQLite创建数据库、表和插入数据3. 编译和运行4. 示例运行输出:5. 注意事项6. 总结080. 使用C语言实现简单的数据库操作 在…...

多模态大语言模型arxiv论文略读(108)
CROME: Cross-Modal Adapters for Efficient Multimodal LLM ➡️ 论文标题:CROME: Cross-Modal Adapters for Efficient Multimodal LLM ➡️ 论文作者:Sayna Ebrahimi, Sercan O. Arik, Tejas Nama, Tomas Pfister ➡️ 研究机构: Google Cloud AI Re…...
力扣-35.搜索插入位置
题目描述 给定一个排序数组和一个目标值,在数组中找到目标值,并返回其索引。如果目标值不存在于数组中,返回它将会被按顺序插入的位置。 请必须使用时间复杂度为 O(log n) 的算法。 class Solution {public int searchInsert(int[] nums, …...
LeetCode - 199. 二叉树的右视图
题目 199. 二叉树的右视图 - 力扣(LeetCode) 思路 右视图是指从树的右侧看,对于每一层,只能看到该层最右边的节点。实现思路是: 使用深度优先搜索(DFS)按照"根-右-左"的顺序遍历树记录每个节点的深度对于…...
【SSH疑难排查】轻松解决新版OpenSSH连接旧服务器的“no matching...“系列算法协商失败问题
【SSH疑难排查】轻松解决新版OpenSSH连接旧服务器的"no matching..."系列算法协商失败问题 摘要: 近期,在使用较新版本的OpenSSH客户端连接老旧SSH服务器时,会遇到 "no matching key exchange method found", "n…...