溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點(diǎn)擊 登錄注冊 即表示同意《億速云用戶服務(wù)條款》

go-micro+php+consul實(shí)現(xiàn)簡單的微服務(wù)是什么樣的

發(fā)布時(shí)間:2021-10-15 10:14:26 來源:億速云 閱讀:99 作者:柒染 欄目:編程語言

這期內(nèi)容當(dāng)中小編將會(huì)給大家?guī)碛嘘P(guān)go-micro+php+consul實(shí)現(xiàn)簡單的微服務(wù)是什么樣的,文章內(nèi)容豐富且以專業(yè)的角度為大家分析和敘述,閱讀完這篇文章希望大家可以有所收獲。

首先我們用go-micro構(gòu)建一個(gè)服務(wù)。(關(guān)于go-micro的使用可以參照官方實(shí)例或者文檔)

//新建一個(gè)微服務(wù)
micro new --type "srv" user-srv

定義我們的服務(wù),這里定義兩個(gè)rpc服務(wù),Register和User

// 修改proto
syntax = "proto3";

package go.micro.srv.user;

service User {
    rpc Register(RegisterRequest) returns (UserInfo) {}
    rpc User(UserInfoRequest) returns (UserInfo) {}
    rpc Stream(StreamingRequest) returns (stream StreamingResponse) {}
    rpc PingPong(stream Ping) returns (stream Pong) {}
}


message UserInfoRequest {
    int64 userId  = 1;
}

message RegisterRequest {
    string username  = 1;
    string email     = 2;
    string password  = 3;
}

message UserInfo {
    int64  id       =  1;
    string username =  2;
    string email    =  3;
}



message StreamingRequest {
    int64 count = 1;
}

message StreamingResponse {
    int64 count = 1;
}

message Ping {
    int64 stroke = 1;
}

message Pong {
    int64 stroke = 1;
}

然后生成執(zhí)行下面命令我們就可以發(fā)現(xiàn)在proto文件中多出兩個(gè)文件。這個(gè)proto為我們生成的,后面會(huì)用到。

protoc --proto_path=${GOPATH}/src:. --micro_out=. --go_out=. proto/user/user.proto

寫我們的業(yè)務(wù)邏輯,修改handle/user.go文件

type User struct{}

// Call is a single request handler called via client.Call or the generated client code
func (e *User) Register(ctx context.Context, req *user.RegisterRequest, rsp *user.UserInfo) error {
    log.Log("Received User.Register request")
    rsp.Id    = 1
    rsp.Email = req.Email
    rsp.Username = req.Username
    return nil
}


func (e *User) User(ctx context.Context, req *user.UserInfoRequest, rsp *user.UserInfo) error {
    log.Log("Received User.Register request")
    rsp.Id    = 1
    rsp.Email = "741001560@qq.com"
    rsp.Username = "chensi"
    return nil
}

// Stream is a server side stream handler called via client.Stream or the generated client code
func (e *User) Stream(ctx context.Context, req *user.StreamingRequest, stream user.User_StreamStream) error {
    log.Logf("Received User.Stream request with count: %d", req.Count)

    for i := 0; i < int(req.Count); i++ {
        log.Logf("Responding: %d", i)
        if err := stream.Send(&user.StreamingResponse{
            Count: int64(i),
        }); err != nil {
            return err
        }
    }

    return nil
}

// PingPong is a bidirectional stream handler called via client.Stream or the generated client code
func (e *User) PingPong(ctx context.Context, stream user.User_PingPongStream) error {
    for {
        req, err := stream.Recv()
        if err != nil {
            return err
        }
        log.Logf("Got ping %v", req.Stroke)
        if err := stream.Send(&user.Pong{Stroke: req.Stroke}); err != nil {
            return err
        }
    }
}

最后修改我們的main.go文件,服務(wù)發(fā)現(xiàn)使用時(shí)consul。

func main() {
    //initCfg()
    // New Service

    micReg := consul.NewRegistry()

    service := micro.NewService(
        micro.Server(s.NewServer()),
        micro.Name("go.micro.srv.user"),
        micro.Version("latest"),
        micro.Registry(micReg),
    )

    // Initialise service
    service.Init()

    // Run service
    if err := service.Run(); err != nil {
        log.Fatal(err)
    }
}

我們使用consul做微服務(wù)發(fā)現(xiàn),當(dāng)然首先你需要安裝consul

