最近在负责做网关类系统,需要考虑做限流熔断功能,基于QPS,基于线程数,对于集群,单机做限流,熔断,而Sentinel能满足我的所有需求,配置接入方便,设计上很适合做扩展。
关于sentinel的详细介绍逅弈大佬已经有详细的博客介绍了,mark一下(https://www.jianshu.com/u/51121bddcd2a)。
我再简单摘要一下。
在整个限流熔断的过程中,实际是基于
slotChain
来实现,而 slotchain
内部则是使用链表来实现。
public interface ProcessorSlot<T> {
void entry(Context context, ResourceWrapper resourceWrapper, T param, int count, boolean prioritized,
Object... args) throws Throwable;
void fireEntry(Context context, ResourceWrapper resourceWrapper, Object obj, int count, boolean prioritized,
Object... args) throws Throwable;
void exit(Context context, ResourceWrapper resourceWrapper, int count, Object... args);
void fireExit(Context context, ResourceWrapper resourceWrapper, int count, Object... args);
}
public abstract class AbstractLinkedProcessorSlot<T> implements ProcessorSlot<T> {
private AbstractLinkedProcessorSlot<?> next = null;
@Override
public void fireEntry(Context context, ResourceWrapper resourceWrapper, Object obj, int count, boolean prioritized, Object... args)
throws Throwable {
if (next != null) {
next.transformEntry(context, resourceWrapper, obj, count, prioritized, args);
}
}
@SuppressWarnings("unchecked")
void transformEntry(Context context, ResourceWrapper resourceWrapper, Object o, int count, boolean prioritized, Object... args)
throws Throwable {
T t = (T)o;
entry(context, resourceWrapper, t, count, prioritized, args);
}
@Override
public void fireExit(Context context, ResourceWrapper resourceWrapper, int count, Object... args) {
if (next != null) {
next.exit(context, resourceWrapper, count, args);
}
}
public AbstractLinkedProcessorSlot<?> getNext() {
return next;
}
public void setNext(AbstractLinkedProcessorSlot<?> next) {
this.next = next;
}
}
可以看到AbstractLinkedProcessorSlot
为一个Slot节点,通过setNext
指定下一个Slot
节点,通过 fireEntry()
方法,调用下一个节点的transformEntry()
最终调用到下一个Slot节点的entry
方法,本身的结构类似于
clsss Slot {
Slot next;
}
这不就是大学时数据结构常提到的链表结构。
再来看看 ProcessorSlotChain
和DefaultProcessorSlotChain
public abstract class ProcessorSlotChain extends AbstractLinkedProcessorSlot<Object> {
//添加头节点
public abstract void addFirst(AbstractLinkedProcessorSlot<?> protocolProcessor);
//添加下一个节点
public abstract void addLast(AbstractLinkedProcessorSlot<?> protocolProcessor);
}
public class DefaultProcessorSlotChain extends ProcessorSlotChain {
AbstractLinkedProcessorSlot<?> first = new AbstractLinkedProcessorSlot<Object>() {
@Override
public void entry(Context context, ResourceWrapper resourceWrapper, Object t, int count, boolean prioritized, Object... args)
throws Throwable {
super.fireEntry(context, resourceWrapper, t, count, prioritized, args);
}
@Override
public void exit(Context context, ResourceWrapper resourceWrapper, int count, Object... args) {
super.fireExit(context, resourceWrapper, count, args);
}
};
AbstractLinkedProcessorSlot<?> end = first;
@Override
public void addFirst(AbstractLinkedProcessorSlot<?> protocolProcessor) {
protocolProcessor.setNext(first.getNext());
first.setNext(protocolProcessor);
if (end == first) {
end = protocolProcessor;
}
}
@Override
public void addLast(AbstractLinkedProcessorSlot<?> protocolProcessor) {
end.setNext(protocolProcessor);
end = protocolProcessor;
}
@Override
public void setNext(AbstractLinkedProcessorSlot<?> next) {
addLast(next);
}
@Override
public AbstractLinkedProcessorSlot<?> getNext() {
return first.getNext();
}
@Override
public void entry(Context context, ResourceWrapper resourceWrapper, Object t, int count, boolean prioritized, Object... args)
throws Throwable {
first.transformEntry(context, resourceWrapper, t, count, prioritized, args);
}
@Override
public void exit(Context context, ResourceWrapper resourceWrapper, int count, Object... args) {
first.exit(context, resourceWrapper, count, args);
}
}
可以看到, DefaultProcessorSlotChain
实质是指定头节点FirstSlot
和endSnot
的链表。就如下面结构 :
public Class Chain{
Slot first;
Slot end;
}
而在初始化 SlotChain
的时候,实质添加顺序是这样子滴
public ProcessorSlotChain build() {
ProcessorSlotChain chain = new DefaultProcessorSlotChain();
chain.addLast(new NodeSelectorSlot());
chain.addLast(new ClusterBuilderSlot());
chain.addLast(new LogSlot());
chain.addLast(new StatisticSlot());
chain.addLast(new SystemSlot());
chain.addLast(new AuthoritySlot());
chain.addLast(new FlowSlot());
chain.addLast(new DegradeSlot());
return chain;
}
所以整个SlotChain的结构如下图:
DefaultProcessorSlotChain
而具体的熔断限流都是每个Slot的具体职责:
-
NodeSelectorSlot
负责收集资源的路径,并将这些资源的调用路径,以树状结构存储起来,用于根据调用路径来限流降级; -
ClusterBuilderSlot
则用于存储资源的统计信息以及调用者信息,例如该资源的 RT, QPS, thread count 等等,这些信息将用作为多维度限流,降级的依据; -
StatistcSlot
则用于记录,统计不同纬度的 runtime 信息; -
SystemSlot
则通过系统的状态,例如 load1 等,来控制总的入口流量; -
AuthorizationSlot
则根据黑白名单,来做黑白名单控制; -
FlowSlot
则用于根据预设的限流规则,以及前面 slot 统计的状态,来进行限流; -
DegradeSlot
则通过统计信息,以及预设的规则,来做熔断降级;
可以看到,我需要的熔断,限流,白名单控制都可以通过配置AuthorizationSlot
,FlowSlot
,DegradeSlot
实现。
网友评论