15、Hyperf 3 微服务系列 - Hyperf 3 服务熔断实操

作者: 温新

分类: 【Hyperf 3 微服务系列】

阅读: 943

时间: 2023-05-29 15:52:41

hi,我是温新,一名 PHPer

Hyperf 3 微服务代码已上传至 Github:https://github.com/ziruchu/hyperf3-microservice-code

本篇文章是行服务熔断实操,在实操之前还请先了解其概念,因为操作起来太简单了,若不去了解其概念,可能会似懂非懂。、

实操服务器

项目说明:

1、note_provider_user_9606 增加模拟业务超时的方法 timeout,当 id > 0 时睡眠 1秒;

2、note_consumer_user_9502 使用熔断进行业务处理

Hyperf 熔断的使用

服务提供者

所在位置:92.168.31.92 note_provider_user_9606

第一步:添加接口方法
<span style="box-sizing: border-box;color: rgb(171, 178, 191);padding-right: 0.1px"><span style="box-sizing: border-box;color: rgb(86, 182, 194) !important"><?</span></span><br></br><span style="box-sizing: border-box;color: rgb(171, 178, 191);padding-right: 0.1px"><span style="box-sizing: border-box;color: rgb(98, 151, 85) !important">// app/JsonRpc/Interface/UserServiceInterface.php</span></span><br></br><span style="box-sizing: border-box;color: rgb(171, 178, 191);padding-right: 0.1px"><span style="box-sizing: border-box;color: rgb(198, 120, 221) !important">public</span> <span style="box-sizing: border-box;color: rgb(198, 120, 221) !important">function</span> <span style="box-sizing: border-box;color: rgb(224, 108, 117) !important">timeout</span>(<span style="box-sizing: border-box;color: rgb(224, 108, 117) !important">$id</span>);</span>
第二步:实现接口方法
<span style="box-sizing: border-box;color: rgb(171, 178, 191);padding-right: 0.1px"><span style="box-sizing: border-box;color: rgb(86, 182, 194) !important"><?</span><span style="box-sizing: border-box;color: rgb(18, 170, 228) !important">php</span></span><br></br><span style="box-sizing: border-box;color: rgb(171, 178, 191);padding-right: 0.1px"><span style="box-sizing: border-box;color: rgb(98, 151, 85) !important">// app/JsonRpc/Service/UserService.php</span></span><br></br><span style="box-sizing: border-box;color: rgb(171, 178, 191);padding-right: 0.1px"><span style="box-sizing: border-box;color: rgb(198, 120, 221) !important">public</span> <span style="box-sizing: border-box;color: rgb(198, 120, 221) !important">function</span> <span style="box-sizing: border-box;color: rgb(224, 108, 117) !important">timeout</span>(<span style="box-sizing: border-box;color: rgb(224, 108, 117) !important">$id</span>)</span><br></br><span style="box-sizing: border-box;color: rgb(171, 178, 191);padding-right: 0.1px">{</span><br></br><span style="box-sizing: border-box;color: rgb(171, 178, 191);padding-right: 0.1px">    <span style="box-sizing: border-box;color: rgb(198, 120, 221) !important">try</span> {</span><br></br><span style="box-sizing: border-box;color: rgb(171, 178, 191);padding-right: 0.1px">        <span style="box-sizing: border-box;color: rgb(98, 151, 85) !important">// 暂停1秒模拟业务耗时</span></span><br></br><span style="box-sizing: border-box;color: rgb(171, 178, 191);padding-right: 0.1px">        <span style="box-sizing: border-box;color: rgb(198, 120, 221) !important">if</span> (<span style="box-sizing: border-box;color: rgb(224, 108, 117) !important">$id</span> <span style="box-sizing: border-box;color: rgb(86, 182, 194) !important">></span> <span style="box-sizing: border-box;color: rgb(209, 154, 102) !important">0</span>) {</span><br></br><span style="box-sizing: border-box;color: rgb(171, 178, 191);padding-right: 0.1px">            <span style="box-sizing: border-box;color: rgb(232, 191, 106) !important">sleep</span>(<span style="box-sizing: border-box;color: rgb(209, 154, 102) !important">1</span>);</span><br></br><span style="box-sizing: border-box;color: rgb(171, 178, 191);padding-right: 0.1px">        }</span><br></br><span style="box-sizing: border-box;color: rgb(171, 178, 191);padding-right: 0.1px">    } <span style="box-sizing: border-box;color: rgb(198, 120, 221) !important">catch</span> (<span style="box-sizing: border-box;color: rgb(18, 170, 228) !important">\Exception</span> <span style="box-sizing: border-box;color: rgb(224, 108, 117) !important">$e</span>) {</span><br></br><span style="box-sizing: border-box;color: rgb(171, 178, 191);padding-right: 0.1px">        <span style="box-sizing: border-box;color: rgb(198, 120, 221) !important">throw</span> <span style="box-sizing: border-box;color: rgb(198, 120, 221) !important">new</span> <span style="box-sizing: border-box;color: rgb(18, 170, 228) !important">\RuntimeException</span>(<span style="box-sizing: border-box;color: rgb(224, 108, 117) !important">$e</span><span style="box-sizing: border-box;color: rgb(86, 182, 194) !important">-></span><span style="box-sizing: border-box;color: rgb(18, 170, 228) !important">getMessage</span>());</span><br></br><span style="box-sizing: border-box;color: rgb(171, 178, 191);padding-right: 0.1px">    }</span><br></br><span style="box-sizing: border-box;color: rgb(171, 178, 191);padding-right: 0.1px">    <span style="box-sizing: border-box;color: rgb(198, 120, 221) !important">echo</span> <span style="box-sizing: border-box;color: rgb(152, 195, 121) !important">'测试熔断'</span> . <span style="box-sizing: border-box;color: rgb(18, 170, 228) !important">PHP_EOL</span>;</span><br></br><span style="box-sizing: border-box;color: rgb(171, 178, 191);padding-right: 0.1px">    <span style="box-sizing: border-box;color: rgb(198, 120, 221) !important">return</span> <span style="box-sizing: border-box;color: rgb(18, 170, 228) !important">ResponseTool</span>::<span style="box-sizing: border-box;color: rgb(18, 170, 228) !important">success</span>([]);</span><br></br><span style="box-sizing: border-box;color: rgb(171, 178, 191);padding-right: 0.1px">}</span>

