1.Sentinel源码分析—FlowRuleManager加载规则做了什么? (2)

MetricTimerListener

public class MetricTimerListener implements Runnable { private static final MetricWriter metricWriter = new MetricWriter(SentinelConfig.singleMetricFileSize(), SentinelConfig.totalMetricFileCount()); .... }

首次初始化MetricTimerListener的时候会创建一个MetricWriter实例。我们先看传入的两个参数SentinelConfig.singleMetricFileSize()和SentinelConfig.totalMetricFileCount()。

SentinelConfig在首次初始化的时候会初始化静态代码块:

SentinelConfig

static { try { initialize(); loadProps(); resolveAppType(); RecordLog.info("[SentinelConfig] Application type resolved: " + appType); } catch (Throwable ex) { RecordLog.warn("[SentinelConfig] Failed to initialize", ex); ex.printStackTrace(); } }

这段静态代码块主要是设置一下配置参数。

SentinelConfig#singleMetricFileSize
SentinelConfig#totalMetricFileCount

public static long singleMetricFileSize() { try { //获取的是 1024 * 1024 * 50 return Long.parseLong(props.get(SINGLE_METRIC_FILE_SIZE)); } catch (Throwable throwable) { RecordLog.warn("[SentinelConfig] Parse singleMetricFileSize fail, use default value: " + DEFAULT_SINGLE_METRIC_FILE_SIZE, throwable); return DEFAULT_SINGLE_METRIC_FILE_SIZE; } } public static int totalMetricFileCount() { try { //默认是:6 return Integer.parseInt(props.get(TOTAL_METRIC_FILE_COUNT)); } catch (Throwable throwable) { RecordLog.warn("[SentinelConfig] Parse totalMetricFileCount fail, use default value: " + DEFAULT_TOTAL_METRIC_FILE_COUNT, throwable); return DEFAULT_TOTAL_METRIC_FILE_COUNT; } }

singleMetricFileSize方法和totalMetricFileCount主要是获取SentinelConfig在静态变量里设入得参数。

然后我们进入到MetricWriter的构造方法中:
MetricWriter

public MetricWriter(long singleFileSize, int totalFileCount) { if (singleFileSize <= 0 || totalFileCount <= 0) { throw new IllegalArgumentException(); } RecordLog.info( "[MetricWriter] Creating new MetricWriter, singleFileSize=" + singleFileSize + ", totalFileCount=" + totalFileCount); // /Users/luozhiyun/logs/csp/ this.baseDir = METRIC_BASE_DIR; File dir = new File(baseDir); if (!dir.exists()) { dir.mkdirs(); } long time = System.currentTimeMillis(); //转换成秒 this.lastSecond = time / 1000; //singleFileSize = 1024 * 1024 * 50 this.singleFileSize = singleFileSize; //totalFileCount = 6 this.totalFileCount = totalFileCount; try { this.timeSecondBase = df.parse("1970-01-01 00:00:00").getTime() / 1000; } catch (Exception e) { RecordLog.warn("[MetricWriter] Create new MetricWriter error", e); } }

构造器里面主要是创建文件夹,设置单个文件大小,总文件个数,设置时间。

讲完了MetricTimerListener的静态属性,现在我们来讲MetricTimerListener的run方法。

MetricTimerListener#run

public void run() { //这个run方法里面主要是做定时的数据采集,然后写到log文件里去 Map<Long, List<MetricNode>> maps = new TreeMap<Long, List<MetricNode>>(); //遍历集群节点 for (Entry<ResourceWrapper, ClusterNode> e : ClusterBuilderSlot.getClusterNodeMap().entrySet()) { String name = e.getKey().getName(); ClusterNode node = e.getValue(); Map<Long, MetricNode> metrics = node.metrics(); aggregate(maps, metrics, name); } //汇总统计的数据 aggregate(maps, Constants.ENTRY_NODE.metrics(), Constants.TOTAL_IN_RESOURCE_NAME); if (!maps.isEmpty()) { for (Entry<Long, List<MetricNode>> entry : maps.entrySet()) { try { //写入日志中 metricWriter.write(entry.getKey(), entry.getValue()); } catch (Exception e) { RecordLog.warn("[MetricTimerListener] Write metric error", e); } } } }

上面的run方法其实就是每秒把统计的数据写到日志里去。其中Constants.ENTRY_NODE.metrics()负责统计数据,我们下面分析以下这个方法。

Constants.ENTRY_NODE这句代码会实例化一个ClusterNode实例。
ClusterNode是继承StatisticNode,统计数据时在StatisticNode中实现的。

1.Sentinel源码分析—FlowRuleManager加载规则做了什么?

Metrics方法也是调用的StatisticNode方法。

我们先看看StatisticNode的全局变量

public class StatisticNode implements Node { //构建一个统计60s的数据,设置60个滑动窗口,每个窗口1s //这里创建的是BucketLeapArray实例来进行统计 private transient volatile Metric rollingCounterInSecond = new ArrayMetric(SampleCountProperty.SAMPLE_COUNT, IntervalProperty.INTERVAL); //上次统计的时间戳 private long lastFetchTime = -1; ..... }

然后我们看看StatisticNode的metrics方法:
StatisticNode#metrics

public Map<Long, MetricNode> metrics() { // The fetch operation is thread-safe under a single-thread scheduler pool. long currentTime = TimeUtil.currentTimeMillis(); //获取当前时间的滑动窗口的开始时间 currentTime = currentTime - currentTime % 1000; Map<Long, MetricNode> metrics = new ConcurrentHashMap<>(); //获取滑动窗口里统计的数据 List<MetricNode> nodesOfEverySecond = rollingCounterInMinute.details(); long newLastFetchTime = lastFetchTime; // Iterate metrics of all resources, filter valid metrics (not-empty and up-to-date). for (MetricNode node : nodesOfEverySecond) { //筛选符合的滑动窗口的节点 if (isNodeInTime(node, currentTime) && isValidMetricNode(node)) { metrics.put(node.getTimestamp(), node); //选出符合节点里最大的时间戳数据赋值 newLastFetchTime = Math.max(newLastFetchTime, node.getTimestamp()); } } //设置成滑动窗口里统计的最大时间 lastFetchTime = newLastFetchTime; return metrics; }

这个方法主要是调用rollingCounterInMinute进行数据的统计,然后筛选出有效的统计结果返回。

我们进入到rollingCounterInMinute是ArrayMetric的实例,所以我们进入到ArrayMetric的details方法中

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

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