首页 文章 精选 留言 我的

精选列表

搜索[深度集成],共10000篇文章
优秀的个人博客,低调大师

多模态测试落地实践深度解读

在AI原生应用爆发式增长的今天,智能客服、车载语音助手、AIGC内容审核平台、医疗影像辅助诊断系统等典型场景,已不再是单一文本或API接口的交互模式——它们融合了语音输入、图像上传、视频流分析、自然语言响应与界面反馈等多种模态。传统以UI自动化或API测试为核心的测试体系,正面临前所未有的挑战:如何验证语音识别是否在嘈杂环境下鲁棒?图像OCR结果是否受光照畸变影响?多轮对话中视觉提示与语音指令是否语义对齐?

优秀的个人博客,低调大师

深度解读:多模态测试团队转型

在AI原生应用爆发式增长的今天,软件交付形态正经历一场静默却深刻的变革——语音助手、图像生成工具、智能座舱、AR导航、跨模态搜索……这些产品已不再依赖单一文本交互,而是融合语音、图像、文本、视频甚至传感器数据,构建起复杂的多模态人机协同体验。传统以GUI功能验证为核心的测试团队,正面临前所未有的能力断层:用Selenium测不了语音唤醒率,Postman验不出图文一致性,人工用例覆盖不了百万级视觉-语义组合场景。转型,已非选择题,而是生存命题。

优秀的个人博客,低调大师

PHP 引用计数机制深度解析

某位开发者正在排查一个问题:为什么 PHP 工作进程在处理大约 8000 个任务之后总是因"Allowed memory size exhausted"而崩溃。最终上线的修复方案是"每处理 1000 个任务就重启工作进程"。方案奏效了。真正导致泄漏的根因——一个带有双向指针的父子对象结构——从未被追查。工作进程现在每天重启十次,而背后的原因无人理解。两年后,一次不相关的重构意外破坏了重启逻辑,同一个缺陷演变为生产事故:工作进程在任务中途崩溃,用户看到错误,工程师们在没有心智模型的情况下进行排查,完全不知道内存最初为什么会增长。

优秀的个人博客,低调大师

RAG系统测试工具深度对比

随着大模型应用从通用对话走向垂直落地,RAG(Retrieval-Augmented Generation)已成为构建可信AI应用的核心范式。然而,一个鲜被讨论的现实是:90%以上的RAG系统上线后遭遇‘幻觉漂移’或‘检索失效’——不是模型不行,而是缺乏系统性测试保障(来源:2024年MLSys Survey of 137企业级RAG项目)。传统单元测试、LLM评估框架(如LangChain Eval、RAGAS)难以覆盖RAG特有的多阶段故障链:文档切片偏差->嵌入向量失真->检索召回漏判->提示注入污染->生成逻辑错位。因此,RAG系统测试已不再是‘可选项’,而是交付前的强制门禁。

优秀的个人博客,低调大师

深度解读GaussDB逻辑解码技术原理

