基于Hyperf的RPC简单微服务架构

为何是RPC?而不是HTTP

一、简单来讲,RPC没有那么多HTTP的Request 和Response Body 字段,好比:content-typeuser-agentaccept-languagecontent-encodingexpires等字段。每每这些字段就占了报文的70%内容,若是请求次数过于频繁,可想而知对于性能和网络开销有多大。php

二、而在内部服务器间相互通信,咱们彻底能够减小握手次数linux

  • 使用HTTP2.0,HTTP2.0能够在一个链接上发送屡次数据,相比目前的http1.1模式,它仍是非阻塞的
  • 使用基于TCP的RPC协议,长链接传输数据

基于以上,微服务间使用HTTPv1.1的服务器间通信并非最好的方案,这就是为何不少PHP框架基于PHP-FPM不适合作微服务的缘由,由于PHP-FPM每一个请求都会产生一个新的Woker进程,若是每一个Worker都跑去与微服务创建HTTP1.1链接,那其实没有意义web

为何须要Consul?

consul是什么?为何须要服务发现?看图就知道了json

我在Server1部署了一套HTTP服务(服务消费者)对外提供接口,可是它同时也依赖Server2的服务(服务提供者),Server1不须要知道Server2的地址,只须要知道Consul这个服务者中心就好了,它会帮我注册全部的服务api

这在现实中举个例子就是,一个大公司的Team A在作HTTP业务核心功能,Team B作了不少服务轮子,那Team A总不能每次开发都跑去Team B问:“大家的地址是多少啊?端口是多少啊? 服务名叫什么啊?告诉我好调用啊”。那若是要调用100个服务,岂不是Team A的人每次都要为了配置IP和端口忙死?数组

1、在Server 1搭建Consul

一、下载consul for linux,解压后就是一个可执行文件,直接mv到/usr/bin/consul浏览器

二、新建一个consul文件夹,在里面新建一个data文件夹和etc文件夹,data文件夹用于存放consul的数据文件,etc用于存放配置文件服务器

三、切换到etc文件夹,新建一个web.json文件,内容以下:网络

{
    "service": {
        //这里写服务的ID,必须惟一
        "id": "CalculatorService",
        //这里写服务名称,通常也是ID名,非惟一
        "name": "CalculatorService",
        //注册服务,服务在哪台服务器上,就填写那台服务器IP,这里我填写server2的ip,由于是server2提供服务给server1调用
        "address": "server2.ip.server2.ip",
        //随便写
        "tags": [
            "webapi"
        ],
        //同上,服务也有端口,就填写那台服务器提供的端口,这里填写server2的端口
        "port": 9502
    }
}

四、回到consul目录,启动consul,其中-config-dir指定刚刚的配置目录,-data-dir指定存放数据的目录app

consul agent -dev -ui -config-dir=./etc -data-dir=./data -client=0.0.0.0

client=0.0.0.0这里须要注意下,网上通常的都是127.0.0.1,若是写成127.0.0.1一样能够运行,可是没办法在外网访问consul的UI界面,因此这里改为0.0.0.0

五、在浏览器输入IP:8500,就能够看到consul安装成功

2、在Server 2安装并设置hyperf服务提供者

一、在app目录下新建RPC文件夹,先新建一个CalculatorServiceInterface接口文件,文件名CalculatorServiceInterface.php

<?php

namespace App\Rpc;

interface CalculatorServiceInterface
{
    public function add(int $a, int $b): int;
}

二、基于这个Interface,在该目录下添加一个实现方式的CalculatorService,文件名:CalculatorService.php

<?php


namespace App\Rpc;

use Hyperf\RpcServer\Annotation\RpcService;

/**
 * 注意,如但愿经过服务中心来管理服务,需在注解内增长 publishTo 属性
 * @RpcService(name="CalculatorService", protocol="jsonrpc-http", server="jsonrpc-http" ,publishTo="consul")
 */
class CalculatorService implements CalculatorServiceInterface
{
    public function add(int $a, int $b) : int
    {
        return $a +$b;
    }
}

在这里使用了注解方式提供服务,name是服务名称,protocol指定使用了jsonrpc-http协议,这里加了publishTo选项,指定一个服务注册中心,由于以前已经搭建好了consul

