Apache SkyWalking 告警动态配置源码简析

简介: AlarmModuleProvider实现了ModuleProvider接口,通过SPI的方式被加载进来。AlarmModuleProvider的prepare方法先被调用,做一些预处理:

AlarmModuleProvider实现了ModuleProvider接口,通过SPI的方式被加载进来。AlarmModuleProviderprepare方法先被调用,做一些预处理:

@Override
public void prepare() throws ServiceNotProvidedException, ModuleStartException {
    Reader applicationReader;
    try {
        applicationReader = ResourceUtils.read("alarm-settings.yml");
    } catch (FileNotFoundException e) {
        throw new ModuleStartException("can't load alarm-settings.yml", e);
    }
    //先从文件中,读取默认的配置,此处还没有加载动态配置。
    RulesReader reader = new RulesReader(applicationReader);
    Rules rules = reader.readRules();

    //创建一个AlarmRulesWatcher实例,这个实例用于监控和转换动态配置。
    alarmRulesWatcher = new AlarmRulesWatcher(rules, this);

    //创建一个NotifyHandler实例,这个实例用于处理被触发的告警。
    notifyHandler = new NotifyHandler(alarmRulesWatcher);
    notifyHandler.init(new AlarmStandardPersistence());

    //注册到服务实现中。
    this.registerServiceImplementation(MetricsNotify.class, notifyHandler);
}

随后,AlarmModuleProviderstart方法被调用:

@Override
public void start() throws ServiceNotProvidedException, ModuleStartException {
    //获取动态配置服务,目前(8.2.0)支持的动态配置有apollo, consul, etcd, k8s configmap, nacos, zookeeper, grpc
    DynamicConfigurationService dynamicConfigurationService = getManager().find(ConfigurationModule.NAME)
                                                                          .provider()
                                                                          .getService(
                                                                              DynamicConfigurationService.class);
    //把之前的AlarmRulesWatcher实例,注册到动态配置服务中
    dynamicConfigurationService.registerConfigChangeWatcher(alarmRulesWatcher);
}

registerConfigChangeWatcher方法的源码在ConfigWatcherRegister抽象类中:

@Override
synchronized public void registerConfigChangeWatcher(ConfigChangeWatcher watcher) {
    if (isStarted) {
        throw new IllegalStateException("Config Register has been started. Can't register new watcher.");
    }
    //利用传入的AlarmRulesWatcher实例,创建一个WatcherHolder实例,其实是对AlarmRulesWatcher实例的再次封装,并格式化好key为alarm.default.alarm-settings。
    WatcherHolder holder = new WatcherHolder(watcher);
    if (register.containsKey(holder.getKey())) {
        throw new IllegalStateException("Duplicate register, watcher=" + watcher);
    }
    //每一个不同的key对应不同的WatcherHolder实例,也就是不同动态配置对应不用的处理办法。
    register.put(holder.getKey(), holder);
}

随后,ConfigWatcherRegister抽象类的start方法被调用:

public void start() {
    isStarted = true;

    //同步动态配置
    configSync();
    LOGGER.info("Current configurations after the bootstrap sync." + LINE_SEPARATOR + register.toString());

    //异步地每隔一段时间做一次动态配置的同步
    Executors.newSingleThreadScheduledExecutor()
             .scheduleAtFixedRate(
                 new RunnableWithExceptionProtection(
                     this::configSync,
                     t -> LOGGER.error("Sync config center error.", t)
                 ), syncPeriod, syncPeriod, TimeUnit.SECONDS);
}

再看一下同步动态配置的configSync方法:

void configSync() {
    //读取所有注册进来的动态配置,包括告警的配置。
    Optional<ConfigTable> configTable = readConfig(register.keys());

    // 如果没有检测到任何配置的更改,configTable可能为null。
    configTable.ifPresent(config -> {
        config.getItems().forEach(item -> {
            String itemName = item.getName();
            //获取到配置对应的WatcherHolder实例
            WatcherHolder holder = register.get(itemName);
            if (holder != null) {
                ConfigChangeWatcher watcher = holder.getWatcher();
                String newItemValue = item.getValue();
                if (newItemValue == null) {
                    if (watcher.value() != null) {
                        // 如果新的配置为null,则发送删除配置的消息类型。
                        watcher.notify(
                            new ConfigChangeWatcher.ConfigChangeEvent(null, ConfigChangeWatcher.EventType.DELETE));
                    } else {
                        // 如果不调用notify方法,则保持配置为空。
                    }
                } else {
                    if (!newItemValue.equals(watcher.value())) {
                        watcher.notify(new ConfigChangeWatcher.ConfigChangeEvent(
                            newItemValue,
                            ConfigChangeWatcher.EventType.MODIFY
                        ));
                    } else {
                        // 如果不调用notify方法,则保持在相同的配置。
                    }
                }
            } else {
                LOGGER.warn("Config {} from configuration center, doesn't match any watcher, ignore.", itemName);
            }
        });

        LOGGER.trace("Current configurations after the sync." + LINE_SEPARATOR + register.toString());
    });
}
注:本文以SkyWalking的8.2.0版本为例进行介绍,如果版本不同会略有差异。
相关文章
|
1月前
|
SQL Apache HIVE
一文彻底掌握Apache Hudi的主键和分区配置
一文彻底掌握Apache Hudi的主键和分区配置
61 0
|
2月前
|
Java 程序员 API
Springboot-swagger配置(idea社区版2023.1.4+apache-maven-3.9.3-bin)
Springboot-swagger配置(idea社区版2023.1.4+apache-maven-3.9.3-bin)
58 1
|
2月前
|
前端开发 Java 数据库连接
Springboot-MyBatis配置-配置端口号与服务路径(idea社区版2023.1.4+apache-maven-3.9.3-bin)
Springboot-MyBatis配置-配置端口号与服务路径(idea社区版2023.1.4+apache-maven-3.9.3-bin)
33 0
|
1月前
|
安全 Linux Apache
Apache代理服务器搭建和配置
Apache代理服务器搭建和配置
|
4月前
|
消息中间件 Apache RocketMQ
电子好书发您分享《Apache RocketMQ 源码解析》
电子好书发您分享《Apache RocketMQ 源码解析》
34 1
|
1月前
|
存储 缓存 负载均衡
【Apache ShenYu源码】如何实现负载均衡模块设计
整个模块为ShenYu提供了什么功能。我们可以看下上文我们提到的工厂对象。/***/核心方法很清晰,我们传入Upsteam列表,通过这个模块的负载均衡算法,负载均衡地返回其中一个对象。这也就是这个模块提供的功能。
18 1
|
1月前
|
Java API Apache
【Apache ShenYu源码】看看贡献者如何实现支持提醒通知设计
在阅读中,还发现了有个html文件忘记加了开源协议,我们提下PR修复下,又收获了一次开源贡献!!PR提交戳这。
23 1
【Apache ShenYu源码】看看贡献者如何实现支持提醒通知设计
|
1月前
|
XML Java Apache
Apache Flink自定义 logback xml配置
Apache Flink自定义 logback xml配置
150 0
|
1月前
|
监控 API Apache
实战!配置DataDog监控Apache Hudi应用指标
实战!配置DataDog监控Apache Hudi应用指标
21 0
|
2月前
|
Java
apache-incubator-streampark源码编译本地运行(七)
apache-incubator-streampark源码编译本地运行(七)
37 1

热门文章

最新文章

推荐镜像

更多