**摘要:**GaussDB内核提供的逻辑解码技术,配合DRS服务,可以实现异构数据库之间的逻辑复制。 本文分享自华为云社区《【GaussTech技术专栏】GaussDB逻辑解码技术原理》,作者:GaussDB 数据库。 1.背景 随着国内各大行业数字化改造步伐的加快,异构数据库数据同步的需求场景越来越多。 异构数据库同步,即将不同类型、不同结构的数据库之间的数据进行同步处理,以确保数据在不同数据库之间的一致性。比如,将当前数据库的数据迁移到其他类型的数据库中,或者将当前数据库中的数据实时备份到另一个数据库,从而提升数据的安全性和可靠性。 华为云提供了DRS服务,该服务涵盖了异构数据库之间的迁移、同步、灾备、订阅、录制回放等功能。目前DRS支持超过20种关系型和非关系型数据库作为源端,其中就包括了GaussDB。以GaussDB作为源数据库的DRS数据同步的原理如下图所示。 DRS驱动源端数据库GaussDB实时解析WAL日志,生成逻辑日志,随后DRS服务接收并解析逻辑日志,将其转换为目标数据库的SQL语句,并驱动目标数据库执行SQL语句,该过程被称为逻辑复制。 对于源端数据库来说,核心要解决的问题是如何将WAL日志转换成逻辑日志,该过程叫逻辑解码。本文我们为大家介绍GaussDB逻辑解码的技术原理。 2. GaussDB逻辑解码 WAL日志包含数据库中发生的所有数据变更,包括插入、更新和删除等操作,同时还包含了诸多数据库内部细节和特有实现。 逻辑解码用于将WAL日志解析为易于理解和处理的逻辑日志格式,包括JSON、二进制或者固定的text格式。用户和逻辑复制工具(如DRS)可以根据自身需求来解析和处理这些逻辑日志。 当启用逻辑解码时,GaussDB除了将每个事务的基本操作写入WAL日志,还会将少量的解码辅助信息(例如csn快照,用于解码阶段的可见性判断)记录到WAL日志中,以支持逻辑解码过程。同时还需要创建一个逻辑复制槽。逻辑复制槽的作用是阻止数据库将已落盘的WAL日志删除,并防止解码所需的系统表记录被清理。 如上图所示,逻辑解码主要包括数据来源、读取/加载、解码、重排/发送几个模块。WAL日志和系统表中存储的表的元数据是逻辑解码的内容来源。逻辑解码从WAL日志捕获用户表DML的变更记录,依据其中的物理存储标识(block number和offset等)和提交序列号(csn),加载系统表对应时刻的表的元数据,再将物理变更记录中强耦合的内部信息转换为用户可理解的表内容,生成和数据库实现无关的逻辑变更记录,最后重排和发送逻辑变更记录。 GaussDB逻辑解码有两种方式,分别为串行解码和并行解码。串行解码流程分为读取、解码、发送三个步骤,整个串行解码流程均在同一个线程内完成,其中解码的耗时占据全流程的70%以上。串行解码性能约3-5M/s。而并行解码是通过多线程并行执行的方式,极大压缩了解码过程耗时。因为串行解码效率较低,我们不推荐使用串行解码,而是推荐效率更高的并行解码,而且当前通过华为云DRS服务启动的GaussDB逻辑解码任务均为并行解码,下面我们重点介绍并行解码。 3. 并行解码 并行解码是通过多线程并发执行来提升逻辑解码性能。 如上图所示,并行逻辑解码包含三类线程: Reader线程 读取WAL日志,抽取业务DML操作以及解码辅助信息对应的record,构建LogicalLogChange内存对象,如果该条DML涉及toast数据,还需要将toast数据拼接到该dml操作的LogicalLogChange对象中,然后按照日志序列号(LSN,WAL日志的唯一标识符,是一个有序值)顺序轮流分发到解码输入队列。 如果解码到了DDL,DDL更新了系统表,Reader线程此时会失效localsyscache,并将失效消息加入Decoder线程输入队列中,广播通知Decoder线程失效本地缓存。后续decoder线程在解码到失效消息时,同样对线程内的localsyscache作失效处理。 Decoder线程 从解码输入队列获取LogicalLogChange对象,根据日志版本内容加载数据表的元信息,将日志中的物理数据转换成表名、列名、列数据等用户易理解的逻辑数据,解码后的内容存放在LogicalLog内存对象中,并将LogicalLog对象加入到解码输出队列。 前面介绍到,Reader线程在将LogicalLogChange对象入队时是按LSN序将其放入解码输入队列,decoder解码完成后也会将LogicalLog按LSN需放入解码输出队列,供后面的Sender线程读取。 Sender线程 按照DML日志生成顺序,从解码输出队列拿取LogicalLog对象,根据每个对象的事务ID构建hash桶,按照每个LogicalLog对象在解码输出队列中的顺序(队列中已按LSN序排序),把同一个事务的LogicalLog对象,归类到对应的hash桶中,再以事务的提交顺序把每个事务的所有LogicalLog对象发送给逻辑日志接收端(例如DRS)。 并行解码可按需配置解码并发度,并发度参数取值范围为1-20,最大可配置20个并发解码线程。 GaussDB并行解码能极大地提升解码性能。典型tpcc场景下,解码速率可达到100MB/s。 4. DDL解码 GaussDB逻辑解码支持DDL解码。如果GaussDB开启了逻辑解码,则会在DDL SQL执行阶段对DDL语句的解析树进行解析,解析的结果组装为Json格式的字符串(示例),并新增一种WAL日志类型,用于将该Json字符串写入WAL日志。逻辑解码线程解析到该WAL日志类型时,按照原Json格式输出DDL的解码逻辑日志。DDL语句alter table t1 add column col3 varchar(64)的Json格式解码结果如下图所示。 5. 多版本数据字典与指定位点解码 逻辑解码在解码DML过程中依赖表的元数据信息,因此需要访问系统表(也叫数据字典),这种解码模式也叫online catalog模式。GaussDB将系统表信息缓存在syscache中,当DDL语句更新了系统表时,需要对syscache进行失效处理。执行DDL时会往WAL中写一条失效消息日志,逻辑解码的每个线程都在本线程内保存了一份syscache的副本,即localcache,解码到失效消息日志时,会对localcache做相应的失效处理。 online catalog模式的逻辑解码依赖表的历史元数据信息,因此需要利用逻辑复制槽来保留系统表的旧版本元组。如果想对任意历史日志进行指定位点解码,逻辑解码依赖的系统表旧版本元组需要需要一直保留,这样会严重影响数据库的性能。 因此,GaussDB单独增加了一套逻辑解码专用的系统表,叫做逻辑解码多版本数据字典。逻辑解码多版本数据字典参考内核系统表,表结构与内核系统表结构基本保持一致,保留了解码过程中表的元数据的所有历史版本,并单独实现了清理机制。 新安装的实例会自动创建好逻辑解码多版本数据字典,非新安装的实例,首次初始化逻辑解码多版本数据字典时,需要调用一个系统函数进行初始化,该系统函数将内核系统表的数据同步到逻辑解码多版本数据字典中。当DDL语句执行完,事务提交前,往内核系统表插入元数据的同时往逻辑解码多版本数据字典插入元数据。解码的时候,解码线程根据当前csn快照,从逻辑解码多版本数据字典中将元数据信息读取到localcache缓存中使用。同时逻辑解码实现了多版本数据字典清理的定时任务,通过guc参数,配置保留时间,将超过保留时间的元组删除。而且,通过该guc参数,我们可以保留任意时间的旧元组,从而在不影响数据库性能的基础上实现从指定位点(即WAL的物理位置)进行逻辑解码,位点可以是包括归档WAL日志在内的任意位置。 通过这种单独增加一套逻辑解码多版本数据字典的方式,可以将逻辑解码与内核系统表解耦,内核系统表无需为逻辑解码保留大量的旧版本元组,保障了内核的运行性能。 6. 分布式CN解码 GaussDB支持分布式解码能力。分布式解码又分为直连DN解码与CN解码。直连DN解码即不通过CN,解码工具直接连接到DN节点上进行DN解码,该解码方式和集中式解码原理一致,只能解本DN分片的数据。分布式解码主要是指连CN进行解码,可以完整解码整个集群的增量数据。 事务提交顺序(CommitCSN)代表事务完成的先后顺序。对于有依赖的两个事务,后执行事务的CommitCSN大于先执行事务的CommitCSN。分布式逻辑解码按照事务提交顺序有序返回事务的逻辑日志。 如图所示,DN各自按照事务提交顺序返回局部事务的逻辑日志,CN通过堆排序协调汇总来自各DN的事务逻辑日志,按堆排序的顺序输出逻辑日志。 相比于直连DN解码,具有链路数少、能保证强一致性、易用性强等优点。 7. 总结 GaussDB内核提供的逻辑解码技术,配合DRS服务,可以实现异构数据库之间的逻辑复制。GaussDB逻辑解码不仅支持DML解码,还支持DDL解码,极大提高了逻辑复制的易用性。支持独立的多版本数据字典模式进行解码,并支持指定位点解码与数据找回。通过开启并行解码,可以极大提高WAL日志解码速率,保证数据同步的高性能。 华为开发者空间,汇聚鸿蒙、昇腾、鲲鹏、GaussDB、欧拉等各项根技术的开发资源及工具,致力于为每位开发者提供一台云主机、一套开发工具及云上存储空间,让开发者基于华为根生态创新。点击链接:华为云开发者云主机,领取您的专属云主机!! 点击关注,第一时间了解华为云新鲜技术~

