深入浅出 RPC - 深入篇

2023-11-18

《深入篇》我们主要围绕 RPC 的功能目标和实现考量去展开,一个基本的 RPC 框架应该提供什么功能,满足什么要求以及如何去实现它?


RPC 功能目标

RPC 的主要功能目标是让构建分布式计算(应用)更容易,在提供强大的远程调用能力时不损失本地调用的语义简洁性。为实现该目标,RPC 框架需提供一种透明调用机制让使用者不必显式的区分本地调用和远程调用,在前文《浅出篇》中给出了一种实现结构,基于 stub 的结构来实现。下面我们将具体细化 stub 结构的实现。


RPC 调用分类

RPC 调用分以下两种:

[plain]   view plain  copy   在CODE上查看代码片 派生到我的代码片
  1. 1. 同步调用  
  2.    客户方等待调用执行完成并返回结果。  
  3. 2. 异步调用  
  4.    客户方调用后不用等待执行结果返回,但依然可以通过回调通知等方式获取返回结果。  
  5.    若客户方不关心调用返回结果,则变成单向异步调用,单向调用不用返回结果。  

异步和同步的区分在于是否等待服务端执行完成并返回结果。


RPC 结构拆解

《浅出篇》给出了一个比较粗粒度的 RPC 实现概念结构,这里我们进一步细化它应该由哪些组件构成,如下图所示。


RPC 服务方通过 RpcServer 去导出(export)远程接口方法,而客户方通过 RpcClient 去引入(import)远程接口方法。客户方像调用本地方法一样去调用远程接口方法,RPC 框架提供接口的代理实现,实际的调用将委托给代理RpcProxy 。代理封装调用信息并将调用转交给RpcInvoker 去实际执行。在客户端的RpcInvoker 通过连接器RpcConnector 去维持与服务端的通道RpcChannel,并使用RpcProtocol 执行协议编码(encode)并将编码后的请求消息通过通道发送给服务方。

RPC 服务端接收器 RpcAcceptor 接收客户端的调用请求,同样使用RpcProtocol 执行协议解码(decode)。解码后的调用信息传递给RpcProcessor 去控制处理调用过程,最后再委托调用给RpcInvoker 去实际执行并返回调用结果。


RPC 组件职责

上面我们进一步拆解了 RPC 实现结构的各个组件组成部分,下面我们详细说明下每个组件的职责划分。

[plain]   view plain  copy   在CODE上查看代码片 派生到我的代码片
  1. 1. RpcServer  
  2.    负责导出(export)远程接口  
  3. 2. RpcClient  
  4.    负责导入(import)远程接口的代理实现  
  5. 3. RpcProxy  
  6.    远程接口的代理实现  
  7. 4. RpcInvoker  
  8.    客户方实现:负责编码调用信息和发送调用请求到服务方并等待调用结果返回  
  9.    服务方实现:负责调用服务端接口的具体实现并返回调用结果  
  10. 5. RpcProtocol  
  11.    负责协议编/解码  
  12. 6. RpcConnector  
  13.    负责维持客户方和服务方的连接通道和发送数据到服务方  
  14. 7. RpcAcceptor  
  15.    负责接收客户方请求并返回请求结果  
  16. 8. RpcProcessor  
  17.    负责在服务方控制调用过程,包括管理调用线程池、超时时间等  
  18. 9. RpcChannel  
  19.    数据传输通道  


RPC 实现分析

在进一步拆解了组件并划分了职责之后,这里以在 Java 平台实现该 RPC 框架概念模型为例,详细分析下实现中需要考虑的因素。

导出远程接口

导出远程接口的意思是指只有导出的接口可以供远程调用,而未导出的接口则不能。在 java 中导出接口的代码片段可能如下:

[java]   view plain  copy   在CODE上查看代码片 派生到我的代码片
  1. DemoService demo   = new ...;  
  2. RpcServer   server = new ...;  
  3. server.export(DemoService.class, demo, options);  

我们可以导出整个接口,也可以更细粒度一点只导出接口中的某些方法,如:

[java]   view plain  copy   在CODE上查看代码片 派生到我的代码片
  1. // 只导出 DemoService 中签名为 hi(String s) 的方法  
  2. server.export(DemoService.class, demo, "hi"new Class<?>[] { String.class }, options);  

