Apache DolphinScheduler - 快速扩展 TaskPlugin 从入门到放弃

目前在大数据生态中,调度系统是不可或缺的一个重要组件。Apache DolphinScheduler 作为一个顶级的 Apache 项目,其稳定性和易用性也可以说是名列前茅的。而对于一个调度系统来说,能够支持的可调度的任务类型同样是一个非常重要的因素,在调度、分布式、高可用、易用性解决了的情况下,随着业务的发展或者各种需求使用到的组件增多,用户自然而然会希望能够快速、方便、简洁地对 Apache Dolphinscheduler 可调度的任务类型进行扩充。本文便带大家了解如何方便、极速扩充一个 Apache DolphinScheduler Task,如图底部一栏是我们本次需要讨论的他们是如何从 0 到 1 扩展的 Task 插件!

先吃点凉菜……

一、什么是 SPI 服务发现(What is SPI)

SPI 全称为 (Service Provider Interface) ,是 JDK 内置的一种服务提供发现机制。大多数人可能会很少用到它,因为它的定位主要是面向开发厂商的,在 java.util.ServiceLoader 的文档里有比较详细的介绍,其抽象的概念是指动态加载某个服务实现。

二、为什么要引入 SPI(Why did we introduce SPI)

不同的企业可能会有自己的组件需要通过 task 去执行,大数据生态中最为常用数仓工具 Apache Hive 来举例,不同的企业使用 Hive 方法各有不同。有的企业通过 HiveServer2 执行任务,有的企业使用 HiveClient 执行任务,而 Apache DolphinScheduler 提供的开箱即用的 Task 中并没有支持 HiveClient 的 Task,所以大部分使用者都会通过 Shell 去执行。然而,Shell 哪有天然的TaskTemplate 好用呢?所以,Apache DolphinScheduler 为了使用户能够更好地根据企业需求定制不同的 Task,便支持了 TaskSPI 化。

我们首先要了解一下 Apache DolphinScheduler 的 Task 改版历程,在 DS 1.3.x 时,扩充一个 Task 需要重新编译整个 Apache DolphinScheduler,耦合严重,所以在 Apache DolphinScheduler 2.0.x 引入了 SPI。前面我们提到了 SPI 的抽象概念是动态加载某个服务的实现,这里我们具象一点,将 Apache DolphinScheduler 的 Task 看成一个执行服务,而我们需要根据使用者的选择去执行不同的服务,如果没有的服务,则需要我们自己扩充,相比于 1.3.x 我们只需要完成我们的 Task 具体实现逻辑,然后遵守 SPI 的规则,编译成 Jar 并上传到指定目录,即可使用我们自己编写的 Task。

三、谁在使用它(Who is using it)

1、Apache DolphinScheduler

  • task

  • datasource

2、Apache Flink

  • flink sql connector:用户实现了一个flink-connector后,Flink也是通过SPI来动态加载

3、Spring Boot

  • spring boot spi

4、Jdbc

  • jdbc4.0以前, 开发人员还需要基于 Class.forName("xxx") 的方式来装载驱动,jdbc4也基于spi的机制来发现驱动提供商了,可以通过META-INF/services/java.sql.Driver文件里指定实现类的方式来暴露驱动提供者

5、更多

  • dubbo

  • common-logging

四、Apache DolphinScheduler SPI Process

剖析一下上面这张图,我给 Apache DolphinScheduler 分为逻辑 Task 以及物理 Task,逻辑 Task 指 DependTask,SwitchTask 这种逻辑上的 Task;物理 Task 是指 ShellTask,SQLTask 这种执行任务的 Task。而在 Apache DolphinScheduler中,我们一般扩充的都是物理 Task,而物理 Task 都是交由 Worker 去执行,所以我们要明白的是,当我们在有多台 Worker 的情况下,要将自定义的 Task 分发到每一台有 Worker 的机器上,当我们启动 Worker 服务时,worker 会去启动一个 ClassLoader 来加载相应的实现了规则的 Task lib,可以看到 HiveClient 和 SeatunnelTask 都是用户自定义的,但是只有 HiveTask 被 Apache DolphinScheduler TaskPluginManage 加载了,原因是 SeatunnelTask 并没有去遵守 SPI 的规则。SPI 的规则图上也有赘述,也可以参考 java.util.ServiceLoader 这个类,下面有一个简单的参考(摘出的一部分代码,具体可以自己去看看)