服务消费者

所在位置:192.168.31.90 note_consumer_user_9502

第一步:安装熔断器组件
<span style="color: rgb(0, 176, 240);">composer require hyperf/circuit-breaker</span><br></br>
第二步:添加接口方法
<span style="box-sizing: border-box;color: rgb(171, 178, 191);padding-right: 0.1px"><span style="box-sizing: border-box;color: rgb(86, 182, 194) !important"><?</span><span style="box-sizing: border-box;color: rgb(18, 170, 228) !important">php</span></span><br></br><span style="box-sizing: border-box;color: rgb(171, 178, 191);padding-right: 0.1px"><span style="box-sizing: border-box;color: rgb(98, 151, 85) !important">// app/JsonRpc/Interface/UserServiceInterface.php  </span></span><br></br><span style="box-sizing: border-box;color: rgb(171, 178, 191);padding-right: 0.1px"> <span style="box-sizing: border-box;color: rgb(198, 120, 221) !important">public</span> <span style="box-sizing: border-box;color: rgb(198, 120, 221) !important">function</span> <span style="box-sizing: border-box;color: rgb(224, 108, 117) !important">timeout</span>(<span style="box-sizing: border-box;color: rgb(224, 108, 117) !important">$id</span>);</span>
第三步:实现接口方法
<span style="box-sizing: border-box;color: rgb(171, 178, 191);padding-right: 0.1px"><span style="box-sizing: border-box;color: rgb(86, 182, 194) !important"><?</span><span style="box-sizing: border-box;color: rgb(18, 170, 228) !important">php</span></span><br></br><span style="box-sizing: border-box;color: rgb(171, 178, 191);padding-right: 0.1px"><span style="box-sizing: border-box;color: rgb(98, 151, 85) !important">// app/JsonRpc/Service/UserService.php</span></span><br></br><span style="box-sizing: border-box;color: rgb(171, 178, 191);padding-right: 0.1px"><span style="box-sizing: border-box;color: rgb(198, 120, 221) !important">public</span> <span style="box-sizing: border-box;color: rgb(198, 120, 221) !important">function</span> <span style="box-sizing: border-box;color: rgb(224, 108, 117) !important">timeout</span>(<span style="box-sizing: border-box;color: rgb(224, 108, 117) !important">$id</span>)</span><br></br><span style="box-sizing: border-box;color: rgb(171, 178, 191);padding-right: 0.1px">{</span><br></br><span style="box-sizing: border-box;color: rgb(171, 178, 191);padding-right: 0.1px">    <span style="box-sizing: border-box;color: rgb(198, 120, 221) !important">return</span> <span style="box-sizing: border-box;color: rgb(224, 108, 117) !important">$this</span><span style="box-sizing: border-box;color: rgb(86, 182, 194) !important">-></span><span style="box-sizing: border-box;color: rgb(18, 170, 228) !important">__request</span>(<span style="box-sizing: border-box;color: rgb(209, 154, 102) !important">__FUNCTION__</span>, <span style="box-sizing: border-box;color: rgb(232, 191, 106) !important">compact</span>(<span style="box-sizing: border-box;color: rgb(152, 195, 121) !important">'id'</span>));</span><br></br><span style="box-sizing: border-box;color: rgb(171, 178, 191);padding-right: 0.1px">}</span>
第四步:控制器实现熔断设置
<span style="box-sizing: border-box;color: rgb(171, 178, 191);padding-right: 0.1px"><span style="box-sizing: border-box;color: rgb(86, 182, 194) !important"><?</span><span style="box-sizing: border-box;color: rgb(18, 170, 228) !important">php</span></span><br></br><span style="box-sizing: border-box;color: rgb(171, 178, 191);padding-right: 0.1px"><span style="box-sizing: border-box;color: rgb(98, 151, 85) !important">// app/Controller/UserController.php</span></span><br></br><span style="box-sizing: border-box;color: rgb(171, 178, 191);padding-right: 0.1px"><span style="box-sizing: border-box;color: rgb(198, 120, 221) !important">use</span> <span style="box-sizing: border-box;color: rgb(18, 170, 228) !important">Hyperf\CircuitBreaker\Annotation\CircuitBreaker</span>;</span><br></br><span style="box-sizing: border-box;color: rgb(171, 178, 191);padding-right: 0.1px"><span style="box-sizing: border-box"></span></span><br></br><span style="box-sizing: border-box;color: rgb(171, 178, 191);padding-right: 0.1px"><span style="box-sizing: border-box;color: rgb(98, 151, 85) !important">#[GetMapping('/users/testCircuitBreaker')]</span></span><br></br><span style="box-sizing: border-box;color: rgb(171, 178, 191);padding-right: 0.1px"><span style="box-sizing: border-box;color: rgb(98, 151, 85) !important">#[CircuitBreaker(options: ['timeout' => 0.05], failCounter: 1, successCounter: 3, fallback: "app\Controller\UserController::testCircuitBreakerFallback")]</span></span><br></br><span style="box-sizing: border-box;color: rgb(171, 178, 191);padding-right: 0.1px"><span style="box-sizing: border-box;color: rgb(198, 120, 221) !important">public</span> <span style="box-sizing: border-box;color: rgb(198, 120, 221) !important">function</span> <span style="box-sizing: border-box;color: rgb(224, 108, 117) !important">testCircuitBreaker</span>()</span><br></br><span style="box-sizing: border-box;color: rgb(171, 178, 191);padding-right: 0.1px">{</span><br></br><span style="box-sizing: border-box;color: rgb(171, 178, 191);padding-right: 0.1px">    <span style="box-sizing: border-box;color: rgb(224, 108, 117) !important">$id</span>     <span style="box-sizing: border-box;color: rgb(86, 182, 194) !important">=</span> (<span style="box-sizing: border-box;color: rgb(18, 170, 228) !important">int</span>)<span style="box-sizing: border-box;color: rgb(224, 108, 117) !important">$this</span><span style="box-sizing: border-box;color: rgb(86, 182, 194) !important">-></span><span style="box-sizing: border-box;color: rgb(18, 170, 228) !important">request</span><span style="box-sizing: border-box;color: rgb(86, 182, 194) !important">-></span><span style="box-sizing: border-box;color: rgb(18, 170, 228) !important">input</span>(<span style="box-sizing: border-box;color: rgb(152, 195, 121) !important">'id'</span>);</span><br></br><span style="box-sizing: border-box;color: rgb(171, 178, 191);padding-right: 0.1px">    <span style="box-sizing: border-box;color: rgb(224, 108, 117) !important">$result</span> <span style="box-sizing: border-box;color: rgb(86, 182, 194) !important">=</span> <span style="box-sizing: border-box;color: rgb(224, 108, 117) !important">$this</span><span style="box-sizing: border-box;color: rgb(86, 182, 194) !important">-></span><span style="box-sizing: border-box;color: rgb(18, 170, 228) !important">userService</span><span style="box-sizing: border-box;color: rgb(86, 182, 194) !important">-></span><span style="box-sizing: border-box;color: rgb(18, 170, 228) !important">timeout</span>(<span style="box-sizing: border-box;color: rgb(224, 108, 117) !important">$id</span>);</span><br></br><span style="box-sizing: border-box;color: rgb(171, 178, 191);padding-right: 0.1px">    <span style="box-sizing: border-box;color: rgb(198, 120, 221) !important">if</span> (<span style="box-sizing: border-box;color: rgb(224, 108, 117) !important">$result</span>[<span style="box-sizing: border-box;color: rgb(152, 195, 121) !important">'code'</span>] <span style="box-sizing: border-box;color: rgb(86, 182, 194) !important">!=</span> <span style="box-sizing: border-box;color: rgb(18, 170, 228) !important">ResponseCode</span>::<span style="box-sizing: border-box;color: rgb(18, 170, 228) !important">SUCCESS</span>) {</span><br></br><span style="box-sizing: border-box;color: rgb(171, 178, 191);padding-right: 0.1px">        <span style="box-sizing: border-box;color: rgb(198, 120, 221) !important">throw</span> <span style="box-sizing: border-box;color: rgb(198, 120, 221) !important">new</span> <span style="box-sizing: border-box;color: rgb(18, 170, 228) !important">RuntimeException</span>(<span style="box-sizing: border-box;color: rgb(224, 108, 117) !important">$result</span>[<span style="box-sizing: border-box;color: rgb(152, 195, 121) !important">'message'</span>]);</span><br></br><span style="box-sizing: border-box;color: rgb(171, 178, 191);padding-right: 0.1px">    }</span><br></br><span style="box-sizing: border-box;color: rgb(171, 178, 191);padding-right: 0.1px"><span style="box-sizing: border-box"></span></span><br></br><span style="box-sizing: border-box;color: rgb(171, 178, 191);padding-right: 0.1px">    <span style="box-sizing: border-box;color: rgb(198, 120, 221) !important">return</span> <span style="box-sizing: border-box;color: rgb(18, 170, 228) !important">ResponseTool</span>::<span style="box-sizing: border-box;color: rgb(18, 170, 228) !important">success</span>(<span style="box-sizing: border-box;color: rgb(224, 108, 117) !important">$result</span>[<span style="box-sizing: border-box;color: rgb(152, 195, 121) !important">'data'</span>]);</span><br></br><span style="box-sizing: border-box;color: rgb(171, 178, 191);padding-right: 0.1px">}</span><br></br><span style="box-sizing: border-box;color: rgb(171, 178, 191);padding-right: 0.1px"><span style="box-sizing: border-box"></span></span><br></br><span style="box-sizing: border-box;color: rgb(171, 178, 191);padding-right: 0.1px"><span style="box-sizing: border-box;color: rgb(98, 151, 85) !important">// 熔断器触发后,所有请求会执行该回调方法</span></span><br></br><span style="box-sizing: border-box;color: rgb(171, 178, 191);padding-right: 0.1px"><span style="box-sizing: border-box;color: rgb(98, 151, 85) !important">#[GetMapping('/users/testCircuitBreakerFallback')]</span></span><br></br><span style="box-sizing: border-box;color: rgb(171, 178, 191);padding-right: 0.1px"><span style="box-sizing: border-box;color: rgb(198, 120, 221) !important">public</span> <span style="box-sizing: border-box;color: rgb(198, 120, 221) !important">function</span> <span style="box-sizing: border-box;color: rgb(224, 108, 117) !important">testCircuitBreakerFallback</span>()</span><br></br><span style="box-sizing: border-box;color: rgb(171, 178, 191);padding-right: 0.1px">{</span><br></br><span style="box-sizing: border-box;color: rgb(171, 178, 191);padding-right: 0.1px">    <span style="box-sizing: border-box;color: rgb(198, 120, 221) !important">return</span> <span style="box-sizing: border-box;color: rgb(18, 170, 228) !important">ResponseTool</span>::<span style="box-sizing: border-box;color: rgb(18, 170, 228) !important">error</span>(<span style="box-sizing: border-box;color: rgb(18, 170, 228) !important">message</span>: <span style="box-sizing: border-box;color: rgb(152, 195, 121) !important">'The server is busy, please try again later ...'</span>);</span><br></br><span style="box-sizing: border-box;color: rgb(171, 178, 191);padding-right: 0.1px">}</span>