java 中还有一种比较特殊的调用就是多态,也就是一个接口可能有多个实现,那么远程调用时到底调用哪个?这个本地调用的语义是通过 jvm 提供的引用多态性隐式实现的,那么对于 RPC 来说跨进程的调用就没法隐式实现了。如果前面DemoService 接口有 2 个实现,那么在导出接口时就需要特殊标记不同的实现,如:

[java]   view plain  copy   在CODE上查看代码片 派生到我的代码片
  1. DemoService demo   = new ...;  
  2. DemoService demo2  = new ...;  
  3. RpcServer   server = new ...;  
  4. server.export(DemoService.class, demo, options);  
  5. server.export("demo2", DemoService.class, demo2, options);  

上面 demo2 是另一个实现,我们标记为 "demo2" 来导出,那么远程调用时也需要传递该标记才能调用到正确的实现类,这样就解决了多态调用的语义。

导入远程接口与客户端代理

导入相对于导出远程接口,客户端代码为了能够发起调用必须要获得远程接口的方法或过程定义。目前,大部分跨语言平台 RPC 框架采用根据 IDL 定义通过 code generator 去生成 stub 代码,这种方式下实际导入的过程就是通过代码生成器在编译期完成的。我所使用过的一些跨语言平台 RPC 框架如 CORBAR、WebService、ICE、Thrift 均是此类方式。

代码生成的方式对跨语言平台 RPC 框架而言是必然的选择,而对于同一语言平台的 RPC 则可以通过共享接口定义来实现。在 java 中导入接口的代码片段可能如下:

[java]   view plain  copy   在CODE上查看代码片 派生到我的代码片
  1. RpcClient client = new ...;  
  2. DemoService demo = client.refer(DemoService.class);  
  3. demo.hi("how are you?");  

在 java 中 'import' 是关键字,所以代码片段中我们用 refer 来表达导入接口的意思。这里的导入方式本质也是一种代码生成技术,只不过是在运行时生成,比静态编译期的代码生成看起来更简洁些。java 里至少提供了两种技术来提供动态代码生成,一种是 jdk 动态代理,另外一种是字节码生成。动态代理相比字节码生成使用起来更方便,但动态代理方式在性能上是要逊色于直接的字节码生成的,而字节码生成在代码可读性上要差很多。两者权衡起来,个人认为牺牲一些性能来获得代码可读性和可维护性显得更重要。

协议编解码

客户端代理在发起调用前需要对调用信息进行编码,这就要考虑需要编码些什么信息并以什么格式传输到服务端才能让服务端完成调用。出于效率考虑,编码的信息越少越好(传输数据少),编码的规则越简单越好(执行效率高)。我们先看下需要编码些什么信息:

[plain]   view plain  copy   在CODE上查看代码片 派生到我的代码片
  1. -- 调用编码 --  
  2. 1. 接口方法  
  3.    包括接口名、方法名  
  4. 2. 方法参数  
  5.    包括参数类型、参数值  
  6. 3. 调用属性  
  7.    包括调用属性信息,例如调用附件隐式参数、调用超时时间等  
  8.   
  9. -- 返回编码 --  
  10. 1. 返回结果  
  11.    接口方法中定义的返回值  
  12. 2. 返回码  
  13.    异常返回码  
  14. 3. 返回异常信息  
  15.    调用异常信息  

除了以上这些必须的调用信息,我们可能还需要一些元信息以方便程序编解码以及未来可能的扩展。这样我们的编码消息里面就分成了两部分,一部分是元信息、另一部分是调用的必要信息。如果设计一种 RPC 协议消息的话,元信息我们把它放在协议消息头中,而必要信息放在协议消息体中。下面给出一种概念上的 RPC 协议消息设计格式:


[plain]   view plain  copy   在CODE上查看代码片 派生到我的代码片
  1. -- 消息头 --  
  2. magic      : 协议魔数,为解码设计  
  3. header size: 协议头长度,为扩展设计  
  4. version    : 协议版本,为兼容设计  
  5. st         : 消息体序列化类型  
  6. hb         : 心跳消息标记,为长连接传输层心跳设计  
  7. ow         : 单向消息标记,  
  8. rp         : 响应消息标记,不置位默认是请求消息  
  9. status code: 响应消息状态码  
  10. reserved   : 为字节对齐保留  
  11. message id : 消息 id  
  12. body size  : 消息体长度  
  13.   
  14. -- 消息体 --  
  15. 采用序列化编码,常见有以下格式  
  16. xml   : 如 webservie soap  
  17. json  : 如 JSON-RPC  
  18. binary: 如 thrift; hession; kryo 等  