public final class ServiceLoader<S> implements Iterable<S> {//scanning dir prefixprivate static final String PREFIX = "META-INF/services/";//The class or interface representing the service being loadedprivate final Class<S> service;//The class loader used to locate, load, and instantiate providersprivate final ClassLoader loader;//Private inner class implementing fully-lazy provider lookupprivate class LazyIterator implements Iterator<S> {Class<S> service;ClassLoader loader;Enumeration<URL> configs = null;String nextName = null;//......private boolean hasNextService() {if (configs == null) {try {//get dir all classString fullName = PREFIX + service.getName();if (loader == null)configs = ClassLoader.getSystemResources(fullName);elseconfigs = loader.getResources(fullName);} catch (IOException x) {//......}//......}}}
}
  • Ps:当然下文会有更简便的方式来实现 SPI——注解 @AutoService

好,接下来正式开始我们的正餐——如何扩展一个 Task Plugin

翠花,上热菜~

一、业务背景

我们需要实现一个 Lock 分布式锁的插件,方便多个工作流同时执行某一段业务时,有一定的业务同步阻塞功能,以免出现并发问题。如图是项目结构图

二、Maven 依赖

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"><parent><artifactId>dolphinscheduler-task-plugin</artifactId><groupId>org.apache.dolphinscheduler</groupId><version>3.1.7</version></parent><modelVersion>4.0.0</modelVersion><artifactId>dolphinscheduler-task-lock</artifactId><packaging>jar</packaging><properties><maven.compiler.source>8</maven.compiler.source><maven.compiler.target>8</maven.compiler.target></properties><dependencies><dependency><groupId>org.apache.dolphinscheduler</groupId><artifactId>dolphinscheduler-spi</artifactId></dependency><dependency><groupId>org.apache.dolphinscheduler</groupId><artifactId>dolphinscheduler-task-api</artifactId></dependency></dependencies>
</project>

三、创建 Task 通道工厂(TaskChannelFactory)

首先我们需要创建任务服务的工厂,其主要作用是帮助构建 TaskChannel 以及 TaskPlugin 参数,同时给出该任务的唯一标识,ChannelFactory 在 Apache DolphinScheduler 的 Task 服务组中,其作用属于是在任务组中的承上启下,交互前后端以及帮助 Worker 构建 TaskChannel

package org.apache.dolphinscheduler.plugin.task.lock;/** Licensed to the Apache Software Foundation (ASF) under one or more* contributor license agreements.  See the NOTICE file distributed with* this work for additional information regarding copyright ownership.* The ASF licenses this file to You under the Apache License, Version 2.0* (the "License"); you may not use this file except in compliance with* the License.  You may obtain a copy of the License at**    http://www.apache.org/licenses/LICENSE-2.0** Unless required by applicable law or agreed to in writing, software* distributed under the License is distributed on an "AS IS" BASIS,* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.* See the License for the specific language governing permissions and* limitations under the License.*/import com.google.auto.service.AutoService;
import org.apache.dolphinscheduler.plugin.task.api.TaskChannel;
import org.apache.dolphinscheduler.plugin.task.api.TaskChannelFactory;
import org.apache.dolphinscheduler.spi.params.base.PluginParams;
import java.util.List;@AutoService(TaskChannelFactory.class)
public class LockTaskChannelFactory implements TaskChannelFactory {/*** 创建任务通道, 基于该通道执行任务* @return 任务通道*/@Overridepublic TaskChannel create() {return new LockTaskChannel();}/*** 返回当前任务的全局唯一标识* @return 任务类型名称*/@Overridepublic String getName() {return "LOCK";}/*** 前端页面需要用到的渲染, 一般也同步到* @return*/@Overridepublic List<PluginParams> getParams() {return null;}
}
  • Tips:这个注解就是我们上文提到过的,我们在文章末尾会稍微讲解下 @AutoService(TaskChannelFactory.class)

四、创建 TaskChannel

有了工厂之后,我们会根据工厂创建出 TaskChannel,TaskChannel 包含如下两个方法,一个是取消,一个是创建,目前不需要关注取消,主要关注创建任务

