深入浅出RPC:选取适合自己的RPC

文章目录

  • 1、RPC概念&&背景
    • 1.1、RPC背景
  • 1.2、RPC是什么,什么时候需要用到?
  • 2、进程间的通信 - IPC与RPC
    • 2.1、什么是IPC
    • 2.2、IPC与RPC联系
  • 3、RPC的实现
    • 3.1、RPC实现的基本思路
    • 3.2、RPC实现的扩展方向
  • 4、RPC的选择


1、RPC概念&&背景

1.1、RPC背景

RPC远程调用的概念最早可以追溯到20世纪80年代,当时Sun Microsystems公司提出了一种名为ONC RPC(Open Network Computing Remote Procedure Call)的协议,用于在NFS(Network File System)中进行远程过程调用。此后,RPC成为了分布式系统中的一种重要通信方式,被广泛应用于各种分布式系统和应用中。

可以看出RPC这个概念已经超过四十年时间,但在今天仍然可以在各种论坛、技术网站上时常遇见“什么是 RPC?”、“如何评价某某 RPC 技术?”、“RPC 更好还是 REST 更好?”之类的问题,仍然“每天”都有新的不同形状的 RPC 轮子被发明制造出来。而对于快速发展的互联网技术,这无异是稀奇的。而这主要的原因主要还是很多论坛上的开发这对于RPC 本身解决什么问题、怎么解决这些问题、为什么要这样解决都或多或少存在认知模糊,接下来本文会一一介绍。

1.2、RPC是什么,什么时候需要用到?

RPC(Remote Procedure Call)是一种远程过程调用协议,它允许一个程序调用另一个程序中的函数或方法,而无需了解底层的网络细节。因此RPC的出现使得分布式系统中的各个组件之间的通信变得更加简单、高效和可靠。

并且RPC协议提供了更加丰富和灵活的功能,例如支持不同的序列化格式、支持异步调用、支持自定义的错误处理等等(如:gRPC、Apache Thrift、CORBA…等),而平常普通的http请求等就很难实现。因此在为了需要自定义上述的的功能,亦或者在分布式系统中需要进行组件的通信时,就需要rpc。(但是这里RPC底层的传输协议其实是可以用HTTP协议的,这种方式被称为HTTP-RPC或者HTTP-based RPC。在这种方式中,HTTP协议被用来传输RPC请求和响应数据。)

上述提到HTTP协议,其实也可以扩展一下,对于分布式中的通信除了常见RPC协议,能够更快的提高数据传输效率,对于常见的HTTP协议来说也有对应的架构,这种架构则是我们常说的restful。
rest(Representational State Transfer)是一种基于HTTP协议的架构风格,用于设计和构建分布式系统。它强调系统中的资源和状态的概念,并使用HTTP动词(GET、POST、PUT、DELETE等)对资源进行操作,并使用URI(Uniform Resource Identifier)标识资源的位置。它相对于RPC的特点更多为:

  • 基于HTTP协议: 使用HTTP协议进行通信,HTTP动词表示对资源的操作,URI表示资源的位置。
  • 资源和状态: 将系统中的所有内容抽象为资源,每个资源都有一个URI标识和一个状态。
  • 无状态: 每个请求都是独立的,不需要保存上下文信息。
  • 可缓存: 支持缓存机制,提高性能和可扩展性。
    因此rest的侧重点更多是灵活、易扩展、易缓存的场景。更多想了解的可以去看看凤凰架构中有对此更深的描述。

因此,在实现分布式系统中的通信时,想要提高网络传输效率使用专门的RPC协议会更加合适和可靠。但是而RPC具体是怎么能支持这些功能,还得从RPC的实现谈起。


2、进程间的通信 - IPC与RPC

在介绍RPC实现之前先来介绍下IPC,因为RPC在实现思想和背景上很多来自于IPC。

2.1、什么是IPC

IPC是一种在同一台计算机上的进程间通信方式,常见的IPC技术包括管道、消息队列、共享内存、信号量、套接字接口(Socket)等。IPC的主要作用是实现进程间数据的传输和共享,使得不同进程之间可以进行协调和互操作。

2.2、IPC与RPC联系

