当前位置: 首页 > news >正文

DolphinScheduler应用实战笔记

DolphinScheduler应用实战笔记

  • 一、前言
  • 二、DS执行SQL或存储过程
  • 二、DS调用DataX同步数据
  • 三、DS调用HTTP接口
  • 四、DS依赖(DEPENDENT)节点
  • 五、DS SPARK 节点
  • 六、DS Flink 节点
  • 七、DS Flink 节点
  • 八、DS SQL 节点
  • 九、DS Java程序
  • 十、DS Python节点

一、前言

DolphinScheduler(后文简称DS)在项目中的应用实战笔记,包含DS执行SQL或存储过程、DS调用DataX同步数据、DS调用HTTP接口。
首先,在DS网页上创建项目:
在这里插入图片描述
点击项目名称进入项目
在这里插入图片描述
这两个工具栏:工作流定义和任务实例会经常使用

二、DS执行SQL或存储过程

点击操作栏的数据源中心,并创建数据源
在这里插入图片描述
在这里插入图片描述

选好并提交要执行sql的数据源即可,例如配置Hive。

点击操作栏的项目管理,点击项目进入,选择工作流定义,然后创建工作流:
在这里插入图片描述
拖拽出SQL标签,并填写数据源配置
在这里插入图片描述
填好节点名称、数据源配置和SQL:
在这里插入图片描述
在这里插入图片描述
SQL语句也可以是调用存储过程:(部分版本的hive不支持存储过程)

表结构:

CREATE TABLE `dev.test`(`id` bigint DEFAULT NULL COMMENT 'ID', `tradedate` timestamp DEFAULT NULL COMMENT '日期', `infosource` string DEFAULT NULL COMMENT '信息来源'
)
COMMENT '测试表'
ROW FORMAT SERDE 'org.apache.hadoop.hive.ql.io.orc.OrcSerde' 
WITH SERDEPROPERTIES ( 'serialization.format'='1') 
STORED AS INPUTFORMAT 'org.apache.hadoop.hive.ql.io.orc.OrcInputFormat' 
OUTPUTFORMAT 'org.apache.hadoop.hive.ql.io.orc.OrcOutputFormat'
LOCATION'hdfs://nameservice1/quark1/user/hive/warehouse/dev.db/test'
TBLPROPERTIES ('timelyre.replaced.count.col'='ID', 'timelyre.timestamp.col'='tradeDate', 'timelyre.tag.cols'='id,InfoSource')

存储过程语句:

CREATE
OR        REPLACE PROCEDURE dev.sp_test(IN_DATA_DATE IN INT)AS V_EXE_BEGIN_TIME TIMESTAMP;--程序开始时间
V_EXE_END_TIME TIMESTAMP;--程序结束时间
BEGIN --记录程序开始执行时间
V_EXE_BEGIN_TIME:=SYSTIMESTAMP;
EXECUTE IMMEDIATE 'truncate  table dev.ai_exce_rate';INSERT INTO TABLE dev.test (id, tradedate, infosource) SELECT client_id, last_modify, key FROM dev.ads_acc_stock_trade_detail LIMIT 10;--记录程序结束时间
V_EXE_END_TIME:=SYSTIMESTAMP;--打印执行日志
DBMS_OUTPUT.PUT_LINE(
'过程: sp_test ,业务日期:'||IN_DATA_DATE||',执行完成。开始时间:'||V_EXE_BEGIN_TIME||',结束时间:'||V_EXE_END_TIME
);
END

调用存储过程

CALL dev.sp_test(${IN_TRADE_DATE})

SQL不是select语句,就选择非查询,然后点击保存。
在页面再次点击保存:
在这里插入图片描述
在这里插入图片描述
租户即是刚刚创建的项目,全局变量就是整个任务都有效。
在这里插入图片描述
保存后,点击上线按钮,上线任务并执行:
在这里插入图片描述
在这里插入图片描述
运行起来后可以去任务实例中,查询任务执行情况:
在这里插入图片描述

二、DS调用DataX同步数据

在操作栏点击资源中心,并新建datax的json
在这里插入图片描述
json样例:

{"job": {"setting": {"speed": {"channel": 3,"byte": 1048576},"errorLimit": {"record": 0,"percentage": 0.02}},"content": [{"reader": {"name": "hdfsreader","parameter": {"path": "/inceptor1/user/hive/warehouse/zx91.db/swscdc/ods_zx91_qt_tradingdaynew_all_day/dc_trade_date=${inTradeDate}","defaultFS": "hdfs://nameservice1","hadoopConfig": {"dfs.nameservices": "nameservice1","dfs.ha.namenodes.nameservice1": "nn1,nn2","dfs.namenode.rpc-address.nameservice1.nn1": "${srcNameService1}","dfs.namenode.rpc-address.nameservice1.nn2": "${srcNameService2}","dfs.client.failover.proxy.provider.nameservice1": "org.apache.hadoop.hdfs.server.namenode.ha.ConfiguredFailoverProxyProvider"},"fileType": "orc","fieldDelimiter": "\t","column": [{"index": "0","type": "decimal"},{"index": "1","type": "timestamp"},{"index": "2","type": "decimal"},{"index": "3","type": "decimal"},{"index": "4","type": "decimal"},{"index": "5","type": "decimal"},{"index": "6","type": "decimal"},{"index": "7","type": "decimal"},{"index": "8","type": "timestamp"},{"index": "9","type": "decimal"},{"index": "10","type": "string"},{"index": "11","type": "int"}]}},"writer": {"name": "hdfswriter","parameter": {"defaultFS": "hdfs://nameservice1","hadoopConfig": {"dfs.nameservices": "nameservice1","dfs.ha.namenodes.nameservice1": "nn1,nn2","dfs.namenode.rpc-address.nameservice1.nn1": "timelyre02:8020","dfs.namenode.rpc-address.nameservice1.nn2": "timelyre03:8020","dfs.client.failover.proxy.provider.nameservice1": "org.apache.hadoop.hdfs.server.namenode.ha.ConfiguredFailoverProxyProvider"},"fileType": "orc","path": "/quark1/user/hive/warehouse/dev.db/ylf/qt_tradingdaynew/dc_trade_date=${inTradeDate}","fileName": "qt_tradingdaynew","writeMode": "nonConflict","fieldDelimiter": "\t","column": [{"name": "id","type": "bigint"},{"name": "tradingdate","type": "timestamp"},{"name": "iftradingday","type": "int"},{"name": "secumarket","type": "int"},{"name": "ifweekend","type": "int"},{"name": "ifmonthend","type": "int"},{"name": "ifquarterend","type": "int"},{"name": "ifyearend","type": "int"},{"name": "xgrq","type": "timestamp"},{"name": "jsid","type": "bigint"},{"name": "dc_etl_time","type": "string"},{"name": "dc_trade_date","type": "bigint"}]}}}]}
}

