站長資訊網
        最全最豐富的資訊網站

        go-micro+php+consul實現簡單的微服務

        go-micro+php+consul實現簡單的微服務

        首先我們用go-micro構建一個服務。(關于go-micro的使用可以參照官方實例或者文檔)

        //新建一個微服務 micro new --type "srv" user-srv

        定義我們的服務,這里定義兩個rpc服務,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; }

        然后生成執行下面命令我們就可以發現在proto文件中多出兩個文件。這個proto為我們生成的,后面會用到。

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

        寫我們的業務邏輯,修改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文件,服務發現使用時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做微服務發現,當然首先你需要安裝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/

        啟動consul的時候由于在是本地虛擬機上面,所以我們可以簡單處理

        consul agent -dev  -client 0.0.0.0 -ui

        這時候可以啟動consul的ui了,我本地vagrant的虛擬機192.168.10.100,那么我們打開的是http://192.168.10.100:8500/ui/dc1/services

        啟動user-srv的服務發現consul里面出現 go.micro.srv.user 的服務注冊信息了

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

        第一次啟動時候官方會要求修改一些php.ini的參數,大家安裝要求走就是了。

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

        安裝好框架之后再根目錄下面新建一個grpc和proto的目錄,把go-micro里面user.proto文件復制到hyperf項目的proto的目錄之下。然后在目錄下執行命令

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

        執行成功之后會發現在grpc目錄下多出兩個文件夾。

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

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

        關于這一塊的代碼,其實官方文檔寫得特別詳細,具體可以參照官方文檔。

        新建一個路由

        Router::addRoute(['GET', 'POST', 'HEAD'], '/grpc', 'AppControllerIndexController@grpc');

        編寫控制器

        public function grpc () {          $client = new AppGrpcUserClient('127.0.0.1:9527', [             'credentials' => null,         ]);          $request = new RegisterRequest();         $request->setEmail("741001560@qq.com");         $request->setUsername("chensi");         $request->setPassword("123456");          /**          * @var GrpcHiReply $reply          */         list($reply, $status) = $client->Register($request);          $message = $reply->getId();         return [             'id' => $message         ];     }

        這時候還需要吧根目錄下的grpc目錄加載進來。修改composer.json文件

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

        然后執行composer dump-autoload命令。然后啟動hyperf項目,打開瀏覽器輸入http://192.168.10.100:9501/grpc回車,這時候我們就能看到結果了。

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

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

        <?php declare(strict_types=1);  namespace AppRegister;  use HyperfConsulHealth; use PsrContainerContainerInterface; use HyperfGuzzleClientFactory;  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']);         }     } }

        這時候發現一個問題如果每次請求過來都去請求一次必然給consul造成很大的負荷。既然用到了swoole框架可以在每次swoole啟動的時候去請求一次,然后把服務發現的信息存起來。修改配置文件server。

        'callbacks' => [ //        SwooleEvent::ON_BEFORE_START => [HyperfFrameworkBootstrapServerStartCallback::class, 'beforeStart'],         SwooleEvent::ON_BEFORE_START => [AppBootstrapServerStartCallback::class, 'beforeStart'],         SwooleEvent::ON_WORKER_START => [HyperfFrameworkBootstrapWorkerStartCallback::class, 'onWorkerStart'],         SwooleEvent::ON_PIPE_MESSAGE => [HyperfFrameworkBootstrapPipeMessageCallback::class, 'onPipeMessage'],     ], 可以在ServerStartCallback類里面請求consul進行服務發現 后面拿到參數就好了。  namespace AppBootstrap; use AppRegisterConsulServices; class ServerStartCallback {     public function beforeStart()     {         $container = HyperfUtilsApplicationContext::getContainer();         $container->get(ConsulServices::class)->getServers();     } }

        改造一下原來的控制器

        public function grpc () {          $container = HyperfUtilsApplicationContext::getContainer();         $servers = $container->get(ConsulServices::class)->servers;         if (empty($servers)) {             return [                 'errCode' => 1000,                 'msg'     => '服務不存在',             ];         }         $key = array_rand($servers,1); // 哈哈哈一個簡單的負載均衡         $hostname = $servers[$key];         $client = new AppGrpcUserClient($hostname, [             'credentials' => null,         ]);         $request = new RegisterRequest();         $request->setEmail("741001560@qq.com");         $request->setUsername("chensi");         $request->setPassword("123456");          /**          * @var GrpcHiReply $reply          */         list($reply, $status) = $client->Register($request);          $message = $reply->getId();         return [             'id' => $message         ];     }

        重啟服務,這時候然后刷新瀏覽器試試。這時候一個簡單基于go rpc server和php client的微服務就搭建完成了。當然了這時候還沒有心跳機制,hyperf官網提供了一個定時器的功能,我們定時去刷服務發現就好了。

        贊(0)
        分享到: 更多 (0)
        網站地圖   滬ICP備18035694號-2    滬公網安備31011702889846號
        主站蜘蛛池模板: 精品亚洲成a人片在线观看少妇| 久久er热视频在这里精品| 欧美精品videosse精子 | 久久免费国产精品| 久久精品国产福利国产秒| 久久免费的精品国产V∧| 欧美亚洲另类精品第一页| 国产精品亚洲专区无码WEB| 久久精品国产一区二区三区日韩| 精品人妻无码一区二区色欲产成人| 免费人成在线观看欧美精品 | aaa级精品久久久国产片| 最新精品露脸国产在线| MM1313亚洲精品无码| 华人亚洲欧美精品国产| 国产韩国精品一区二区三区久久 | 国产精品免费αv视频| 久久精品国产亚洲网站| 国产AV无码专区亚洲精品| 麻豆国产在线精品国偷产拍 | 久久精品国产亚洲av瑜伽| 久久久国产精品网站| 91原创国产精品| 国产国产精品人在线视| 蜜臀久久99精品久久久久久小说| 在线成人精品国产区免费| 日本免费精品一区二区三区| 久久国产午夜精品一区二区三区| 国产综合精品久久亚洲| 国产在线观看一区二区三区精品| 国产精品美女久久久久AV福利| 国产精品人人做人人爽| 国产精品一香蕉国产线看观看 | 国内精品视频在线观看| 国模和精品嫩模私拍视频| 精品99久久aaa一级毛片| 国产中文在线亚洲精品官网| 国产一区精品| 亚洲国产精品自产在线播放| 一本之道av不卡精品| 亚洲AV无码成人精品区蜜桃|