这几天公司有需求要实现sentinel告警通知,大概的要求是这样,当某些接口请求异常次数达到某一阈值,或者qps达到某个阈值,把接口熔断。当然,我们原计划是自己写方法来实现的,但是后来还是采用了sentinel。因为作为微服务架构的主流的熔断解决方案,我们倾向于sentinel。但是看接下来的需求,我们也遇到了问题,因为我们需要对熔断的接口进行告警通知。
需求来源:针对目前日益增多的第三方接口问题导致的服务缓慢及中断,需要对所有现有第三方接口进行监测、通知、及熔断处理。需求描述:1、在后台里新增”后台接口服务“功能模块2、接口健康监测:持续对第三方提供的系统接口服务进行检测,当出现接口超时等异常情况时将进行系统预警(短信通知,可设置多个接收人手机),以便甲方协同解决问题。3、服务熔断:因第三方接口质量、性能问题导致接口访问达到熔断标准时(1分钟内连续30次以上接口访问失败或者超时),为不影响甲方用户体验,乙方有权进行服务熔断,关闭不可用接口4、第三方接口调用需要记录详细的接口日志,如果调用失败,错误信息需要有“第三方”的标识,明确显示是哪方的错误。
第一、通过修改sentinel源码,实现告警
通过修改sentinel源码的方式,当然是可行的。只是设计到的内容比较多。第一种方法的内容,可以具体参考:https://blog.csdn.net/qq_42019951/article/details/127136222
我们今天主要讲第二种方法。
如下是在Sentinel源码中主要使用了责任链设计模式,责任链中最重要的统计流量的功能便是在 StatisticSlot
中实现的,看下它的源码:
@Spi(order = Constants.ORDER_STATISTIC_SLOT)
public class StatisticSlot extends AbstractLinkedProcessorSlot<DefaultNode> {
@Override
public void entry(Context context, ResourceWrapper resourceWrapper, DefaultNode node, int count,
boolean prioritized, Object... args) throws Throwable {
try {
//关注点1: 执行后续校验逻辑,如果触发流控熔断则会抛出异常
fireEntry(context, resourceWrapper, node, count, prioritized, args);
//关注点2: 对通过的QPS及线程数进行统计
node.increaseThreadNum();
node.addPassRequest(count);
if (context.getCurEntry().getOriginNode() != null) {
// Add count for origin node.
context.getCurEntry().getOriginNode().increaseThreadNum();
context.getCurEntry().getOriginNode().addPassRequest(count);
}
if (resourceWrapper.getEntryType() == EntryType.IN) {
// Add count for global inbound entry node for global statistics.
Constants.ENTRY_NODE.increaseThreadNum();
Constants.ENTRY_NODE.addPassRequest(count);
}
// 扩展点1:成功回调
for (ProcessorSlotEntryCallback<DefaultNode> handler :
StatisticSlotCallbackRegistry.getEntryCallbacks()) {
handler.onPass(context, resourceWrapper, node, count, args);
}
} catch (PriorityWaitException ex) {
node.increaseThreadNum();
if (context.getCurEntry().getOriginNode() != null) {
// Add count for origin node.
context.getCurEntry().getOriginNode().increaseThreadNum();
}
if (resourceWrapper.getEntryType() == EntryType.IN) {
// Add count for global inbound entry node for global statistics.
Constants.ENTRY_NODE.increaseThreadNum();
}
// Handle pass event with registered entry callback handlers.
for (ProcessorSlotEntryCallback<DefaultNode> handler :
StatisticSlotCallbackRegistry.getEntryCallbacks()) {
handler.onPass(context, resourceWrapper, node, count, args);
}
} catch (BlockException e) {
//关注点3:触发流控
// Blocked, set block exception to current entry.
context.getCurEntry().setBlockError(e);
//统计流控指标
node.increaseBlockQps(count);
if (context.getCurEntry().getOriginNode() != null) {
context.getCurEntry().getOriginNode().increaseBlockQps(count);
}
if (resourceWrapper.getEntryType() == EntryType.IN) {
// Add count for global inbound entry node for global statistics.
Constants.ENTRY_NODE.increaseBlockQps(count);
}
// 扩展点2:流控回调,所以如果增加流控告警功能,需要对此处的handler进行扩展
for (ProcessorSlotEntryCallback<DefaultNode> handler :
StatisticSlotCallbackRegistry.getEntryCallbacks()) {
handler.onBlocked(e, context, resourceWrapper, node, count, args);
}
throw e;
} catch (Throwable e) {
// Unexpected internal error, set error to current entry.
context.getCurEntry().setError(e);
throw e;
}
}
}
第二、我们自己写具体的告警通知
在我们调试通sentinel之后,我们简单测试几个接口,通过jmeter压测,配合具体的策略,可以实现熔断。当接口请求触发了熔断策略时,被熔断的接口会返回 “limited by sentinel”。我们需要的,不是这个,而是返回这个之前,我们就进行拦截,返回更友好的提示信息。
1、如果我们限流的接口是通过feign调用的的接口,比如我们现在的需求描述一样。这种时候怎么做比较好呢,这种时候,我么只要在熔断的fallback里写具体的警告就可以了。
2、如果我们限流的是最外层,面向用户的接口,那么我们要拦截的是sentinel抛出的异常。因为sentinel在被熔断后,会抛出BlockException异常。我们进行异常捕获,然后发送告警通知就可以了。具体发放什么通知,这个是另一个业务了。
以上就是关于sentinel告警通知的我们的实践。
这几天公司有需求要实现sentinel告警通知,大概的要求是这样,当某些接口请求异常次数达到某一阈值,或者qps达到某个阈值,把接口熔断。当然,我们原计划是自己写方法来实现的,但是后来还是采用了sentinel。因为作为微服务架构的主流的熔断解决方案,我们倾向于sentinel。但是看接下来的需求,我们也遇到了问题,因为我们需要对熔断的接口进行告警通知。
Java是世界上最好的语言之一,也深受开发者们的喜爱。Java是一个开源软件,广泛应用于软件开发和其它行业。随着社会的发展,我们都在使用计算机,因此开发 Java程序变得越来越重要。Java的语言非常有吸引力,可以在任何地方和不同级别提供不同的应用。Java是一种技术,它能轻松的用于复杂且高价值的项目。现在学习 Java已经成为一种非常棒但是并不容易的技能了。
今天在知乎上看到很多好的视频,想通过浏览器直接下载,于是动手试了一下,发现是可以的。这说明知乎在视频这方面,没有做太多的限制,不像B站上的视频,要下载还是有些费劲。下次再分析B站的视频怎么下载。