ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

Apache DolphinScheduler Alert SPI 告警插件架构与开发实践

Apache DolphinScheduler Alert SPI 告警插件架构与开发实践 Apache DolphinScheduler Alert SPI 告警插件架构与开发实践【免费下载链接】dolphinschedulerApache DolphinScheduler is the modern data orchestration platform. Agile to create high performance workflow with low-code项目地址: https://gitcode.com/GitHub_Trending/dol/dolphinscheduler本文以 Apache DolphinScheduler 的告警插件扩展机制Alert SPI为主线系统讲解AlertChannelFactory扩展接口、插件参数体系、基于PrioritySPI的插件加载与优先级仲裁机制并结合仓库中 Email 等内置插件的真实源码给出从接口设计到插件落地的完整参考路径。读完本文你将能够独立实现一个自定义告警渠道插件并理解 DolphinScheduler 如何做到“插件开发者只写业务逻辑加载、路由、前端表单生成全部由内核完成”。一、微内核 插件架构Alert SPI 的设计出发点DolphinScheduler 正在向微内核microkernel 插件架构演进。任务执行、资源存储、注册中心乃至告警通道这些核心能力都被设计为扩展点extension point目标是利用 SPI 提升系统自身灵活性与可扩展性。关于告警相关代码官方扩展文档明确指向dolphinscheduler-alert-api模块该模块定义了告警插件的扩展接口和基础代码任何需要实现告警插件化的工作都建议先阅读这个模块的代码。这一设计带来一个非常实际的开发体验插件加载、实例化、按名称路由等底层逻辑全部由内核实现插件开发者只需要关注org.apache.dolphinscheduler.alert.api.AlertChannelFactory一个接口的扩展。也就是说你不需要理解 ServiceLoader 的细节、不需要处理插件之间的冲突只要实现接口、声明好参数内核就会把你写的插件挂载进告警体系。官方同时给出了扩展稳定性承诺扩展接口除新增外几乎不做变更除非出现重大结构调整或不兼容的大版本升级因此基于当前接口编写的插件可以长期复用。二、Alert SPI 五大核心类dolphinscheduler-alert-api模块是 ALERT SPI 的核心全部关键类位于 org.apache.dolphinscheduler.alert.api 包下。逐个看2.1 AlertChannelFactory插件工厂接口所有告警插件都必须实现 AlertChannelFactory 接口。该接口用于定义插件名称与所需参数create方法用于创建具体的告警插件实例。源码中它只有三个抽象方法和一个默认方法public interface AlertChannelFactory extends PrioritySPI { /** 返回告警渠道的名称 */ String name(); /** 创建告警渠道实例 */ AlertChannel create(); /** 返回该插件需要在 Web UI 上展示的可配置参数 */ ListPluginParams params(); default SPIIdentify getIdentify() { return SPIIdentify.builder().name(name()).build(); } }三个方法各管一事方法职责name()插件在系统中的唯一标识名称如Email上层系统按名称路由到对应插件params()返回插件参数定义列表内核据此转换为 JSON驱动前端动态渲染配置表单create()每次需要发送告警时内核调用它拿到一个AlertChannel实例2.2 AlertChannel发送告警的唯一入口AlertChannel 是告警插件本体接口只有一个方法public interface AlertChannel { AlertResult process(AlertInfo info); }上层告警系统调用process方法并通过其返回的AlertResult获得告警结果。插件的全部业务逻辑构造请求、调用 API、落盘脚本等都收敛在这一个方法内。2.3 AlertInfo / AlertData进参上层系统调用插件实例时会构造一个 AlertInfo 传入process方法。从源码看它包含三部分public class AlertInfo { private MapString, String alertParams; // 前端为插件实例填写的参数 private AlertData alertData; // 告警内容本体 private int alertPluginInstanceId; // 告警插件实例 ID }其中 AlertData 承载告警内容包括id告警记录 IDtitle告警标题content告警正文HTML 文本log告警关联日志alertType告警类型编码对应AlertType#code。2.4 AlertResult出参AlertResult 是插件的返回信息只有success与message两个字段并提供两个静态工厂方法插件实现中直接复用即可public static AlertResult success() { return new AlertResult(true, null); } public static AlertResult fail(String message) { return new AlertResult(false, message); }三、插件参数体系用 Java 代码“画”出前端表单这是 Alert SPI 最巧妙的设计。DolphinScheduler 采用了前端组件库form-create其能力基于 JSON 动态生成前端 UI 组件。插件开发者完全不需要关心前端只要把插件参数用org.apache.dolphinscheduler.spi.params包下的参数类定义好内核会把这些参数统一转换为 JSON前端据此渲染出表单。开发者只关心前后端之间交换的数据。3.1 参数类的演进从文档描述到当前源码原文档指出该包当时封装了RadioParam单选、TextParam文本、PasswordParam密码三类参数基类为AbsPluginParams。对照当前仓库源码 dolphinscheduler-spi/src/main/java/org/apache/dolphinscheduler/spi/params参数体系已扩展为基类 PluginParams即文档中的AbsPluginParams演进而来配套DataType、FormType、ParamsOptions、ParamsProps、Validate等基础定义input包InputParam文本输入可通过setType(password)变体为密码框对应原文档的 TextParam / PasswordParam 能力、InputNumberParam数字输入radio包RadioParam单选按钮select包SelectParam下拉选择PluginParamsTransfer负责参数列表与 JSON 之间的转换。每个 DS 告警插件都在AlertChannelFactory的实现中返回一个PluginParams列表这保证了“接口声明”与“表单渲染”的一致性。3.2 实例拆解Email 插件的 params() 实现以 EmailAlertChannelFactory 为例它的params()方法定义了 12 个前端可见参数Override public ListPluginParams params() { ListPluginParams paramsList new ArrayList(); // 收件人必填附国际化占位提示 InputParam receivesParam InputParam .newBuilder(MailParamsConstants.NAME_PLUGIN_DEFAULT_EMAIL_RECEIVERS, MailParamsConstants.PLUGIN_DEFAULT_EMAIL_RECEIVERS) .setPlaceholder(JSONUtils.toJsonString(AlertInputTips.getAllMsg(AlertInputTips.RECEIVERS))) .addValidate(Validate.newBuilder().setRequired(true).build()) .build(); // SMTP 端口数字类型默认 25 InputNumberParam mailSmtpPort InputNumberParam .newBuilder(MailParamsConstants.NAME_MAIL_SMTP_PORT, MailParamsConstants.MAIL_SMTP_PORT) .setValue(25) .addValidate(Validate.newBuilder() .setRequired(true) .setType(DataType.NUMBER.getDataType()).build()) .build(); // SMTP 鉴权开关单选 Yes/No默认 true RadioParam enableSmtpAuth RadioParam .newBuilder(MailParamsConstants.NAME_MAIL_SMTP_AUTH, MailParamsConstants.MAIL_SMTP_AUTH) .addParamsOptions(new ParamsOptions(STRING_YES, STRING_TRUE, false)) .addParamsOptions(new ParamsOptions(STRING_NO, STRING_FALSE, false)) .setValue(STRING_TRUE) .addValidate(Validate.newBuilder().setRequired(true).build()) .build(); // 密码通过 setType(password) 复用文本输入组件 InputParam mailPassword InputParam .newBuilder(MailParamsConstants.NAME_MAIL_PASSWD, MailParamsConstants.MAIL_PASSWD) .setPlaceholder(JSONUtils.toJsonString(AlertInputTips.getAllMsg(AlertInputTips.PASSWORD))) .setType(password) .build(); // 展示形态Table / Text / Attachment / Table_Attachment 四选一 RadioParam showType RadioParam .newBuilder(AlertConstants.NAME_SHOW_TYPE, AlertConstants.SHOW_TYPE) .addParamsOptions(new ParamsOptions(ShowType.TABLE.getDescp(), ShowType.TABLE.getDescp(), false)) .addParamsOptions(new ParamsOptions(ShowType.TEXT.getDescp(), ShowType.TEXT.getDescp(), false)) // ... 其余选项 .setValue(ShowType.TABLE.getDescp()) .addValidate(Validate.newBuilder().setRequired(true).build()) .build(); paramsList.add(receivesParam); // ... 依次加入其余参数 return paramsList; }从中可以提炼出参数定义的通用套路Builder 模式InputParam.newBuilder(paramKey, paramLabel)第一参数是提交到后端的 key第二参数是表单标签默认值setValue(...)指定初始值校验addValidate(Validate.newBuilder().setRequired(true).build())标记必填数字类型用DataType.NUMBER国际化提示setPlaceholder传入AlertInputTips中的多语言提示 JSON单选选项RadioParam通过多个ParamsOptions展示文案、提交值、是否默认描述选项。这些参数定义会被内核转换后交给前端 form-create最终在“告警组Alert Group”配置页动态生成表单用户填写后以MapString, String形式回流到AlertInfo.alertParams——这正是process(AlertInfo)里读取配置的来源。四、插件加载与优先级仲裁机制4.1 原生 Java SPI AutoServiceDolphinScheduler 使用原生 Java SPI做插件发现。插件侧的注册成本极低——以 Email 插件为例工厂类上只需一行注解AutoService(AlertChannelFactory.class) public final class EmailAlertChannelFactory implements AlertChannelFactory { ... }AutoService在编译期自动生成META-INF/services下的服务声明文件插件开发者无需手写服务注册文件。4.2 PrioritySPI同名插件的优先级仲裁AlertChannelFactory继承自 PrioritySPI。这意味着插件可以声明优先级当两个插件同名时可通过重写getIdentify方法自定义SPIIdentify中的优先级高优先级插件会被加载若两个插件同名且优先级相同服务在加载插件时会抛出IllegalArgumentException。PrioritySPI接口本身只声明了getIdentify()与基于优先级的compareTo。真正执行仲裁的是 PrioritySPIFactory其核心逻辑值得逐行看public PrioritySPIFactory(ClassT spiClass) { for (T t : ServiceLoader.load(spiClass)) { if (map.containsKey(t.getIdentify().getName())) { resolveConflict(t); } else { map.put(t.getIdentify().getName(), t); } } } private void resolveConflict(T newSPI) { SPIIdentify identify newSPI.getIdentify(); T oldSPI map.get(identify.getName()); if (newSPI.compareTo(oldSPI.getIdentify().getPriority()) 0) { throw new IllegalArgumentException( String.format(These two spi plugins has conflict identify name with the same priority: %s, %s, oldSPI.getIdentify(), newSPI.getIdentify())); } else if (newSPI.compareTo(oldSPI.getIdentify().getPriority()) 0) { log.info(The {} plugin has high priority, will override {}, newSPI.getIdentify(), oldSPI); map.put(identify.getName(), newSPI); } else { log.info(The low plugin {} will be skipped, newSPI); } }从源码结构看加载流程即ServiceLoader扫描所有实现了该接口的类 → 以getIdentify().getName()为键存入map→ 命中重名时进入resolveConflict优先级相同则直接抛异常快速失败新插件优先级更高则覆盖旧插件否则跳过。这种“快速失败 日志可追溯”的仲裁策略既允许团队内部覆盖官方插件同名更高优先级又能防止两个同名插件静默并存造成难以排查的歧义。AlertChannelFactory中的默认实现getIdentify()仅以name()构建SPIIdentify不显式设置优先级因此普通插件无需关心优先级只有需要覆盖同名插件时才重写它。五、模块结构API 与内置插件的分层告警 SPI 在仓库中对应两个 Maven 模块dolphinscheduler-alert-apiALERT SPI 核心模块定义插件扩展接口与基础代码本文第二节的五大类均在此扩展插件必须实现其中定义的AlertChannelFactory接口dolphinscheduler-alert-plugins内置插件聚合模块官方提供了一批开箱即用的告警渠道插件。上层调用方则是dolphinscheduler-alert-server告警服务它负责接收告警、查询告警组、按渠道类型加载对应插件并调用process发送。插件开发者面向的契约边界就是alert-api模块这正是“内核与插件解耦”的体现。六、内置告警插件一览原文档列举了 Email、DingTalk、EnterpriseWeChat、Script、SMS、FeiShu、Slack、PagerDuty、WebexTeams、Telegram、Http 等内置实现。对照当前仓库dolphinscheduler-alert-plugins目录下的实际模块内置插件清单为插件模块说明dolphinscheduler-alert-email邮件告警支持 SMTP 鉴权、TLS/SSL、表格/文本/附件等多种展示形态dolphinscheduler-alert-dingtalk钉钉群机器人告警dolphinscheduler-alert-wechat企业微信告警dolphinscheduler-alert-scriptShell 脚本告警内核把告警参数传给脚本你在脚本中实现任意告警逻辑是对接内部自建告警系统的通用方式dolphinscheduler-alert-feishu飞书告警dolphinscheduler-alert-slackSlack 告警dolphinscheduler-alert-pagerdutyPagerDuty 告警dolphinscheduler-alert-webexteamsWebexTeams 告警dolphinscheduler-alert-telegramTelegram 告警dolphinscheduler-alert-httpHTTP 告警由于大多数告警插件最终都是一次 HTTP 请求如果你的渠道尚未被支持可直接用 Http 插件实现自己的告警逻辑官方也欢迎把通用插件回馈社区dolphinscheduler-alert-aliyunVoice阿里云语音告警dolphinscheduler-alert-prometheusPrometheus 告警需要说明的是原文档中提及的 SMS短信渠道在当前仓库的插件目录中未找到对应模块实际可用渠道以仓库目录为准。此外dolphinscheduler-alert-all作为聚合模块可在打包时一次性引入全部内置插件。内置插件都遵循同一套骨架例如 Email 插件由 EmailAlertChannelFactory定义名称与参数 EmailAlertChannelprocess中解析alertParams完成 SMTP 发送组成配套template包下的AlertTemplate/DefaultHTMLTemplate负责 HTML 邮件模板渲染exception包下的AlertEmailException统一错误语义——这套“Factory Channel 模板 异常”的组织方式可以直接套用到任何新插件上。七、开发自己的告警插件步骤清单综合上文开发一个自定义告警渠道插件的完整路径是新建模块在dolphinscheduler-alert-plugins下创建插件模块依赖dolphinscheduler-alert-api实现工厂编写XxxAlertChannelFactory implements AlertChannelFactory实现name()唯一渠道名、params()用InputParam/RadioParam等定义前端表单参数可参照 EmailAlertChannelFactory、create()实现通道编写XxxAlertChannel implements AlertChannel在process(AlertInfo info)中从info.getAlertParams()读取用户配置、从info.getAlertData()读取告警内容发送成功后返回AlertResult.success()失败返回AlertResult.fail(message)注册服务工厂类加AutoService(AlertChannelFactory.class)注解编译期自动生成 SPI 注册文件如需覆盖同名插件重写getIdentify()提供更高优先级验证可参照 EmailAlertChannelFactoryTest 编写单测覆盖参数定义与工厂行为打包后在系统的“告警组”页面即可看到你的插件渠道并配置参数。整条链路中插件开发者只触碰两个接口和一组参数类服务发现、冲突仲裁、参数 JSON 化、前端表单渲染全部由内核PrioritySPIFactoryPluginParamsTransfer form-create承担。这种把复杂度压在扩展点之下的设计也是 DolphinScheduler 整个 SPI 体系任务、数据源、注册中心、告警共用的模式——读懂了 Alert SPI再去看 task.md、datasource.md、registry.md 等其它扩展点的文档基本可以触类旁通。【免费下载链接】dolphinschedulerApache DolphinScheduler is the modern data orchestration platform. Agile to create high performance workflow with low-code项目地址: https://gitcode.com/GitHub_Trending/dol/dolphinscheduler创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表