9.源码分析---SOFARPC是如何实现故障剔除的? (4)

如果是第一次来到这个方法的话,那么会实例化一个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的结构图:

9.源码分析---SOFARPC是如何实现故障剔除的?

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

public abstract class AbstractInvocationStat implements InvocationStat { /** * 统计维度 */ protected final InvocationStatDimension dimension; /** * 调用次数 */ protected final AtomicLong invokeCount = new AtomicLong(0L); /** * 异常次数 */ protected final AtomicLong exceptionCount = new AtomicLong(0L); /** * when useless in one window, this value increment 1. <br /> * If this value is greater than threshold, this stat will be deleted. */ private final transient AtomicInteger uselessCycle = new AtomicInteger(0); }

上面的这些参数,我们接下来还会用到。

权重降级具体实现

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里面。

内容版权声明:除非注明,否则皆为本站原创文章。

转载注明出处:https://www.heiqu.com/wppwdd.html