就如同开始强调的一样,rpc最初的目标只是为了让计算机能够跟调用本地方法一样去调用远程方法!! 在分布式系统中,不同组件之间可能需要进行本地进程间通信和远程过程调用,**这时就可以同时使用IPC和RPC来实现。**例如,在分布式系统中,一个组件可能需要调用另一个组件的本地函数或方法,这时可以使用IPC来实现本地进程间通信。而当两个组件位于不同的节点上时,就可以使用RPC来实现远程过程调用。此外,RPC的实现方式通常是基于网络协议和框架,而网络协议和框架中也使用了IPC的技术。例如,在TCP/IP协议中,就使用了IPC中的套接字(socket)技术来实现进程间通信。

这边要注意一个点在早先由于 Socket 是各个操作系统都有提供的标准接口,完全有可能把远程方法调用的通信细节隐藏在操作系统底层,从应用层面上看来可以做到远程调用与本地的进程间通信在编码上完全一致。但这这种透明的调用方法,容易造成滥用,而造成通信是无成本的假象,而导致了分布式系统下性能的下降。当然现在回来看通信是无成本的假象肯定是错的,毕竟分布式系统架构应是容错,一致性,高性能的trade off,而通信代价本就是性能中的一环。而在当时RPC这种观却是很盛行,对此Andrew Tanenbaum 教授曾发表了论文《A Critique of The Remote Procedure Call Paradigm》进行质疑,以及最终CM 和 Sun 院士Peter Deutsch、套接字接口发明者Bill Joy、Java 之父James Gosling等一众在 Sun Microsystems 工作的大佬们共同总结了现在分布式系统很著名的:通过网络进行分布式运算的八宗罪(8 Fallacies of Distributed Computing),有兴趣的可以去了解。

3、RPC的实现

3.1、RPC实现的基本思路

由上文可以知晓RPC的实现一开始是为了像本地方法那样调用远程方法,但是实际上远程调用中的 “远程” 的概念注定会有很多实现上的分歧,这也是本文的第二个内容,如何解决这些问题。
首先远程调用的大致链路其实都是大同小异的,大概如下图(图源来自论文Implementing Remote Procedure Calls):
在这里插入图片描述
由图可以分解出以下几个步骤:

  • 定义接口和数据类型: 首先需要定义接口和数据类型,包括接口方法名、参数类型、返回值类型等。这些定义通常使用IDL(Interface Definition Language)语言来描述,以便于不同语言之间的调用和序列化。
  • 生成代码: 根据接口和数据类型的定义,生成客户端和服务器端的代码。这些代码通常包括序列化和反序列化方法、网络传输方法等,以便于客户端和服务器端进行数据交换和通信。
  • 实现服务器端(被调用方): 在服务器端实现接口方法,根据客户端请求进行相应的处理,并将处理结果返回给客户端。服务器端还需要实现服务注册和发现、负载均衡、容错等机制,以提高系统的可用性和可靠性。
  • 实现客户端(调用方): 在客户端调用远程接口方法,将参数序列化并通过网络发送给服务器端,然后等待服务器端返回处理结果,并将结果反序列化后返回给调用方。客户端还需要实现服务发现和选择、负载均衡、重试等机制,以提高系统的可用性和可靠性。
  • 集成框架: 将生成的代码和实现的服务器端、客户端集成到RPC框架中,并提供相应的API和工具,以便于开发人员使用和集成。
  • 测试和优化: 对实现的RPC框架进行测试和优化,包括性能测试、功能测试、安全测试等,以确保系统的稳定性、可靠性和安全性。

3.2、RPC实现的扩展方向

除了上面几个基本步骤,不同的RPC通常会在下列三个方向,去进行自己扩展。

  • 如何表示数据 - 数据的序列化与反序列化的实现
  • 如何传递数据- 确定数据传输时所采用的格式与规则( Wire Protocol )
  • 如何统一方法调用- 确定请求端/接受端方法调用的方式

3.2.1 如何表示数据