package org.apache.dolphinscheduler.plugin.task.lock;/** Licensed to the Apache Software Foundation (ASF) under one or more* contributor license agreements.  See the NOTICE file distributed with* this work for additional information regarding copyright ownership.* The ASF licenses this file to You under the Apache License, Version 2.0* (the "License"); you may not use this file except in compliance with* the License.  You may obtain a copy of the License at**    http://www.apache.org/licenses/LICENSE-2.0** Unless required by applicable law or agreed to in writing, software* distributed under the License is distributed on an "AS IS" BASIS,* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.* See the License for the specific language governing permissions and* limitations under the License.*/import org.apache.dolphinscheduler.common.utils.JSONUtils;
import org.apache.dolphinscheduler.plugin.task.api.TaskChannel;
import org.apache.dolphinscheduler.plugin.task.api.TaskExecutionContext;
import org.apache.dolphinscheduler.plugin.task.api.parameters.AbstractParameters;
import org.apache.dolphinscheduler.plugin.task.api.parameters.ParametersNode;
import org.apache.dolphinscheduler.plugin.task.api.parameters.resource.ResourceParametersHelper;public class LockTaskChannel implements TaskChannel {@Overridepublic void cancelApplication(boolean status) {}@Overridepublic LockTask createTask(TaskExecutionContext taskRequest) {return new LockTask(taskRequest);}@Overridepublic AbstractParameters parseParameters(ParametersNode parametersNode) {return JSONUtils.parseObject(parametersNode.getTaskParams(), LockParameters.class);}@Overridepublic ResourceParametersHelper getResources(String parameters) {return null;}
}

五、创建 Task 实现

通过 TaskChannel 我们得到了可执行的物理 Task,但是我们需要给当前 Task 添加相应的实现,才能够让 Apache DolphinScheduler 去执行你的任务,首先在编写 Task 之前我们需要先了解一下 Task 之间的关系

通过上图我们可以看到,基于 Yarn 执行任务的 Task 都会去继承 AbstractYarnTask,不需要经过 Yarn 执行的都会去直接继承 AbstractTaskExecutor,主要是包含一个 AppID,以及 CanalApplication setMainJar 之类的方法,想知道的小伙伴可以自己去深入研究一下,如上可知我们实现的 LockTask 就需要继承 AbstractTask,在构建 Task 之前,我们需要构建一下适配 LockTask 的 LockParameters 对象用来反序列化

这里其实主要根据自己的业务情况来增加需要的参数,顺便提醒下:如果自己在 DS 的上一层还有 SDK 封装的话,记得补齐这边对应的参数 TaskParams

