如果是第一次来到这个方法的话,那么会实例化一个ServiceExceptionInvocationStat放入到ALL_STATS变量中,然后遍历InvocationStatFactory的遍历LISTENERS,调用监听器的onAddInvocationStat方法。
LISTENERS里面的实例是我们在TimeWindowRegulator#init方法里面add进去的TimeWindowRegulatorListener。
注意,这里用了两个封装类,都是接下来要用到的。分别是InvocationStatDimension和ServiceExceptionInvocationStat。
InvocationStatDimension
public class InvocationStatDimension { /** * One provider of service reference */ private final ProviderInfo providerInfo; /** * Config of service reference */ private final ConsumerConfig consumerConfig; /** * cache value: dimensionKey */ private transient String dimensionKey; /** * cache value : originWeight */ private transient Integer originWeight; }ServiceExceptionInvocationStat的结构图:
ServiceExceptionInvocationStat
public class ServiceExceptionInvocationStat extends AbstractInvocationStat { /** * Instantiates a new Service exception invocation stat. * * @param invocation the invocation */ public ServiceExceptionInvocationStat(InvocationStatDimension invocation) { super(invocation); } @Override public long catchException(Throwable t) { //统计异常次数 if (t instanceof SofaRpcException) { SofaRpcException exception = (SofaRpcException) t; if (exception.getErrorType() == RpcErrorType.CLIENT_TIMEOUT || exception.getErrorType() == RpcErrorType.SERVER_BUSY) { return exceptionCount.incrementAndGet(); } } return exceptionCount.get(); } }然后直接看它父类的具体参数就好了
AbstractInvocationStat
上面的这些参数,我们接下来还会用到。
权重降级具体实现TimeWindowRegulatorListener是TimeWIndowRegulator的内部类。
class TimeWindowRegulatorListener implements InvocationStatListener { @Override public void onAddInvocationStat(InvocationStat invocationStat) { //度量策略不为空 if (measureStrategy != null) { //ServiceHorizontalMeasureStrategy MeasureModel measureModel = measureStrategy.buildMeasureModel(invocationStat); if (measureModel != null) { measureModels.add(measureModel); startRegulate(); } } } @Override public void onRemoveInvocationStat(InvocationStat invocationStat) { if (measureStrategy != null) { measureStrategy.removeMeasureModel(invocationStat); } } }这个监听器里面就是调用ServiceHorizontalMeasureStrategy#buildMeasureModel,返回调控模型。
我们先看一下MeasureModel里面封装了什么:
MeasureModel
public class MeasureModel { /** * App name of measure model * 服务名 */ private final String appName; /** * service name of measure model * 被调用的服务 */ private final String service; /** * all dimension statics stats of measure model * InvokeStat集合 */ private final ConcurrentHashSet<InvocationStat> stats = new ConcurrentHashSet<InvocationStat>(); .... }所以根据这几个全局变量,我们可以推测,MeasureModel应该是根据appName+service为维度,里面有很多的InvocationStat。
我们再回到ServiceHorizontalMeasureStrategy#buildMeasureModel
public MeasureModel buildMeasureModel(InvocationStat invocationStat) { InvocationStatDimension statDimension = invocationStat.getDimension(); //AppName + ":" + Service String key = statDimension.getDimensionKey(); MeasureModel measureModel = appServiceMeasureModels.get(key); if (measureModel == null) { measureModel = new MeasureModel(statDimension.getAppName(), statDimension.getService()); MeasureModel oldMeasureModel = appServiceMeasureModels.putIfAbsent(key, measureModel); if (oldMeasureModel == null) { measureModel.addInvocationStat(invocationStat); return measureModel; } else { oldMeasureModel.addInvocationStat(invocationStat); return null; } } else { measureModel.addInvocationStat(invocationStat); return null; } }buildMeasureModel方法里面的做法也和我上面说的一样。根据appName+service为维度封装不同的invocationStat在MeasureModel里面。