CircuitBreaker 熔断器注解参数说明:

第五步:测试

当 id < 0 时,正常返回结果:

<span style="box-sizing: border-box;color: rgb(171, 178, 191);padding-right: 0.1px"><span style="box-sizing: border-box;color: rgb(224, 108, 117) !important">$</span> <span style="box-sizing: border-box;color: rgb(18, 170, 228) !important">curl</span> <span style="box-sizing: border-box;color: rgb(18, 170, 228) !important">http</span>:<span style="box-sizing: border-box;color: rgb(98, 151, 85) !important">//192.168.31.90:9502/users/testCircuitBreaker?id=-1</span></span><br></br><span style="box-sizing: border-box;color: rgb(171, 178, 191);padding-right: 0.1px">{<span style="box-sizing: border-box;color: rgb(152, 195, 121) !important">"code"</span>:<span style="box-sizing: border-box;color: rgb(209, 154, 102) !important">200</span>,<span style="box-sizing: border-box;color: rgb(152, 195, 121) !important">"message"</span>:<span style="box-sizing: border-box;color: rgb(152, 195, 121) !important">"success"</span>,<span style="box-sizing: border-box;color: rgb(152, 195, 121) !important">"data"</span>:[]}</span>

下面使用 jmeter 进行并发测试,1 秒并发 100 次请求,结果如下:

14-3 并发熔断测试.jpg

当熔断开启会,会自动去调用 testCircuitBreakerFallback 方法,并返回我们自定义的内容。

当感觉到乏了,请不要放弃,一定要坚持下去。我写的每一篇文章都是正常运行后才发布出来的,经过了实际的测试。假如没有跑起来,先静一静,找哪是哪个地方出错了。

本篇文章到此结束,我是温新。

请登录后再评论