Sentinel概述
分布式系统的流量哨兵,以流量为切入点,对比Redis的哨兵模式可以得出sentinel在微服务中的作用是对流量进行监控与管理,例如流量的控制,熔断降级,系统负载保护等。
由Sentinel的源码可以看出,Sentinel在对流量进行管控的时候是通过责任链的模式来处理的。在Restful中,将系统的一切定义为资源,sentinel在此处也借鉴了此种思想,将需要流量控制的一切当作资源,然后定义一系列的规则来对资源进行处理。
资源与规则
资源概述
虽然官网说资源可以是Java应用程序中的任何内容,通过对源码的阅读,从提供的注解和demo来看,对应资源的范围应该是指方法和代码片段。
责任链模式处理资源
虽然使用责任链模式可以做到请求与责任处理分离,但是由于使用链表来实现责任链,故不够灵活,对于所有的资源管控都需要一个完整的流程处理,存在性能损耗和可扩展性受限,如果可以使用跳表,针对不同的资源可以实现定制化规则会更完美。
备注:此处使用StatisticSlot进行统计的时候,可能会存在高并发的问题;如果进行日志记载的时候抛出异常,也会影响业务的执行。
规则概述
Sentinel有提供3种规则或者说是策略来对资源进行管控,存在管控台可以动态实时调整:
系统保护规则SystemRule
漏桶算法来进行流量塑型;包括系统负载,AvgRt,Qps,最大线程数等粒度。
备注:注意是否存在流量兜底和请求丢失?
流量控制规则FlowRule
(a)并发数控制的立即拒绝和QPS流量控制:
QPS的控制行为:0直接拒绝default,1冷启动warm up,2匀速器rate limiter
(b)通过调用关系的限流:调用方限流,链路限流和关联流量控制
NodeSelectorSlot建立不同资源间的调用的关系,通过ClusterNodeBuilderSlot记录每个资源的实时统计信息
备注:流量的控制应该同ClusterNodeBuilderSlot和StatisticSlot存在直接的关系,如果任何Slot的统计数据存在问题,则流量控制是不精准的,不过这种精准性的要求应该是存在滑动空间是可以妥协的。限流的规则可以是多种多样的,可以对资源使用多种限流规则。
熔断降级规则DegradeRule
并发线程数控制,异常比例ExceptionRatio和响应时间RT控制。
针对RT而言,准降级状态触发后,连续5个时间窗口依旧超过限流阈值,会进行降级处理。
针对异常比例,不存在准降级状态的触发,直接进行降级处理。
规则加载
1、所有的规则都可以通过对应的硬编码模式XxxRuleManager来加载
2、可以在内存中通过动态的修改生效,通过API来进行修改
3、Sentinel有提供通过实现DataSource接口的方式来定义规则的存储
可通过配置中心的获取,通过Redis和Zookeeper获取,通过数据库和文件获取。
DataSource概述
DataSource的推模式,需要继承抽象类AbstractDataSource,实现readResource()方法,需要在构造方法中添加监听器。
DataSource的拉模式,需要继承抽象类AutoRefreshDataSource,实现readResource()方法即可。
最后将数据源注册到规则管理器中。
Entry概述
由源码可知,所有需要被保护的相关资源都需要被Entry给包围起来,如果任何设置的规则在请求达到临界值时都会被blocked,然后返回false和抛出BlockException。
Entry存在侵入业务代码的嫌疑,如果抛出内部异常会阻碍业务的运行。如果完全不侵入业务代码,估计框架也很难实现其功能,通常智能学习Spring来解决如何将影响降到最低。
Entry的进入和离开时成对出现的,要不然会抛出ErrorEntryFreeException异常,这点值得注意。对比ReentrantLock的进入与离开产生死锁而言,sentinel做的很人道。
SphU对资源的处理
Entry entry = null;
// 务必保证finally会被执行
try {
// 资源名可使用任意有业务语义的字符串
entry = SphU.entry("自定义资源名");
/** * 被保护的业务逻辑 */
} catch (BlockException e1) {
// 资源访问阻止,被限流或被降级
// 进行相应的处理操作
} finally {
if (entry != null) {
entry.exit();
}
}
SphO对资源的处理
// 资源名可使用任意有业务语义的字符串
if (SphO.entry("自定义资源名")) {
// 务必保证finally会被执行
try {
/** * 被保护的业务逻辑 */
} finally {
SphO.exit();
}
} else {
// 资源访问阻止,被限流或被降级
// 进行相应的处理操作
}
总结
通常实际运用中使用try...catch的方式来对资源进行处理。Sentinel的功能还算比较齐全,它的使用难度和学习成本都不大。Sentinel对业务代码的侵入比较小,它依赖的jar包也不多,整体的代码量更是少的可怜。Sentinel是双十一抗流量的利器,也是完善Dubbo生态圈的重要组件。Sentinel也有提供DashBoard来查对应的指标输出和设置对应的规则,但是UI比较简陋。