在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 [email protected] * @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 次后熔断,相应 fallback
为 AppServiceUserService
类的 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://www.gaodaima.com/weixin_40670060/article/details/109582821