Featured image of post Thrift

Rpc

本文阅读量

Thrift

Apache Thrift是一个跨语言的服务部署框架,通过一个中间语言(IDL, 接口定义语言)来定义RPC的接口和数据类型,然后通过一个编译器生成不同语言的代码(支持C++,Java,Python,PHP, GO,Javascript,Ruby,Erlang,Perl, Haskell, C#等),并由生成的代码负责RPC协议层和传输层的实现

本文是基于thrift@0.9版本

1、安装

2、使用

2.1 编写IDL文件

现在开始编写一个简单IDL文件goods.thrift

1
2
3
4
5
6
7
namespace php Services.Goods
service Goods
{
    string getName(1:i64 id);

    i16 getId(1:string name);
}

2.2 通过生成器生成PHP文件

1
2
3
4
# 生成服务端
thrift --gen php:server goods.thrift
# 生成客户端
thrift --gen php goods.thrift

生成文件在gen-php目录下面的Services/Goods/(目录与namesapce定义一致),这是个公共文件,服务端和客户端都需要包括它。其中客户端调用的代码(GoodsClient )已经生成好了 目前的目录结构:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
├── gen-php
│   └── Services
│       └── Goods
│           ├── GoodsClient.php
│           └── GoodsIf.php
│           └── GoodsProcessor.php
│           └── Goods_getAllGoods_args.php
│           └── Goods_getAllGoods_result.php
│           └── Goods_getDetail_args.php
│           └── Goods_getDetail_result.php
│           └── Goods_getGname_args.php
│           └── Goods_getGname_result.php
├── goods.thrift

2.3 下载Thrift

Thrift的PHP类库在Thrift源码中https://github.com/apache/thrift. 可以将thrift/lib/php/lib/Thrift目录复制到当前目录下载下来。

2.4 将代码继承到thinkphp

服务端-商品服务

目录机构如下

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
├── application
├── extend
│   └── Thrift  # 2.3步下载的Thrift源码
│   └── Services # 2.2 步生成的php代码
│       └── Goods
│           ├── GoodsClient.php
│           └── GoodsIf.php
│           └── GoodsProcessor.php
│           └── Goods_getAllGoods_args.php
│           └── Goods_getAllGoods_result.php
│           └── Goods_getDetail_args.php
│           └── Goods_getDetail_result.php
│           └── Goods_getGname_args.php
│           └── Goods_getGname_result.php

GoodsHandler.php 需要实现接口GoodsIf

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
<?php
namespace app\services\controller;
use Services\Goods\GoodsIf;

class GoodsHandler implements GoodsIf {
    /**
     * @param string $id
     * @return string
     */
    public function getGname($id){
        return '商品名称';
    }
    /**
     * @param string $name
     * @return string
     */
    public function getId($name){
      	return 1;
    }
}

服务端代码Rpcservice.php,使用command来进行启动

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
<?php
namespace app\common\command;

use app\common\command\Common;
use think\console\Input;
use think\console\input\Argument;
use think\console\input\Option;
use think\console\Output;

use Thrift\ClassLoader\ThriftClassLoader;
use Thrift\Exception\TException;
use Thrift\Factory\TTransportFactory;
use Thrift\Factory\TBinaryProtocolFactory;
use Thrift\Server\TServerSocket;
use Thrift\Server\TSimpleServer;

use app\services\controller\GoodsHandler;
use Services\Goods\GoodsProcessor;

class Rpcservice extends Common
{
    protected function execute(Input $input, Output $output){
        try {
            $handler = new GoodsHandler();
            $processor = new GoodsProcessor($handler);

            $transportFactory = new TTransportFactory(); 
            $protocolFactory = new TBinaryProtocolFactory(true, true);

            //作为cli方式运行,监听端口,官方实现
            $transport = new TServerSocket('127.0.0.1', 9090);
            $server = new TSimpleServer($processor, $transport, $transportFactory, $transportFactory, $protocolFactory, $protocolFactory);
            $server->serve();
        } catch (TException $tx) {
            print 'TException: '.$tx->getMessage()."\n";
        }
    }
    
}

定义command

1
2
3
return [
    'rpc_service'             => 'app\common\command\Rpcservice', // 启动rpc service
];

启动rpc service

1
php think rpc_service

客户端-订单服务

目录机构如下

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
├── application
├── extend
│   └── Thrift  # 2.3步下载的Thrift源码
│   └── Services # 2.2 步生成的php代码
│       └── Goods
│           ├── GoodsClient.php
│           └── GoodsIf.php
│           └── GoodsProcessor.php
│           └── Goods_getAllGoods_args.php
│           └── Goods_getAllGoods_result.php
│           └── Goods_getDetail_args.php
│           └── Goods_getDetail_result.php
│           └── Goods_getGname_args.php
│           └── Goods_getGname_result.php

GoodsClient.php调用rpc服务

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
<?php
namespace app\index\controller;
use Services\Goods\GoodsClient as Client;
use Thrift\Transport\TSocket;
use Thrift\Transport\TBufferedTransport;
use Thrift\Protocol\TBinaryProtocol;
class GoodsClient extends Rpc
{
    /**
    * @description: 方法描述
    * @author   liangdong
    * @method
    * @date     2021/06/29 10:46:50
    * +-----------------------------
    * @params   int      name
    * @return
    */
    public function getAllGoods()
    {
        try {
            //仅在与服务端处于同一输出输出流有用
            //使用方式:php Client.php | php Server.php 
            //$transport = new TBufferedTransport(new TPhpStream(TPhpStream::MODE_R | TPhpStream::MODE_W));
        
            //socket方式连接服务端
            //数据传输格式和数据传输方式与服务端一一对应
            //如果服务端以http方式提供服务,可以使用THttpClient/TCurlClient数据传输方式
            $transport = new TBufferedTransport(new TSocket('192.168.1.4', 9090));
            $protocol = new TBinaryProtocol($transport);
            $client = new Client($protocol);
        
            $transport->open();
            
            //同步方式进行交互
            $recv = $client->getGname(1);
            echo $recv." \n";
        
            $transport->close();
        
        } catch (TException $tx) {
            print 'TException: '.$tx->getMessage()."\n";
        }
    }
}
使用 Hugo 构建
主题 StackJimmy 设计