wget https://releases.hashicorp.com/consul/1.2.0/consul_1.6.1_linux_amd64.zip

unzip consul_1.6.1_linux_amd64.zip

mv consul /usr/local/bin/

啟動(dòng)consul的時(shí)候由于在是本地虛擬機(jī)上面,所以我們可以簡單處理

consul agent -dev  -client 0.0.0.0 -ui

這時(shí)候可以啟動(dòng)consul的ui了,我本地vagrant的虛擬機(jī)192.168.10.100,那么我們打開的是http://192.168.10.100:8500/ui/dc1/services

啟動(dòng)user-srv的服務(wù)發(fā)現(xiàn)consul里面出現(xiàn) go.micro.srv.user 的服務(wù)注冊信息了

下面來寫hyperf的代碼了。按照官方文檔安裝框架,安裝的時(shí)候rpc需要選擇grpc,需要注意的是你的系統(tǒng)上面需要安裝php7.2以上的版本,swoole版本也需要4.3的版本以上,我用的是最新homestead,所以相對而言安裝這些依賴比較簡單,所以在此強(qiáng)烈推薦。

第一次啟動(dòng)時(shí)候官方會(huì)要求修改一些php.ini的參數(shù),大家安裝要求走就是了。

這部分的流程自己參照官方文檔,至于一些擴(kuò)展的安裝可以谷歌或者百度。

安裝好框架之后再根目錄下面新建一個(gè)grpc和proto的目錄,把go-micro里面user.proto文件復(fù)制到hyperf項(xiàng)目的proto的目錄之下。然后在目錄下執(zhí)行命令

protoc --php_out=plugins=grpc:../grpc user.proto

執(zhí)行成功之后會(huì)發(fā)現(xiàn)在grpc目錄下多出兩個(gè)文件夾。

接下來我們開始編寫client的代碼,在hyperf項(xiàng)目的app目錄下新建一個(gè)Grpc的目錄并且新建一個(gè)UserClient.php的文件

namespace App\Grpc;


use Go\Micro\Srv\User\RegisterRequest;
use Go\Micro\Srv\User\UserInfo;
use Hyperf\GrpcClient\BaseClient;