格式确定后编解码就简单了,由于头长度一定所以我们比较关心的就是消息体的序列化方式。序列化我们关心三个方面:

1. 序列化和反序列化的效率,越快越好。 
2. 序列化后的字节长度,越小越好。 
3. 序列化和反序列化的兼容性,接口参数对象若增加了字段,是否兼容。

上面这三点有时是鱼与熊掌不可兼得,这里面涉及到具体的序列化库实现细节,就不在本文进一步展开分析了。

传输服务

协议编码之后,自然就是需要将编码后的 RPC 请求消息传输到服务方,服务方执行后返回结果消息或确认消息给客户方。RPC 的应用场景实质是一种可靠的请求应答消息流,和 HTTP 类似。因此选择长连接方式的 TCP 协议会更高效,与 HTTP 不同的是在协议层面我们定义了每个消息的唯一 id,因此可以更容易的复用连接。

既然使用长连接,那么第一个问题是到底 client 和 server 之间需要多少根连接?实际上单连接和多连接在使用上没有区别,对于数据传输量较小的应用类型,单连接基本足够。单连接和多连接最大的区别在于,每根连接都有自己私有的发送和接收缓冲区,因此大数据量传输时分散在不同的连接缓冲区会得到更好的吞吐效率。所以,如果你的数据传输量不足以让单连接的缓冲区一直处于饱和状态的话,那么使用多连接并不会产生任何明显的提升,反而会增加连接管理的开销。

连接是由 client 端发起建立并维持。如果 client 和 server 之间是直连的,那么连接一般不会中断(当然物理链路故障除外)。如果 client 和 server 连接经过一些负载中转设备,有可能连接一段时间不活跃时会被这些中间设备中断。为了保持连接有必要定时为每个连接发送心跳数据以维持连接不中断。心跳消息是 RPC 框架库使用的内部消息,在前文协议头结构中也有一个专门的心跳位,就是用来标记心跳消息的,它对业务应用透明。

执行调用

client stub 所做的事情仅仅是编码消息并传输给服务方,而真正调用过程发生在服务方。server stub 从前文的结构拆解中我们细分了 RpcProcessor 和RpcInvoker 两个组件,一个负责控制调用过程,一个负责真正调用。这里我们还是以 java 中实现这两个组件为例来分析下它们到底需要做什么?

java 中实现代码的动态接口调用目前一般通过反射调用。除了原生的 jdk 自带的反射,一些第三方库也提供了性能更优的反射调用,因此 RpcInvoker 就是封装了反射调用的实现细节。

调用过程的控制需要考虑哪些因素,RpcProcessor 需要提供什么样地调用控制服务呢?下面提出几点以启发思考:

[plain]   view plain  copy   在CODE上查看代码片 派生到我的代码片
  1. 1. 效率提升  
  2.    每个请求应该尽快被执行,因此我们不能每请求来再创建线程去执行,需要提供线程池服务。  
  3. 2. 资源隔离  
  4.    当我们导出多个远程接口时,如何避免单一接口调用占据所有线程资源,而引发其他接口执行阻塞。  
  5. 3. 超时控制  
  6.    当某个接口执行缓慢,而 client 端已经超时放弃等待后,server 端的线程继续执行此时显得毫无意义。  


RPC 异常处理

无论 RPC 怎样努力把远程调用伪装的像本地调用,但它们依然有很大的不同点,而且有一些异常情况是在本地调用时绝对不会碰到的。在说异常处理之前,我们先比较下本地调用和 RPC 调用的一些差异:

1. 本地调用一定会执行,而远程调用则不一定,调用消息可能因为网络原因并未发送到服务方。
2. 本地调用只会抛出接口声明的异常,而远程调用还会跑出 RPC 框架运行时的其他异常。
3. 本地调用和远程调用的性能可能差距很大,这取决于 RPC 固有消耗所占的比重。

正是这些区别决定了使用 RPC 时需要更多考量。当调用远程接口抛出异常时,异常可能是一个业务异常,也可能是 RPC 框架抛出的运行时异常(如:网络中断等)。业务异常表明服务方已经执行了调用,可能因为某些原因导致未能正常执行,而 RPC 运行时异常则有可能服务方根本没有执行,对调用方而言的异常处理策略自然需要区分。

