乐趣区

关于php:在windows使用docker环境搭建hyperf微服务

在 windows 应用 docker 环境搭建 hyperf 微服务

创立 hyperf 我的项目环境

docker run -d --name hyperfrpc -v d/dataproject/hyperfrpc:/hyperf-skeleton -p 9501:9501 -it --entrypoint /bin/sh hyperf/hyperf:7.4-alpine-v3.11-swoole

参数解释:

-d 示意在后盾运行

–name 示意给容器取个名字

-v 示意挂载到本机的目录

-p 示意映射到主机的端口,冒号前的是本机,前面是 docker 容器端口

-it 终端

–entrypoint 通过这个来笼罩 dockerfile 里定义的 entrypoint

镜像容器运行后,而后进入容器中,在容器内装置 Composer

# 下载 composer.phar 文件
wget https://github.com/composer/composer/releases/download/1.8.6/composer.phar
#给 composer.phar 文件加可执行权限
chmod u+x composer.phar
#挪动该文件到 /usr/local/bin/composer
mv composer.phar /usr/local/bin/composer

将 Composer 镜像设置为阿里云镜像,减速国内下载速度

composer config -g repo.packagist composer https://mirrors.aliyun.com/composer

通过 Composer 装置 hyperf/hyperf-skeleton 我的项目

composer create-project hyperf/hyperf-skeleton

进入装置好的 Hyperf 我的项目目录,linux 目录

cd hyperf-skeleton

测试 Hyperf 环境是否胜利

php bin/hyperf.php start

在 powshell 关上一个 cli

docker exec -it hyperfrpc /bin/bash

进行测试

curl 127.0.0.1:9501

看到输入

{"method":"GET","message":"Hello Hyperf."}

环境胜利

在 hyperf-skeleton 目录下创立消费者和提供者

删除刚刚创立的 hyperf 我的项目

rm -rf hyperf-skeleton

创立 provider

composer create-project hyperf/hyperf-skeleton hyperf-skeleton/provider

创立时,选项只抉择一个 JSON-PRC with Service Governance,其余都选 n

创立 consumer

cd hyperf-skeleton

复制 provider 为 consumer

cp -r provider consumer

在 windows 应用编辑器编辑 provider

随便应用一个编辑器而后关上我的项目,目录是你创立 docker 容器时挂载的中央,咱们下面挂载了 d /dataproject/hyperfrpc

咱们能够在目录看到存在 provider、consumer

编写 provider

咱们在 app 目录下创立一个文件夹,叫 Rpc,在 Rpc 下创立 CalculatorService 和 CalculatorServiceInterface

服务端口

CalculatorServiceInterface 是服务接口

<?php
​
namespace AppRpc;
​
interface CalculatorServiceInterface
{public function add(int $a, int $b);
​
 public function minus(int $a, int $b);
}

服务实现类

CalculatorService 就是咱们服务提供者的服务实现类, 咱们只须要服务实现类上增加注解 @RpcService 就能够将服务公布

name,给服务起个名字

protocol,应用的协定,这里个别应用 jsonrpc-http

server,绑定的 server

<?php
namespace AppRpc;
​
use HyperfRpcServerAnnotationRpcService;
​
/**
 * Class CalculatorService
 * @package AppRpc
 * @RpcService(name="CalculatorService",protocol="jsonrpc-http",server="jsonrpc-http")
 */
class CalculatorService implements CalculatorServiceInterface
{
​
 public function add(int $a,int $b)
 {return $a+$b;}
 public function minus(int $a,int $b)
 {return $a-$b;}
}

增加对应 server

接下来,咱们去 config/autoload/server.php 下,增加刚刚在注解 @RpcService 上写的 server=“jsonrpc-http”的这个 server

咱们找到 servers

而后发现曾经存在一个 name 是 http 的 server 了,咱们复制一个 name 是 http 的 server,之后增加在 http 这个 server 的上面,而后批改一下

咱们把 name 批改成 jsonrpc-http

咱们把 port 批改成 9502

咱们把 callbacks 批改一下,把 HyperfHttpServerServer::class 批改成 HyperfJsonRpcHttpServer::class, 如上面

