基於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

那這裏就把整個簡單的微服務體系完成了,寫得很差大佬們見諒哈~

相關文章
相關標籤/搜索