目录
分布式环境下可能出现的问题
常见的容错机制
Sentinel控制台部署(docker安装)
Sentinel整合springAlibaba
sentinel—整合openfeign降级
热点资源流控
服务不可用:
在分布式环境下,造成服务不可用的因素还是较多的,例如流量激增导致系统cpu飙高无法处理正常请求、消息投递过快导致未处理消息造成挤压、sql过慢卡爆连接池、业务调用异常,产生大量副作用等都可能造成服务不可用
服务雪崩效应:
服务提供者的不可用导致服务调用者的不可用,并将不可用逐渐放大的过程,就叫服务雪崩效应导致
在服务提供者不可用的时候,会出现大量重试的情况:用户重试、代码逻辑重试,这些重试最终导致:进一步加大请求流量。所以归根结底导致雪崩效应的最根本原因是:大量请求线程同步等待造成的资源耗尽。当服务调用者使用同步调用时, 会产生大量的等待线程占用系统资源。一旦线程资源被耗尽,服务调用者提供的服务也将处于不可用状态, 于是服务雪崩效应产生了。
超时机制
在不做任何处理的情况下,服务提供者不可用会导致消费者请求线程强制等待,而造成系统资源耗尽。加入超时机制,一旦超时,就释放资源。由于释放资源速度较快,一定程度上可以抑制资源耗尽的问题。
服务限流
当流量达到一定程度之后,可以限制服务器的访问,达到流量舒缓的目的
线程池隔离
原理:用户的请求将不再直接访问服务,而是通过线程池中的空闲线程来访问服务,如果线程池已满,则会进行降级处理,用户的请求不会被阻塞,至少可以看到一个执行结果(例如返回友好的提示信息),而不是无休止的等待或者看到系统崩溃。
信号量隔离
信号隔离也可以用于限制并发访问,防止阻塞扩散, 与线程隔离最大不同在于执行依赖代码的线程依然是请求线程(该线程需要通过信号申请, 如果客户端是可信的且可以快速返回,可以使用信号隔离替换线程隔离,降低开销。信号量的大小可以动态调整, 线程池大小不可以。
服务熔断
远程服务不稳定或网络抖动时暂时关闭,就叫服务熔断。
服务降级
有服务熔断,必然要有服务降级。所谓降级,就是当某个服务熔断之后,服务将不再被调用,此时客户端可以自己准备一个本地的fallback(回退)回调,返回一个缺省值。 例如:(备用接口/缓存/mock数据) 。这样做,虽然服务水平下降,但好歹可用,比直接挂掉要强,当然这也要看适合的业务场景。
拉取Sentinel-dashboard镜像
docker pull bladex/sentinel-dashboard
查看Sentinel-dashboard镜像是否下载完成
docker images
启动Sentinel-dashboard
docker run --name sentinel -d -p 8858:8858 -d bladex/sentinel-dashboard
访问Sentinel-dashboard页面
用户名和密码都是 : sentinel
一、引入坐标
com.alibaba.cloud
spring-cloud-starter-alibaba-sentinel
二、设置sentinel的ip端口
cloud:
sentinel:
transport:
dashboard: 127.0.0.1:8080
三、创建一个可访问的接口
@RestController
@RequestMapping("/order")
public class OrderController {
@RequestMapping("/flow")
public String flow() throws InterruptedException {
return "正常访问";
}
}
四、访问接口,便可以再sentinel控制台看到相关的信息
五、打开簇点链路查看所有的链路,并且添加流控规则
阈值类型:
单机阈值:配合阈值类型使用,例如QPS,每秒允许访问两次
流控模式:
直接:例如流控的资源是/order/flow,那么当触发流控的时候,限制的就是本身资源
关联:例如下图,当关联资源/order/flowThread的访问每秒超过两次的时候,就会对资源/order/flow进行流控。
链路:在整个调用链路中,可以通过在配置文件中加上以下配置,让sentinel帮我们维护一个调用链路树
server:
port: 8861
spring:
application:
name: order-sentinel
cloud:
sentinel:
transport:
dashboard: 127.0.0.1:8080
web-context-unify: false # 默认将调用链路收敛, 导致链路流控效果无效
这里getUser方法注册为sentinel的资源(注意,使用了sentinelResource就不能使用同一异常管理,必须使用sentinelResource的blockHandler标明回退方法)
然后两个接口都调用改方法
那么这里就会形成一个调用链路树。
这时候就可以通过链路模式选择对拿一条链路进行限流,否则就会将两条链路都限流
流控效果:
快速失败:达到阈值之后,后面的请求直接失败
Warm UP(适用于激增流量):可以起到一个预热效果,有一个默认的冷加载因子是3,也就是说从阈值/3开始,然后QPS逐渐递增直到达到阈值,这里的阈值设置为10,那么第一秒中,允许访问的请求数为10/3=3,第二秒钟递增,直接递增达到阈值10。而未被允许的请求直接限流
排队等待(适用于脉冲流量):当QPS达到阈值之后,不会立刻拒绝请求,而是排队等待,设置如果在超时时间内通过,则正常访问,如果超时了,那么就返回失败
六、添加降级规则
慢调用比例:如下如中的最大RT设置为1000毫秒,则当一条请求超过1000毫秒就属于慢调用,再结合比例阈值与最小请求数。当请求数大于5并且慢调用的请求占达十分之一、则开启熔断,熔断时间为五秒钟,当过了五秒之后,就会进入半开状态,对于新进的请求如果第一条就是慢调用请求,那么会立即再次熔断,而不会根据比例来判断,如果第一条是正常请求,那么接下来只有达到比例阈值才会进行熔断
异常比例:出现异常得次数占总次数得比例达到阈值则开启熔断
异常数:当请求出现异常的次数达到阈值时就开启熔断
一、引入依赖
com.alibaba.cloud
spring-cloud-starter-alibaba-nacos-discovery
org.springframework.cloud
spring-cloud-starter-openfeign
com.alibaba.cloud
spring-cloud-starter-alibaba-sentinel
二、开启openfeign整合sentinel
server:
port: 8041
# 应用名称 (nacos会将该名称当做服务名称)
spring:
application:
name: order-service
cloud:
nacos:
server-addr: 120.79.10.137:8849
discovery:
username: nacos
password: nacos
namespace: public
feign:
sentinel:
# openfeign整合sentinel
enabled: true
三、编写feign调用接口,并且在feignclient中的fallback属性标明fallback方法的类字节码
@FeignClient(value="stock-nacos",path = "/stock",fallback = StockFeignServiceFallback.class)
public interface StockFeignService {
@RequestMapping("/reduct")
public String reduct2();
}
四、创建fallback方法的类字节码,实现feign调用的接口
@Component
public class StockFeignServiceFallback implements StockFeignService {
@Override
public String reduct2() {
return "降级啦!!!";
}
}
首先要强调的是sentinel针对热点规则,必须使用@SentinelResource使用,如果仅仅针对接口进行热点资源流控是不起作用的
/**
* 热点规则,必须使用@SentinelResource
* @param id
* @return
* @throws InterruptedException
*/
@RequestMapping("/get/{id}")
@SentinelResource(value = "getById",blockHandler = "HotBlockHandler")
public String getById(@PathVariable("id") Integer id) throws InterruptedException {
System.out.println("正常访问");
return "正常访问";
}
public String HotBlockHandler(@PathVariable("id") Integer id,BlockException e) throws InterruptedException {
return "热点异常处理";
}
如下图所示,新增热点规则,限流模式只能通过QPS进行限流
参数索引:表示要控制限流的是第几个参数,下图的含义为,1秒钟内的第一个参数最大请求吞吐量为10,超过即限流
点击新增后,可以通过编辑进行高级部分的限流
意思为当第一个参数的值是1的时候,每秒只能通过两个请求 ,但是保存的时候可能是存在某些bug,保存回失败。这时候需要添加两条参数例外项,先保存然后再删除不用的那一条。