三、打开config/autoload/server.php,在servers数组下,添加一个数组:

[
    'name' => 'jsonrpc-http',
    'type' => Server::SERVER_HTTP,
    'host' => '0.0.0.0',
    'port' => 9502,
    'sock_type' => SWOOLE_SOCK_TCP,
    'callbacks' => [
       SwooleEvent::ON_REQUEST => [\Hyperf\JsonRpc\HttpServer::class, 'onRequest'],
    ],
],

这样hyperf就会把代码里的服务,以9502端口发布出去并运行,这里的端口,其实就与上面的consul配置文件web.json文件对应起来,从而使到consul能发现9502这个服务

3、在Server 1安装并设置hyperf服务消费者

一、我这里新建一个项目来表示消费者consumer服务模,一样在app目录下新建RPC文件夹,先新建一个CalculatorServiceInterface接口文件,文件名CalculatorServiceInterface.php

<?php

namespace App\Rpc;

interface CalculatorServiceInterface
{
    public function add(int $a, int $b): int;
}

二、打开app/Controllers/IndexController.php

<?php
namespace App\Controller;

use App\Rpc\CalculatorServiceInterface;
use Hyperf\Di\Annotation\Inject;
use Hyperf\HttpServer\Annotation\AutoController;

/**
 * Class IndexController
 * @package App\Controller
 * @AutoController()
 */
class IndexController extends AbstractController
{
    /**
     * //在这里咱们注入了一个接口类,并直接调用接口的add方法,但在本项目并无add 
方法的实现,真正的add方法在服务提供者里已经实现了,hyperf会帮咱们找到相应服务并使用
     * @Inject()
     * @var CalculatorServiceInterface
     */
    private $calculatorService;

    public function index()
    {
        return $this->calculatorService->add(1,2);
    }
}

二、在config/autoload下新建services.php

<?php
return [
    'consumers' => [
        [
            // name 需与服务提供者的 name 属性相同
            'name' => 'CalculatorService',
            // 服务接口名,可选,默认值等于 name 配置的值,若是 name 直接定义为接口类则可忽略此行配置,如 name 为字符串则须要配置 service 对应到接口类
            'service' => \App\Rpc\CalculatorServiceInterface::class,


            // 这个消费者要从哪一个服务中心获取节点信息,如不配置则不会从服务中心获取节点信息
            'registry' => [
                'protocol' => 'consul',
                //这里的address,表示consul搭建在那台服务器上,就填写哪台服务器的IP
                'address' => 'http://127.0.0.1:8500',
            ],
        ]
    ],
];

这样当请求进来的时候,IndexController就会注入Service,hyperf就会告知这个service应该要去services.php去找到这个服务(也就是consul)

三、把config/autoload/server.php里的port改为9503,待会经过9503访问index控制器,这里只是演示,现实中你能够随意更改为你想访问的端口

'servers' => [
        [
            'name' => 'http',
            'type' => Server::SERVER_HTTP,
            'host' => '0.0.0.0',
            'port' => 9503,
            'sock_type' => SWOOLE_SOCK_TCP,
            'callbacks' => [
                SwooleEvent::ON_REQUEST => [Hyperf\HttpServer\Server::class, 'onRequest'],
            ],
        ],
    ],

4、跑起来

一、从新启动consul,若是以前启动过,先kill -9 consul的PID

consul agent -dev -ui -config-dir=./etc -data-dir=./data -client=0.0.0.0

二、切换到Server2的hyperf-provider,启动

php bin/hyperf.php start

三、切换到Server1的hyperf-consumer,启动

php bin/hyperf.php start

四、在浏览器打开Server1的HTTP 8500端口,查看consul界面,能够看到能够找到Server2下的hyperf的provider

五、在浏览访问一下Servier1的服务

能够看到Server1下的9503服务是正常的,它会访问Server1下的consul-8500中心,而后consul-8500中心会去访问Server2下的9502服务,再交还给Server1的9503

那这里就把整个简单的微服务体系完成了,写得很差大佬们见谅哈~

相关文章
相关标签/搜索