对于如何表示数据的做法是将交互双方所涉及的数据转换为某种事先约定好的中立数据流格式来进行传输,将数据流转换回不同语言中对应的数据类型来进行使用,而这就是序列化协议的初衷,除此之外设计一个好的序列化协议还有以下几个作用:

  • 跨语言和跨平台: 在分布式系统中,不同计算机可能使用不同的编程语言和操作系统,因此需要一种通用的数据格式,以便于跨语言和跨平台进行数据传输和交互。序列化协议可以将数据转换为一种通用的格式,使得不同计算机之间可以正确地对数据进行编码和解码。
  • 数据压缩: 在网络传输过程中,数据的大小会影响网络带宽和传输速度,因此需要对数据进行压缩。序列化协议可以将数据压缩为更小的二进制格式,从而减少网络传输的数据量,提高网络传输效率。
  • 数据安全: 在网络传输过程中,数据可能会被篡改或窃取,因此需要对数据进行加密和解密。序列化协议可以将数据转换为二进制格式,并进行加密和解密操作,从而保证数据的安全性和完整性。
    数据可读性:在调试和排错过程中,需要查看网络传输的数据内容,以便于定位问题。序列化协议可以将数据转换为文本格式,使得数据更易于读取和理解。

也因此每种RPC都有其对应使用的序列化协议:

  • ONC RPC : External Data Representation (XDR)
  • gRPC: 使用Protocol Buffers作为默认的序列化协议,也支持JSON。
  • Java RMI : Java Remote Message Protocol(JRMP,也支持RMI-IIOP)
  • Web Service : XML Serialization
  • CORBA: 支持多种序列化协议,包括GIOP(General Inter-ORB Protocol)、IIOP(Internet Inter-ORB Protocol)、RMI-IIOP和TAO。
  • Apache Thrift: 支持多种序列化协议,包括二进制、压缩二进制、JSON、可扩展二进制和结构化数据格式(TJSON、TSV)。

3.2.2 如何传递数据
数据的传输并不是简单的约定好数据格式进行序列化反序列化就行,还需要考虑数据传输时需要的额外的信息譬如异常、超时、安全、认证、授权、事务,等等,都可能产生双方需要交换信息的需求,对这一类的行为则被称作Wire Protocol。而常见的Wire Protocol协议主要有:

  • 两端都是http endpoint可以直接HTTP
  • Java RMI 的Java Remote Message Protocol(JRMP,也支持RMI-IIOP)
  • CORBA 的Internet Inter ORB Protocol(IIOP,是 GIOP 协议在 IP 协议上的实现版本)
  • DDS 的Real Time Publish Subscribe Protocol(RTPS)
  • Web Service 的Simple Object Access Protocol(SOAP)
  • Wire Protoco通常是指应用层协议和传输层协议之间的协议。在OSI模型中,Wire Protocol可以被看作是第5层(会话层)和第6层(表示层)之间的协议。在TCP/IP协议栈中,Wire Protocol通常被认为是传输层协议和应用层协议之间的协议,例如HTTP、SMTP等应用层协议使用TCP或UDP作为传输层协议进行数据传输。
  • 而上面提到的序列化反序列化序列化和反序列化通常是在应用层协议中实现的,因为它们是将高级语言对象转换为字节流的过程,这些对象通常在应用程序中定义和使用。例如,在Java中,序列化和反序列化通常使用Java对象序列化(Java Object Serialization)API来实现。

3.2.3 如何统一方法调用

  • 在本地方法调用中方法调用并不是太大的问题,编译器或者解释器会根据语言规范,将调用的方法签名转换为进程空间中子过程入口位置的指针,但是远程调用可能则要考虑不同的语言,则在实现上需要考虑不同语言之间方法签名的差异。由于不同语言的方法调用方式和参数传递方式可能不同,因此在RPC中需要使用一种通用的方法来描述方法签名和参数列表,以便在客户端和服务器之间进行方法调用。

  • 通常情况下,RPC实现会使用一种IDL(Interface Description Language,接口定义语言)来描述方法签名和参数列表,以便在客户端和服务器之间进行交互。IDL通常使用一种中立的语言来描述接口,例如CORBA中使用的IDL语言。在IDL中,可以定义接口、方法、参数类型、返回类型等信息,以便在不同语言之间进行交互。

  • 在实际的RPC实现中,通常会使用代码生成工具来根据IDL文件自动生成客户端和服务器端的代码。这些生成的代码包含了方法调用的代码,以及将参数和返回值进行序列化和反序列化的代码,以便在不同语言之间进行方法调用。这样可以大大简化RPC实现的过程,同时也可以保证不同语言之间的方法调用是正确的。