package org.apache.dolphinscheduler.plugin.task.lock;/** Licensed to the Apache Software Foundation (ASF) under one or more* contributor license agreements.  See the NOTICE file distributed with* this work for additional information regarding copyright ownership.* The ASF licenses this file to You under the Apache License, Version 2.0* (the "License"); you may not use this file except in compliance with* the License.  You may obtain a copy of the License at**    http://www.apache.org/licenses/LICENSE-2.0** Unless required by applicable law or agreed to in writing, software* distributed under the License is distributed on an "AS IS" BASIS,* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.* See the License for the specific language governing permissions and* limitations under the License.*/import org.apache.dolphinscheduler.plugin.task.api.parameters.AbstractParameters;public class LockParameters extends AbstractParameters {private String key;private Long timeout;private Integer lockType;public Integer getLockType() {return lockType;}public void setLockType(Integer lockType) {this.lockType = lockType;}public String getKey() {return key;}public void setKey(String key) {this.key = key;}public Long getTimeout() {return timeout;}public void setTimeout(Long timeout) {this.timeout = timeout;}@Overridepublic boolean checkParameters() {// 创建 Task 时,会调用该方法进行参数校验return key != null && !key.isEmpty() && timeout != null && lockType != null;}
}

继续把常量类也提一嘴,这个就是在 Task 实现类里如需要用到一些常量可以在这里定义

package org.apache.dolphinscheduler.plugin.task.lock;/** Licensed to the Apache Software Foundation (ASF) under one or more* contributor license agreements.  See the NOTICE file distributed with* this work for additional information regarding copyright ownership.* The ASF licenses this file to You under the Apache License, Version 2.0* (the "License"); you may not use this file except in compliance with* the License.  You may obtain a copy of the License at**    http://www.apache.org/licenses/LICENSE-2.0** Unless required by applicable law or agreed to in writing, software* distributed under the License is distributed on an "AS IS" BASIS,* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.* See the License for the specific language governing permissions and* limitations under the License.*/public class LockConstants {public static final String LOG_TASK_NAME = "lock";
}

现在真的看 Task 实现类了……主要关注 handle 核心方法,这里如果有 redisson 相关报红的只需要注入下即可,当然这里因为不是 Bean 容器,所以需要从外面通过静态类单例模式来引入即可

package org.apache.dolphinscheduler.plugin.task.lock;/** Licensed to the Apache Software Foundation (ASF) under one or more* contributor license agreements.  See the NOTICE file distributed with* this work for additional information regarding copyright ownership.* The ASF licenses this file to You under the Apache License, Version 2.0* (the "License"); you may not use this file except in compliance with* the License.  You may obtain a copy of the License at**    http://www.apache.org/licenses/LICENSE-2.0** Unless required by applicable law or agreed to in writing, software* distributed under the License is distributed on an "AS IS" BASIS,* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.* See the License for the specific language governing permissions and* limitations under the License.*/import org.apache.dolphinscheduler.common.enums.LockType;
import org.apache.dolphinscheduler.common.redis.LockClient;
import org.apache.dolphinscheduler.common.utils.JSONUtils;
import org.apache.dolphinscheduler.plugin.task.api.*;
import org.apache.dolphinscheduler.plugin.task.api.parameters.AbstractParameters;
import org.apache.dolphinscheduler.plugin.task.lock.LockParameters;
import org.redisson.api.RLock;
import org.redisson.api.RedissonClient;
import java.util.concurrent.TimeUnit;/*** lock task*/
public class LockTask extends AbstractTask {protected LockParameters lockParameters;protected TaskExecutionContext taskRequest;public LockTask(TaskExecutionContext taskRequest) {super(taskRequest);this.taskRequest = taskRequest;}@Overridepublic void init() {logger.info(LockConstants.LOG_TASK_NAME + " task params {}", taskRequest.getTaskParams());lockParameters = JSONUtils.parseObject(taskRequest.getTaskParams(), LockParameters.class);if (!lockParameters.checkParameters()) {throw new TaskException(LockConstants.LOG_TASK_NAME + " task params is not valid");}}@Overridepublic void handle(TaskCallBack taskCallBack) throws TaskException {try {run();} catch (Exception e) {logger.error(LockConstants.LOG_TASK_NAME + " task failure", e);setExitStatusCode(TaskConstants.EXIT_CODE_FAILURE);throw new TaskException("run " + LockConstants.LOG_TASK_NAME + " task error", e);}}/*** 核心处理* @param*/private void run() {Integer lockType = lockParameters.getLockType();if (lockType == LockType.LCOKED.getCode()) {lockHandle();} else if (lockType == LockType.UNLOCKED.getCode()) {unlockHandle();} else {setExitStatusCode(TaskConstants.EXIT_CODE_FAILURE);}}/*** 加锁处理* @param*/private void lockHandle() {boolean islock = false;RedissonClient redissonClient = LockClient.get();String key = lockParameters.getKey();Long timeout = lockParameters.getTimeout();RLock lock = redissonClient.getLock(key);try {islock = lock.tryLock(timeout, TimeUnit.SECONDS);setExitStatusCode(TaskConstants.EXIT_CODE_SUCCESS);} catch (Exception e) {throw new RuntimeException(e);} finally {if (!islock) {lock.forceUnlock();}}}/*** 解锁处理* @param*/private void unlockHandle() {RedissonClient redissonClient = LockClient.get();String key = lockParameters.getKey();RLock lock = redissonClient.getLock(key);if (lock.isLocked()) {lock.forceUnlock();}setExitStatusCode(TaskConstants.EXIT_CODE_SUCCESS);}@Overridepublic void cancel() throws TaskException {}@Overridepublic AbstractParameters getParameters() {return lockParameters;}
}

六、遵守 SPI 规则

方法一

(1)Resource下创建META-INF/services文件夹,创建接口全类名相同的文件

└── META-INF
    └── services
        └── org.apache.dolphinscheduler.spi.task.TaskChannelFactory

(2)在文件中写入实现类的全限定类名

org.apache.dolphinscheduler.plugin.task.lock.LockTaskChannelFactory

方法二(推荐)

使用上文一直提到的 @AutoService 注解,只要加在工厂类头上即可,注意别引入错了 package 是 google 旗下的。这样一来就会在编译的时候自动出现在 target 里

import com.google.auto.service.AutoService;@AutoService(TaskChannelFactory.class)
public class LockTaskChannelFactory implements TaskChannelFactory {…}

七、打包 & 部署

mvn clean install

Tips:当然在其他的 Api-Server 等其他 Xxx-Server 里,如果用到了该插件也是需要放在其路径下,重点在 worker-server 和 api-server,其余看情况。好了,本次教程到此结束~

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/125995.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

国内访问香港服务器选择什么路线?

​  国内访问香港服务器可以选择多种路线。首先&#xff0c;我们了解下各个线路的速度延迟。 一、CN2直连&#xff1a;解决了不同互联网服务提供商之间访问的难题&#xff0c;不需要绕到国际网络再从中国的三个网络入口进入。 二、优化直连&#xff1a;全国平均延迟60ms&…

Ubuntu----Linux命令-----防火墙(查看、关闭、启动)

一、查看防火墙状态 命令&#xff1a;ufw status 说明&#xff1a; 活动&#xff1a;防火墙是开启的 不活动&#xff1a;防火墙是关闭的 二、开启防火墙 命令&#xff1a;sudo ufw enable 开启防火墙后&#xff0c;可以查看防火墙状态 三、关闭防火墙 命令&#xff1a;sud…

如何通过构建遥感光谱反射信号与地表参数之间的关系模型来准确估算植被参数?植被参数光学遥感反演方法(Python)及遥感与生态模型数据同化算法

目录 专题一 植被参数遥感反演理论 专题二 植被叶片及冠层反射率模拟与处理 专题三 植被遥感模型参数敏感性分析 专题四 基于查找表(LUT)方法反演植被参数 专题五 基于优化算法反演植被参数 专题六 基于机器学习反演植被参数 专题七 遥感数据同化理论 专题八 同化遥感反…

单目标应用:基于成长优化算法(Growth Optimizer,GO)的微电网优化调度MATLAB

一、微网系统运行优化模型 微电网是由分布式电源、储能装置和能量转换装置等组成的小型发配电系统&#xff0c;具有成本低、电压低、污染小等特点。由于环保和能源压力&#xff0c;清洁可再生能源和分布式能源工业发展潜力巨大。微电网控制器可实现对电网的集中控制&#xff0…

Canonical 发布公告,Ubuntu可以在 Windows 10 商店找到

导读Canonical 前几天正式发布公告称&#xff0c;“Windows 10 Loves Ubuntu”&#xff0c;其 Ubuntu 16.04 LTS 在 Windows 10 商店中以应用的方式出现&#xff0c;这是继 openSUSE 及 SLES 之后&#xff0c;又一款可以从 Windows 10 商店中下载的 Linux 操作系统。 一些用户已…

GO语言网络编程(并发编程)并发介绍,Goroutine

GO语言网络编程&#xff08;并发编程&#xff09;并发介绍&#xff0c;Goroutine 1、并发介绍 进程和线程 A. 进程是程序在操作系统中的一次执行过程&#xff0c;系统进行资源分配和调度的一个独立单位。 B. 线程是进程的一个执行实体,是CPU调度和分派的基本单位,它是比进程更…

Apache Linki 1.3.1+DataSphereStudio+正常启动+微服务+端口号

我使用的是一键部署容器化版本&#xff0c;官方文章 默认会启动6个 Linkis 微服务&#xff0c;其中下图linkis-cg-engineconn服务为运行任务才会启动,一共七个 LINKIS-CG-ENGINECONN:38681 LINKIS-CG-ENGINECONNMANAGER:9102 引擎管理服务 LINKIS-CG-ENTRANCE:9104 计算治理入…

Linux常用命令——convertquota命令

在线Linux命令查询工具 convertquota 把老的配额文件转换为新的格式 补充说明 convertquota命令用于将老的磁盘额数据文件&#xff08;“quota.user”和“quota.group”&#xff09;转换为新格式的文件&#xff08;“quota.user”和“quota.group”&#xff09;。 语法 c…

C/C++输出绝对值 2019年9月电子学会青少年软件编程(C/C++)等级考试一级真题答案解析

目录 C/C输出绝对值 一、题目要求 1、编程实现 2、输入输出 二、解题思路 1、案例分析 三、程序代码 四、程序说明 五、运行结果 六、考点分析 C/C输出绝对值 2019年9月 C/C编程等级考试一级编程题 一、题目要求 1、编程实现 输入一个浮点数&#xff0c;输出这个…

cpolar内网穿透

目录 一、引言二、什么是cpolar三、内网穿透四、如何使用cpolar1、下载cpolar软件安装包2、注册cpolar账号3、使用cpolar 一、引言 当我们完成了一个tomcat的web项目之后&#xff0c;如果我们想让其他电脑访问到这个项目&#xff0c;我们可以让其他电脑和本机连接到同一个局域…

git标签基础

打标签:git可以给仓库历史中某个提交打上标签,以示重要,比较有代表人们会使用这个功能来标记发布结点(V1.0,V2.0) 列出本地标签: git tag --list git tag -l "V1.85*" 列出远端仓库的中所有标签 git ls-remote --tags给标签添加一些描述信息 git tag -a v1.3 -m …

【文字到语音的论文总结】

1.文字到语音的整个过程 文字到语音的一般整体结构 主要是下面这个流程&#xff0c;每个网络可能会把其中两者或是三者融合在一起来&#xff1b; 长度不同的问题 生成的语音可能和文字的长度并不一样&#xff0c;因此需要解决这个问题 Tactron使用的是交叉注意力的方式解…

【数学建模】2023数学建模国赛C题完整思路和代码解析

C题第一问代码和求解结果已完成&#xff0c;第一问数据量有点大&#xff0c;经过编程整理出来了单品销售额的汇总数据、将附件2中的单品编码替换为分类编码&#xff0c;整理出了蔬菜各品类随着时间变化的销售量&#xff0c;并做出了这些疏菜品类的皮尔森相关系数的热力图&#…

MySQL——select语句的简单介绍和查询时常用的参数

select语句详解 基本的select语句 select 要查询的列名 from 要查询的表 where 限制条件; 如果要查询表的所有内容&#xff0c;则把要查询的列名用—个星号*号表示(之间的案例中都已经使用过)&#xff0c;代表要查询表中所有的列。 而大多数情况&#xff0c;我们只需要查看…

AI绘画:StableDiffusion实操教程-完美世界-魔女(附高清图下载)

前段时间我分享了StableDiffusion的非常完整的教程&#xff1a;“AI绘画&#xff1a;Stable Diffusion 终极宝典&#xff1a;从入门到精通 ” 尽管如此&#xff0c;还有读者反馈说&#xff0c;尽管已经成功安装&#xff0c;但生成的图片与我展示的结果相去甚远。真实感和质感之…

【Mysql】给查询记录增加序列号方法

在MySQL 8.0版本中&#xff0c;你可以使用ROW_NUMBER()函数来添加序号。以下是一个示例查询&#xff0c;演示如何添加序号&#xff1a; SELECT ROW_NUMBER() OVER (ORDER BY column_name) AS serial_number,column1, column2, ... FROMyour_table;请将column_name替换为你想要…

微电网的概念

微电网分布式控制理论与方法  顾伟等 微电网的概念和作用 微电网是由多种分布式电源、储能、负载以及相关监控保护装置构成的能够实现自我控制和管理的自治型电力系统&#xff0c;既可以与电网并网进行&#xff0c;也可以以孤岛运行。 分布式发电是指将容量在兆瓦以内的可再…

C++笔记基础全部完整版

01 面向对象 基本概念 面向对象程序设计&#xff08;Object-Oriented Programming&#xff0c;OOP&#xff09;是一种新的程序设计范型。程序设计范型是指设计程序的规范、模型和风格&#xff0c;它是一类程序设计语言的基础。 面向过程 面向过程程序设计范型是使用较广泛的…

gitlab 合并分支

打开我们的gitlab&#xff0c;找到我们的项目&#xff0c;在左侧菜单中找到Merge requests&#xff0c;点击Merge requests&#xff0c;进入下一个页面 点击New merge requests&#xff0c;创建一个新的merge&#xff0c;进入下一个页面 选择自己分支和目标分支&#xff0c;自己…

jmeter 线程组 Open Model Thread Group 阶梯式压测、高峰流量压测

简介 Open Model Thread Group 是5.4.1 版本中引入的一个实验性线程组&#xff0c;可以弹性模拟负载测试。例如设置多个线程模式&#xff0c;再根据这些线程模式调整不同的并发数、暂停时间。由于Open Model Thread Group 是一个实验性线程组&#xff0c;可能会存在一些限制和不…