Apache DolphinScheduler 1.3.4升级至3.1.2版本过程中的踩坑记录
因为在工作中需要推动Apache DolphinScheduler的升级,经过预研,从1.3.4到3.1.2有的体验了很大的提升,在性能和功能性有了很多的改善,推荐升级。
查看官方的升级文档,可知有提供升级脚本,如果只是跨小版本的更新那么只用执行脚本就好了,但跨多个大版本升级时依然容易出现各种问题,特此总结。
旧版本:1.3.4
新版本:3.1.2
问题合集
1.资源中心报错
升级完成后使用资源中心报错 IllegalArgumentException: Failed to specify server's Kerberos principal name
资源中心使用的HDFS,开启了kerberos认证
解决方法:
编辑 dolphinscheduler/api-server/conf/hdfs-site.xml添加以下内容
<property><name>dfs.namenode.kerberos.principal.pattern</name><value>*</value>
</property>
2.任务实例日志丢失
升级完成后查看任务实例的日志,报错未找到日志,查看报错信息,检查新版本的目录结构和表里的日志路径,发现原因是新版本的日志路径有变更。
升级前的日志路径在 /logs/ 下。
升级后的日志路径在 /worker-server/logs/ 下。
因此需要修改这里的目录
解决方法: 执行SQL修改日志路径
update t_ds_task_instance set log_path=replace(log_path,'/logs/','/worker-server/logs/');
然后将原日志文件copy到新的日志路径
cp -r {旧版本dolphinscheduler目录}/logs/[1-9]* {新版本dolphinscheduler目录}/worker-server/logs/*
3.升级完创建工作流报错
查看报错信息,原因是 t_ds_process_definition_log 和 t_ds_process_definition 主键的初始值不一致,那么修改成一致的就好了!
解决方法: 执行SQL
# 查出主键自增值
select AUTO_INCREMENT FROM information_schema.TABLES WHERE TABLE_SCHEMA = 'dolphinscheduler' AND TABLE_NAME = 't_ds_process_definition' limit 1
# 将上面SQL的执行结果填写到下方参数处执行
alter table dolphinscheduler_bak1.t_ds_process_definition_log auto_increment = {max_id};
4.升级后任务实例列表为空
检查查询的SQL
在 dolphinscheduler-dao/src/main/resources/org/apache/dolphinscheduler/dao/mapper/TaskInstanceMapper.xml 文件里,select id="queryTaskInstanceListPaging"的SQL
select<include refid="baseSqlV2"><property name="alias" value="instance"/></include>,process.name as process_instance_namefrom t_ds_task_instance instanceleft join t_ds_task_definition_log define on define.code=instance.task_code and define.version=instance.task_definition_versionleft join t_ds_process_instance process on process.id=instance.process_instance_idwhere define.project_code = #{projectCode}<if test="startTime != null">and instance.start_time <![CDATA[ >=]]> #{startTime}</if>......省略多余部分
查询任务实例列表的SQL会关联 t_ds_task_definition_log 表,经检查发现是 define.code=instance.task_code 这一句关联不上。
结合下面的查询条件 define.project_code = #{projectCode} 可知,关联 t_ds_task_definition_log 主要是为了过滤 projectCode,那么来修改下这个SQL:
解决方法:
select<include refid="baseSqlV2"><property name="alias" value="instance"/></include>,process.name as process_instance_namefrom t_ds_task_instance instance
-- left join t_ds_task_definition_log define
-- on define.code=instance.task_code and
-- define.version=instance.task_definition_versionjoin t_ds_process_instance processon process.id=instance.process_instance_idjoin t_ds_process_definition defineon define.code=process.process_definition_codewhere define.project_code = #{projectCode}<if test="startTime != null">and instance.start_time <![CDATA[ >=]]> #{startTime}</if>......省略多余部分
直接用 t_ds_process_definition 关联,也有 project_code 字段可以用来关联过滤,这里修改后就能查出数据了。
5.执行升级脚本的过程中报空指针
(1)分析日志,定位到 UpgradeDao.java 517行
查看代码
513 if (TASK_TYPE_SUB_PROCESS.equals(taskType)) {
514 JsonNode jsonNodeDefinitionId = param.get("processDefinitionId");
515 if (jsonNodeDefinitionId != null) {
516 param.put("processDefinitionCode",
517 processDefinitionMap.get(jsonNodeDefinitionId.asInt()).getCode());
518 param.remove("processDefinitionId");
519 }
520 }
很明显是 processDefinitionMap.get(jsonNodeDefinitionId.asInt()) 返回了null,加个null判断,如果返回null直接跳过,并将相关信息打印出来,升级结束后可以根据日志核对。
解决方法:
修改后:
if (jsonNodeDefinitionId != null) {if (processDefinitionMap.get(jsonNodeDefinitionId.asInt()) != null) {param.put("processDefinitionCode",processDefinitionMap.get(jsonNodeDefinitionId.asInt()).getCode());param.remove("processDefinitionId");} else {logger.error("*******************error");logger.error("*******************param:" + param);logger.error("*******************jsonNodeDefinitionId:" + jsonNodeDefinitionId);}
}
(2)分析日志,定位到 UpgradeDao.java 675行
查看代码
669 if (mapEntry.isPresent()) {
670 Map.Entry<Long, Map<String, Long>> processCodeTaskNameCodeEntry = mapEntry.get();
671 dependItem.put("definitionCode", processCodeTaskNameCodeEntry.getKey());
672 String depTasks = dependItem.get("depTasks").asText();
673 long taskCode =
674 "ALL".equals(depTasks) || processCodeTaskNameCodeEntry.getValue() == null ? 0L
675 : processCodeTaskNameCodeEntry.getValue().get(depTasks);
676 dependItem.put("depTaskCode", taskCode);
677 }
很明显是 processCodeTaskNameCodeEntry.getValue().get(depTasks) 返回了null,修改下逻辑,不为null才赋值并打印相关日志。
解决方法:
修改后:
long taskCode =0;if (processCodeTaskNameCodeEntry.getValue() != null&&processCodeTaskNameCodeEntry.getValue().get(depTasks)!=null){taskCode =processCodeTaskNameCodeEntry.getValue().get(depTasks);}else{logger.error("******************** depTasks:"+depTasks);logger.error("******************** taskCode not in "+JSONUtils.toJsonString(processCodeTaskNameCodeEntry));}dependItem.put("depTaskCode", taskCode);
6.接入LDAP后登陆失败,不知道Email字段名
可在 api-server/conf/application.yaml 配置接入LDAP
security:authentication:# Authentication types (supported types: PASSWORD,LDAP)type: LDAP# IF you set type `LDAP`, below config will be effectiveldap:# ldap server configurls: xxxbase-dn: xxxusername: xxxpassword: xxxuser:# admin userId when you use LDAP loginadmin: xxxidentity-attribute: xxxemail-attribute: xxx# action when ldap user is not exist (supported types: CREATE,DENY)not-exist-action: CREATE
要成功接入LDAP至少需要urls,base-dn,username,password,identity和email正确填写,不知道email字段名可以按下面的方式处理,email先空着
启动服务后用LDAP用户登录
解决办法: LDAP 认证的代码在 dolphinscheduler-api/src/main/java/org/apache/dolphinscheduler/api/security/impl/ldap/LdapService.java 的 ldapLogin()
ctx = new InitialLdapContext(searchEnv, null);
SearchControls sc = new SearchControls();
sc.setReturningAttributes(new String[]{ldapEmailAttribute});
sc.setSearchScope(SearchControls.SUBTREE_SCOPE);
EqualsFilter filter = new EqualsFilter(ldapUserIdentifyingAttribute, userId);
NamingEnumeration<SearchResult> results = ctx.search(ldapBaseDn, filter.toString(), sc);
if (results.hasMore()) {// get the users DN (distinguishedName) from the resultSearchResult result = results.next();NamingEnumeration<? extends Attribute> attrs = result.getAttributes().getAll();while (attrs.hasMore()) {// Open another connection to the LDAP server with the found DN and the passwordsearchEnv.put(Context.SECURITY_PRINCIPAL, result.getNameInNamespace());searchEnv.put(Context.SECURITY_CREDENTIALS, userPwd);try {new InitialDirContext(searchEnv);} catch (Exception e) {logger.warn("invalid ldap credentials or ldap search error", e);return null;}Attribute attr = attrs.next();if (attr.getID().equals(ldapEmailAttribute)) {return (String) attr.get();}}
}
第三行会根据填的字段过滤,先注释第三行
// sc.setReturningAttributes(new String[]{ldapEmailAttribute});
重新执行后第10行会返回全部字段
NamingEnumeration<? extends Attribute> attrs = result.getAttributes().getAll();
通过打印或调试在里面找到email字段填到配置文件里,再还原上面注释的代码,重启服务后即可正常接入LDAP登录。
7.管理员给普通用户授权资源文件不生效
经多次测试,发现普通用户只能看到所属用户为自己的资源文件,管理员授权后依然无法查看资源文件
解决办法:
文件 dolphinscheduler-api/src/main/java/org/apache/dolphinscheduler/api/permission/ResourcePermissionCheckServiceImpl.java 的 listAuthorizedResource() 方法,将 return 的集合修改为 relationResources
@Overridepublic Set<Integer> listAuthorizedResource(int userId, Logger logger) {List<Resource> relationResources;if (userId == 0) {relationResources = new ArrayList<>();} else {// query resource relationList<Integer> resIds = resourceUserMapper.queryResourcesIdListByUserIdAndPerm(userId, 0);relationResources = CollectionUtils.isEmpty(resIds) ? new ArrayList<>() : resourceMapper.queryResourceListById(resIds);}List<Resource> ownResourceList = resourceMapper.queryResourceListAuthored(userId, -1);relationResources.addAll(ownResourceList);return relationResources.stream().map(Resource::getId).collect(toSet()); // 解决资源文件授权无效的问题
// return ownResourceList.stream().map(Resource::getId).collect(toSet());}
检查新版本的 Change log ,发现在3.1.3版本修复了这个bug
https://github.com/apache/dolphinscheduler/pull/13318
8.kerberos过期的问题
因为kerberos配置了票据过期时间,一段时间后资源中心的hdfs资源将无法访问,最好的解决办法是添加定时更新凭证的相关逻辑。
解决办法:
在文件 dolphinscheduler-service/src/main/java/org/apache/dolphinscheduler/service/utils/CommonUtils.java 添加方法
/*** * 定时更新凭证*/private static void startCheckKeytabTgtAndReloginJob() {// 每天循环,定时更新凭证Executors.newScheduledThreadPool(1).scheduleWithFixedDelay(() -> {try {UserGroupInformation.getLoginUser().checkTGTAndReloginFromKeytab();logger.warn("Check Kerberos Tgt And Relogin From Keytab Finish.");} catch (IOException e) {logger.error("Check Kerberos Tgt And Relogin From Keytab Error", e);}}, 0, 1, TimeUnit.DAYS);logger.info("Start Check Keytab TGT And Relogin Job Success.");}
然后在该文件的 loadKerberosConf 方法返回 true 前调用:
public static boolean loadKerberosConf(String javaSecurityKrb5Conf, String loginUserKeytabUsername,String loginUserKeytabPath, Configuration configuration) throws IOException {if (CommonUtils.getKerberosStartupState()) {System.setProperty(Constants.JAVA_SECURITY_KRB5_CONF, StringUtils.defaultIfBlank(javaSecurityKrb5Conf,PropertyUtils.getString(Constants.JAVA_SECURITY_KRB5_CONF_PATH)));configuration.set(Constants.HADOOP_SECURITY_AUTHENTICATION, Constants.KERBEROS);UserGroupInformation.setConfiguration(configuration);UserGroupInformation.loginUserFromKeytab(StringUtils.defaultIfBlank(loginUserKeytabUsername,PropertyUtils.getString(Constants.LOGIN_USER_KEY_TAB_USERNAME)),StringUtils.defaultIfBlank(loginUserKeytabPath,PropertyUtils.getString(Constants.LOGIN_USER_KEY_TAB_PATH)));startCheckKeytabTgtAndReloginJob(); // 此处调用return true;}return false;}
这篇文章主要是记录升级过程中遇到的问题,希望能够对大家有所帮助!
本文由 白鲸开源科技 提供发布支持!
相关文章:
Apache DolphinScheduler 1.3.4升级至3.1.2版本过程中的踩坑记录
因为在工作中需要推动Apache DolphinScheduler的升级,经过预研,从1.3.4到3.1.2有的体验了很大的提升,在性能和功能性有了很多的改善,推荐升级。 查看官方的升级文档,可知有提供升级脚本,如果只是跨小版本的…...
最后一块石头的重量(超级妙的背包问题)
1049. 最后一块石头的重量 II 有一堆石头,用整数数组 stones 表示。其中 stones[i] 表示第 i 块石头的重量。 每一回合,从中选出任意两块石头,然后将它们一起粉碎。假设石头的重量分别为 x 和 y,且 x < y。那么粉碎的可能结果…...
如何评估和提升审查者在前端代码审查中的专业技能?
评估和提升审查者在前端代码审查中的专业技能可以通过以下步骤: 技能评估: 定期进行技能评估,了解审查者在前端开发各方面的能力,包括但不限于HTML、CSS、JavaScript、框架使用、代码规范等。 代码审查实践: 通过实…...
C++(区别于C的)基础内容总结
参考: C 教程 | 菜鸟教程 (runoob.com) 简介 C 被认为是一种中级语言,它综合了高级语言和低级语言的特点。 C 是由 Bjarne Stroustrup 于 1979 年在新泽西州美利山贝尔实验室开始设计开发的。C 进一步扩充和完善了 C 语言,最初命名为带类的C&…...
实现代码灵活性:用Roslyn动态编译和执行存储在数据库中的C#代码
在许多现代应用程序中,动态编译和执行代码是提升灵活性和功能的一种强大技术。本文将介绍如何使用Roslyn编译器平台动态编译和执行存储在数据库中的C#代码,并结合实际公司案例来说明这些技术的应用场景。 1. 引言 在很多应用场景中,我们可能…...
探索哈希表:C++中的实现与操作详解【Map、Set、数据结构】
探索哈希表:C中的实现与操作详解 介绍 哈希表(Hash Table)是一种常见的数据结构,它提供了一种高效的键值对存储方式,能够快速进行插入、删除和查找操作。在这篇博客中,我们将详细介绍哈希表的概念、在C中的…...
Python酷库之旅-第三方库Pandas(062)
目录 一、用法精讲 241、pandas.Series.view方法 241-1、语法 241-2、参数 241-3、功能 241-4、返回值 241-5、说明 241-6、用法 241-6-1、数据准备 241-6-2、代码示例 241-6-3、结果输出 242、pandas.Series.compare方法 242-1、语法 242-2、参数 242-3、功能 …...
python学习之旅(基础篇看这篇足够了!!!)
目录 前言 1.输入输出 1.1 输入 1.2 输出 2. 变量与常量 2.1 变量 2.2 常量 2.3 赋值 2.4格式化输出 3. 数据类型 4. 四则运算 5.“真与假” 5.1 布尔数 5.2 比较运算和逻辑运算 5.3 布尔表达式 6.判断语句 6.1 基本的if语句 6.2 if-else语句 6.3 if-elif-el…...
Azure OpenAI Embeddings vs OpenAI Embeddings
题意:Azure OpenAI 嵌入与 OpenAI 嵌入的比较 问题背景: Is anyone getting different results from Azure OpenAI embeddings deployment using text-embedding-ada-002 than the ones from OpenAI? Same text, same model, and the results are cons…...
重生奇迹MU职业成长三步走
在重生奇迹MU游戏中,转职是最重要的玩法之一。每个职业在转职后都会发生巨大的变化,经过三次转职后,你才有资格成为该游戏中最强大的冒险者。 一转,一切才刚刚开始 玩家完成第一次转职任务后,标志着我们成功度过了游…...
2024年中国数据中台行业研究报告
数据中台丨研究报告 核心摘要: 数据中台是企业数字化建设的重要构成,其通过整合企业基础设施和数据能力,实现数据资产化和服务复用,降低运营成本,支撑业务创新。受宏观经济影响,部分企业减少了对数据中台等…...
MySQL——数据表的基本操作(一)创建数据表
数据库创建成功后,就需要创建数据表。所谓创建数据表指的是在已存在的数据库中建立新表。需要注意的是,在操作数据表之前,应该使用 “ USE 数据库名 ” 指定操作是在哪个数据库中进行,否则会抛出 “ No database selected ” 错误。创建数据表…...
EPLAN EDZ 文件太大导入很慢如何解决?
目前各个品牌都在提供 EPLAN EDZ部件库文件,但是一般都是一个总的EDZ文件,导入过程中,因为电脑配置和其他问题,导致导入过程中EPLAN会崩溃或者长时间不动。 我们分析下EDZ文件的构成,这是个压缩文件,换了个壳而已。用压缩软件把edz打开,这里不是解压,直接右键,用解压…...
刷题——缺失的第一个正整数
缺失的第一个正整数_牛客题霸_牛客网 我选择了一个我比较能看懂的, int minNumberDisappeared(vector<int>& nums) {// write code heremap<int, int>hash;int n nums.size();//哈希表记录数组中出现的每个数字for(int i 0; i < n; i)hash[n…...
代理设置--一些库的代理设置
首先最好能获取一个免费代理,来继续下面的阅读和实验 也可以在本机设置代理,具体流程由于比较敏感,请自行搜索 代理设置成功后的测试网站是 http://www.httpbin.org/get , 访问该链接可以得到请求相关的信息,返回结果中的 ori…...
Debezium系列之:PostgreSQL数据库赋予账号数据采集权限的详细步骤
Debezium系列之:PostgreSQL数据库赋予账号数据采集权限的详细步骤 一、账号需要的权限二、创建账号,赋予登陆、复制权限三、赋予账号数据库权限四、赋予账号对表的权限五、创建PostgreSQL数据库复制组六、账号权限授予完整案例七、扩展——分区表设置八、扩展-撤销账号的权限…...
javascript:判断输入值是数字还是字母
1 代码示例 要判断输入值是数字还是字母,我们可以通过JavaScript获取输入框的值,然后使用isNaN函数来检查输入值是否为数字。 <!DOCTYPE html> <html><head><meta charset"UTF-8"><title></title><s…...
Java-排序算法-复盘知识点
刷了24道简单排序题,18道中等排序题之后,给排序算法来个简单的复盘(从明天开始刷动态规划咯) 1.对于找多数元素(出现次数超过一半的元素)可以使用摩尔投票法。 2.HashSet的add方法非常实用:如…...
HarmonyOS 原生智能之语音识别实战
HarmonyOS 原生智能之语音识别实战 背景 公司很多业务场景使用到了语音识别功能,当时我们的语音团队自研了语音识别模型,方案是云端模型加端侧SDK交互,端侧负责做语音采集、VAD、opus编码,实时传输给云端,云端识别后…...
基于Gromacs的蛋白质与小分子配体相互作用模拟教程
在生命科学的广阔领域中,蛋白质与小分子配体之间的相互作用扮演着至关重要的角色。这些相互作用不仅影响着生物体内的各种生命活动,如信号传导、代谢调控和药物作用等,同时也是药物设计和开发的核心内容。因此,深入理解并模拟这些…...
在软件开发中正确使用MySQL日期时间类型的深度解析
在日常软件开发场景中,时间信息的存储是底层且核心的需求。从金融交易的精确记账时间、用户操作的行为日志,到供应链系统的物流节点时间戳,时间数据的准确性直接决定业务逻辑的可靠性。MySQL作为主流关系型数据库,其日期时间类型的…...
以下是对华为 HarmonyOS NETX 5属性动画(ArkTS)文档的结构化整理,通过层级标题、表格和代码块提升可读性:
一、属性动画概述NETX 作用:实现组件通用属性的渐变过渡效果,提升用户体验。支持属性:width、height、backgroundColor、opacity、scale、rotate、translate等。注意事项: 布局类属性(如宽高)变化时&#…...
ffmpeg(四):滤镜命令
FFmpeg 的滤镜命令是用于音视频处理中的强大工具,可以完成剪裁、缩放、加水印、调色、合成、旋转、模糊、叠加字幕等复杂的操作。其核心语法格式一般如下: ffmpeg -i input.mp4 -vf "滤镜参数" output.mp4或者带音频滤镜: ffmpeg…...
css的定位(position)详解:相对定位 绝对定位 固定定位
在 CSS 中,元素的定位通过 position 属性控制,共有 5 种定位模式:static(静态定位)、relative(相对定位)、absolute(绝对定位)、fixed(固定定位)和…...
微信小程序云开发平台MySQL的连接方式
注:微信小程序云开发平台指的是腾讯云开发 先给结论:微信小程序云开发平台的MySQL,无法通过获取数据库连接信息的方式进行连接,连接只能通过云开发的SDK连接,具体要参考官方文档: 为什么? 因为…...
Android15默认授权浮窗权限
我们经常有那种需求,客户需要定制的apk集成在ROM中,并且默认授予其【显示在其他应用的上层】权限,也就是我们常说的浮窗权限,那么我们就可以通过以下方法在wms、ams等系统服务的systemReady()方法中调用即可实现预置应用默认授权浮…...
【JavaSE】绘图与事件入门学习笔记
-Java绘图坐标体系 坐标体系-介绍 坐标原点位于左上角,以像素为单位。 在Java坐标系中,第一个是x坐标,表示当前位置为水平方向,距离坐标原点x个像素;第二个是y坐标,表示当前位置为垂直方向,距离坐标原点y个像素。 坐标体系-像素 …...
智能仓储的未来:自动化、AI与数据分析如何重塑物流中心
当仓库学会“思考”,物流的终极形态正在诞生 想象这样的场景: 凌晨3点,某物流中心灯火通明却空无一人。AGV机器人集群根据实时订单动态规划路径;AI视觉系统在0.1秒内扫描包裹信息;数字孪生平台正模拟次日峰值流量压力…...
视频行为标注工具BehaviLabel(源码+使用介绍+Windows.Exe版本)
前言: 最近在做行为检测相关的模型,用的是时空图卷积网络(STGCN),但原有kinetic-400数据集数据质量较低,需要进行细粒度的标注,同时粗略搜了下已有开源工具基本都集中于图像分割这块,…...
C++课设:简易日历程序(支持传统节假日 + 二十四节气 + 个人纪念日管理)
名人说:路漫漫其修远兮,吾将上下而求索。—— 屈原《离骚》 创作者:Code_流苏(CSDN)(一个喜欢古诗词和编程的Coder😊) 专栏介绍:《编程项目实战》 目录 一、为什么要开发一个日历程序?1. 深入理解时间算法2. 练习面向对象设计3. 学习数据结构应用二、核心算法深度解析…...
