xrpc: 一个基于消息队列的的Go语言RPC框架

文章目录

    • 前言
    • XRPC的特性
    • XRPC的实现
      • 通信
      • 编码/解码
      • 服务调用
    • 总结

项目地址:
GitHub
Gitee

前言

RPC作为分布式系统中的基础组件, 使用非常广泛。大多数的RPC框架都是基于点对点的网络连接, 比如golang原生的rpc框架、grpc等.

点对点连接的通讯方式, 随着集群节点的增加, 会导致集群的拓扑结构越来越复杂, 服务之间的耦合度越来越高, 服务的扩展性和可维护性都会受到影响.

而消息队列的通讯方式, 可以很好的解决这个问题。每个服务只需要关注自己订阅的消息, 不需要关心消息的发送者是谁, 也不需要关心消息的接收者是谁.

XRPC设计的原则是为了实现一套基于消息队列的、易于拓展和易于使用的轻量级RPC框架.

XRPC的特性

除了上面提到的使用消息队列作为RPC的通道之外, XRPC还有以下几个比较实用的特点

  • 支持任意参数数量的远程调用, 不需要把接口的参数都打包成一个结构体再调用, 可以像调用本地函数一样
  • 支持CallCast两种远程调用方式, Call会一直阻塞直到接收到返回值或者超时, 而Cast适用于不需要等待返回值的情况
  • 代码生成, 实现了一套IDL, 最大程度贴近go语法, 用来定义rpc服务的接口信息, 自动生成接口代码

此外, XRPC的核心代码非常精简, 而且非常容易拓展.

XRPC的实现

一个RPC框架可以大体分为三个部分:通信、编码/解码、服务调用. 我从这三个方面分别介绍XRPC是怎么做的.

XRPC的每个服务都会订阅一个主题, 等待接收远程调用的消息, 每个服务可以注册多个接口. 客户端将要调用的接口和参数序列化后发布到对应的主题, 服务端收到消息后利用反射调用对应接口, 并将结果通过消息队列返回客户端.

通信

XRPC抽象出了一套消息队列接口

type MQueen interface {GenerateSubj() stringPublish(string, []byte) errorSubscribe(string, MQCallback) errorUnSubscribe() error
}
  • GenerateSubj 生成一个唯一的订阅主题名
  • Publish 发布一条消息到指定的主题
  • Subscribe 订阅指定的主题
  • UnSubscribe 取消订阅

要拓展使用其他的消息队列, 只需要实现MQueen接口即可, 目前实现的有nats.

编码/解码

编码/解码部分XRPC也抽象了一个接口

type Codec interface
{Unmarshal(b []byte, dst any) errorMarshal(v any) ([]byte, error)
}

同样只要实现这个接口就可以拓展自己的序列化方式, 目前实现的有gob、protobuf, 默认采用gob

服务调用

XRPC的支持注册任意数量参数的接口, 以及CallCast两种远程调用方式.
并且实现了一套IDL, 最大程度贴近go语法, 用来定义rpc接口信息, 并自动生成相关代码, 下面是一个简单的例子.

首先定义我们的RPC服务接口hello.service

package main service HelloService {Hello(string) (string, error)
}

可以看到语法和Go非常类似, 它里面定义了一个名叫HelloService服务, 包含一个Hello方法, 有一个参数两个返回值.

一个文件里面可以定义多个服务, 每个服务可以定义多个接口, 接口支持任意数量的参数.

然后生成接口代码, 执行下面的命令会在当前目录生成一个hello.service.go文件

xrpc hello.service

接下来就可以实现我们的RPC服务

type HelloRPCService struct {*xrpc.RPCServer
}func (s *HelloRPCService) Hello(request string) (string, error) {reply := "hello:" + requestreturn reply, nil
}// 创建服务
func newHelloService(nc *nats.Conn) *HelloRPCService {s := &HelloRPCService{RPCServer: xrpc.NewRPCServer(xrpc.SetMQ(natsmq.NewMQueen(nc)),xrpc.SetSubj("hello_server"),),}RegisterHelloServiceServer(s.RPCServer, s)return s
}
  • HelloRPCService 实现了我们定义的RPC接口,
  • Hello 接口将收到的消息添加"hello:"前缀并将结果返回
  • newHelloService 方法用来创建RPC服务, 采用nats消息队列, 指定订阅的主题为hello_server

接下来创建RPC客户端