'servers' => [
 [
 'name' => 'http',
 'type' => Server::SERVER_HTTP,
 'host' => '0.0.0.0',
 'port' => 9501,
 'sock_type' => SWOOLE_SOCK_TCP,
 'callbacks' => [Event::ON_REQUEST => [HyperfHttpServerServer::class, 'onRequest'],
 ],
 ],
 [
 'name' => 'jsonrpc-http',
 'type' => Server::SERVER_HTTP,
 'host' => '0.0.0.0',
 'port' => 9502,
 'sock_type' => SWOOLE_SOCK_TCP,
 'callbacks' => [Event::ON_REQUEST => [HyperfJsonRpcHttpServer::class, 'onRequest'],
 ],
 ],

编写 consumer

咱们就在 consumer 我的项目的 controller 调用一下刚刚写的 CalculatorService 把。

对应接口

在调用之前咱们须要把服务接口从 provider 哪里复制一份过去

咱们在 consumer 的 app 目录下创立 Rpc 目录,在 Rpc 目录下创立刚刚复制的 CalculatorServiceInterface

<?php
​
namespace AppRpc;
​
interface CalculatorServiceInterface
{public function add(int $a, int $b);
​
 public function minus(int $a, int $b);
}

应用 controller 调用

咱们就在 IndexController 外面的 index 办法调用服务, 然而当初还无奈生产胜利,咱们还须要一些配置。

<?php
​
declare(strict_types=1);
/**
 * This file is part of Hyperf.
 *
 * @link     https://www.hyperf.io
 * @document https://hyperf.wiki
 * @contact  group@hyperf.io
 * @license  https://github.com/hyperf/hyperf/blob/master/LICENSE
 */
namespace AppController;
​
​
​
use HyperfDiAnnotationInject;
​
class IndexController extends AbstractController
{
 /**
 * @Inject
 * @var AppRpcCalculatorServiceInterface
 */
 private $calculatorService;
​
 public function index()
 {return $this->calculatorService->add(1,2);
 }
}
​

创立 services 的配置文件

咱们须要去到 /config/autoload 目录下创立 services.php 文件,文件配置如下

<?php
​
​
use AppRpcCalculatorServiceInterface;
​
return [
 'consumers'=>[
 [
 'name'=>'CalculatorService',
 'service'=>CalculatorServiceInterface::class,
 'nodes'=>[['host'=>'127.0.0.1','port'=>9502],
 ],
 ],
 ],
];

这个服务的 name 和咱们编写注解的 name 是统一的

服务的 service 对应 consumer 的 CalculatorServiceInterface,

因为咱们没有应用注册核心,所以咱们间接应用节点地址,对应下面代码中的 nodes

批改 consumer 的启用端口

因为 consumer 复制过去的,所以咱们须要批改一下端口

在 /config/autoload 下的 server.php 文件下

咱们找到 server,定位到 name 是 http 的 server,将端口批改成 9503

'servers' => [
 [
 'name' => 'http',
 'type' => Server::SERVER_HTTP,
 'host' => '0.0.0.0',
 'port' => 9503,
 'sock_type' => SWOOLE_SOCK_TCP,
 'callbacks' => [Event::ON_REQUEST => [HyperfHttpServerServer::class, 'onRequest'],
 ],
 ],
 ],

consumer 编写实现

启动 provider

进入终端

cd hyperf-skeleton/
cd provider/
php bin/hyperf.php start

启动 consumer

cd hyperf-skeleton/
cd consumer/
php bin/hyperf.php start

发动申请

在关上一个终端

curl 127.0.0.1:9503

咱们应该能够看到输入了

3

应用 consul

咱们这里应用的是 consul

咱们在终端 provider 目录试下装置 hyperf 的服务治理

composer hyperf/service-governance

装置 consul 组件

composer require hyperf/consul

公布一下对应的配置文件

php bin/hyperf.php vendor:publish hyperf/consul

咱们能够看到 consul 的配置文件就曾经生成胜利了

能够到 cogfig/autoload 目录下的 consul.php 文件查看

return [
 'uri' => 'http://127.0.0.1:8500',
 'token' => '',
];

默认是到本地的 8500 端口

下载并启动 consul 服务

# 下载并解压 consul
cd /opt/
​
mkdir consul
​
chmod 777 consul
​
cd consul
​
wget https://releases.hashicorp.com/consul/1.3.0/consul_1.3.0_linux_amd64.zip
​
unzip consul_1.3.0_linux_amd64.zip
​
cp consul /usr/local/bin/
​
#查看是否装置胜利
consul
​
consul version
​
#启动 consul 服务
consul agent -dev -ui -node=consul-dev -client=127.0.0.1
​
​
#3. 再开一个终端,输出查看 8500 端口
curl 127.0.0.1:8500
#看见 <a href="/ui/">Moved Permanently</a>. 就胜利了

将 provider 的实现类注册进 consul

在注解上增加 publishTo=”consul”

<?php
​
namespace AppRpc;
​
use HyperfRpcServerAnnotationRpcService;
​
/**
 * Class CalculatorService
 * @package AppRpc
 * @RpcService(name="CalculatorService",protocol="jsonrpc-http",server="jsonrpc-http",publishTo="consul")
 */
class CalculatorService implements CalculatorServiceInterface
{
​
 public function add(int $a,int $b)
 {return $a+$b;}
 public function minus(int $a,int $b)
 {return $a-$b;}
}

将 consumer 的 services 批改

这里的 services 是 config/autoload 下的

<?php
​
​
use AppRpcCalculatorServiceInterface;
​
return [
 'consumers'=>[
 [
 'name'=>'CalculatorService',
 'service'=>CalculatorServiceInterface::class,
 'registry'=>[
 'protocol'=>'consul',
 'address'=>'http://127.0.0.1:8500',
 ],
//            'nodes'=>[//                ['host'=>'127.0.0.1','port'=>9502],
//            ],
 ],
 ],
];

registry 将去 consul 外面取服务,咱们须要先将 nodes 正文

重启 provider

CTRL+C
php bin/hyperf.php start

重启 consumer

CTRL+C
php bin/hyperf.php start

终端测试

curl 127.0.0.1:9503
#能够看到还是输入,咱们曾经把 nodes 正文了
3

服务熔断

为什么要熔断

分布式系统中常常会呈现因为某个根底服务不可用造成整个零碎不可用的状况,这种景象被称为服务雪崩效应。为了应答服务雪崩,一种常见的做法是服务降级。

比方咱们须要到另外服务中查问用户列表,用户列表须要关联很多的表,查问效率较低,但平时并发量不高的时候,响应速度还说得过去。一旦并发量激增,就会导致响应速度变慢,并会使对方服务呈现慢查。

在比方咱们进行一些 Db 查问的时候,须要查问多个表,在这种状况下,平时并发量不高的时候,相应速度还能够说得过去。一旦并发量激增得时候,就可能呈现服务不可用的状况,最初导致整个零碎都不可用,这种景象被称为服务雪崩效应。为了应答服务雪崩,一种常见的做法是服务降级。

降级是指本人的待遇降落了,从 RPC 调用环节来讲,就是去拜访一个本地的伪装者而不是实在的服务。

应用熔断器

熔断器的应用非常简略,只须要退出 HyperfCircuitBreakerAnnotationCircuitBreaker 注解,就能够依据规定策略,进行熔断。

这个时候,咱们只须要配置一下熔断超时工夫 timeout 为 0.05 秒,失败计数 failCounter 超过 1 次后熔断,相应 fallbackAppServiceUserService 类的 searchFallback 办法。这样当响应超时并触发熔断后,就不会再申请对端的服务了,而是间接将服务降级从以后我的项目中返回数据,即依据 fallback 指定的办法来进行返回。

创立应用熔断器的 Service

咱们在服务提供者 provider 里的 appService 下创立一个 UserService 来进行应用,

首先,咱们先在 APP 目录下创立目录 Service

而后再 Service 目录下创立 UserService,具体如下:

<?php
​
namespace AppService;
use HyperfCircuitBreakerAnnotationCircuitBreaker;
​
class UserService
{
 /**
 * @return string[]
 * @CircuitBreaker(timeout="0.05",failCounter=1,successCounter=1,fallback="AppSerViceUserService::searchFallback")
 */
 public function search()
 {for ($i=1;$i<=3;$i++){sleep(1);
 $a=$i;
 print $a."n";
 }
 return ['message'=>"失常",];
}
 public static function searchFallback()
 {
 return ['message'=>"流量过大,熔断",];
 }
}

在咱们须要的服务上加上 @CircuitBreaker 这个注解就能够进行服务熔断了,接下来我阐明一下几个参数

timeout=”0.05″ 熔断超时工夫

failCounter= 1 失败记数,超过次数后熔断

successCounter= 1 胜利记数

fallback=”AppSerViceUserService::searchFallback” 发送熔断后调用的办法

在控制器中应用

咱们编写一个控制器,就叫做 UserController 吧。

咱们在 UserController 中注入刚刚编写的 UserService,我为了不便就没有形象成接口了

而后再 UserController 外面编写一个办法来调用 UserService 的办法

代码如下:

<?php
namespace AppController;
use HyperfCircuitBreakerAnnotationCircuitBreaker;
use HyperfDiAnnotationInject;
use HyperfHttpServerAnnotationAutoController;
use AppServiceUserService;
​
/**
 * Class UserController
 * @package AppController
 * @AutoController()
 */
class UserController extends AbstractController
{
 /**
 * @Inject
 * @var UserService
 */
 private $UserService;
​
 public function search()
 {return  $this->UserService->search();
 }
}

测试

因为咱们之前在创立 docker 绑定了 9501,所以咱们在 windows 上能够用浏览器拜访 9501 端口

咱们关上浏览器

拜访, 多刷新几次就能够看见服务熔断这个返回,或者你关上 2 个拜访窗口
`
127.0.0.1:9501/user/search
`
或者咱们能够在终端上拜访,不过须要屡次拜访

curl curl 127.0.0.1:9501/user/search
curl curl 127.0.0.1:9501/user/search
curl curl 127.0.0.1:9501/user/search

服务限流

限流的目标是通过对并发拜访 / 申请进行限速或者一个工夫窗口内的申请进行限速爱护零碎,一旦达到限度速率就能够拒绝服务(定向到谬误页或告知资源没有了),排队等待(比方秒杀、评论和下单)、降级(返回兜底数据和默认数据,如商品详情页默认有货)。上面咱们将应用到令牌桶限流器。

装置

咱们先进入 provider 目录
`
composer require hyperf/rate-limit
`
公布配置

php bin/hyperf.php vendor:publish hyperf/rate-limit

应用

<?php
​
namespace AppController;
​
use HyperfDiAopProceedingJoinPoint;
use HyperfHttpServerAnnotationController;
use HyperfHttpServerAnnotationRequestMapping;
use HyperfRateLimitAnnotationRateLimit;
​
/**
 * @Controller(prefix="rate-limit")
 * @RateLimit(limitCallback={RateLimitController::class, "limitCallback"})
 */
class RateLimitController
{
 /**
 * @RequestMapping(path="test")
 * @RateLimit(create=1, capacity=3)
 */
 public function test()
 {return ["QPS 1, 峰值 3"];
 }
 
 public static function limitCallback(float $seconds, ProceedingJoinPoint $proceedingJoinPoint)
 {
 // $seconds 下次生成 Token 的距离, 单位为秒
 // $proceedingJoinPoint 此次申请执行的切入点
 // 能够通过调用 `$proceedingJoinPoint->process()` 继续执行或者自行处理
 echo "限流中";
 return $proceedingJoinPoint->process();}
}

create

1

每秒生成令牌数

consume

1

每次申请耗费令牌数

capacity

2

令牌桶最大容量

limitCallback

[]

触发限流时回调办法

waitTimeout

1

排队超时工夫

参考文档:

https://hyperf.wiki/2.1/#/zh-cn/microservice

https://blog.csdn.net/weixin_40670060/article/details/109582821

退出移动版