优秀的个人博客,低调大师

精细调度:Apache DolphinScheduler脚本深度解析

在现代数据处理和工作流管理中,Apache DolphinScheduler以其灵活性和强大的调度能力受到开发者的广泛欢迎。 本文将逐步解析DolphinScheduler的关键脚本,希望能提供一个详尽的操作指南,帮助大家掌握安装、配置和操作的每一步。 建立在./bin/env/下目录的配置文件建立好的前提。 安装流程解析 ./install.sh 通过source获取install_env.sh和dolphinscheduler_env.sh中的环境变量,如master、worker的基本信息。 在当前机器上创建安装目录,并给目录授权。 向其他节点发送dolphinscheduler的解压文件 停止所有的服务 删除zk上的dolphinscheduler根节点 启动dolphinscheduler所有的服务。 拷贝文件到工作节点 workDir=`dirname $0` workDir=`cd ${workDir};pwd` source ${workDir}/env/install_env.sh # 获取workers=${workers:-"ds1:default,ds2:default,ds3:default,ds4:default,ds5:default"} # 获取数组 workersGroup=(${workers//,/ }) # 顺序取数组中的值 for workerGroup in ${workersGroup[@]} do # 比如:ds1:default echo $workerGroup; # 获取worker的ip worker=`echo $workerGroup|awk -F':' '{print $1}'` # 获取worker对应ip的组,默认为default group=`echo $workerGroup|awk -F':' '{print $2}'` # 将ip放置到一个集合 workerNames+=($worker) # 组放到一个集合 groupNames+=(${group:-default}) done # 获取需要安装的机器ip: ips=${ips:-"ds1,ds2,ds3,ds4,ds5"} hostsArr=(${ips//,/ }) # 开始遍历所有需要安装的机器 for host in ${hostsArr[@]} do # 连接目标ip,验证安装目录是否存在,如果不存在,则会进行文件夹的创建,因此,需要事先创建好ssh免密登录 if ! ssh -o StrictHostKeyChecking=no -p $sshPort $host test -e $installPath; then # 创建安装目录 比如:/home/dolphinscheduler/apache-dolphinscheduler ssh -o StrictHostKeyChecking=no -p $sshPort $host "sudo mkdir -p $installPath; sudo chown -R $deployUser:$deployUser $installPath" fi 如果当前机器时server-worker的机器 echo "scp dirs to $host/$installPath starting" for i in ${!workerNames[@]}; do if [[ ${workerNames[$i]} == $host ]]; then workerIndex=$i break fi done # 这里表示用给定的组去替换default这个字符串,不过配置文件中,默认是不存在这个值的,暂时不用管 # set worker groups in application.yaml [[ -n ${workerIndex} ]] && sed -i "s/- default/- ${groupNames[$workerIndex]}/" $workDir/../worker-server/conf/application.yaml # 将相关的七个文件都拷贝到安装目录下。 for dsDir in bin master-server worker-server alert-server api-server ui tools do echo "start to scp $dsDir to $host/$installPath" # Use quiet mode to reduce command line output scp -q -P $sshPort -r $workDir/../$dsDir $host:$installPath done # restore worker groups to default [[ -n ${workerIndex} ]] && sed -i "s/- ${groupNames[$workerIndex]}/- default/" $workDir/../worker-server/conf/application.yaml echo "scp dirs to $host/$installPath complete" done Zookeeper上根节点的删除 执行命令: bash ${workDir}/remove-zk-node.sh $zkRoot 具体的脚本细节: print_usage(){ printf $"USAGE:$0 rootNode\n" exit 1 } # 如果启动参数的个数不等于1,就会报错, if [ $# -ne 1 ];then print_usage fi # 获取zk上的rootNode: /dolphinscheduler rootNode=$1 # 获取当前 remove-zk-node.sh 脚本的目录,bin BIN_DIR=`dirname $0` BIN_DIR=`cd "$BIN_DIR"; pwd` # 获取dolphin的根目录,可能是安装目录,可能是包目录 DOLPHINSCHEDULER_HOME=$BIN_DIR/.. # 刷新环境变量 source ${BIN_DIR}/env/install_env.sh source ${BIN_DIR}/env/dolphinscheduler_env.sh # 获取java环境 export JAVA_HOME=$JAVA_HOME # 设置配置文件目录,不过不存在配置文件目录 export DOLPHINSCHEDULER_CONF_DIR=$DOLPHINSCHEDULER_HOME/conf # 获取需要的lib包 export DOLPHINSCHEDULER_LIB_JARS=$DOLPHINSCHEDULER_HOME/api-server/libs/* # 下面就是具体的执行命令: export DOLPHINSCHEDULER_OPTS="-Xmx1g -Xms1g -Xss512k -XX:+DisableExplicitGC -XX:+UseConcMarkSweepGC -XX:+CMSParallelRemarkEnabled -XX:LargePageSizeInBytes=128m -XX:+UseCMSInitiatingOccupancyOnly -XX:CMSInitiatingOccupancyFraction=70 " export STOP_TIMEOUT=5 CLASS=org.apache.zookeeper.ZooKeeperMain exec_command="$DOLPHINSCHEDULER_OPTS -classpath $DOLPHINSCHEDULER_CONF_DIR:$DOLPHINSCHEDULER_LIB_JARS $CLASS -server $REGISTRY_ZOOKEEPER_CONNECT_STRING rmr $rootNode" cd $DOLPHINSCHEDULER_HOME $JAVA_HOME/bin/java $exec_command # 下面来看下这个具体的执行命令是什么? /bin/java -Xmx1g -Xms1g -Xss512k -XX:+DisableExplicitGC -XX:+UseConcMarkSweepGC -XX:+CMSParallelRemarkEnabled -XX:LargePageSizeInBytes=128m -XX:+UseCMSInitiatingOccupancyOnly -XX:CMSInitiatingOccupancyFraction=70 # 类路径下的参数 -classpath /conf:/api-server/libs/* # 启动的主要类 org.apache.zookeeper.ZooKeeperMain # 启动的相关参数,这个是zookeeper自身定义的东西,参数需要查看zookeepeer的类 # 主要是zookeeper的连接信息,主要从 dophinscheduler_env.sh 脚本中获取的变量:export REGISTRY_ZOOKEEPER_CONNECT_STRING=${REGISTRY_ZOOKEEPER_CONNECT_STRING:-localhost:2181} -server localhost:2181 rmr /dolphinscheduler 整体启停流程解析 # 一键开启集群所有服务 bash ./bin/start-all.sh # 一键关闭集群所有服务 bash ./bin/stop-all.sh 启动过程如下: 通过source获取install_env.sh中的变量,及api-server、master-server、worker-server、alert-server这几个dolphin中节点的基本部署信息。 通过ssh在各个节点上使用 dolphinscheduler-daemon.sh 命令对各个服务做启停。 启停顺序为 master-server、worker-server、alert-server、api-server。 启动时最后会通过 status-all.sh 对各个服务的状态做查询。 节点状态查询解析 根据作者本人所了解的,获取服务的状态一般通过两种方式: 启动服务时,将服务的进程id写入到文件中,通常在/var/run/目录中,当然,也可以自定义目录。 通过ps命令获取对应的进程id。 当然,Apache DolphinScheduler也是通过写进程文件pid的方式来获取进程id来查询服务状态和停止服务的。 如何单节点启停以及状态查询 在海豚调度的整个启动,停止,状态查询中,最终所用到的脚本是 dolphinscheduler-daemon.sh。 有时候,因为某种原因,可能导致Apache DolphinScheduler集群中某一个服务挂掉,不可能通过start-all.sh命令来操作所有,同时,在集群各个服务的扩缩容中,也需要单节点启动,因此合理使用该脚本就比较重要。 命令的使用规范: dolphinscheduler-daemon.sh (start|stop|status) <api-server|master-server|worker-server|alert-server|standalone-server> 脚本解析 dolphinscheduler-daemon.sh 脚本 # 这是一个用法的示例 usage="Usage: dolphinscheduler-daemon.sh (start|stop|status) <api-server|master-server|worker-server|alert-server|standalone-server> " # 携带的参数必须是两个,如果是一个就会报错 # if no args specified, show usage if [ $# -le 1 ]; then echo $usage exit 1 fi # 执行的命令 startStop=$1 # shift相当于是将$2 变成$1, shift # 执行的任务类型 command=$1 shift echo "Begin $startStop $command......" BIN_DIR=`dirname $0` BIN_DIR=`cd "$BIN_DIR"; pwd` # 获取安装路径的家目录,注意,因为执行的时候,cd 到了installPath DOLPHINSCHEDULER_HOME=`cd "$BIN_DIR/.."; pwd` # 获取dolphin的环境变量,为下面的环境变量覆盖做帮助 BIN_ENV_FILE="${DOLPHINSCHEDULER_HOME}/bin/env/dolphinscheduler_env.sh" # 这段话的意思就是使用/bin/env/dolphinscheduler_env.sh配置文件,代替每个服务下配置目录conf下的配置文件 # Overwrite server dolphinscheduler_env.sh in path `<server>/conf/dolphinscheduler_env.sh` when exists # `bin/env/dolphinscheduler_env.sh` file. User could only change `bin/env/dolphinscheduler_env.sh` instead # of each server's dolphinscheduler_env.sh when they want to start the server # 定义了一个函数,具体看后面的使用,覆盖环境变量 function overwrite_server_env() { local server=$1 local server_env_file="${DOLPHINSCHEDULER_HOME}/${server}/conf/dolphinscheduler_env.sh" if [ -f "${BIN_ENV_FILE}" ]; then echo "Overwrite ${server}/conf/dolphinscheduler_env.sh using bin/env/dolphinscheduler_env.sh." cp "${BIN_ENV_FILE}" "${server_env_file}" else echo "Start server ${server} using env config path ${server_env_file}, because file ${BIN_ENV_FILE} not exists." fi } # 当前机器的hostname export HOSTNAME=`hostname` # 执行命令服务的日志文件 export DOLPHINSCHEDULER_LOG_DIR=$DOLPHINSCHEDULER_HOME/$command/logs # 设置超时时间 export STOP_TIMEOUT=5 # 创建日志文件夹 if [ ! -d "$DOLPHINSCHEDULER_LOG_DIR" ]; then mkdir $DOLPHINSCHEDULER_LOG_DIR fi # 定义服务的启动进程文件 pid=$DOLPHINSCHEDULER_HOME/$command/pid # 进入到服务的主目录 cd $DOLPHINSCHEDULER_HOME/$command # 服务的运行日志,out日志 if [ "$command" = "api-server" ]; then log=$DOLPHINSCHEDULER_HOME/api-server/logs/$command-$HOSTNAME.out elif [ "$command" = "master-server" ]; then log=$DOLPHINSCHEDULER_HOME/master-server/logs/$command-$HOSTNAME.out elif [ "$command" = "worker-server" ]; then log=$DOLPHINSCHEDULER_HOME/worker-server/logs/$command-$HOSTNAME.out elif [ "$command" = "alert-server" ]; then log=$DOLPHINSCHEDULER_HOME/alert-server/logs/$command-$HOSTNAME.out elif [ "$command" = "standalone-server" ]; then log=$DOLPHINSCHEDULER_HOME/standalone-server/logs/$command-$HOSTNAME.out else echo "Error: No command named '$command' was found." exit 1 fi # 定义一个函数,获取服务的当前状态 state="" function get_server_running_status() { state="STOP" if [ -f $pid ]; then TARGET_PID=`cat $pid` if [[ $(ps -p "$TARGET_PID" -o comm=) =~ "bash" ]]; then state="RUNNING" fi fi } # 使用case语句,根据情况做启动,停止,状态查看 case $startStop in (start) # if server is already started, cancel this launch # 如果服务已经启动,直接退出启动过程 get_server_running_status if [[ $state == "RUNNING" ]]; then echo "$command running as process $TARGET_PID. Stop it first." exit 1 fi # 开始做启动 echo starting $command, logging to $DOLPHINSCHEDULER_LOG_DIR # 覆盖配置文件 overwrite_server_env "${command}" # 执行具体的命令,输入到日志文件,并将标准输出2重定向到标准输出1 nohup /bin/bash "$DOLPHINSCHEDULER_HOME/$command/bin/start.sh" > $log 2>&1 & echo $! > $pid ;; # 停止服务,通过kill命令 (stop) if [ -f $pid ]; then TARGET_PID=`cat $pid` if kill -0 $TARGET_PID > /dev/null 2>&1; then echo stopping $command pkill -P $TARGET_PID sleep $STOP_TIMEOUT if kill -0 $TARGET_PID > /dev/null 2>&1; then echo "$command did not stop gracefully after $STOP_TIMEOUT seconds: killing with kill -9" pkill -P -9 $TARGET_PID fi else echo no $command to stop fi rm -f $pid else echo no $command to stop fi ;; # 查询状态 (status) get_server_running_status if [[ $state == "STOP" ]]; then # font color - red state="[ \033[1;31m $state \033[0m ]" else # font color - green state="[ \033[1;32m $state \033[0m ]" fi echo -e "$command $state" ;; (*) echo $usage exit 1 ;; 启动脚本关键点说明 这里主要讲一点关于env中配置目录中的关键点,可以发现在dolphinscheduler_env.sh中有一些数据库方面的配置。如下: # Database related configuration, set database type, username and password export DATABASE=${DATABASE:-postgresql} export SPRING_PROFILES_ACTIVE=${DATABASE} export SPRING_DATASOURCE_URL export SPRING_DATASOURCE_USERNAME export SPRING_DATASOURCE_PASSWORD 比较了解SpringBoot的同学知道,JAVA的配置一般是来自于Yaml文件中的,因此对于一些初试用的同学对配置可能就比较迷惑。 打开spring的官网: https://docs.spring.io/spring-boot/docs/2.2.9.RELEASE/reference/htmlsingle/#boot-features-external-config, 我们可以看到有这样的描述: SpringBoot使用一种非常特殊的PropertySource顺序,旨在允许合理地覆盖值。按以下顺序考虑属性: $HOME/.config/spring-boot当 devtools 处于活动状态时,文件夹中的Devtools全局设置属性。 @TestPropertySource对你的测试进行注释。 properties测试的属性。可用于测试应用程序的特定部分的测试@SpringBootTest注释。 命令行参数。 来自SPRING_APPLICATION_JSON(嵌入环境变量或系统属性中的内联 JSON)的属性。 ServletConfig初始化参数。 ServletContext初始化参数。 JNDI 属性来自java:comp/env. Java 系统属性 ( System.getProperties())。 操作系统环境变量。 ARandomValuePropertySource仅在 中具有属性random.*。 打包的 jar(和 YAML 变体)之外的特定于配置文件的应用程序属性application-{profile}.properties。 特定于配置文件的应用程序属性打包在 jar(application-{profile}.properties和 YAML 变体)内。 打包的 jar(和 YAML 变体)之外的应用程序属性application.properties。 打包在 jar 内的应用程序属性application.properties(和 YAML 变体)。 @PropertySource类上的注释@Configuration。Environment请注意,在刷新应用程序上下文之前,不会将此类属性源添加到中。现在配置某些属性为时已晚,例如在刷新开始之前读取的logging.和。spring.main. 默认属性(由设置指定SpringApplication.setDefaultProperties)。 其中就有操作系统环境变量,而使用方式就是大写和下划线作为分隔符,具体细节大家看链接的官网就明白了。 通过以上深入的脚本解析,开发者应能更加熟练地操纵Apache DolphinScheduler,从而提升数据工作流的效率和稳定性。随着技术的不断进步,了解并掌握这些基本的脚本操作对于保持技术竞争力是至关重要的。 本文由 白鲸开源科技 提供发布支持!