func newHelloRPCServiceClient(nc *nats.Conn) *HelloServiceClient {return NewHelloServiceClient(xrpc.NewRPCClient(xrpc.SetMQ(natsmq.NewMQueen(nc)),xrpc.SetSubj("hello_client"),))
}

现在我们就可以调用远程接口了

func main() {nc, err := nats.Connect("nats://127.0.0.1:4222", nats.MaxReconnects(1000))if err != nil {panic(err)}defer nc.Close()// 启动RPC服务s := newHelloService(nc)err = s.Start()if err != nil {panic(err)}defer s.Stop()// 创建RPC客户端c := newHelloRPCServiceClient(nc)defer c.Close()// 调用Hello方法, 第一个参数是rpc服务的名称reply, err := c.Hello("hello_server", "yc90s")if err != nil {panic(err)}fmt.Println(reply) // 输出: hello:yc90s
}

Hello接口的第一个参数是RPC服务订阅的主题名, 例子里是hello_server, 后面的参数是传递给远程接口实际调用的参数, 程序最后输出"hello:yc90s"

总结

RPC作为分布式系统中基础又重要的一个组件, 所以我将其单独开源出来, 后续会再xrpc基础上, 再开源一个分布式服务器框架, 欢迎感兴趣的同学一起交流

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

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

相关文章

(全注解开发)学习Spring-MVC的第三天

全注解开发 第一部分 : 1.1 消除spring-mvc.xml 这些是原来spring-mvc.xml配置文件的内容 <!--1、组件扫描, 使Controller可以被扫描到--><context:component-scan base-package"com.itheima.controller"/><!--2、非自定义的Bean, 文件上传解析器--&…

mysql-多表查询-外连接

一、外连接查询语法 &#xff08;1&#xff09;左外连接 select 所要查询的内容 from 左表 left outer join 右表 on 条件; &#xff08;2&#xff09;右外连接 select 所要查询的内容 from 左表 right outer join 右表 on 条件; 二、示例 用以下两张表示例 左外连接 右外…

Pyglet综合应用|推箱子游戏之关卡图片载入内存

目录 读取图片 分割图片 综合应用 本篇为之前写的博客《怎样使用Pyglet库给推箱子游戏画关卡地图》的续篇&#xff0c;内容上有相关性&#xff0c;需要阅读的请见链接&#xff1a; https://hannyang.blog.csdn.net/article/details/136209138 「推箱子」是一款风靡全球的益…

c++内存的四大分区详解

目录 前言&#xff1a; 1、程序的基本运行流程 2&#xff0c;为啥要分为四个区域&#xff1f; 3&#xff0c;分为哪四个区域&#xff1f; 4&#xff0c;4个区域详解 代码区&#xff1a; 为什么会设置这两个功能呢&#xff1f; 全局区&#xff1a; 栈区&#xff1a; 堆…

system V 共享内存

1.共享内存的原理 要理解共享内存的原理&#xff0c;首先我们得记起进程间通信的前提&#xff1a;必须让不同的进程看到同一份资源&#xff08;必须由OS提供&#xff09; 我们都知道进程都会有自己的进程地址空间&#xff0c;然后都会通过页表与物理内存进行映射&#xff0c;…

图纸透明加密:保护机械图纸安全的新方法

随着信息技术的不断发展&#xff0c;机械制造行业对于图纸安全的需求越来越高。机械图纸是企业的核心竞争力之一&#xff0c;泄露可能导致严重的商业损失和技术风险。为了解决这一问题&#xff0c;图纸透明加密成为了一种新的保护机械图纸安全的方法。本文将介绍图纸透明加密的…

面试字节跳动,我被怼的好狠,怎一个惨字了得

人们都说&#xff0c;这个世界上有两种人注定单身&#xff0c;一种是太优秀的&#xff0c;另一种是太平凡的。 我一听呀&#xff1f;那我这岂不是就不优秀了吗&#xff0c;于是毅然决然和女朋友分了手。 人们都说&#xff0c;互联网寒冬来了&#xff0c;这个时候还在大面积招人…

【LeetCode】343. 整数拆分(中等)——代码随想录算法训练营Day40

题目链接&#xff1a;343. 整数拆分 题目描述 给定一个正整数 n &#xff0c;将其拆分为 k 个 正整数 的和&#xff08; k > 2 &#xff09;&#xff0c;并使这些整数的乘积最大化。 返回 你可以获得的最大乘积 。 示例 1: 输入: n 2 输出: 1 解释: 2 1 1, 1 1 1。…

从零开始手写mmo游戏从框架到爆炸(二十一)— 战斗系统二

