天天看点

分布式限流系统Sentinel-线上日志数量不自动清理问题定位

作者:架构成长指南

Sentinel介绍

Sentinel是阿里巴巴开源的分布式限流平台,目前在Github有18.4k的star,他主要以流量为切入点,从流量控制、熔断降级、系统自适应保护等多个维度来帮助用户保障微服务的稳定性

问题描述

最近发现生产的Sentinel日志文件数量一直在增多,所以对Sentinel日志文件生成策略进行分析,发现在生成日志文件时,如果参数配置不合理,就会产生如下效果,具体原因请查看问题定位章节

分布式限流系统Sentinel-线上日志数量不自动清理问题定位

问题定位

分布式限流系统Sentinel-线上日志数量不自动清理问题定位

日志写入流程图

上图为Sentinel日志文件写入流程,在写入指标时,如果检测到文件不存在或文件大小超过50M就会创建文件,而在创建文件时首先会获取文件名称,而文件名称有以下两种策略

日志文件名称获取

在获取日志名称时,首先会产生名称前缀,前缀有以下两种格式,通过csp.sentinel.log.use.pid来决定使用哪一种,如果值为true,则使用第一种,名称中包含pid,为false则不包含pid

  1. 应用名称-metrics.log.pidxxx
  2. 应用名称-metrics.log

有了文件前缀以后再拼接当前日期,就会产生以下两种格式名称

  1. 应用名称-metrics.log.pidxxx.yyyy-MM-dd
  2. 应用名称-metrics.log.yyyy-MM-dd

删除多余文件

在获取文件名称以后,就会创建日志文件,在创建时首先会查找历史日志文件,如果文件数大于6个,那么会进行循环删除,直到剩下6个文件,具体代码如下,看到逻辑比较简单,比较重要的方法是listMetricFiles,下面具体查看一下

//批量删除文件
private void removeMoreFiles() throws Exception {
        List<String> list = listMetricFiles(baseDir, baseFileName);
        if (list == null || list.isEmpty()) {
            return;
        }
        for (int i = 0; i < list.size() - totalFileCount + 1; i++) {
            String fileName = list.get(i);
            String indexFile = formIndexFileName(fileName);
            //删除指标文件
            new File(fileName).delete();
            ...
            //删除以idx结尾的索引文件
            new File(indexFile).delete();
            ..
        }
    }
           

查找历史文件

如下代码,listMetricFiles会接收2个参数,分表日志文件路径和日志文件前缀,具体逻辑为从指定路径下面查找以文件前缀开头的非idx得文件

假设应用名称为sentinel-demo,pid为5687,那么文件前缀为sentinel-demo-metrics.log.pid5687,根据前缀查询会返回相关文件,但如果系统发布重启了,pid就会发生变化,就无法查到上个经常产生的文件,查找不到文件就没法删除,这样依次类推,就会产生大量文件,因此产生大量文件原因就是由于指定了csp.sentinel.log.use.pid为true导致的

/**
     * 查找指标文件
     * baseDir 日志文件路径
     * baseFileName为文件前缀
     * @throws Exception
     */
    public static List<String> listMetricFiles(String baseDir, String baseFileName) throws Exception {
        List<String> list = new ArrayList<String>();
        File baseFile = new File(baseDir);
        File[] files = baseFile.listFiles();
        if (files == null) {
            return list;
        }
        for (File file : files) {
            String fileName = file.getName();
            if (file.isFile()
                && fileNameMatches(fileName, baseFileName)
                && !fileName.endsWith(MetricWriter.METRIC_FILE_INDEX_SUFFIX)
                && !fileName.endsWith(".lck")) {
                list.add(file.getAbsolutePath());
            }
        }
        Collections.sort(list, MetricWriter.METRIC_FILE_NAME_CMP);
        return list;
    }
    /**
    * fileName 本地文件名称
    * baseFileName 文件前缀,格式为一下两种,sentinel-demo为应用名称,5687为pid
    *  sentinel-demo-metrics.log  
    *  sentinel-demo-metrics.log.pid5687
    */
    public static boolean fileNameMatches(String fileName, String baseFileName) {
        if (fileName.startsWith(baseFileName)) {
            String part = fileName.substring(baseFileName.length());
            // part is like: ".yyyy-MM-dd.number", eg. ".2018-12-24.11"
            return part.matches("\\.[0-9]{4}-[0-9]{2}-[0-9]{2}(\\.[0-9]*)?");
        } else {
            return false;
        }
    }
           

参数说明

  • csp.sentinel.log.use.pid 日志文件包含pid
  • csp.sentinel.metric.file.total.count 日志文件保留数量,默认值为6
  • csp.sentinel.metric.file.single.size 单日志文件大小,默认为50M

总结

由于系统启动时指定了csp.sentinel.log.use.pid为true,所以日志文件名称会包含pid,但由于系统重启pid会发生变化,所以在清理历史文件时,根据文件前缀没法查找到上一个pid的日志文件,因此就会产生大量的日志文件

修复方式

  1. 显示指定csp.sentinel.log.use.pid为false
  2. 启动时不指定csp.sentinel.log.use.pid

继续阅读