优秀的个人博客,低调大师

深度解析KubeEdge EdgeMesh 高可用架构

摘要:通过高可用特性应用场景、高可用特性使用手册、课题总结、未来展望等四个部分的内容来向大家介绍新版本EdgeMesh的高可用架构。 本文分享自华为云社区《KubeEdge EdgeMesh 高可用架构详解|KubeEdge云原生边缘计算社区》,作者:南开大学|达益鑫。 EdgeMesh项目解决了边缘计算场景下复杂网络的通信问题,中心化的edgemesh-server作为一个中继组件,协助其他节点进行网络穿透和流量中转。之前的edgemesh-server本身不具备高可用特性,会遇到性能瓶颈与单点故障问题,目前EdgeMesh v1.12版本的高可用架构不仅优化了上述问题,也带来了更加稳定的系统运行时,还覆盖了多种边缘网络的痛点场景,如分布式动态中继连接场景和私有局域网的网络自治场景等。此外,EdgeMesh 在v1.12中还带来了基于PSK密码的安全连接、对接HTTPS的边缘Kube API Endpoint等特性和能力,整体提升了EdgeMesh的性能、稳定性与安全性。 作为开源之夏课题【EdgeMesh:高可用架构的设计与实现】的实践者,这是我第一次接触开源社区相关的项目,非常有幸能深入地参与到KubeEdge开源项目的开发之中,也非常开心能够参与EdgeMesh高可用特性的方案设计与代码开发。我将通过高可用特性应用场景、高可用特性使用手册、课题总结、未来展望等四个部分的内容来向大家介绍新版本EdgeMesh的高可用架构以及我个人在KubeEdge社区的成长经历。 高可用架构的主要目的是为了保障系统的稳定性以及提升系统的整体性能,此次EdgeMesh的高可用特性在原有功能的基础上还覆盖了多种边缘网络的痛点场景。以下为EdgeMesh高可用特性在边缘计算场景下的具体应用场景,用户可以依据这些用例来理解本特性能提供的服务。 ▍1.1 单点故障以及高负载场景 如图所示,当单个节点承担中继功能时,所有其他的节点都需要连接该节点才能够获取网络连接的服务。在这样的场景当中,单个节点的负载就会相应地增加,过高的通信负载或者是密集的连接数量,在诸多情况下是限制服务性能的主要原因,同时如果该节点出现故障则会导致中继连接断开,使得中继连接功能暂时性停滞。 为了能够优化这部分的问题,覆盖高负载访问场景,EdgeMesh 新版本考量使用分布式网络连接的思想,通过给予每一个节点能够提供中继功能的结构,使每一个节点都具有为其他节点提供中继的能力。针对这部分场景需求,用户可以在集群初始化时指定多个特定的节点作为默认的中继节点,依据自身情况调节集群内负载的分配,EdgeMesh将会在提供中继服务的时候,优先尝试连接这些节点;如果不做设置,EdgeMesh也会寻找合适的节点执行中继功能,分散减轻单个节点的中继访问负担。 ▍1.2 分布式动态中继连接场景 如图所示,位于上海的边缘应用A和B通过中继互相通信,需要把流量转发到处于北京数据中心里的relay节点,数据传输在远距离的两地之间绕了一圈,导致服务时延较长,用户体验较差。非常遗憾的是,边缘计算场景下集群规模经常横跨多地或者是多区域部署,如果中继节点距离请求服务的节点非常遥远,就会造成极大的延迟,影响用户的体验。这个情况尤其是在中继连接对象与自己不在相邻地理位置下的时候,体现得尤为明显。 为了能够优化这部分的体验,覆盖远距离服务场景,EdgeMesh新版本考量就近中继的原则,用户可以根据集群节点的地理位置分布情况,支持选择一个地理位置适中的relay节点。当应用需要中继连接服务的时候,edgemesh-agent就会动态优先选择就近的relay节点作为中继来提供网络连接服务,以此缩短中继服务的时延。 ▍1.3 私有局域网网络自治场景 如图所示,在老版本的EdgeMesh的代码实现中,edgemesh-agent必须保持与云上中继服务edgemesh-server的连接,当局域网内的节点离线后,导致edgemesh-agent断开与中继节点的连接,断连节点上的服务就彻底失去流量代理的能力了,这在部分私有局域网网络内或者是网络情况波动较大的环境当中会给用户造成较大的困扰。 为了能够优化这部分的问题,提高网络应用连接的稳定性,EdgeMesh 新版本考量了分布式管理及网络自治的想法,让EdgeMesh能够通过mDNS机制保障私有局域网网络内或者是离线局域网内节点之间的相互发现和转发流量,维持应用服务的正常运转。针对这部分场景需求,用户并不需要再单独设置任何的参数来启用此功能,该功能一般面对两种情形进行服务维持:a. 在刚部署EdgeMesh的时候,部分节点就已经在私有局域网下,那这个局域网内的节点依旧可以通过EdgeMesh来相互之间访问和转发流量。 b. 在集群正常运转过程当中,部分节点离线后,这部分节点依旧可以通过EdgeMesh来维持相互之间的网络连接和流量转发。 ▍2.1 基本原理介绍 在EdgeMesh v1.12版本中,社区将edgemesh-server的能力合并到了edgemesh-agent的EdgeTunnel模块当中,使得具备中继能力的edgemesh-agent能够自动成为中继服务器,为其他节点提供内网穿透和中继转发的功能,新老系统架构对比如下: EdgeMesh高可用特性的主要实现原理是:当集群内有节点具备中继能力时,其上的edgemesh-agent会承担起中继节点的角色,来为其他节点提供内网穿透和流量中继转发的服务。在集群初始化或者是有节点新加入集群时,EdgeMesh系统会基于mDNS机制发现局域网内的节点并作记录,同时DHT机制会发现跨局域网的其他节点并对其发起连接建立请求,这样当集群内跨局域网的两节点需要连接的时候,中继节点就可以为它们提供流量中继和协助内网穿透的服务。 EdgeMesh高可用特性的核心功能如上图所示,集群当中A节点与B节点通过R1中继节点连接来提供服务,当R1节点无法提供中继服务的时候,A、B节点可以通过高可用特性自动切换到中继节点R2并重新建立连接。在这个过程当中用户几乎感受不到网络连接的变化。接下来我将简单介绍不同情况下使用EdgeMesh高可用特性的方式。 ▍2.2 部署时启用高可用特性 您可以通过以下配置方法,在安装EdgeMesh时启用高可用特性,配置过程当中您可以依据集群连接的需求配置中继节点的地址: # 启用高可用特性 helm install edgemesh --namespace kubeedge \ --set agent.relayNodes[0].nodeName=k8s-master,agent.relayNodes[0].advertiseAddress="{1.1.1.1}" \ https://raw.githubusercontent.com/kubeedge/edgemesh/main/build/helm/edgemesh.tgz relayNodes 参数是中继节点表,类型为 []relayNode,您可以通过配置它来指定集群中应该承担中继节点角色的edgemesh-agent。 relayNode.nodeName 参数使用节点名的方式来指定relay节点,这必须与K8s的节点名相同,您可以通过 kubectl get nodes 查看您的k8s节点名。 relayNode.advertiseAddress 参数用于指定relay节点的地址,其应当与节点在K8s集群当中的节点地址一致, 如果您购买了公有云的公网IP并挂载到此relay节点上,则 relayNode.advertiseAddress 参数最好应该填写该公网IP地址。 需要注意的是:设置中继节点的数量由relayNodes[num] 中索引值 num 来规定,num 取值从 0 开始,relayNodes[0] 表示中继节点1。 更多的安装配置信息请详见: helm安装: https://edgemesh.netlify.app/zh/guide/#helm-安装 手动安装: https://edgemesh.netlify.app/zh/guide/ ▍2.3 运行时添加新中继节点 如果您在使用EdgeMesh高可用特性时,想要在集群当中添加新的中继节点,可以通过修改 edgemesh-agent-cfg 当中的 relayNodes 参数来达到目的,以下为具体修改配置的方式: kubectl -n kubeedge edit configmap edgemesh-agent-cfg # 进入config 文件当中进行编辑 apiVersion: v1 data: edgemesh-agent.yaml: |- modules: edgeProxy: enable: true edgeTunnel: enable: true # 设置添加或者是修改为新的中继节点 relayNodes: - nodeName: R1 advertiseAddress: - 1.1.1.1 - nodeName: R2 <------ 在此配置新增节点 advertiseAddress: - 192.168.5.103 之后您可以使用 kubeadm join 或者 keadm join 添加加新的中继节点R2,接着通过以下操作查看添加的中继节点是否正常运行: # 查看节点是否正常添加 kubectl get nodes NAME STATUS ROLES AGE VERSION k8s-master Ready control-plane,master 249d v1.21.8 k8s-node1 Ready <none> 249d v1.21.8 ke-edge1 Ready agent,edge 234d v1.19.3-kubeedge-v1.8.2 ke-edge2 Ready agent,edge 5d v1.19.3-kubeedge-v1.8.2 R2 Ready agent,edge 1d v1.19.3-kubeedge-v1.8.2 <------ 新节点 # 查看中继节点的 edgemesh-agent 是否正常运行 kubectl get all -n kubeedge -o wide NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES pod/edgemesh-agent-59fzk 1/1 Running 0 10h 192.168.5.187 ke-edge1 <none> <none> pod/edgemesh-agent-hfsmz 1/1 Running 1 10h 192.168.0.229 k8s-master <none> <none> pod/edgemesh-agent-tvhks 1/1 Running 0 10h 192.168.0.71 k8s-node1 <none> <none> pod/edgemesh-agent-tzntc 1/1 Running 0 10h 192.168.5.121 ke-edge2 <none> <none> pod/edgemesh-agent-kasju 1/1 Running 0 10h 192.168.5.103 R2 <none> <none> <------ new edgemesh-agent running on R2 ▍2.4 运行时转化节点成中继 如果您在集群运行过程当中,想要将一些已有节点转化为中继节点,只需要修改 edgemesh-agent-cfg 当中的 relayNodes 参数即可, 以下为具体修改配置的方式:修改完此配置后,需要重启R2节点(转化节点)上的edgemesh-agent。在这个过程当中,假设新设置的节点有中继能力,那么在重新Tunnel模块运行时会执行以下逻辑: edgemesh-agent会读取configmap里的中继节点表relayNodes,检查自己是否被用户设置为中继节点。如果在relayNodes中读取到R2存在,则表明R2被设置为默认初始的中继节点。 R2节点上的edgemesh-agent会尝试成为relay ,启动对应的中继功能。 如果发现该节点没有中继能力(一般挂载了公网IP的节点会具备中继能力),那么该节点还是不能承担起中继节点的角色,造成这个结果的原因可能是该节点的advertiseAddress并不能让所有节点访问。 以上就是EdgeMesh高可用架构的原理以及应用场景的介绍了,此次课题结项完成了开源之夏的所有产出要求,也同时作为KubeEdge v1.12新版本的一个重要特性发布,非常高兴能够为开源社区及KubeEdge的开发和完善做出贡献。于我个人而言,当初是在测试5G边缘架构时认识到了KubeEdge, 并为其设计以及功能设想所折服,这与我理想的边缘网络智能架构有诸多的相似之处,也成为我参与开源之夏的契机。在项目开发当中,从功能设计、实现方案到代码编写,各类问题层出不穷,主要是校内知识和研发方式与开源社区及工业环境脱节导致的问题,不过这些困难都在老师社区的帮助和自身努力之下逐一解决了,也是在这个过程当中领我体会到了开源工作中各社区之间相互借鉴推进,各个开发者之间相互帮助交流的强大,也更加理解到优秀的社区环境以及高效的社区例会机制能够快速同步各处开发进度,修正不合理的开发方向和想法,集思广益的同时步步为营,这样让我更加向往社区的工作了。 就EdgeMesh发展设想而言,此次开发已经实现了当初设想的目的,但在参与社区例会,了解整个开源项目的发展之中,许多的想法和创新也随之涌现,是否能够引入ebpf、Webassembly等新兴技术来优化甚至是革新EdgeMesh提供的网络服务;是否可以将人工智能引入到边缘集群的管理和自治当中,让人工智能作为基础建设的一部分,这些设想都让人热血沸腾,忍不住想要参与到社区的开发和研究当中。就我个人而言,未来也会更多地参与到社区的开发和研究当中,一方面我原本所期盼的将科研成果转化为产业价值的目标,已通过开源之夏初见眉目;另一方面,诸多的设想和创新还未能够与大家交流,还未能够得到实践和测试;这些都不断鼓励着我更加深入到社区项目的研发当中。最后非常感谢王杰章老师的悉心教导,可以说老师的耐心沟通和鼓励指导是项目能够成功推进的重要动力;同时还要感谢开源之夏能够给予我们机会参与到实际的开发当中,走出了高校学术的楼阁,尽管此次开源之夏已经结束,但我们的开源之旅却正要开始。 附:KubeEdge社区贡献和技术交流地址 网站:https://kubeedge.io Github地址: https://github.com/kubeedge/kubeedge Slack地址: https://kubeedge.slack.com 邮件列表:https://groups.google.com/forum/#!forum/kubeedge 每周社区例会: https://zoom.us/j/4167237304 Twitter: https://twitter.com/KubeEdge 文档地址: https://docs.kubeedge.io/en/latest/ 点击关注,第一时间了解华为云新鲜技术~