导航&#xff1a;从零开始手写mmo游戏从框架到爆炸&#xff08;零&#xff09;—— 导航-CSDN博客 上一章&#xff08;从零开始手写mmo游戏从框架到爆炸&#xff08;二十&#xff09;— 战斗系统一-CSDN博客&#xff09;我们只是完成了基本的战斗&#xff0c;速度属性并没有…

R语言数据分析(三)

R语言数据分析&#xff08;三&#xff09; 文章目录 R语言数据分析&#xff08;三&#xff09;一、可视化步骤1.1 创建ggplot1.2 添加美学和图层1.3 简化代码 二、可视化分布2.1 分类变量2.2 数值变量 三、可视化关系3.1 数值变量和分类变量3.2 两个分类变量3.3 两个数值变量3.…

C++的STL都由什么组成

C标准模板库&#xff08;STL&#xff09;是C语言的一部分&#xff0c;提供了一系列模板类和函数&#xff0c;旨在帮助程序员处理常见的编程任务&#xff0c;如数据结构和算法操作。 STL主要包括四大组件&#xff1a; 容器&#xff08;Containers&#xff09;、 迭代器&#xff…

虚拟机器centos7无法识别yum 命令异常处理笔记

问题现象 启动虚拟机后执行ipconfig 提示未找到该命令,然后执行yum install -y net-tools提示 curl#6 - "Could not resolve host: mirrorlist.centos.org; 未知的错误"的错误 [roothaqdoop~]# ifconfig -bash: ifconfig: 未找到命令 [roothadoop~]# yum install …

以Scala官方提供的方法解读TraversableOnce

代码提供 让我们先来看Scala中提供的一段代码 static List toList$(final TraversableOnce $this) { return $this.toList(); } default List toList() {return (List)this.to(scala.collection.immutable.List..MODULE$.canBuildFrom()); } 上述代码片段是Scala中的两个方…

Android自编译Pixel3内核加入KernelSU

背景 让Pixel3 AOSP Android10 4.9内核用上Kernel SU 环境: Ubuntu 18.04 vm aosp10r2 移植参考官方,和github项目 Commits OnlyTomInSecond/android_kernel_xiaomi_sdm845 (github.com) 这个项目是 LineageOS/android_kernel_xiaomi_sdm845 编译的前提 已经有完整…

超级抽象的前端2

vue3的调用方法失败的原因 function validateConfirm(rule, value, callback) {if (value ! form.password) {callback(new Error(两次输入的密码不一致))} else {callback()}function showAgreement() {dialogVisible.value true}function submitForm() {// 这里是提交表单的…

逆推求期望DP

我的开始的想法&#xff1a;状态设置 dp[i][j] 为玩了 i 个职业 j 个阵营的期望天数&#xff0c;初始值很好解决 dp[1][1]1 &#xff0c;但是有个问题&#xff0c;每对 (i,j) 除了边界那里&#xff0c;会由三个地方来决定这一个(i-1,j-1)(i,j-1)(i-1,j)&#xff0c;所以&#x…

LayUI发送Ajax请求

页面初始化操作 var processData null $(function () {initView();initTable();// test(); })function initView() {layui.use([laydate, form], function () {var laydate layui.laydate;laydate.render({elem: #applyDateTimeRange,type: datetime,range: true});}); }初始…

【spring】 ApplicationListener的使用及原理简析

文章目录 使用示例&#xff1a;原理简析&#xff1a; 前言&#xff1a;ApplicationListener 是spring提供的一个监听器&#xff0c;它可以实现一个简单的发布-订阅功能&#xff0c;用有点外行但最简单通俗的话来解释&#xff1a;监听到主业务在执行到了某个节点之后&#xff0c…

Elasticsearch中可避免的坑

版本定位&#xff1a;7.x 总结的坑&#xff1a; term及terms词条查询时&#xff0c;如果有text及keyword类型&#xff0c;则需加.keywordqueryString全字段搜索时&#xff0c;最好指定字段&#xff1b;并要提前设置好字段mapping&#xff1a;keyword并指定分词器。reindex做数…

【ACM出版】第五届计算机信息和大数据应用国际学术会议(CIBDA 2024)

第五届计算机信息和大数据应用国际学术会议&#xff08;CIBDA 2024&#xff09; 2024 5th International Conference on Computer Information and Big Data Applications 重要信息 大会官网&#xff1a;www.ic-cibda.org 大会时间&#xff1a;2024年3月22-24日 大会地点&#…