Skip to content
体验新版
项目
组织
正在加载...
登录
切换导航
打开侧边栏
晶之木
advanced-java
提交
fce3c1ff
A
advanced-java
项目概览
晶之木
/
advanced-java
与 Fork 源项目一致
从无法访问的项目Fork
通知
3
Star
1
Fork
0
代码
文件
提交
分支
Tags
贡献者
分支图
Diff
Issue
0
列表
看板
标记
里程碑
合并请求
0
Wiki
0
Wiki
分析
仓库
DevOps
项目成员
Pages
A
advanced-java
项目概览
项目概览
详情
发布
仓库
仓库
文件
提交
分支
标签
贡献者
分支图
比较
Issue
0
Issue
0
列表
看板
标记
里程碑
合并请求
0
合并请求
0
Pages
分析
分析
仓库分析
DevOps
Wiki
0
Wiki
成员
成员
收起侧边栏
关闭侧边栏
动态
分支图
创建新Issue
提交
Issue看板
前往新版Gitcode,体验更适合开发者的 AI 搜索 >>
提交
fce3c1ff
编写于
1月 05, 2019
作者:
Y
yanglbme
浏览文件
操作
浏览文件
下载
电子邮件补丁
差异文件
feat: add hystrix-circuit-breaker
深入 Hystrix 断路器执行原理
上级
82173fe7
变更
4
隐藏空白更改
内联
并排
Showing
4 changed file
with
186 addition
and
5 deletion
+186
-5
README.md
README.md
+1
-0
docs/high-availability/hystrix-circuit-breaker.md
docs/high-availability/hystrix-circuit-breaker.md
+181
-0
docs/high-availability/hystrix-fallback.md
docs/high-availability/hystrix-fallback.md
+3
-4
docs/high-availability/hystrix-introduction.md
docs/high-availability/hystrix-introduction.md
+1
-1
未找到文件。
README.md
浏览文件 @
fce3c1ff
...
...
@@ -88,6 +88,7 @@
-
[
深入 Hystrix 执行时内部原理
](
/docs/high-availability/hystrix-process.md
)
-
[
基于 request cache 请求缓存技术优化批量商品数据查询接口
](
/docs/high-availability/hystrix-request-cache.md
)
-
[
基于本地缓存的 fallback 降级机制
](
/docs/high-availability/hystrix-fallback.md
)
-
[
深入 Hystrix 断路器执行原理
](
/docs/high-availability/hystrix-circuit-breaker.md
)
### 高可用系统
-
如何设计一个高可用系统?
...
...
docs/high-availability/hystrix-circuit-breaker.md
0 → 100644
浏览文件 @
fce3c1ff
## 深入 Hystrix 断路器执行原理
### RequestVolumeThreshold
```
java
HystrixCommandProperties
.
Setter
()
.
withCircuitBreakerRequestVolumeThreshold
(
int
)
```
表示在滑动窗口中,至少有多少个请求,才可能触发断路。
Hystrix 经过断路器的流量超过了一定的阈值,才有可能触发断路。比如说,要求在 10s 内经过断路器的流量必须达到 20 个,而实际经过断路器的流量才 10 个,那么根本不会去判断要不要断路。
### ErrorThresholdPercentage
```
java
HystrixCommandProperties
.
Setter
()
.
withCircuitBreakerErrorThresholdPercentage
(
int
)
```
表示异常比例达到多少,才会触发断路,默认值是 50(%)。
如果断路器统计到的异常调用的占比超过了一定的阈值,比如说在 10s 内,经过断路器的流量达到了 30 个,同时其中异常访问的数量也达到了一定的比例,比如 60% 的请求都是异常(报错 / 超时 / reject),就会开启断路。
### SleepWindowInMilliseconds
```
java
HystrixCommandProperties
.
Setter
()
.
withCircuitBreakerSleepWindowInMilliseconds
(
int
)
```
断路开启,也就是由 close 转换到 open 状态(close -> open)。那么之后在
`SleepWindowInMilliseconds`
时间内,所有经过该断路器的请求全部都会被断路,不调用后端服务,直接走 fallback 降级机制。
而在该参数时间过后,断路器会变为
`half-open`
半开闭状态,尝试让一条请求经过断路器,看能不能正常调用。如果调用成功了,那么就自动恢复,断路器转为 close 状态。
### Enabled
```
java
HystrixCommandProperties
.
Setter
()
.
withCircuitBreakerEnabled
(
boolean
)
```
控制是否允许断路器工作,包括跟踪依赖服务调用的健康状况,以及对异常情况过多时是否允许触发断路。默认值是
`true`
。
### ForceOpen
```
java
HystrixCommandProperties
.
Setter
()
.
withCircuitBreakerForceOpen
(
boolean
)
```
如果设置为 true 的话,直接强迫打开断路器,相当于是手动断路了,手动降级,默认值是
`false`
。
### ForceClosed
```
java
HystrixCommandProperties
.
Setter
()
.
withCircuitBreakerForceClosed
(
boolean
)
```
如果设置为 true,直接强迫关闭断路器,相当于手动停止断路了,手动升级,默认值是
`false`
。
## 实例 Demo
### HystrixCommand 配置参数
在 GetProductInfoCommand 中配置 Setter 断路器相关参数。
-
滑动窗口中,最少 20 个请求,才可能触发断路。
-
异常比例达到 40% 时,才触发断路。
-
断路后 3000ms 内,所有请求都被 reject,直接走 fallback 降级,不会调用 run() 方法。3000ms 过后,变为 half-open 状态。
run() 方法中,我们判断一下 productId 是否为 -1,是的话,直接抛出异常。这么写,我们之后测试的时候就可以传入 productId=-1,
**模拟服务执行异常**
了。
在降级逻辑中,我们直接给它返回降级商品就好了。
```
java
public
class
GetProductInfoCommand
extends
HystrixCommand
<
ProductInfo
>
{
private
Long
productId
;
private
static
final
HystrixCommandKey
KEY
=
HystrixCommandKey
.
Factory
.
asKey
(
"GetProductInfoCommand"
);
public
GetProductInfoCommand
(
Long
productId
)
{
super
(
Setter
.
withGroupKey
(
HystrixCommandGroupKey
.
Factory
.
asKey
(
"ProductInfoService"
))
.
andCommandKey
(
KEY
)
.
andCommandPropertiesDefaults
(
HystrixCommandProperties
.
Setter
()
// 是否允许断路器工作
.
withCircuitBreakerEnabled
(
true
)
// 滑动窗口中,最少有多少个请求,才可能触发断路
.
withCircuitBreakerRequestVolumeThreshold
(
20
)
// 异常比例达到多少,才触发断路,默认50%
.
withCircuitBreakerErrorThresholdPercentage
(
40
)
// 断路后多少时间内直接reject请求,之后进入half-open状态,默认5000ms
.
withCircuitBreakerSleepWindowInMilliseconds
(
3000
)));
this
.
productId
=
productId
;
}
@Override
protected
ProductInfo
run
()
throws
Exception
{
System
.
out
.
println
(
"调用接口查询商品数据,productId="
+
productId
);
if
(
productId
==
-
1L
)
{
throw
new
Exception
();
}
String
url
=
"http://localhost:8081/getProductInfo?productId="
+
productId
;
String
response
=
HttpClientUtils
.
sendGetRequest
(
url
);
return
JSONObject
.
parseObject
(
response
,
ProductInfo
.
class
);
}
@Override
protected
ProductInfo
getFallback
()
{
ProductInfo
productInfo
=
new
ProductInfo
();
productInfo
.
setName
(
"降级商品"
);
return
productInfo
;
}
}
```
### 断路测试类
我们在测试类中,前 30 次请求,传入 productId=-1,然后休眠 3s,之后 70 次请求,传入 productId=1。
```
java
@SpringBootTest
@RunWith
(
SpringRunner
.
class
)
public
class
CircuitBreakerTest
{
@Test
public
void
testCircuitBreaker
()
{
String
baseURL
=
"http://localhost:8080/getProductInfo?productId="
;
for
(
int
i
=
0
;
i
<
30
;
++
i
)
{
// 传入-1,会抛出异常,然后走降级逻辑
HttpClientUtils
.
sendGetRequest
(
baseURL
+
"-1"
);
}
TimeUtils
.
sleep
(
3
);
System
.
out
.
println
(
"After sleeping..."
);
for
(
int
i
=
31
;
i
<
100
;
++
i
)
{
// 传入1,走服务正常调用
HttpClientUtils
.
sendGetRequest
(
baseURL
+
"1"
);
}
}
}
```
### 测试结果
测试结果,我们可以明显看出系统断路与恢复的整个过程。
```
c
调用接口查询商品数据,
productId
=-
1
ProductInfo
(
id
=
null
,
name
=
降级商品
,
price
=
null
,
pictureList
=
null
,
specification
=
null
,
service
=
null
,
color
=
null
,
size
=
null
,
shopId
=
null
,
modifiedTime
=
null
,
cityId
=
null
,
cityName
=
null
,
brandId
=
null
,
brandName
=
null
)
// ...
// 这里重复打印了 20 次上面的结果
ProductInfo
(
id
=
null
,
name
=
降级商品
,
price
=
null
,
pictureList
=
null
,
specification
=
null
,
service
=
null
,
color
=
null
,
size
=
null
,
shopId
=
null
,
modifiedTime
=
null
,
cityId
=
null
,
cityName
=
null
,
brandId
=
null
,
brandName
=
null
)
// ...
// 这里重复打印了 8 次上面的结果
// 休眠 3s 后
调用接口查询商品数据,
productId
=
1
ProductInfo
(
id
=
1
,
name
=
iphone7
手机
,
price
=
5599
.
0
,
pictureList
=
a
.
jpg
,
b
.
jpg
,
specification
=
iphone7
的规格
,
service
=
iphone7
的售后服务
,
color
=
红色
,
白色
,
黑色
,
size
=
5
.
5
,
shopId
=
1
,
modifiedTime
=
2017
-
01
-
01
12
:
00
:
00
,
cityId
=
1
,
cityName
=
null
,
brandId
=
1
,
brandName
=
null
)
// ...
// 这里重复打印了 69 次上面的结果
```
前 30 次请求,我们传入的 productId 为 -1,所以服务执行过程中会抛出异常。我们设置了最少 20 次请求通过断路器并且异常比例超出 40% 就触发断路。因此执行了 21 次接口调用,每次都抛异常并且走降级,21 次过后,断路器就被打开了。
之后的 9 次请求,都不会执行 run() 方法,也就不会打印以下信息。
```
调用接口查询商品数据,productId=-1
```
而是直接走降级逻辑,调用 getFallback() 执行。
休眠了 3s 后,我们在之后的 70 次请求中,都传入 productId 为 1。由于我们前面设置了 3000ms 过后断路器变为
`half-open`
状态。因此 Hystrix 会尝试执行请求,发现成功了,那么断路器关闭,之后的所有请求也都能正常调用了。
\ No newline at end of file
docs/high-availability/hystrix-fallback.md
浏览文件 @
fce3c1ff
...
...
@@ -23,7 +23,7 @@ fallback 降级逻辑中,也可以直接返回一个默认值。
假如说,品牌服务接口挂掉了,那么我们可以尝试从本地内存中,获取一份稍过期的数据,先凑合着用。
### 本地缓存获取数据
###
步骤一:
本地缓存获取数据
本地获取品牌名称的代码大致如下。
```
java
...
...
@@ -50,7 +50,7 @@ public class BrandCache {
}
```
### 实现 GetBrandNameCommand
###
步骤二:
实现 GetBrandNameCommand
在 GetBrandNameCommand 中,run() 方法的正常逻辑是去调用品牌服务的接口获取到品牌名称,如果调用失败,报错了,那么就会去调用 fallback 降级机制。
这里,我们直接
**模拟接口调用报错**
,给它抛出个异常。
...
...
@@ -94,7 +94,7 @@ public class GetBrandNameCommand extends HystrixCommand<String> {
`FallbackIsolationSemaphoreMaxConcurrentRequests`
用于设置 fallback 最大允许的并发请求量,默认值是 10,是通过 semaphore 信号量的机制去限流的。如果超出了这个最大值,那么直接 reject。
### CacheController 调用接口
###
步骤三:
CacheController 调用接口
在 CacheController 中,我们通过 productInfo 获取 brandId,然后创建 GetBrandNameCommand 并执行,去尝试获取 brandName。这里执行会报错,因为我们在 run() 方法中直接抛出异常,Hystrix 就会去调用 getFallback() 方法走降级逻辑。
```
java
...
...
@@ -118,7 +118,6 @@ public class CacheController {
System
.
out
.
println
(
productInfo
);
return
"success"
;
}
}
```
...
...
docs/high-availability/hystrix-introduction.md
浏览文件 @
fce3c1ff
...
...
@@ -41,7 +41,7 @@ Hystrix 可以对其进行资源隔离,比如限制服务 B 只有 40 个线
-
阻止任何一个依赖服务耗尽所有的资源,比如 tomcat 中的所有线程资源。
-
避免请求排队和积压,采用限流和
`fail fast`
来控制故障。
-
提供 fallback 降级机制来应对故障。
-
使用资源隔离技术,比如
`bulkhead`
(舱壁隔离技术)、
`swimlane`
(泳道技术)、
`circuit breaker`
(
短
路技术)来限制任何一个依赖服务的故障的影响。
-
使用资源隔离技术,比如
`bulkhead`
(舱壁隔离技术)、
`swimlane`
(泳道技术)、
`circuit breaker`
(
断
路技术)来限制任何一个依赖服务的故障的影响。
-
通过近实时的统计/监控/报警功能,来提高故障发现的速度。
-
通过近实时的属性和配置
**热修改**
功能,来提高故障处理和恢复的速度。
-
保护依赖服务调用的所有故障情况,而不仅仅只是网络故障情况。
\ No newline at end of file
编辑
预览
Markdown
is supported
0%
请重试
或
添加新附件
.
添加附件
取消
You are about to add
0
people
to the discussion. Proceed with caution.
先完成此消息的编辑!
取消
想要评论请
注册
或
登录