加入收藏 | 设为首页 | 会员中心 | 我要投稿 安卓应用网 (https://www.0791zz.com/)- 科技、建站、经验、云计算、5G、大数据,站长网!
当前位置: 首页 > 编程开发 > PHP > 正文

PHP laravel+thrift+swoole打造微服务框架

发布时间:2020-05-25 08:17:15 所属栏目:PHP 来源:互联网
导读:Laravel作为最受欢迎的php web框架一直广受广大互联网公司的喜爱。 笔者也参与过一些由laravel开发的项目。虽然laravel的性能广受诟病但是业界也有一些比较好的解决方案,比如堆机器,

Laravel作为最受欢迎的php web框架一直广受广大互联网公司的喜爱。

笔者也参与过一些由laravel开发的项目。虽然laravel的性能广受诟病但是业界也有一些比较好的解决方案,比如堆机器,比如使用swoole进行加速。

一个项目立项到开发上线,随着时间和需求的不断激增,会越来越复杂,变成一个大项目,如果前期项目架构没设计的不好,代码会越来越臃肿,难以维护,后期的每次产品迭代上线都会牵一发而动全身。项目微服务化,松耦合模块间的关系,是一个很好的选择,随然增加了维护成本,但是还是很值得的。

那么有什么办法使一个laravel项目改造成微服务呢?

最近研究thrift的时候发现thrift对php之城非常好,那么可不可以使用使用thrift作为rpc框架,使用swoole来实现异步TCP服务,打造一个微服务框架呢。

心动不如行动我们开始尝试一下吧。首先我们创建一个laravel的项目,笔者使用的laravel官方提供的homestead的环境。

laravel new laravel-thrift-app 

安装laravel-s https://github.com/hhxsv5/laravel-s/blob/master/README-CN.md

composer require "hhxsv5/laravel-s:~3.5.0" -vvv 

laravel-s是一个由swoole写的laravel扩展,赋予laravel更好的性能,具体使用方法参看官方文档。

在项目的根目录下新建一个thrift的目录,然后在该子目录下创建 Thrift IDL 文件 user.thrift,用于定义和用户相关的服务接口。

1 namespace php App.Thrift.User  
2 // 定义用户接口 
3 service User {     
4 string getInfo(1:i32 id)
5  }

这里我们定义了一个接口,接着在项目根目录下运行如下命令,根据上述 IDL 文件生成相关的服务代码:

thrift -r --gen php:server -out ./ thrift/user.thrift 

查看文件这时候我们会发现在AppThriftUser`目录下生成对应的服务代码。

通过 Composer 安装 Thrift PHP 依赖包:

composer require apache/thrift 

编写服务代码,在 app目录下新建一个 Services/Server 子目录,然后在该目录下创建服务接口类 UserService,该类实现自 `AppThriftUserUserIf` 接口:

 1 <?php
 2 namespace AppServicesServer;
 3 
 4 
 5 use AppThriftUserUserIf;
 6 
 7 class UserService implements UserIf
 8 {
 9     public function getInfo($id)
10     {
11         return "chenSi".$id;
12     }
13 }

在 app 目录下新建一个 Sockets目录用于存放 Swoole 相关代码,首先我们创建一个 ServerTransport.php用来存放服务端代理类,并编写代码如下:

 1 <?php
 2 namespace AppSockets;
 3 
 4 
 5 use ThriftServerTServerTransport;
 6 
 7 class ServerTransport extends TServerTransport
 8 {
 9     /**
10      * @var array 服务器选项
11      */
12     public $options = [
13         'dispatch_mode'         => 1,//1: 轮循,3: 争抢
14         'open_length_check'     => true,//打开包长检测
15         'package_max_length'    => 8192000,//最大的请求包长度,8M
16         'package_length_type'   => 'N',//长度的类型,参见PHP的pack函数
17         'package_length_offset' => 0,//第N个字节是包长度的值
18         'package_body_offset'   => 4,//从第几个字节计算长度
19     ];
20 
21     /**
22      * @var SwooleServer
23      */
24     public $server;
25     protected $host;
26     protected $port;
27     protected $sockType;
28 
29 
30     public function __construct($swoole,$host,$port = 9999,$sockType = SWOOLE_SOCK_TCP,$options = [])
31     {
32         $this->server = $swoole;
33         $this->host   = $host;
34         $this->port   = $port;
35         $this->sockType = $sockType;
36         $this->options = array_merge($this->options,$options);
37 
38     }
39 
40 
41     public function listen()
42     {
43         $this->server =$this->server->addlistener($this->host,$this->port,$this->sockType);
44         $this->server->set($this->options);
45         return null;
46     }
47 
48 
49     public function close()
50     {
51         //$this->server->shutdown();
52         return null;
53     }
54 
55 
56     protected function acceptImpl()
57     {
58         return null;
59     }
60 }

我们在代理类的构造函数中初始化 Swoole TCP 服务器参数,由于我们使用的是laravel-s然后在该类中定义 listen 方法启动这个swoole增加监听的端口并监听客户端请求。

我们在 app/Sockets目录下创建 Transport.php文件用于存放基于 Swoole 的传输层实现代码:

  1 <?php
  2 /**
  3  * Created by PhpStorm.
  4  * User: 74100
  5  * Date: 2019/10/21
  6  * Time: 2:22
  7  */
  8 namespace AppSockets;
  9 
 10 use SwooleServer as SwooleServer;
 11 use ThriftExceptionTTransportException;
 12 use ThriftTransportTTransport;
 13 
 14 class Transport extends TTransport
 15 {
 16     /**
 17      * @var swoole服务器实例
 18      */
 19     protected $server;
 20     /**
 21      * @var int 客户端连接描述符
 22      */
 23     protected $fd = -1;
 24     /**
 25      * @var string 数据
 26      */
 27     protected $data = '';
 28     /**
 29      * @var int 数据读取指针
 30      */
 31     protected $offset = 0;
 32 
 33     /**
 34      * SwooleTransport constructor.
 35      * @param SwooleServer $server
 36      * @param int $fd
 37      * @param string $data
 38      */
 39     public function __construct(SwooleServer $server,$fd,$data)
 40     {
 41         $this->server = $server;
 42         $this->fd = $fd;
 43         $this->data = $data;
 44     }
 45 
 46     /**
 47      * Whether this transport is open.
 48      *
 49      * @return boolean true if open
 50      */
 51     public function isOpen()
 52     {
 53         return $this->fd > -1;
 54     }
 55 
 56     /**
 57      * Open the transport for reading/writing
 58      *
 59      * @throws TTransportException if cannot open
 60      */
 61     public function open()
 62     {
 63         if ($this->isOpen()) {
 64             throw new TTransportException('Swoole Transport already connected.',TTransportException::ALREADY_OPEN);
 65         }
 66     }
 67 
 68     /**
 69      * Close the transport.
 70      * @throws TTransportException
 71      */
 72     public function close()
 73     {
 74         if (!$this->isOpen()) {
 75             throw new TTransportException('Swoole Transport not open.',TTransportException::NOT_OPEN);
 76         }
 77         $this->server->close($this->fd,true);
 78         $this->fd = -1;
 79     }
 80 
 81     /**
 82      * Read some data into the array.
 83      *
 84      * @param int $len How much to read
 85      * @return string The data that has been read
 86      * @throws TTransportException if cannot read any more data
 87      */
 88     public function read($len)
 89     {
 90         if (strlen($this->data) - $this->offset < $len) {
 91             throw new TTransportException('Swoole Transport[' . strlen($this->data) . '] read ' . $len . ' bytes failed.');
 92         }
 93         $data = substr($this->data,$this->offset,$len);
 94         $this->offset += $len;
 95         return $data;
 96     }
 97 
 98     /**
 99      * Writes the given data out.
100      *
101      * @param string $buf The data to write
102      * @throws TTransportException if writing fails
103      */
104     public function write($buf)
105     {
106         if (!$this->isOpen()) {
107             throw new TTransportException('Swoole Transport not open.',TTransportException::NOT_OPEN);
108         }
109         $this->server->send($this->fd,$buf);
110     }
111 }

Transport类主要用于从传输层写入或读取数据,最后我们创建 Server.php 文件,用于存放基于 Swoole 的 RPC 服务器类:

 1 <?php
 2 /**
 3  * Created by PhpStorm.
 4  * User: 74100
 5  * Date: 2019/10/21
 6  * Time: 2:24
 7  */
 8 namespace AppSockets;
 9 
10 use SwooleServer as SwooleServer;
11 use ThriftServerTServer;
12 
13 class Server extends TServer
14 {
15     public function serve()
16     {
17 
18         $this->transport_->server->on('receive',[$this,'handleReceive']);
19         $this->transport_->listen();
20 
21     }
22 
23     public function stop()
24     {
25         $this->transport_->close();
26     }
27 
28     /**
29      * 处理RPC请求
30      * @param Server $server
31      * @param int $fd
32      * @param int $fromId
33      * @param string $data
34      */
35     public function handleReceive(SwooleServer $server,$fromId,$data)
36     {
37         $transport = new Transport($server,$data);
38         $inputTransport = $this->inputTransportFactory_->getTransport($transport);
39         $outputTransport = $this->outputTransportFactory_->getTransport($transport);
40         $inputProtocol = $this->inputProtocolFactory_->getProtocol($inputTransport);
41         $outputProtocol = $this->outputProtocolFactory_->getProtocol($outputTransport);
42         $this->processor_->process($inputProtocol,$outputProtocol);
43     }
44 }

(编辑:安卓应用网)

【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!

    推荐文章
      热点阅读