值得一提的是IDL的实现有点类似寻找一个分布式id一样。如确定方法直接规定一个唯一的、在任何机器上都不重复的编号,调用的时候则不管这个方法签名是如何定义的,直接通过编号确定方法。而这个唯一但绝不重复的编码方案,这就是后来的UUID。

其他用于表示方法的协议还有:

  • Android 的Android Interface Definition Language(AIDL)
  • CORBA 的OMG Interface Definition Language(OMG IDL)
  • Web Service 的Web Service Description Language(WSDL)
  • JSON-RPC 的JSON Web Service Protocol(JSON-WSP)

因此其实RPC的很多实现思路都是可以从IPC上得到借鉴或启发,但是rpc随着发展早已不满足于简单的进行通信,早已还需要考量性能、通用等方面。

4、RPC的选择

经过的几十年的时间,rpc的发展并不是趋向一个统一的未来,因为随着多样化的需求、不断的技术发展和创建、以及需要跨语言和跨平台支持甚至包括生态的推动。现在的rpc已经成为一个百家争鸣之势如 RMI(Sun/Oracle)、Thrift(Facebook/Apache)、Dubbo(阿里巴巴/Apache)、gRPC(Google)、Motan1/2(新浪)、Finagle(Twitter)、brpc(百度/Apache)、.NET Remoting(微软)、Arvo(Hadoop)、JSON-RPC 2.0(公开规范,JSON-RPC 工作组)等等。

接下来会简单根据不同的场景建议选择不同的rpc框架并介绍其优缺点:

  • gRPC:
    • 优点: 高性能、低延迟、跨语言支持、多种通信协议、流式传输支持。
    • 适用场景: 大规模分布式系统、跨语言通信、需要高性能和低延迟的实时通信场景。
  • Dubbo:
    • 优点: 丰富的服务治理功能、高度可扩展、支持大规模分布式系统、灵活的扩展机制。
    • 适用场景: Java应用程序的分布式服务、需要服务治理功能的场景。
  • Apache Thrift:
    • 优点: 跨语言支持、多种序列化方式、代码生成工具、高效的数据传输。
    • 适用场景: 跨语言通信、大数据分析、需要高效数据传输的场景。
  • ZeroMQ:
    • 优点: 轻量级、快速、异步消息传递、支持多种通信模式。
    • 适用场景: 轻量级通信、需要快速和高效的消息传递的场景。
  • MQTT:
    • 优点: 轻量级、低功耗、支持发布-订阅模式。
    • 适用场景: 物联网应用、需要低功耗和轻量级通信的场景。
  • WebRTC:
    • 优点: 支持实时音视频通信、低延迟、Web浏览器原生支持。
    • 适用场景: 实时音视频通信、Web端的实时通信IM场景。

而大家平时搭建业务则一般就可以通过业务上所需要的通信特点进行去选择,例如如果是im场景下 WebRTC去提高通讯效率,如果是大型电商那种分布式系统的话可以使用gRPC,java则使用Dubbo,如果是搭建数据中心考虑跨语言则去选择Apache Thrift,当然如果最简单平常的也可以直接利用Springcloud中的Spring Cloud Netflix项目实现的多种组件,如Ribbon、Feign、Hystrix等,用于构建分布式系统中的服务通信和治理。

而想具体区分优缺点的则是可以从上面实现提到的序列化协议、传输协议实现入手:

  • gRPC:
    传输协议: 默认使用HTTP/2作为底层传输协议,HTTP/2支持多路复用、头部压缩和服务器推送等特性,可以提高性能和效率。
    序列化协议:默认使用Protocol Buffers(protobuf)作为序列化协议,protobuf是一种高效、紧凑的二进制序列化协议,适合高性能通信。

  • Dubbo:
    传输协议: Dubbo支持多种传输协议,包括dubbo、rmi、http、hessian、webservice等,可以根据需求选择合适的协议。
    序列化协议: Dubbo同样支持多种序列化协议,如hessian、json、protobuf等,可以根据需求选择合适的协议。

  • Apache Thrift:
    传输协议: Thrift支持多种传输协议,包括二进制、压缩、JSON、XML等,可以根据需求选择合适的协议。
    序列化协议: Thrift支持多种序列化协议,包括二进制、JSON、compact等,可以根据需求选择合适的协议。

  • ZeroMQ:
    传输协议: ZeroMQ是一种异步通信库,支持多种传输协议,如TCP、IPC、inproc等,可以根据需求选择合适的协议。
    序列化协议: ZeroMQ并不关心消息的格式和内容,用户可以自行定义消息的序列化方式。

  • WebRTC:
    传输协议: WebRTC是一种用于实时通信的开放式技术,通常使用UDP作为底层传输协议,可以实现较低的延迟和更好的实时性。
    序列化协议: WebRTC通常使用JSON或二进制格式来序列化和传输数据。

