RPC
PRC即远程过程调用,是一种常用的分布式系统间访问接口的方式。PhpBoot 提供强大又简单易用的 RPC 支持,可以让你像使用本地接口一样,方便的使用远程接口。
1. 示例
下面将通过实现一个订单服务的示例,演示 PhpBoot RPC 的使用。
1.1. 定义接口
为保持示例尽量简单,这里我们只实现“创建订单”这一个接口。
/**
* @path /orders
*/
interface OrderServiceInterface
{
/**
* @route POST /
* @param ProductInfo $product 商品快照
* @return string 返回订单号
*/
public function createOrder(ProductInfo $product);
}
1.2. 实现接口
接口定义好以后, 我们需要在服务端,实现该服务接口,以便可以对外提供访问。
/**
* @path /orders
*/
class OrderService implements OrderServiceInterface
{
/**
* @route POST /
* @param ProductInfo $product 商品快照
* @return string 返回订单号
*/
public function createOrder(ProductInfo $product)
{
// create the order
return $orderId;
}
}
1.3. 远程调用接口
在客户端,可以通过下面方法调用远程的接口。
$orderService = $app->make(
RpcProxy::class,
[
'interface'=>OrderServiceInterface::class,
'prefix'=>'http://10.x.x.1/'
]
);
/**@var OrderServiceInterface $orderService*/
$orderId = $orderService->createOrder($product);
另一种推荐的方法是通过依赖注入创建代理类。如
//配置依赖
return [
OrderServiceInterface::class
=> \DI\objet(RpcProxy::class)
->constructorParameter('interface', OrderServiceInterface::class)
->constructorParameter('prefix', 'http://10.x.x.1/')
]
// 注入依赖
class AnotherService
{
...
/**
* @inject
* @var OrderServiceInterface
*/
private $orderService;
public function doSomething()
{
$orderId = $this->orderService->createOrder($product)
}
}
2. 注意
由于 RpcProxy 默认通过 __call 实现远程方法的调用,所以无法传递引用参数。当接口参数中存在引用参数时,应该针对接口实现一个RpcProxy的子类,并重写包含引用参数的方法。以下是示例
// 这是个典型的例子,接口的方法中有引用类型参数
/**
* @path /orders
*/
interface OrderServiceInterface
{
/**
* @route GET /
* @param int $offset
* @param int $limit
* @param int $total 此为引用类型参数, 用于返回查询的总条数
* @return Order[] 返回订单列表
*/
public function getOrders($offset, $limit, &$total);
}
// 这是个典型的例子,接口的方法中有引用类型参数
/**
* @path /orders
*/
class OrderServiceProxy extends RpcProxy implements OrderServiceInterface
//如果不想实现OrderServiceInterface的所有方法,也可以不继承OrderServiceInterface
{
/**
* @route GET /
* @param int $offset
* @param int $limit
* @param int $total 此为引用类型参数, 用于返回查询的总条数
* @return Order[] 返回订单列表
*/
public function getOrders($offset, $limit, &$total)
{
return $this->__call(__FUNCTION__, [$offset, $limit, &$total]);
}
}
//接下来可以通过OrderServiceProxy 访问远程接口了
$orderService = $app->make(
OrderServiceProxy::class,
[
'interface'=>OrderServiceInterface::class,
'prefix'=>'http://10.x.x.1/'
]
);
$orderService->getOrders...
3. 并发访问
在使用远程服务时,有时可能需要同时访问多个远程接口。如果能并行执行,在一些情况下可以大大减少接口执行时间。PhpBoot RPC 提供了并发执行的功能。使用方法如下:
$orderService = $app->make ...
$bookService = $app->make ...
$rpcRes = MultiRpc::run([
function()use(orderService){
return orderService->getOrders(...);
},
function(){
return bookService->getBooks(...);
}
])
$res = []
foreach($rpcRes as $i){
list($success, $error) = $i
if($error){
//执行失败的原因
}else{
//执行成功, 处理$success
}
}
return $res;
注意,MultiRpc 内部是将需并发执行的操作,调用转换为递归调用,并在递归的最后,等待所有异步操作完成。 所以实际上,真正并发执行的只是网络请求,所有网络请求结束后,后续代码执行还是串行的