资源下载

更多资源
Mario

Mario

马里奥是站在游戏界顶峰的超人气多面角色。马里奥靠吃蘑菇成长,特征是大鼻子、头戴帽子、身穿背带裤,还留着胡子。与他的双胞胎兄弟路易基一起,长年担任任天堂的招牌角色。

腾讯云软件源

腾讯云软件源

为解决软件依赖安装时官方源访问速度慢的问题,腾讯云为一些软件搭建了缓存服务。您可以通过使用腾讯云软件源站来提升依赖包的安装速度。为了方便用户自由搭建服务架构,目前腾讯云软件源站支持公网访问和内网访问。

Nacos

Nacos

Nacos /nɑ:kəʊs/ 是 Dynamic Naming and Configuration Service 的首字母简称,一个易于构建 AI Agent 应用的动态服务发现、配置管理和AI智能体管理平台。Nacos 致力于帮助您发现、配置和管理微服务及AI智能体应用。Nacos 提供了一组简单易用的特性集,帮助您快速实现动态服务发现、服务配置、服务元数据、流量管理。Nacos 帮助您更敏捷和容易地构建、交付和管理微服务平台。

Rocky Linux

Rocky Linux

Rocky Linux(中文名:洛基)是由Gregory Kurtzer于2020年12月发起的企业级Linux发行版,作为CentOS稳定版停止维护后与RHEL(Red Hat Enterprise Linux)完全兼容的开源替代方案,由社区拥有并管理,支持x86_64、aarch64等架构。其通过重新编译RHEL源代码提供长期稳定性,采用模块化包装和SELinux安全架构,默认包含GNOME桌面环境及XFS文件系统,支持十年生命周期更新。

用户登录
用户注册