而这些使用的协议则会决定其底层存在的风险,并且在选择时也可以适当考虑是否社区还在维护,更新,生态是否完善等…

以下提供几个常见的rpc的地址:

  • grpc中文文档:https://doc.oschina.net/grpc
  • grpc官方文档:https://grpc.io/docs/
  • dubbo官方文档:https://cn.dubbo.apache.org/zh-cn/overview/home/
  • Apache Thrift官方文档:https://thrift.apache.org/
  • WebRTC官方文档:https://webrtc.org/?hl=zh-cn

如有不足,欢迎指正~

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

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

相关文章

Elasticsearch——快速入门

从零基础的内容开始介绍Elasticsearch,主要包含以下内容: Elasticsearch的定义、优点,以及典型的业务场景。Elasticsearch中重要的概念。Elasticsearch典型的接入方式。安装Elasticsearch。使用Kibana调试Elasticsearch。Elasticsearch节点的…

【LeetCode刷题笔记(8-3)】【Python】【接雨水】【双指针】【困难】

文章目录 引言接雨水题目描述提示 解决方案3:【双指针】结束语 接雨水 【LeetCode刷题笔记(8-1)】【Python】【接雨水】【动态规划】【困难】 【LeetCode刷题笔记(8-2)】【Python】【接雨水】【单调栈】【困难】 引言…

从如何使用到如何实现一个Promise

promise是什么?主要用来解决什么问题? Promise是异步编程的一种解决方案,比传统解决方案--回调函数和事件--更合理更强大。 Promise特点: (1)对象的状态不受外界影响。Promise对象代表一个异步操作&…

ModuleNotFoundError: No module named ‘openai.error‘

ModuleNotFoundError: No module named ‘openai.error’ result self.fn(*self.args, **self.kwargs) File “H:\chatGPTWeb\chatgpt-on-wechat\channel\chat_channel.py”, line 168, in _handle reply self._generate_reply(context) File “H:\chatGPTWeb\chatgpt-on-wec…

2023_Spark_实验二十九:Flume配置KafkaSink

实验目的:掌握Flume采集数据发送到Kafka的方法 实验方法:通过配置Flume的KafkaSink采集数据到Kafka中 实验步骤: 一、明确日志采集方式 一般Flume采集日志source有两种方式: 1.Exec类型的Source 可以将命令产生的输出作为源&…

性能加速包: SpringBoot 2.7JDK 17,你敢尝一尝吗 | 京东物流技术团队

前言 众所周知,SpringBoot3.0迎来了全面支持JDK17的局面,且最低支持版本就是JDK17,这就意味着,Spring社区将完全抛弃JDK8,全面转战JDK17。作为JAVA开源生态里的扛把子,Spring可以说是整个JAVA生态的风向标…

(8)Linux Makefile | 依赖关系,依赖方法

💭前言: 本篇文章会着重讲解Linux中的自动化构建代码工具: make/makefile的介绍与使用。 在Linux下编译代码时,每次都会输入 gcc code.c -o code.exe在删除可执行程序时,每次都会输入 rm -rf code.exe这样非常的不方便,很麻烦,于是乎学习自动化构建代…

原来Python的协程有2种实现方式

什么是协程 在 Python 中,协程(Coroutine)是一种轻量级的并发编程方式,可以通过协作式多任务来实现高效的并发执行。协程是一种特殊的生成器函数,通过使用 yield 关键字来挂起函数的执行,并保存当前的执行…

《Effective C++》学习笔记 续