由于 RPC 固有的消耗相对本地调用高出几个数量级,本地调用的固有消耗是纳秒级,而 RPC 的固有消耗是在毫秒级。那么对于过于轻量的计算任务就并不合适导出远程接口由独立的进程提供服务,只有花在计算任务上时间远远高于 RPC 的固有消耗才值得导出为远程接口提供服务。


总结

至此我们提出了一个 RPC 实现的概念框架,并详细分析了需要考虑的一些实现细节。无论 RPC 的概念是如何优雅,但是“草丛中依然有几条蛇隐藏着”,只有深刻理解了 RPC 的本质,才能更好地应用。




FROM:  http://blog.csdn.net/mindfloating/article/details/39474123/

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

深入浅出 RPC - 深入篇 的相关文章

  • RPC框架详解

    第一部分 RPC框架 1 Socket回顾与I 0模型 1 1 Socket网络编程回顾 Socket 套接字就是两台主机之间逻辑连接的端点 TCP IP协议是传输层协议 主要解决数据如何在网络中传输 而HTTP是应用层协议 主要解决如何包
  • 笔记/samba搭建

    1 安装 yum y install samba 2 配置 vim etc samba smb conf global 安全模式 user shared domain security user 认证模式 passdb backend td
  • 遥感+python 1.4 RPC校正

    遥感 python 1 4 RPC校正 目录 遥感 python 1 4 RPC校正 一 正射校正 二 RPC校正原理 三 代码实现 本章节 笔者主要讲述RPC校正的概念 原理 即代码实现 一 正射校正 正射校正一般是通过在像片上选取一些地
  • doris & StarRocks 错题本

    一 spark streaming load写入失败 Reason column count mismatch expect 25 real 1 src line demo masking 1 2018 02 17 1 B35C300672
  • Dubbo源码分析-Spring与Dubbo整合原理与源码分析(二)

    Spring与Dubbo整合的整体流程 基于apache dubbo 2 7 15 因为dubbo有较多的兼容以前的代码比如 DubboReference 以前就有两个版本 Reference 和 com alibaba dubbo con
  • 使用RPC对某者web端骑行数据进行爬取

    使用RPC技术hook web端JS 骑行app某者web端爬虫 2022 2 1 获取轨迹ID 通过更改年月 可以发现获取每个月轨迹ID 的方式 这个非常简单 只需要拷贝请求头headers就可以直接获取 2 获取轨迹详情 可以发现三个请
  • RPC 开发系列一:RPC 基本介绍

    一 什么是 RPC RPC 的全称是 Remote Procedure Call 即远程过程调用 功能 屏蔽远程调用跟本地调用的区别 让我们感觉就是调用项目内的方法 隐藏底层网络通信的复杂性 让我们更专注于业务逻辑 二 RPC 通信流程 发
  • Dubbo源码分析-服务导出源码解析(三)

    在这个版本中dubbo会通过注解 PostConstruct把ServiceBean实例放到ConfigManager中 public abstract class AbstractConfig implements Serializabl
  • go 进阶 go-zero相关: 七. 拦截器与熔断拦截器

    目录 一 拦截器的基础使用 1 服务端拦截器 2 客户端拦截器 二 拦截器底层底层执行原理 三 go zero默认添加的拦截器 客户端 1 熔断器拦截器 BreakerInterceptor 服务端 一 拦截器的基础使用 在go zero
  • AVRO 中的数据验证

    我是 AVRO 新手 如果这是一个简单的问题 请原谅 我有一个使用 AVRO 模式进行记录调用的用例 假设我有 avro 架构 name abc namepsace xyz type record fields name CustId ty
  • 套接字异常:“端点映射器没有更多可用端点”

    我正在使用winsock 和C 来设置服务器应用程序 我遇到的问题是调用listen导致第一次机会异常 我想通常这些可以被忽略 但我发现其他人也有同样的问题 它导致应用程序偶尔挂起 任何帮助将不胜感激 第一个机会例外是 0x 1234567
  • 至多一次和恰好一次

    我正在研究分布式系统 当涉及到 RPC 部分时 我听说过这两种语义 最多一次和恰好一次 据我所知 当我们不希望重复执行时 最多一次用于数据库实例 第一个问题 这是如何实现的 服务器如何知道它不应该再次执行该请求 它可能是重复的 但也可能是合
  • 我如何利用 ZeroMQ 编写自己的 Protocol Buffers RPC 实现

    根据 下的 Google Protocol Buffers 文档定义服务 https developers google com protocol buffers docs proto3 services 他们说 也可以将协议缓冲区与您自己
  • GWT RPC - 每个应用程序多个 RPC 服务

    我目前正在使用一个具有大型 RPC 服务的 GWT 应用程序 它有 100 多个方法 所有方法都做不同的事情 如果我将其拆分为多个 RPC 服务 我会获得什么样的性能优势 障碍 我相信我必须为每一个创建一个新的 servlet 所以我的主要
  • 哪种 rpc/消息传递框架最适合这种情况?

    用例 一个 Java 进程与一个或两个 C 进程 始终在同一台机器上 需要双向 二进制 非持久通信 其中一个 C 进程负责实例化其他进程 我环顾四周 看到了 XML JSON RPC Protocol Buffers Thrift zero
  • 用于远程IP(主机)的Java RMI

    我是新手 我无法理解RMI正确 互联网上有大量的教程 但据我所知 它们都是针对本地主机的 服务器和客户端都运行在同一台机器上 我想在任何机器上运行客户端 并且主机将位于一台计算机上 让我们考虑一下IP 11 11 11 11 上1099 但
  • 协议缓冲区 Java RPC 堆栈

    根据this http en wikipedia org wiki Protocol Buffers维基百科条目 Protocol Buffers 与 Facebook 的 Thrift 协议非常相似 只是它不包含用于定义服务的具体 RPC
  • 如何通过RPC监听firestore

    我想听firestore中的实时变化 而且我也只允许使用Go 由于 Firestore SDK for Go 没有任何选项来监听实时更改 因此我决定使用 firestore v1beta1 sdk 我编写了以下代码来做到这一点 func T
  • MessagePack:快速跨平台序列化器和RPC - 请分享经验

    寻找一些我偶然发现的快速 简单且稳定的 RPC 库消息包 http msgpack org 项目看起来非常好 它也正在积极开发中 如果您以任何方式使用它 可以分享一下您的经验吗 附 我认为这个问题应该是社区维基 好吧 过了一段时间 我发现
  • 远程过程调用认证

    我正在使用远程过程调用 RPC 在本地计算机上通信数据 我的要求是使用 RPC 在两个处理之间通信数据 但服务器应该通过某种方式对客户端进行身份验证 我遇到了 RpcBindingSetAuthInfo 它设置身份验证和授权信息 第四个参数