class UserClient extends BaseClient
{
    public function Register(RegisterRequest $argument)
    {
        return $this->simpleRequest(
            '/user.User/Register',
            $argument,
            [UserInfo::class, 'decode']
        );
    }

關(guān)于這一塊的代碼,其實(shí)官方文檔寫得特別詳細(xì),具體可以參照官方文檔。

新建一個(gè)路由

Router::addRoute(['GET', 'POST', 'HEAD'], '/grpc', 'App\Controller\IndexController@grpc');

編寫控制器

public function grpc ()
{

        $client = new \App\Grpc\UserClient('127.0.0.1:9527', [
            'credentials' => null,
        ]);

        $request = new RegisterRequest();
        $request->setEmail("741001560@qq.com");
        $request->setUsername("chensi");
        $request->setPassword("123456");

        /**
         * @var \Grpc\HiReply $reply
         */
        list($reply, $status) = $client->Register($request);

        $message = $reply->getId();
        return [
            'id' => $message
        ];
    }

這時(shí)候還需要吧根目錄下的grpc目錄加載進(jìn)來。修改composer.json文件

```

// psr-4 下面新增兩個(gè)行
"autoload": {
        "psr-4": {
            "App\\": "app/",
            "GPBMetadata\\": "grpc/GPBMetadata",
            "Go\\": "grpc/Go"
        },
        "files": []
    }

然后執(zhí)行composer dump-autoload命令。然后啟動(dòng)hyperf項(xiàng)目,打開瀏覽器輸入http://192.168.10.100:9501/grpc回車,這時(shí)候我們就能看到結(jié)果了。

這時(shí)候我們會(huì)發(fā)現(xiàn)一個(gè)問題,那就是consul在client端壓根沒用到,在代碼中我們還是需要指明我們的端口號。然后再看看官方文檔其實(shí)是支持consul的,那么將代碼改造下。

在app下新建一個(gè)Register的目錄創(chuàng)建一個(gè)文件ConsulServices.php,然后開始編寫服務(wù)發(fā)現(xiàn)的代碼,安裝consul包以后,由于官方提供的consul包沒有文檔所以需要自己去看源代碼。官方在consul提供的api上面做了簡單的封裝,如KV、Health等,在實(shí)例化話的時(shí)候需要穿一個(gè)客戶端過去。下面提供一個(gè)簡單的實(shí)例。

<?php
declare(strict_types=1);

namespace App\Register;

use Hyperf\Consul\Health;
use Psr\Container\ContainerInterface;
use Hyperf\Guzzle\ClientFactory;

class ConsulServices
{

    public $servers;
    private $container;


    public function __construct(ContainerInterface $container)
    {
        $this->container = $container;
    }

    public function getServers()
    {
        $health = new Health(function ()  {
            return $this->container->get(ClientFactory::class)->create([
                'base_uri' => 'http://127.0.0.1:8500',
            ]);
        });
        $resp = $health->service("go.micro.srv.user");
        $servers = $resp->json();
        if (empty($servers)){
            $this->servers = [];
        }
        foreach ($servers as $server) {
            $this->servers[] = sprintf("%s:%d",$server['Service']['Address'],$server['Service']['Port']);
        }
    }
}

這時(shí)候發(fā)現(xiàn)一個(gè)問題如果每次請求過來都去請求一次必然給consul造成很大的負(fù)荷。既然用到了swoole框架可以在每次swoole啟動(dòng)的時(shí)候去請求一次,然后把服務(wù)發(fā)現(xiàn)的信息存起來。修改配置文件server。

'callbacks' => [
//        SwooleEvent::ON_BEFORE_START => [Hyperf\Framework\Bootstrap\ServerStartCallback::class, 'beforeStart'],
        SwooleEvent::ON_BEFORE_START => [\App\Bootstrap\ServerStartCallback::class, 'beforeStart'],
        SwooleEvent::ON_WORKER_START => [Hyperf\Framework\Bootstrap\WorkerStartCallback::class, 'onWorkerStart'],
        SwooleEvent::ON_PIPE_MESSAGE => [Hyperf\Framework\Bootstrap\PipeMessageCallback::class, 'onPipeMessage'],
    ],
可以在ServerStartCallback類里面請求consul進(jìn)行服務(wù)發(fā)現(xiàn) 后面拿到參數(shù)就好了。

namespace App\Bootstrap;
use App\Register\ConsulServices;
class ServerStartCallback
{
    public function beforeStart()
    {
        $container = \Hyperf\Utils\ApplicationContext::getContainer();
        $container->get(ConsulServices::class)->getServers();
    }
}

改造一下原來的控制器

public function grpc ()
{

        $container = \Hyperf\Utils\ApplicationContext::getContainer();
        $servers = $container->get(ConsulServices::class)->servers;
        if (empty($servers)) {
            return [
                'errCode' => 1000,
                'msg'     => '服務(wù)不存在',
            ];
        }
        $key = array_rand($servers,1); // 哈哈哈一個(gè)簡單的負(fù)載均衡
        $hostname = $servers[$key];
        $client = new \App\Grpc\UserClient($hostname, [
            'credentials' => null,
        ]);
        $request = new RegisterRequest();
        $request->setEmail("741001560@qq.com");
        $request->setUsername("chensi");
        $request->setPassword("123456");

        /**
         * @var \Grpc\HiReply $reply
         */
        list($reply, $status) = $client->Register($request);

        $message = $reply->getId();
        return [
            'id' => $message
        ];
    }

重啟服務(wù),這時(shí)候然后刷新瀏覽器試試。這時(shí)候一個(gè)簡單基于go rpc server和php client的微服務(wù)就搭建完成了。當(dāng)然了這時(shí)候還沒有心跳機(jī)制,hyperf官網(wǎng)提供了一個(gè)定時(shí)器的功能,我們定時(shí)去刷服務(wù)發(fā)現(xiàn)就好了。

上述就是小編為大家分享的go-micro+php+consul實(shí)現(xiàn)簡單的微服務(wù)是什么樣的了,如果剛好有類似的疑惑,不妨參照上述分析進(jìn)行理解。如果想知道更多相關(guān)知識(shí),歡迎關(guān)注億速云行業(yè)資訊頻道。

向AI問一下細(xì)節(jié)

免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點(diǎn)不代表本網(wǎng)站立場,如果涉及侵權(quán)請聯(lián)系站長郵箱:is@yisu.com進(jìn)行舉報(bào),并提供相關(guān)證據(jù),一經(jīng)查實(shí),將立刻刪除涉嫌侵權(quán)內(nèi)容。

AI