Sentinel源码分析—Sentinel是如何进行流量统计的?

本文深入剖析Sentinel流量统计的实现,从SphU.entry方法开始,逐步解析Env、InitExecutor、MetricCallbackInit、CtSph、ContextUtil等关键组件的工作原理,展示了Sentinel如何通过责任链模式、回调函数及统计节点进行流量控制和统计。通过示例代码,详细解释了线程数、请求通过量的统计方法,以及FlowRuleChecker的检查流程,揭示了Sentinel流量控制的内部逻辑。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

  这一篇我还是继续上一篇没有讲完的内容,先上一个例子:
  
  private static final int threadCount = 100;
  
  public static void main(String[] args) {
  
  initFlowRule();
  
  for (int i = 0; i < threadCount; i++) {
  
  Thread entryThread = new Thread(new Runnable() {
  
  @Override
  
  public void run() {
  
  while (true) {
  
  Entry methodA = null;
  
  try {
  
  TimeUnit.MILLISECONDS.sleep(5);
  
  methodA = SphU.entry("methodA");
  
  } catch (BlockException e1) {
  
  // Block exception
  
  } catch (Exception e2) {
  
  // biz exception
  
  } finally {
  
  if (methodA != null) {
  
  methodA.exit();
 
  entryThread.setName("working thread");
  
  entryThread.start();
 
  private static void initFlowRule() {
  
  List<FlowRule> rules = new ArrayList<FlowRule>();
  
  FlowRule rule1 = new FlowRule();
  
  rule1.setResource("methodA");
  
  // set limit concurrent thread for 'methodA' to 20
  
  rule1.setCount(20);
  
  rule1.setGrade(RuleConstant.FLOW_GRADE_THREAD);
  
  rule1.setLimitApp("default");
  
  rules.add(rule1);
  
  FlowRuleManager.loadRules(rules);
  
  }
  
  SphU#entry
  
  我先把例子放上来
  
  Entry methodA = null;
  
  try {
  
  methodA = SphU.entry("methodA");
  
  // dosomething
  
  } catch (BlockException e1) {
  
  block.incrementAndGet();
  
  } catch (Exception e2) {
  
  // biz exception
  
  } finally {
  
  total.incrementAndGet();
  
  if (methodA != null) {
  
  methodA.exit();
  
  }
  
  }
  
  我们先进入到entry方法里面:
  
  SphU#entry
  
  public static Entry entry(String name) throws BlockException {
  
  return Env.sph.entry(name, EntryType.OUT, 1, OBJECTS0);
  
  }
  
  这个方法里面会调用Env的sph静态方法,我们进入到Env里面看看
  
  public class Env {
  
  public static final Sph sph = new CtSph();
  
  static {
  
  // If init fails, the process will exit.
  
  InitExecutor.doInit()
  
  这个方法初始化的时候会调用InitExecutor.doInit()
  
  InitExecutor#doInit
  
  public static void doInit() {
  
  //InitExecutor只会初始化一次,并且初始化失败会退出
  
  if (!initialized.compareAndSet(false, true)) {
  
  return;
  
  }
  
  try {
  
  //通过spi加载InitFunc子类,默认是MetricCallbackInit
  
  ServiceLoader<InitFunc> loader = ServiceLoader.load(InitFunc.class);
  
  List<OrderWrapper> initList = new ArrayList<OrderWrapper>();
  
  for (InitFunc initFunc : loader) {
  
  RecordLog.info("[InitExecutor] Found init func: " + initFunc.getClass().getCanonicalName());
  
  //由于这里只有一个loader里面只有一个子类,那么直接就返回initList里面包含一个元素的集合
  
  insertSorted(initList, initFunc);
  
  }
  
  for (OrderWrapper w : initList) {
  
  //这里调用MetricCallbackInit的init方法
  
  w.func.init();
  
  RecordLog.info(String.format("[InitExecutor] Executing %s with order %d",
  
  w.func.getClass(www.tyyLeapp.com).getCanonicalName(), w.order));
  
  }
  
  } catch (Exception ex) {
  
  RecordLog.warn("[InitExecutor] WARN: Initialization failed", ex);
  
  ex.printStackTrace();
  
  } catch (Error error) {
  
  RecordLog.warn("[InitExecutor] ERROR: Initialization failed with fatal error", error);
  
  error.printStackTrace();
  
  }
  
  }
  
  这个方法主要是通过spi加载InitFunc 的子类,默认是MetricCallbackInit。
  
  然后会将MetricCallbackInit封装成OrderWrapper实例,然后遍历,调用
  
  MetricCallbackInit的init方法:
  
  MetricCallbackInit#init
  
  public void init(www.qjljdgt.cn) throws Exception {
  
  //添加回调函数
  
  //key是com.alibaba.csp.sentinel.metric.extension.callback.MetricEntryCallback
  
  StatisticSlotCallbackRegistry.addEntryCallback(MetricEntryCallback.class.getCanonicalName(),
  
  new MetricEntryCallback(www.liantingzheng.com));
  
  //key是com.alibaba.csp.sentinel.metric.extension.callback.MetricExitCallback
  
  StatisticSlotCallbackRegistry.addExitCallback(MetricExitCallback.class.getCanonicalName(),
  
  new MetricExitCallback());
  
  }
  
  这个init方法就是注册了两个回调实例MetricEntryCallback和MetricExitCallback。
  
  然后会通过调用Env.sph.entry会最后调用到CtSph的entry方法:
  
  public Entry entry(String name, www.jintianxuesha.com EntryType type, int count, Object... args) throws BlockException {
  
  //这里name是Resource,type是out
  
  StringResourceWrapper resource = new StringResourceWrapper(name, type);
  
  //count是1 ,args是一个空数组
  
  return entry(resource, count, args);
  
  }
  
  这个方法会将resource和type封装成StringResourceWrapper实例,然后调用entry重载方法追踪到CtSph的entryWithPriority方法。
  
  //这里传入得参数count是1,prioritized=false,args是容量为1的空数组
  
  private Entry entryWithPriority(ResourceWrapper resourceWrapper, int count, boolean prioritized, Object... args)
  
  throws BlockException {
  
  //获取当前线程的

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值