随机推荐

  • Shell监控jvm发短信

    Shell脚本 jstat crontab curl 监控JVM发送短信 bin bash 定时监控本机器下所有java应用的 JVM信息 定时任务配置 crontab e 写入如下 5分钟执行一次检测 5 home admin monit
  • 【H5】 svg动画 旋转属性与虚线属性

    svg 动画 旋转 transform rotate angle x y 不要写在style里面 angle 旋转角度 x y旋转中心 绘制虚线 stroke dasharray a b a b c d 旋转属性 transform rot
  • 立陶宛央行抢跑数字货币背后:前瞻的区块链战略 中国已有企业布局

    7月2日 据路透社报道 立陶宛将在下周开始预售2 4万枚由央行发行的数字货币 该名为LBCoin的数字货币基于区块链技术生产 立陶宛成为是欧盟国家中第一家正式发行央行数字货币的地区 不是2015年就开始研究央行数字货币的英国 不是今年2月试
  • 人工智能芯片未来发展前景如何?

    随着深度学习技术的快速发展 以及互联网和云计算时代海量数据和高效计算能力的支撑 计算机视觉技术 语音技术 自然语言理解技术等人工智能技术取得了突破性进展 并解锁多个行业的人工智能场景 产生了巨大的商业价值 驱动了人工智能行业的发展 同时 伴
  • TEA系列加解密算法详解

    文章目录 TEA系列概述 TEA算法介绍 TEA加密过程 C语言实现 XTEA算法介绍 XTEA加密过程 C语言实现 XTEA算法介绍 XXTEA加密过程 C语言实现 参考 TEA系列概述 TEA算法是由剑桥大学计算机实验室的David W
  • python 序列化_python怎么序列化

    pickle模块 json模块 1 把变量从内存中变成可存储或传输的过程 称之为序列化 Python中叫pickling 其他语言中也被称为serialization marshalling flattening等 都是相同的意思 2 序列
  • XSS安全漏洞的防范

    XSS安全漏洞 通过URL带入的 这种带入主要是前端解析url中的参数 并对数参数执行了innerHTML 或者 html 或者 append 操作 在将参数html 或者append 到html文件中时 会执行其中的js代码 被错误用户获
  • HBase Split 过程

    看了下hbase split的代码 记录一下学习心得 Java代码 private void split final HRegion parent final byte midKey throws IOException final lon
  • chat gpt 常见角色及对应的提示词汇总

    提示词的存在让ChatGPT能够扮演特定的角色 对用户的回答更加专业对口 以下是一些常见的ChatGPT角色及对应的提示词 目录 ChatGPT 市场推广提示 ChatGPT 业务提示 ChatGPT 内容提示 Web 开发的 ChatGP
  • Ubuntu系统中防火墙的使用和开放端口

    Ubuntu系统中防火墙的使用和开放端口 目录 1 Ubuntu查看防火墙的状态 2 2 Ubuntu开启防火墙 2 3 Ubuntu添加开放SSH端口 3 4 Ubuntu防火墙常用命令 5 4 1 查看ufw防火墙的状态 5 4 2 启
  • ARM汇编之APCS规则

    APCS规则简述 寄存器使用规则 寄存器r0 r3用于函数调用过程中传递函数形参 各有一个别名 a1 a4 使用前后可以不用恢复原来的值 R4 r11用于保存函数内部局部变量的值 每个函数使用前 必须要保存被调用函数的值 使用完毕 必须恢复
  • 在Linux远程服务器上搭建JavaWeb开发环境

    配置 远程linux服务器版本为CentOS7 6 使用的是阿里云服务器 目录 1 安装JDK 1 1 查看yum源中JDK版本 1 2 使用yum安装JDK1 8 1 3 查看是否安装成功 2 安装MySQL 2 1 查看是否已安装mys
  • C++ 循环

    有时候 程序需要多次执行同一块代码 一般情况下 语句是顺序执行的 函数中的第一个语句先执行 接着是第二个语句 依此类推 循环语句允许多次执行一个语句或语句组 大多数编程语言中循环语句的一般形式 循环类型 C 编程语言提供了以下几种循环类型
  • Anaconda环境的创建、激活、删除和管理

    1 Anaconda环境的创建 conda create n 环境的名字 自定义 python 3 7 其中环境的名字 自定义 表示创建环境的名字 可以自定义 建议为英文 后面python 3 7表示创建的解释器的版本 conda crea
  • 这里有141个创业公司的死亡案例,看鸡汤不如听教训

    今天我们打算跟大家聊聊失败 关于成功的方法论有着趋同性 多半与 天时地利人和 有关 而关于失败 却很少有人愿意公开谈起 也许因为野兽总是不想将伤口暴露在外 探讨失败的意义 可能远远大于成功 因为面对挫折 即使自认为最无畏的人也会有这样的时刻
  • PicGo安装与配置-Gitee图床

    PicGo安装与配置 Gitee图床 文章目录 PicGo安装与配置 Gitee图床 1 前言 2 下载 3 安装 4 Gitee 5 Node js 6 配置PicGo 6 1 PicGo界面配置 6 2 npm安装PicGo插件Gite
  • 空格的正则表达式

    在正则表达式想使用空格的时候不能采用 s的方法 因为 s指的是空白 就是所有空白 如果想表示单纯的空格的话可以采用 方括号本身就是匹配其中的字符 那么其中放空格就是匹配空格 如果有其他正则表达式问题可以查看 https blog csdn
  • GCP reliable google cloud infrastructure, devops lab

    最后更新2022 03 13 先到menu source repository里建立repository 还是不很好找 source repository在CI CD分类里面 点右上角的add repository按钮 输名字devops
  • uniapp集成unipush2.0

    unipush3 0集成 unipush推出2 0服务 之前一直用的1 0 现在项目推荐使用2 0 最近也是对2 0这个推送做了测试 下面就主要对华为这个来总结一下 其余的厂商大同小异 1 push1 0和2 0对比 个人理解 2 0比1
  • 深入浅出 RPC - 深入篇

    深入篇 我们主要围绕 RPC 的功能目标和实现考量去展开 一个基本的 RPC 框架应该提供什么功能 满足什么要求以及如何去实现它 RPC 功能目标 RPC 的主要功能目标是让构建分布式计算 应用 更容易 在提供强大的远程调用能力时不损失本地