条款31:将文件间编译依存关系降至最低 请记住: 支持”编译依存性最小化“的一般构想是:相依于声明式,不要相依于定义式。基于此构想的两个手段是Handle class和Interface class程序库头文件应该以”完全且仅有声明式“的形式存在…

uniapp 用于开发H5项目展示饼图,使用ucharts 饼图示例

先下载ucharts H5示例源码: uCharts: 高性能跨平台图表库,支持H5、APP、小程序(微信小程序、支付宝小程序、钉钉小程序、百度小程序、头条小程序、QQ小程序、快手小程序、360小程序)、Vue、Taro等更多支持canvas的框架平台&#…

网络安全之Linux环境配置及Linux基础知识讲解<三>

目录 一.下载安装Vmware二.下载安装Kali三.Linux目录结构四.Linux文件属性五.文件目录管理六.vim编辑器 一.下载安装Vmware Vmware官网:https://www.vmware.com 二.下载安装Kali Kali包含数百种工具,可用于各种信息安全任务,例如渗透测试、…

(C++)将x减到0的最小操作数--滑动窗口

个人主页:Lei宝啊 愿所有美好如期而遇 力扣(LeetCode)官网 - 全球极客挚爱的技术成长平台备战技术面试?力扣提供海量技术面试资源,帮助你高效提升编程技能,轻松拿下世界 IT 名企 Dream Offer。https://le…

微机总线地址物理内存地址虚拟内存地址简介

硬件地址的相关概念 Raspberry Pi 发布适用于 ARM 外设的 BCM2835 数据表 地址映射 总线地址 物理地址 虚拟地址 页表和内存管理单元MMU 《 Linux内核设计与实现(第三版)》 树莓派博通BCM2835芯片手册 硬件地址的相关概念 总线地址 32位的操作系统 &…

【赠书活动】OpenCV4工业缺陷检测的六种方法

文章目录 前言机器视觉缺陷检测工业上常见缺陷检测方法延伸阅读推荐语 赠书活动 前言 随着工业制造的发展,对产品质量的要求越来越高。工业缺陷检测是确保产品质量的重要环节,而计算机视觉技术的应用能够有效提升工业缺陷检测的效率和精度。 OpenCV是一…

【机器学习】卷积神经网络(CNN)的特征数计算

文章目录 基本步骤示例图解过程 基本步骤 在卷积神经网络(CNN)中,计算最后的特征数通常涉及到以下步骤: 确定输入尺寸: 首先,你需要知道输入数据的尺寸。对于图像数据,这通常是 (batch_size, c…

1-完全理解以太坊智能合约

了解区块链 区块链技术的核心概念是分布式账本,它是许多参与者共享的特定类型的数据库。 这个特殊的数据库只是一个交易列表,记录着网络中发生的每笔交易。每个人都可以拥有自己的交易列表备份,再加上强有力的货币激励措施消除各方之间信任…

记录今日将C语言的Windows程序更改为python语言Windows程序,实现子窗口控制,类似微信程序框架最简单的原型

基本思路 为什么要选择python制作Windows应用程序,主要就是源代码直接展示,发现问题随时修改,同时可以不断增加新的功能方便。 由于C语言的Windows程序中结构类型在python中不能使用, 因此我们按照ctypes模块指导意见继承structu…

基于双目RGB图像和图像深度信息的三维室内场景建模matlab仿真

目录 1.算法运行效果图预览 2.算法运行软件版本 3.部分核心程序 4.算法理论概述 4.1 双目视觉原理 4.2 深度信息获取 4.3 表面重建 5.算法完整程序工程 1.算法运行效果图预览 2.算法运行软件版本 matlab2022a 3.部分核心程序 .....................................…

STM32与Freertos入门(三)任务的创建、删除

1、串口配置 首先将串口进行配置,后续经常会应用,具体步骤点击:串口配置。 2、任务 创建一个任务,就是开辟一个空间、每个任务中都会有while(1)死循环。 2.1相关函数 动态创建:xTaskCreate…

ros2/ros 4轮2驱机器人xacro/urdf文件示例代码

这个实验中最重要的是&#xff1a;colcon build 之后要记得source install/setup.bash.否则修改的文件是不会更新的。知道了吧 <robot name"half" xmlns:xacro"http://wiki.ros.org/wiki/xacro"><xacro:property name"PI" value"3…