> For the complete documentation index, see [llms.txt](https://xiaoxiami.gitbook.io/swoole/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://xiaoxiami.gitbook.io/swoole/rpc.md).

# swoole RPC调用

## 什么是rpc?

RPC全称为Remote Procedure Call，翻译过来为“远程过程调用”。目前，主流的平台中都支持各种远程调用技术，以满足分布式系统架构中不同的系统之间的远程通信和相互调用，也是实现微服务当中的重要的环节。

调用方式：总是由Client向Server发出一个执行若干过程请求，Server接受请求，使用客户端提供的参数，计算完成之后将结果返回给客户端。

## 为什么需要RPC?

如果是自己的一个单体应用，只是自己一个人开发，流量特别小的情况，不需要RPC,但是在进入公司尤其是大型互联网公司就有可能面临这个问题。

1、分布式部署及微服务

当我们的系统访问量增大、业务增多时，我们会发现一台单机运行此系统已经无法承受。此时，我们可以将业务拆分成几个互不关联的应用，分别部署在各自机器上，以划清逻辑并减小压力。

2、不同技术选型

公司业务规模扩大，有可能引入不同的语言，比如A团队要开发**CPU密集型**的采用java语言，B团队要开发**IO密集型的采用了PHP**，不同语言之间如何通讯

## 遇到的问题

1）要搭建一个新服务，免不了需要依赖其它团队的服务，而现在他人的服务都在远端，怎么调用？

2）其它团队使用的语言并不是PHP，不同语言之间如何进行调用？

## 如何调用服务？

由于各服务部署在不同机器，服务间的调用免不了网络通信过程，服务消费方每调用一个服务都要写一坨网络通信相关的代码，不仅复杂而且极易出错。

如果有一种方式能让我们像调用本地服务一样调用远程服务，而让调用者对网络通信这些细节透明，那么将大大提高生产力，比如服务消费方在执行

`$client->getUserInfo()`时，实质上调用的是远端的服务。这种方式其实就是RPC。

**rpc客户端调用流程**

![](https://3149448975-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-LfnT31GMG1d9KiXwANW%2F-LfnT7UNILQRAFnaeTSW%2F-LfnTFosmrG1tkspkoxe%2Frpc%E5%AE%A2%E6%88%B7%E7%AB%AF%E8%B0%83%E7%94%A8%E6%B5%81%E7%A8%8B.png?generation=1558862959100138\&alt=media)

## 服务治理

客户端通过发送一个规定的rpc协议，请求服务的注册中心，由服务注册中心检索可用服务，并且实现调用转发，服务内容由代码服务器在启动的时候，注册到服务中心。服务中心暂时利用redis存储内容。

原理图：

![](https://3149448975-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-LfnT31GMG1d9KiXwANW%2F-LfnT7UNILQRAFnaeTSW%2F-LfnTFouf4xMsc0ZgS-9%2F1.png?generation=1558862974438126\&alt=media)**服务中心**

* 1、通过redis方式存储代码服务器发送过来的注册服:利用redis集合进行存储服务
* 2、多端口混合协议监听接收注册服务: 客户端如果是普通的网页端只需要，接收普通的http请求，但是是硬件设备需要接收tcp的协议，不同协议统一转换，同时查询可用服务发送到服务端
* 3、提供RPC服务，服务调用
* 4、心跳维持、健康检查、绑定服务器:定时检测代码服务端健康状态，如果服务宕机，从服务列表当中删除
* 5、协议的统一转换:将客户端的不同协议的请求在转发到代码服务架构时，转换成统一的协议，去请求 &#x20;
* 6、负载均衡

  通过查看服务端的连接数、任务排队数、系统负载、内存状态，决定当前的rpc客户端请求会得到哪台机器的地址

系统负载参考这篇文章 :<http://www.ruanyifeng.com/blog/2011/07/linux_load_average_explained.html>

6.1、通过redis字符串类型保存每台服务器状态

注册服务之后代码服务端，定时发送当前机器状态，存储在redis当中提供给服务端选择，通过redis字符串存储某个服务当前的服务器相关状态key为当前的，在调用服务时根据情况，比如系统状态更好加分，连接数更少加分

目前先设置三项

```php
[
       'load'=>0.1, //15分钟负载
       'connection_num'=>20,  //连接数
       tasking'=>2   //任务排队数
]
```

6.2、通过评分算法获取状态最好的机器

通过评分算法实现不同选项的评分，选取状态最好的一台服务机器，返回给客户端，通过匹配redis集合当中的服务名，得到不同服务的地址，并且通过读取redis存储的字符类型获取服务状态，利用评分算法选取

**代码服务端**

* 1、注册服务到注册中心:在进程启动时将当前的代码服务端提供的服务，发送请求注册到注册中心
* 2、接收服务中心的服务调用: 默认触发onRequest事件
* 3、心跳维持:通过发送心跳包维持代码服务在线状态

**客户端**&#x20;

* 1、异步客户端、同步客户端创建
* 2、通过请求服务中心获取到健康的服务地址
* 3、通过请求服务中心获取代码

> 注意事项：
>
> 1、协议规定
>
> 根据相应的协议规范，并且能够携带验证标识，来决定调用远程代码服务器上面的某个类当中的某个方法，响应相应的服务
>
> 2、服务中心存储
>
> 用redis作为存储工具，也可以使用swoole\_table或者其它的存储工具

扩展的原理图：

![](https://3149448975-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-LfnT31GMG1d9KiXwANW%2F-LfnT7UNILQRAFnaeTSW%2F-LfnTFoynNfkBPIG3pxI%2Findex.png?generation=1558862960195148\&alt=media)