注意读和写的字段顺序要一样。
再编写shell文件,来加载datax的json文件,datax_push_tdh.sh:

#!/bin/bash
# ********************************************************************************
# * Filename     : datax_push_tdh.sh
# * Author       : dcx
# * Version      : 1.0.0
# * Created Date : 20240827
# * Description  : DataX 推送TDH集群任务执行器
# * History      :
# * <author> <version> <modified Date> <description>
# * dcx 1.0.0 2024-08-27 基于datax_push.sh修改,用于推送时序数据库(timelyre)
# *
# ********************************************************************************# Module 1: 设置环境变量
export HADOOP_USER_NAME=swscdc
## dolphinscheduler 生产集群 TDH 客户端
source /usr/local/bigdata_client/TDH-oc-Client/init.sh
## dolphinscheduler 开发集群 TDH 客户端
# source /usr/local/bigdata_client/TDH-Client/init.sh# Module 2: 公共函数
## 定义帮助文档
function ShowUsage() {cat <<EOF
USAGE: $0 [OPTIONS]OPTIONS:-h --help           查看帮助文档.-d --dc-trade-date  [*]业务日期,格式为YYYYMMDD.-j --json-file-name [*]Datax Json 配置文件名.--src-name-service  源 HDFS HA NameService,格式为"TDHHOST1:PORT;TDHHOST2:PORT".--src-jdbc          源数据库连接信息,格式为jdbc连接串.--src-username      源数据库用户名.--src-password      源数据库用户密码.--tar-name-service  目标 HDFS HA NameService,格式为"TDHHOST1:PORT;TDHHOST2:PORT".--tar-jdbc          目标数据库连接信息,格式为jdbc连接串.--tar-username      目标数据库用户名.--tar-password      目标数据库用户密码.--tar-tablename     目标数据库表名(推送TDH集群进行日分区处理).--push-days         数据推送周期,格式为"days,0/1",days:天数(正整数>=1与负整数<=-1),0:自然日,1:交易日,即推送n个自然日或交易日的数据. --jvm-buffer        JVM堆参数,即为防止jvm报内存溢出,根据实际情况调整jvm的堆参数,建议将内存设置为4G或者8G.--inc-value         非时间戳增量标识字段值.--dependence        当前依赖项,格式为"table_name1;table_name2;table_name3".--tar-es-url        推送ESURL信息.--custom-partition  自定义分区值,即非日分区传入.--nonpath-err       HDFS路径不存在时强制成功,该参数表示中止执行并不提示错误,否则默认将置为报错状态.EOF
}
## 定义日志记录函数
function Logger() {echo -e "$(date +%Y/%m/%d\ %H:%M:%S)" : "${0##.*/}" "[${1}]"- "${2}"
}# Module 3: 获取传入参数与参数值校验
## 使用 getopt 获取参数
OPTINOS=$(getopt --option hd:j: --long help,dc-trade-date:,json-file-name:,src-name-service:,src-jdbc:,src-username:,src-password:,tar-name-service:,tar-jdbc:,tar-username:,tar-password:,tar-tablename:,push-days:,jvm-buffer:,inc-value:,dependence:,tar-es-url:,custom-partition:,nonpath-err -n "$0" -- "$@")
VALID_OPTINOS=$?
[[ "${VALID_OPTINOS}" -ne "0" ]] && {echo "Try '$0 -h or --help' for more information."exit 10
}
## 使用 set 将 ${OPTINOS} 设置为位置参数
eval set -- "${OPTINOS}"
## 使用 shift 和 while 循环解析位置参数
while true; docase "$1" in-h | --help)ShowUsageexit 0;;-d | --dc-trade-date)Logger "INFO" "业务日期: $2"DC_TRADE_DATE=$2shift 2;;-j | --json-file-name)Logger "INFO" "Datax Json 配置文件名: $2"JSON_FILE_NAME=$2shift 2;;--src-name-service)Logger "INFO" "源 HDFS HA NameService: $2"SRC_NAME_SERVICE=$2shift 2;;--src-jdbc)Logger "INFO" "源数据库连接信息: $2"SRC_JDBC=$2shift 2;;--src-username)Logger "INFO" "源数据库用户名: $2"SRC_USERNAME=$2shift 2;;--src-password)Logger "INFO" "源数据库用户密码: $2"SRC_PASSWORD=$2shift 2;;--tar-name-service)Logger "INFO" "目标 HDFS HA NameService: $2"TAR_NAME_SERVICE=$2shift 2;;--tar-jdbc)Logger "INFO" "目标数据库连接信息: $2"TAR_JDBC=$2shift 2;;--tar-username)Logger "INFO" "目标数据库用户名: $2"TAR_USERNAME=$2shift 2;;--tar-password)Logger "INFO" "目标数据库用户密码: $2"TAR_PASSWORD=$2shift 2;;--tar-tablename)Logger "INFO" "目标数据库表名(推送TDH集群进行日分区处理): $2"TAR_TABLE_NAME=$2shift 2;;--push-days)Logger "INFO" "数据推送周期: $2"PUSH_DAYS=$2shift 2;;--jvm-buffer)Logger "INFO" "JVM堆参数: $2"JVM_BUFFER=$2shift 2;;--inc-value)Logger "INFO" "非时间戳增量标识字段值: $2"INC_VALUE=$2shift 2;;--dependence)Logger "INFO" "当前依赖项: $2"DEPENDENCE=$2shift 2;;--tar-es-url)Logger "INFO" "推送ES的URL信息: $2"TAR_ES_URL=$2shift 2;;--custom-partition)Logger "INFO" "自定义分区值: $2"CUSTOM_PARTITION=$2shift 2;;--nonpath-err)Logger "INFO" "HDFS路径不存在时强制成功: True"NONPATH_ERR="True"shift 1;;--)shiftbreak;;*)Logger "WARNING" "无效选项: $1"ShowUsageexit 10;;esac
done
## 校验参数值
if [[ -z "${DC_TRADE_DATE}" ]]; thenLogger "ERROR" "[-d | --dc-trade-date] : 业务日期不能为空!"ShowUsageexit 10
elif ! [[ "$(expr "${DC_TRADE_DATE}" : "[1-3][0-9][0-9][0-9][0-1][0-9][0-3][0-9]")" = "8" ]]; thenLogger "ERROR" "[-d | --dc-trade-date] : 业务日期格式错误!"ShowUsageexit 10
elif [[ -z "${JSON_FILE_NAME}" ]]; thenLogger "ERROR" "[-j | --json-file-name] : DATAX JSON 配置文件名不能为空!"ShowUsageexit 10
elif [[ -n "${PUSH_DAYS}" && ! "${PUSH_DAYS}" =~ ^(-)?[1-9]+,(0|1)$ ]]; thenLogger "ERROR" "[--push-days] : 数据推送周期格式错误!"ShowUsageexit 10
fi# Module 4: 定义全局变量
# 日志表
LOG_TABLE_NAME="dwd:dwd_dc_etl_exec_logs"
## 记录开始时间
ETL_START_TIME="$(date "+%Y-%m-%d %H:%M:%S")"
## 日志表 任务名称
PROC_NAME=${JSON_FILE_NAME#*.}
## 日志表 任务类型,1:存储过程,2:数据推送,3:数据推送
PROC_TYPE=3
## 日志表 执行表名或者工作流名
TABLE_NAME=${JSON_FILE_NAME#*.}
## 日志表 任务执行结果标志位.1:成功,2:失败
EXEC_FLAG=1
# 是否写日志标志,0-不写入,0-写入
IS_WRITE_LOG=1
# Inceptor 生产集群连接信息
INCEPTOR_JDBC="jdbc:inceptor2://10.151.6.28:10000/dev"
INCEPTOR_USERNAME="swscdc"
INCEPTOR_PASSWORD=$(echo "U3dzYzYwMDM2OQo=" | base64 -d)
# 设置全局DataX执行参数
PARAMS="-DparaReaderJdbc=${SRC_JDBC} -DsrcUsername=${SRC_USERNAME} -DsrcPassword=${SRC_PASSWORD} -DcustomPartition=${CUSTOM_PARTITION} -DtarEsUrl=${TAR_ES_URL} -DparaWriterJdbc=${TAR_JDBC} -DtarUsername=${TAR_USERNAME} -DtarPassword=${TAR_PASSWORD} -DincValue='${INC_VALUE}'"# Module 5: 业务处理函数
## 获取 json 文件引入资源函数
function GetJsonFile() {for file in "$1"/*; doif test -f "$file"; thenif [[ "${file##*/}" == "${JSON_FILE_NAME#*.}.json" ]]; thenJSON_FILE="${file}"fielseGetJsonFile "${file}"fidone
}
## 分区处理函数
function PartitionDel() {Logger "INFO" "[PartitionDel] - 开始增删分区 ..."Logger "INFO" "[PartitionDel] - TABLE : [${TAR_TABLE_NAME}], PARTITION : [${PARAM_TRADE_DATE}]"local alter_sql="ALTER TABLE ${TAR_TABLE_NAME} DROP PARTITION (dc_trade_date=${PARAM_TRADE_DATE});ALTER TABLE ${TAR_TABLE_NAME} ADD PARTITION (dc_trade_date=${PARAM_TRADE_DATE});"Logger "INFO" "[PartitionDel] - SQL : [${alter_sql}]."local part_del_times=1while true; dobeeline -u "${TAR_JDBC}" -n ${TAR_USERNAME} -p ${TAR_PASSWORD} -e "${alter_sql}"local beeline_result=$?if [[ "${beeline_result}" = "0" ]]; thenLogger "INFO" "[PartitionDel] - 增删分区完成."breakelseLogger "INFO" "[PartitionDel] - 增删分区失败,将进行失败重做."if [[ ${part_del_times} -ge 10 ]]; thenLogger "ERROR" "[PartitionDel] - 失败重做次数已超过限制[>=10],退出执行."exit 10elseLogger "INFO" "[PartitionDel] - 失败重做次数: [${part_del_times}], 失败重做间隔: [30s]"sleep 30spart_del_times=$((part_del_times + 1))fifidone
}
## 调用 datax 执行函数
function PushData() {Logger "INFO" "[PushData] - 开始数据推送 ..."# 设置DataX执行参数local now_params# 判断源数据库类型,inceptor或者关系型数据库if [[ -n "${SRC_NAME_SERVICE}" ]]; then## 推送前检查HDFS路径是否存在PathIsExistif [[ ${NOW_STATUS} == "False" ]]; thenreturnfi## HDFS HA NameService 参数值分割处理local src_name_service1 src_name_service2src_name_service1=$(echo "${SRC_NAME_SERVICE}" | awk -F ";" '{print $1}')src_name_service2=$(echo "${SRC_NAME_SERVICE}" | awk -F ";" '{print $2}')now_params="-DinTradeDate=${PARAM_TRADE_DATE} ${PARAMS} -DsrcNameService1=${src_name_service1} -DsrcNameService2=${src_name_service2}"elsenow_params="-DinTradeDate=${PARAM_TRADE_DATE} ${PARAMS}"fi## 判断目标是否为TDH集群if [[ -n "${TAR_NAME_SERVICE}" ]]; then## HDFS HA NameService 参数值分割处理local tar_name_service1 tar_name_service2tar_name_service1=$(echo "${TAR_NAME_SERVICE}" | awk -F ";" '{print $1}')tar_name_service2=$(echo "${TAR_NAME_SERVICE}" | awk -F ";" '{print $2}')now_params="-DinTradeDate=${PARAM_TRADE_DATE} ${PARAMS} -DtarNameService1=${tar_name_service1} -DtarNameService2=${tar_name_service2}"fi# 根据是否设置了JVM_BUFFER参数来决定是否需要修改JVM堆参数if [[ -n "${JVM_BUFFER}" ]]; thenLogger "INFO" "[PushData] - JVM堆参数 : ${JVM_BUFFER}G"JVM="-Xms${JVM_BUFFER}G -Xmx${JVM_BUFFER}G"else# JVM堆参数默认为2GJVM="-Xms2G -Xmx2G"fi# 执行DataX任务Logger "INFO" "[PushData] - DataX执行参数: ${now_params}"python /usr/local/datax/bin/datax.py --jvm="${JVM}" "${JSON_FILE}" -p"${now_params}"local datax_result=$?if [[ "${datax_result}" == 0 ]]; thenLogger "INFO" "[PushData] - 数据推送完成."elseLogger "ERROR" "[PushData] - 数据推送失败."exit 10fi
}
## 写入 Hyperbase 日志函数
function WriteEtlLogToHyperbase() {local key=${JSON_FILE_NAME#*.}-${PARAM_TRADE_DATE}local data_date=${PARAM_TRADE_DATE}local etl_end_timeetl_end_time="$(date "+%Y-%m-%d %H:%M:%S")"local write_log_times=1Logger "INFO" "[WriteEtlLogToHyperbase] - 写入推送完成日志信息 ..."Logger "INFO" "[WriteEtlLogToHyperbase] - TABLE : [dwd.dwd_dc_etl_exec_logs]"Logger "INFO" "[WriteEtlLogToHyperbase] - Hyperbase写入值: {key : ${key}, proc_name : ${PROC_NAME}, proc_type : ${PROC_TYPE}, table_name : ${TABLE_NAME}, data_date : ${data_date}, etl_start_time : ${data_date}, etl_end_time : ${etl_end_time}, exec_flag : ${EXEC_FLAG}}"while true; doecho "hput '${LOG_TABLE_NAME}','${key}','f:q1','${PROC_NAME}'hput '${LOG_TABLE_NAME}','${key}','f:q2','${PROC_TYPE}'hput '${LOG_TABLE_NAME}','${key}','f:q3','${TABLE_NAME}'hput '${LOG_TABLE_NAME}','${key}','f:q4','${data_date}'hput '${LOG_TABLE_NAME}','${key}','f:q5','${ETL_START_TIME}'hput '${LOG_TABLE_NAME}','${key}','f:q6','${etl_end_time}'hput '${LOG_TABLE_NAME}','${key}','f:q7','${EXEC_FLAG}'" | hbase shell -n >/dev/null 2>&1local write_result=$?if [[ "${write_result}" == "0" ]]; thenLogger "INFO" "[WriteEtlLogToHyperbase] - 日志信息写入完成."breakelseLogger "INFO" "[WriteEtlLogToHyperbase] - 日志信息写入失败,将进行失败重做."if [[ ${write_log_times} -ge 3 ]]; thenLogger "ERROR" "[WriteEtlLogToHyperbase] - 失败重做次数已超过限制[>=3],退出执行."exit 10elseLogger "INFO" "[WriteEtlLogToHyperbase] - 失败重做次数: [${write_log_times}], 失败重做间隔: [10s]"sleep 10swrite_log_times=$((write_log_times + 1))fifidone
}
## 检查当前依赖项是否完成函数
function CheckSourceByHbaseShell() {Logger "INFO" "[CheckSourceByHbaseShell] - 检查当前依赖项是否完成 ..."# 设置分隔符为分号IFS=';'# 将字符串转换为数组read -ra arr <<< "${DEPENDENCE}"# 将IFS变量重置为默认值IFS=$' \t\n'# 循环读取数组for elem in "${arr[@]}"; dolocal key="${elem}-${PARAM_TRADE_DATE}"Logger "INFO" "[CheckSourceByHbaseShell] - 依赖项: ${elem}, key: ${key}"while true; dolocal hbase_result check_resulthbase_result=$(echo "hget '${LOG_TABLE_NAME}','${key}'" | hbase shell -n 2>&1)check_result=$(echo "${hbase_result}"| awk '/row\(s\)/{print $0}' | awk -F " " '{print $1}' | sed ':a;N;$!ba;s/\n//g' | sed s/[[:space:]]//g)if [[ -n "${check_result}" && "${check_result}" != "0" ]]; thenLogger "INFO" "[CheckSourceByHbaseShell] - 检查到依赖项已完成."breakelseLogger "INFO" "[CheckSourceByHbaseShell] - 检查到依赖项未完成,将等待1m后再次检查."sleep 1mfidonedone
}
## 获取自然日或交易日函数
function GetNatureOrTradeDays() {local is_trade_dateDAYS=$(echo "${PUSH_DAYS}" | awk -F "," '{print $1}')is_trade_date=$(echo "${PUSH_DAYS}" | awk -F "," '{print $2}')local sub_query_sqllocal days_absif [[ "${is_trade_date}" == "0" ]]; thenDAYS_FLAG="自然日"if [[ "${DAYS}" -gt 0 ]]; thensub_query_sql="AND T.DATE >= ${DC_TRADE_DATE} ORDER BY T.DATE LIMIT ${DAYS};"elsedays_abs=$((0 - "${DAYS}"))sub_query_sql="AND T.DATE <= ${DC_TRADE_DATE} ORDER BY T.DATE DESC LIMIT ${days_abs};"fielseDAYS_FLAG="交易日"if [[ "${DAYS}" -gt 0 ]]; thensub_query_sql="AND T.IS_TRADE_DATE = 1 AND T.DATE >= ${DC_TRADE_DATE} ORDER BY T.DATE LIMIT ${DAYS};"elsedays_abs=$((0 - "${DAYS}"))sub_query_sql="AND T.IS_TRADE_DATE = 1 AND T.DATE <= ${DC_TRADE_DATE} ORDER BY T.DATE DESC LIMIT ${days_abs};"fifi# 初始化空数组DAYS_ARR=()local query_sql="SELECT T.DATE FROM DIM.DIM_TRADE_DATE_ADD_YEAR T WHERE T.MKT_CODE = '1' ${sub_query_sql}"local query_result trade_daysquery_result=$(beeline -u "${INCEPTOR_JDBC}" -n "${INCEPTOR_USERNAME}" -p "${INCEPTOR_PASSWORD}" -e "${query_sql}" --showHeader=false --silent=true)trade_days=$(echo "${query_result}" | awk -F "|" '{print $2}' | sed ':a;N;$!ba;s/\n/;/g' | sed s/[[:space:]]//g | grep -oP '\d{8}' | paste -sd ' ' -)# 设置分隔符为分号IFS=' '# 将字符串转换为数组read -ra DAYS_ARR <<< "${trade_days}"# 将IFS变量重置为默认值IFS=$' \t\n'
}
## HDFS路径检查函数
function PathIsExist() {Logger "INFO" "[PathIsExist] - 开始检查HDFS路径是否存在 ..."local hdfs_pathhdfs_path=$(sed -n '/.*"path": "\(.*\)",/{s//\1/p;q}' "${JSON_FILE}" | sed "s/\${inTradeDate}/${PARAM_TRADE_DATE}/g" | sed "s/\${customPartition}/${CUSTOM_PARTITION}/g")hdfs_path=$(echo -e "${hdfs_path}" | sed -e 's/\n//g' -e 's/\r//g')Logger "INFO" "[PathIsExist] - fs.defaultFS path : ${hdfs_path}"Logger "INFO" "[PathIsExist] - 路径检查命令 : hadoop fs -test -e ${hdfs_path} >/dev/null 2>&1"hadoop fs -test -e "${hdfs_path}" >/dev/null 2>&1local test_result=$?if [[ "${test_result}" == 0 ]]; thenLogger "INFO" "[PathIsExist] - 已检查到配置项fs.defaultFS,path存在."Logger "INFO" "[PathIsExist] - HDFS路径检查完成."NOW_STATUS="True"elseif [[ "${NONPATH_ERR}" == "True" ]]; thenLogger "INFO" "[PathIsExist] - 已检查到配置项fs.defaultFS,path不存在,则默认本次无任何数据进行推送,中止执行,任务状态将置为成功!"Logger "INFO" "[PathIsExist] - HDFS路径检查完成."Logger "INFO" "[PushData] - 数据推送完成."NOW_STATUS="False"elseLogger "ERROR" "[PathIsExist] - 无法读取路径${hdfs_path}下的所有文件,请确认您的配置项fs.defaultFS,path的值是否正确,是否有读写权限,网络是否已断开!"Logger "INFO" "[PathIsExist] - HDFS路径检查完成."Logger "ERROR" "[PushData] - 数据推送失败."exit 10fifi
}
## 构建 main 函数
function Main() {GetJsonFile .## 判断 json 文件是否是否存在且是否为空文件if [[ ! -s ${JSON_FILE} ]]; thenLogger "INFO" "[Main] - 配置文件 : ${JSON_FILE_NAME#*.}.json"Logger "ERROR" "[Main] - 配置文件不存或者为空文件,请检查是否引入资源或者引入错误资源."exit 10fi## 判断是否需要推送某个时间段内的数据if [[ -z "${PUSH_DAYS}" ]]; then## 设置后续函数的中PARAM_TRADE_DATE值为DC_TRADE_DATEPARAM_TRADE_DATE="${DC_TRADE_DATE}"# 判断是否需要进行当前依赖项检查if [[ -n "${DEPENDENCE}" ]]; thenCheckSourceByHbaseShellfi## 判断是否需要推送TDH集群进行日分区处理if [[ -n "${TAR_TABLE_NAME}" ]]; then## 增删分区PartitionDelfi## 推送数据PushData# 写入推送成功日志if [[ ${IS_WRITE_LOG} -gt 0 ]]; then## 向生产环境日志表写入日志,因为旧集群未启用HBase,所以暂时不写日志.WriteEtlLogToHyperbasefielse## 进行循环推数GetNatureOrTradeDaysLogger "INFO" "[Main] - 推送近${DAYS}个${DAYS_FLAG}内的数据 ..."Logger "INFO" "[Main] - ${DAYS_FLAG} : ${DAYS_ARR[*]}"for idx in "${!DAYS_ARR[@]}"; doPARAM_TRADE_DATE="${DAYS_ARR[idx]}"Logger "INFO" "[Main] - [${idx}] - 业务日期 : ${DC_TRADE_DATE}, 数据日期 : ${PARAM_TRADE_DATE}"# 判断是否需要进行当前依赖项检查if [[ -n "${DEPENDENCE}" ]]; thenCheckSourceByHbaseShellfi## 判断是否需要推送TDH集群进行日分区处理if [[ -n "${TAR_TABLE_NAME}" ]]; then## 增删分区PartitionDelfi## 推送数据PushData## 写入推送成功日志if [[ ${IS_WRITE_LOG} -gt 0 ]]; then## 向生产环境日志表写入日志,因为旧集群未启用HBase,所以暂时不写日志.WriteEtlLogToHyperbasefidonefi
}# Module 6: 执行 main 函数
Main

这个就仅供参考~
然后就新建工作流定义,选择shell任务节点,需要填好名称、执行脚本和引入json和shell脚本。
在这里插入图片描述
执行脚本:

sh tag_platform/shell/datax_push_tdh.sh -d ${IN_TRADE_DATE} -j ${JSON_FILE_NAME} --src-name-service ${SRC_NAME_SERVICE} --tar-jdbc ${TAR_JDBC} --tar-username ${TAR_USERNAME} --tar-password ${TAR_PASSWORD} --tar-tablename ${TAR_TABLENAME} 

然后上线任务并执行即可。

三、DS调用HTTP接口

选择HTTP任务节点
在这里插入图片描述

参数说明:节点名称:一个工作流定义中的节点名称是唯一的。运行标志:标识这个节点是否能正常调度,如果不需要执行,可以打开禁止执行开关。描述信息:描述该节点的功能。任务优先级:worker 线程数不足时,根据优先级从高到低依次执行,优先级一样时根据先进先出原则执行。Worker分组:任务分配给worker组的机器机执行,选择Default,会随机选择一台worker机执行。失败重试次数:任务失败重新提交的次数,支持下拉和手填。失败重试间隔:任务失败重新提交任务的时间间隔,支持下拉和手填。超时告警:勾选超时告警、超时失败,当任务超过"超时时长"后,会发送告警邮件并且任务执行失败.请求地址:http 请求 URL。请求类型:支持 GETPOStHEADPUTDELETE。请求参数:支持 ParameterBodyHeaders。校验条件:支持默认响应码、自定义响应码、内容包含、内容不包含。校验内容:当校验条件选择自定义响应码、内容包含、内容不包含时,需填写校验内容。自定义参数:是 http 局部的用户自定义参数,会替换脚本中以${变量}的内容。

四、DS依赖(DEPENDENT)节点

运行说明:依赖节点,就是依赖检查节点。比如 A 流程依赖昨天的 B 流程执行成功,依赖节点会去检查 B 流程在昨天是否有执行成功的实例。

例如,A 流程为周报任务,B、C 流程为天任务,A 任务需要 B、C 任务在上周的每一天都执行成功,如图示:
在这里插入图片描述
假如,周报 A 同时还需要自身在上周二执行成功:
在这里插入图片描述

五、DS SPARK 节点

执行说明:通过 SPARK 节点,可以直接直接执行 SPARK 程序,对于 spark 节点,worker 会使用 spark-submit 方式提交任务 参数说明:程序类型:支持 JAVAScalaPython 三种语言主函数的 class:是 Spark 程序的入口 Main Class 的全路径主 jar 包:是 Spark 的 jar 包部署方式:支持 yarn-cluster、yarn-client、和 local 三种模式Driver:设置 Driver 内核数 及 内存数Executor:设置 Executor 数量、Executor 内存数、Executor 内核数命令行参数:是设置 Spark 程序的输入参数,支持自定义参数变量的替换。其他参数:支持 --jars、--files、--archives、--conf 格式资源:如果其他参数中引用了资源文件,需要在资源中选择指定自定义参数:是 MR 局部的用户自定义参数,会替换脚本中以${变量}的内容注意:JAVAScala 只是用来标识,没有区别,如果是 Python 开发的 Spark 则没有主函数的 class ,其他都是一样

六、DS Flink 节点

参数说明:程序类型:支持 JAVAScalaPython 三种语言主函数的 class:是 Flink 程序的入口 Main Class 的全路径主 jar 包:是 Flink 的 jar 包部署方式:支持 cluster、local 三种模式slot 数量:可以设置slot数taskManage 数量:可以设置 taskManage 数jobManager 内存数:可以设置 jobManager 内存数taskManager 内存数:可以设置 taskManager 内存数命令行参数:是设置Spark程序的输入参数,支持自定义参数变量的替换。其他参数:支持 --jars、--files、--archives、--conf 格式资源:如果其他参数中引用了资源文件,需要在资源中选择指定自定义参数:是 Flink 局部的用户自定义参数,会替换脚本中以${变量}的内容注意:JAVAScala 只是用来标识,没有区别,如果是 Python 开发的 Flink 则没有主函数的class,其他都是一样

七、DS Flink 节点

例如:

项目管理 -> 工作流 -> 工作流定义 -> 创建工作流
------------------------------------------------------
Task 1:拖拽 SQL 节点到画布,新增一个 SQL 任务
节点名称:Test_sql_hive_01
... ...
数据源:Hive  test_hiveserver2
sql类型:查询   表格:√ 附件:√
主题:Test Hive
收件人:tourist@sohh.cn
sql语句(结尾不要加分号):select * from test_table where score=${i}
自定义参数:i -> IN -> INTEGER -> 97
前置sql:INSERT INTO test_table values(null, 'Dog',97)
后置sql-> 确认添加
Task 2:拖拽 SQL 节点到画布,新增一个 SQL 任务
节点名称:Test_sql_hive_02
... ...
数据源:Hive  test_hiveserver2_ha
sql类型:非查询
sql语句(结尾不要加分号):create table test_table2 as select * from test_table
自定义参数:
前置sql:
后置sql-> 确认添加
------------------------------------------------------
串联任务节点 Test_sql_hive_01、 Test_sql_hive_02
------------------------------------------------------
保存 ->
设置 DAG 图名称:Test_sql_hive
选择租户:Default
超时告警:off
设置全局:
------------------------------------------------------
添加 -> 上线 -> 运行

八、DS SQL 节点

参数说明:数据源:选择对应的数据源sql 类型:支持查询和非查询两种,查询是 select  类型的查询,是有结果集返回的,可以指定邮件通知为 表格、附件 或 表格与附件 三种模板。非查询是没有结果集返回的,是针对 update、delete、insert 三种类型的操作主题、收件人、抄送人:邮件相关配置sql 参数:输入参数格式为 key1=value1;key2=value2…sql 语句:SQL 语句UDF 函数:对于 HIVE 类型的数据源,可以引用资源中心中创建的 UDF 函数,其他类型的数据源暂不支持 UDF 函数自定义参数:SQL 任务类型自定义参数会替换 sql 语句中 ${变量}。而存储过程是通过自定义参数给方法参数设置值,自定义参数类型和数据类型同存储过程任务类型一样。前置 sql:执行 “sql语句” 前的操作后置 sql:执行 “sql语句” 后的操作

例如MySQL:

项目管理 -> 工作流 -> 工作流定义 -> 创建工作流
------------------------------------------------------
Task 1:拖拽 SQL 节点到画布,新增一个 SQL 任务
节点名称:Test_sql_mysql_01
... ...
数据源:MYSQL   test01_mysql
sql类型:查询   表格:√ 附件:√
主题:Test MySQL
收件人:tourist@sohh.cn
sql语句:select * from test_table where score=${i};
自定义参数:i -> IN -> INTEGER -> 97
前置sql:INSERT INTO test_table values(null, 'Dog',97)
后置sql-> 确认添加
Task 2:拖拽 SQL 节点到画布,新增一个 SQL 任务
节点名称:Test_sql_mysql_02
... ...
数据源:MYSQL   test01_mysql
sql类型:非查询
sql语句:create table test_table2 as select * from test_table;
自定义参数:
前置 sql:
后置 sql-> 确认添加
------------------------------------------------------
串联任务节点 Test_sql_mysql_01、Test_sql_mysql_02
------------------------------------------------------
保存 ->
设置 DAG 图名称:Test_sql_mysql
选择租户:Default
超时告警:off
设置全局:
------------------------------------------------------
添加 -> 上线 -> 运行

九、DS Java程序

Java 程序参数说明:

程序类型:JAVA主函数的 class:是 MR 程序的入口 Main Class 的全路径主jar包:是 MR 的 jar 包命令行参数:是设置 MR 程序的输入参数,支持自定义参数变量的替换其他参数:支持 –D-files、-libjars、-archives格式资源:如果其他参数中引用了资源文件,需要在资源中选择指定自定义参数:是MR局部的用户自定义参数,会替换脚本中以${变量}的内容

例如:

# 将 MR 的示例 jar 包上传到 资源中心;并创建测试文本上传到 HDFS 目录
# CDH 版本 Jar 包位置:/opt/cloudera/parcels/CDH/lib/hadoop-mapreduce/hadoop-mapreduce-examples.jar
项目管理 -> 工作流 -> 工作流定义 -> 创建工作流
------------------------------------------------------
拖拽 MR 节点到画布,新增一个 MR 任务
节点名称:Test_mr_java_01
... ...
程序类型:JAVA
主函数的class:wordcount
主jar包:hadoop-mapreduce-examples.jar
命令行参数:/tmp/test.txt /tmp/output
其他参数:
资源:
自定义参数:
-> 确认添加
------------------------------------------------------
保存 ->
设置DAG图名称:Test_mr_java
选择租户:Default
超时告警:off
设置全局:
------------------------------------------------------
添加 -> 上线 -> 运行(运行MR的权限问题此处不再描述)
------------------------------------------------------
查看结果:
sudo -u hdfs hadoop fs -cat /tmp/output/*

十、DS Python节点

运行说明:使用 python 节点,可以直接执行 python 脚本,对于 python 节点,worker会使用 python ** 方式提交任务。参数说明:脚本:用户开发的 Python 程序 资源:是指脚本中需要调用的资源文件列表 自定义参数:是 Python 局部的用户自定义参数,会替换脚本中以 ${变量} 的内容。
例如:

项目管理 -> 工作流 -> 工作流定义 -> 创建工作流
------------------------------------------------------
拖拽 Python 节点到画布,新增一个 Python 任务
节点名称:Test_python_01
... ...
脚本:#!/user/bin/python# -*- coding: UTF-8 -*-for num in range(0, 10): print 'Round %d ...' % num
资源:
自定义参数:
-> 确认添加
------------------------------------------------------
保存 ->
设置 DAG 图名称:Test_python
选择租户:Default
超时告警:off
设置全局:
------------------------------------------------------
添加 -> 上线 -> 运行

相关文章:

DolphinScheduler应用实战笔记

DolphinScheduler应用实战笔记 一、前言二、DS执行SQL或存储过程二、DS调用DataX同步数据三、DS调用HTTP接口四、DS依赖(DEPENDENT)节点五、DS SPARK 节点六、DS Flink 节点七、DS Flink 节点八、DS SQL 节点九、DS Java程序十、DS Python节点 一、前言 DolphinScheduler&…...

IThenticate查重为何成为英语期刊论文投稿首选工具

发表一篇英语论文&#xff0c;我发现很多人在准备向期刊投稿之前&#xff0c;都会选择使用IThenticate查重系统对论文进行相似性检测。是什么魔力&#xff0c;让这个查重工具让投稿者如此偏爱使用它查重呢&#xff1f; 一、什么是IThenticate查重系统&#xff1f; 在了解它被…...

C++ 在项目中使用Git

目录 一&#xff1a;配置邮箱和姓名 二&#xff1a;生成SSH Key 三&#xff1a;git 工作区和状态 四&#xff1a;git log 常用法 五&#xff1a;git diff 常用法 六&#xff1a;git 分支操作 七&#xff1a;git 回溯分支 八&#xff1a;git rebase -i 压缩历史提交…...

Python(TensorFlow和PyTorch)及C++注意力网络导图

&#x1f3af;要点 谱图神经网络计算注意力分数对比图神经网络、卷积网络和图注意力网络药物靶标建模学习和预测相互作用腹侧和背侧皮质下结构手写字体字符序列文本识别组织病理学图像分析长短期记忆财务模式预测相关性生物医学图像特征学习和迭代纠正 Python注意力机制 对…...

选择firewalld还是iptables

firewalld与iptables介绍 firewalld和iptables都是Linux系统中用于管理防火墙规则的重要工具&#xff0c;但它们在功能、使用方式和适用场景上存在显著差异。 动态性&#xff1a; firewalld可以动态修改单条规则&#xff0c;并且能够动态管理规则集。这意味着在更新规则时不会…...

C到C++入门基础知识

一&#xff1a;命名空间&#xff1a;namespace &#xff08;一&#xff09;&#xff1a;命名空间的定义 注&#xff1a;命名空间只能定义在全局&#xff0c;不能定义在函数内部。 &#xff08;1&#xff09;类似于C语言的结构体&#xff0c;C语言的命名空间定义为&#xff1…...

Aigtek功率放大器的主要参数有什么

功率放大器是一种电子设备&#xff0c;通常用于放大输入信号的功率。为了评估和描述功率放大器的性能&#xff0c;有一些主要参数需要了解。下面将介绍一些常见的功率放大器参数。 增益&#xff1a;功率放大器的增益是指输出功率与输入功率之间的比值。它表示了信号经过放大器后…...

运维工程师概述及职责

运维工程师 运维运维工程师&#xff08;Operations Engineer 或 System Administrator&#xff09;是负责确保计算机系统、服务器、网络、存储设备等基础设施稳定运行的专业人员。 运维工程师在IT行业中扮演着至关重要的角色&#xff0c;是连接开发团队和业务团队的桥梁&#…...

Android系统dumpsys命令详解

文章目录 1. dumpsys 的工作原理2. 基本使用方法执行 dumpsys限制 dumpsys 的输出 3. 常见的 dumpsys 服务1. Activity Manager (activity)2. Battery Service (battery)3. Window Manager (window)4. Package Manager (package)5. Power Manager (power)6. Media DRM (media.d…...

[Unity Demo]从零开始制作空洞骑士Hollow Knight第二集:通过InControl插件实现绑定玩家输入以及制作小骑士移动空闲动画

提示&#xff1a;文章写完后&#xff0c;目录可以自动生成&#xff0c;如何生成可参考右边的帮助文档 文章目录 前言一、通过InControl插件实现绑定玩家输入二、制作小骑士移动和空闲动画 1.制作动画2.玩家移动和翻转图像3.状态机思想实现动画切换总结 前言 好久没来CSDN看看&…...

基于鸿蒙API10的RTSP播放器(七:亮度调节功能测试)

目标&#xff1a; 当我的手指在设备左方进行上下移动的时候&#xff0c;可以进行屏幕亮度的调节&#xff0c;在调节的同时&#xff0c;有实时的调节进度条显示 步骤&#xff1a; 界面逻辑&#xff1a;使用Stack() 组件&#xff0c;完成音量图标和进度条的组合显示&#xff0c…...

基于SpringBoot+Vue的校内跑腿业务管理系统

作者&#xff1a;计算机学姐 开发技术&#xff1a;SpringBoot、SSM、Vue、MySQL、JSP、ElementUI、Python、小程序等&#xff0c;“文末源码”。 专栏推荐&#xff1a;前后端分离项目源码、SpringBoot项目源码、SSM项目源码 系统展示 【2025最新】基于JavaSpringBootVueMySQL的…...

嵌入式鸿蒙系统开发语言与开发方法分析

大家好,今天主要给大家分享一下,HarmonyOS系统的主力开发语言ArkTS语言开发方法,它是基于TypeScript(简称TS)语言扩展而来。 第一:ArkTS语言基本特性 目的:声明式UI,让开发者以更简洁,更自然的方式开发高性能应用。 声明式 UI基本特性: 基本UI描述:ArkTS定义了各种装饰…...

SpringBoot开发——整合Spring Data MongoDB

文章目录 一、MongoDB简介1、MongoDB是什么2、MongoDB 基本概念(1)文档(2)集合(3)数据库3、MongoDB的系统数据库4、MongoDB数据模型二、SpringBoot整合Spring Data MongoDB1、创建项目,添加Spring Data MongoDB依赖2、创建实体类Student3、创建StudentRepository接口4、创建…...

camouflaged object detection中的decoder最核心的作用

在 camouflaged object detection&#xff08;COD&#xff09;任务中&#xff0c;decoder 的确有一个核心作用是进行 上采样 以恢复图像的分辨率&#xff0c;但这并不是它唯一或最核心的作用。我们可以从更广泛的视角来看 decoder 的作用。 1. 上采样&#xff08;Upsampling&a…...

Java volatile

Volatile 作用&#xff1a;保证变量的可见性&#xff0c;有序性&#xff08;禁止指令重排序&#xff09;。不保证原子性。 如何保证可见性的&#xff1f; 场景&#xff1a;每个 线程 下都有一块 工作内存。要使用变量需要从 主内存 中把 变量 读取出来&#xff0c;使用完成后写…...

一条sql是如何执行的详解

一条sql是如何执行的详解 1. SQL 解析&#xff08;Parsing&#xff09; 2. 查询重写&#xff08;Query Rewrite&#xff09; 3. 查询规划&#xff08;Query Planning&#xff09; 4. 查询执行&#xff08;Query Execution&#xff09; 5. 结果返回 示例&#xff1a;查询执…...

“先天项目经理圣体”丨超适合做项目经理的4种人

总有人在问&#xff0c;什么样的人适合做项目经理&#xff0c;当项目经理需要什么样的特质&#xff1f; 你别说&#xff0c;还真有那么一些人是“先天项目经理圣体”&#xff0c;天生就是吃项目经理这碗饭的。 沟通达人丨靠“嘴”走天下 我们知道项目经理大部分的时间都在进行…...

如何从object中抽取某几个值,然后转换成数组

可以使用Object.entries(), Array.prototype.filter()和Array.prototype.map()或者解构赋值的方式从对象中抽取某些值并转换为数组 示例 1&#xff1a;使用 Object.entries(), filter() 和 map() const obj {a: 1,b: 2,c: 3,d: 4 };const keysToExtract [a, c];const extr…...

数据结构(14)——哈希表(1)

欢迎来到博主的专栏&#xff1a;数据结构 博主ID&#xff1a;代码小豪 文章目录 哈希表的思想映射方法&#xff08;哈希函数&#xff09;除留余数法 哈希表insert闭散列负载因子扩容find和erase 哈希表的思想 在以往的线性表中&#xff0c;查找速度取决于线性表是否有序&#…...

K近邻算法_分类鸢尾花数据集

import numpy as np import pandas as pd from sklearn.datasets import load_iris from sklearn.model_selection import train_test_split from sklearn.metrics import accuracy_score1.数据预处理 iris load_iris() df pd.DataFrame(datairis.data, columnsiris.featur…...

nacos和eureka的区别详解

Nacos 和 Eureka 都是服务发现和注册中心的解决方案&#xff0c;但它们在功能、设计和使用场景上有所不同。以下是它们的详细区别&#xff1a; 1. 基本概念 Eureka&#xff1a;是由 Netflix 开发的服务发现工具。它主要用于 Java 微服务架构中的服务注册与发现。Eureka 通过 R…...

AI大模型包含哪些些技术?

Prompt Prompt提示是模型接收以生成响应或完成任务的初始文本输入。 我们给AI一组Prompt输入&#xff0c;用于指导模型生成响应以执行任务。这个输入可以是一个问题、一段描述、一组关键词&#xff0c;或任何其他形式的文本&#xff0c;用于引导模型产生特定内容的响应。 Tra…...

分布式技术概览

文章目录 分布式技术1. 分布式数据库&#xff08;Distributed Databases&#xff09;2. 分布式文件系统&#xff08;Distributed File Systems&#xff09;3. 分布式哈希表&#xff08;Distributed Hash Tables, DHTs&#xff09;4. 分布式缓存&#xff08;Distributed Caching…...

动手学习RAG: moka-ai/m3e 模型微调deepspeed与对比学习

动手学习RAG: 向量模型动手学习RAG: moka-ai/m3e 模型微调deepspeed与对比学习动手学习RAG&#xff1a;迟交互模型colbert微调实践 bge-m3 1. 环境准备 pip install transformers pip install open-retrievals注意安装时是pip install open-retrievals&#xff0c;但调用时只…...

Nacos rce-0day漏洞复现(nacos 2.3.2)

Nacos rce-0day漏洞复现&#xff08;nacos 2.3.2&#xff09; NACOS是 一个开源的服务发现、配置管理和服务治理平台&#xff0c;属于阿里巴巴的一款开源产品。影像版本:nacos2.3.2或2.4.0版本指纹&#xff1a;fofa&#xff1a;app“NACOS” 从 Github 官方介绍文档可以看出国…...

yjs04——matplotlib的使用(多个坐标图)

1.多个坐标图与一个图的折线对比 1.引入包&#xff1b;字体&#xff08;同&#xff09; import matplotlib.pyplot as plt import random plt.rcParams[font.family] [SimHei] plt.rcParams[axes.unicode_minus] False 2.创建幕布 2.1建立图层幕布 一个图&#xff1a;plt.fig…...

MOS管和三极管有什么区别?

MOS管是基于金属-氧化物-半导体结构的场效应晶体管&#xff0c;它的控制电压作用于氧化物层&#xff0c;通过调节栅极电势来控制源漏电流。MOS管是FET中的一种&#xff0c;现主要用增强型MOS管&#xff0c;分为PMOS和NMOS。 MOS管的三个极分别是G(栅极)&#xff0c;D(漏极)&…...

医院多参数空气质量监控和压差监测系统简介@卓振思众

在现代医院管理中&#xff0c;确保患者和医疗人员的健康与安全是首要任务。为实现这一目标&#xff0c;医院需要依赖高科技设施来维持最佳的环境条件。特别是&#xff0c;多参数空气质量监测系统和压差监测系统在这一方面发挥了不可替代的作用。【卓振思众】多参数空气质量监测…...

[项目实战]EOS多节点部署

文章总览&#xff1a;YuanDaiMa2048博客文章总览 EOS多节点部署 &#xff08;一&#xff09;环境设计&#xff08;二&#xff09;节点配置&#xff08;三&#xff09;区块信息同步&#xff08;四&#xff09;启动节点并验证同步EOS单节点的环境如何配置 &#xff08;一&#xf…...