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的蛋白质与小分子配体相互作用模拟教程
在生命科学的广阔领域中,蛋白质与小分子配体之间的相互作用扮演着至关重要的角色。这些相互作用不仅影响着生物体内的各种生命活动,如信号传导、代谢调控和药物作用等,同时也是药物设计和开发的核心内容。因此,深入理解并模拟这些…...
Linux 文件类型,目录与路径,文件与目录管理
文件类型 后面的字符表示文件类型标志 普通文件:-(纯文本文件,二进制文件,数据格式文件) 如文本文件、图片、程序文件等。 目录文件:d(directory) 用来存放其他文件或子目录。 设备…...
(十)学生端搭建
本次旨在将之前的已完成的部分功能进行拼装到学生端,同时完善学生端的构建。本次工作主要包括: 1.学生端整体界面布局 2.模拟考场与部分个人画像流程的串联 3.整体学生端逻辑 一、学生端 在主界面可以选择自己的用户角色 选择学生则进入学生登录界面…...
Golang 面试经典题:map 的 key 可以是什么类型?哪些不可以?
Golang 面试经典题:map 的 key 可以是什么类型?哪些不可以? 在 Golang 的面试中,map 类型的使用是一个常见的考点,其中对 key 类型的合法性 是一道常被提及的基础却很容易被忽视的问题。本文将带你深入理解 Golang 中…...
3.3.1_1 检错编码(奇偶校验码)
从这节课开始,我们会探讨数据链路层的差错控制功能,差错控制功能的主要目标是要发现并且解决一个帧内部的位错误,我们需要使用特殊的编码技术去发现帧内部的位错误,当我们发现位错误之后,通常来说有两种解决方案。第一…...
高等数学(下)题型笔记(八)空间解析几何与向量代数
目录 0 前言 1 向量的点乘 1.1 基本公式 1.2 例题 2 向量的叉乘 2.1 基础知识 2.2 例题 3 空间平面方程 3.1 基础知识 3.2 例题 4 空间直线方程 4.1 基础知识 4.2 例题 5 旋转曲面及其方程 5.1 基础知识 5.2 例题 6 空间曲面的法线与切平面 6.1 基础知识 6.2…...
Springcloud:Eureka 高可用集群搭建实战(服务注册与发现的底层原理与避坑指南)
引言:为什么 Eureka 依然是存量系统的核心? 尽管 Nacos 等新注册中心崛起,但金融、电力等保守行业仍有大量系统运行在 Eureka 上。理解其高可用设计与自我保护机制,是保障分布式系统稳定的必修课。本文将手把手带你搭建生产级 Eur…...
相机Camera日志分析之三十一:高通Camx HAL十种流程基础分析关键字汇总(后续持续更新中)
【关注我,后续持续新增专题博文,谢谢!!!】 上一篇我们讲了:有对最普通的场景进行各个日志注释讲解,但相机场景太多,日志差异也巨大。后面将展示各种场景下的日志。 通过notepad++打开场景下的日志,通过下列分类关键字搜索,即可清晰的分析不同场景的相机运行流程差异…...
c#开发AI模型对话
AI模型 前面已经介绍了一般AI模型本地部署,直接调用现成的模型数据。这里主要讲述讲接口集成到我们自己的程序中使用方式。 微软提供了ML.NET来开发和使用AI模型,但是目前国内可能使用不多,至少实践例子很少看见。开发训练模型就不介绍了&am…...
高效线程安全的单例模式:Python 中的懒加载与自定义初始化参数
高效线程安全的单例模式:Python 中的懒加载与自定义初始化参数 在软件开发中,单例模式(Singleton Pattern)是一种常见的设计模式,确保一个类仅有一个实例,并提供一个全局访问点。在多线程环境下,实现单例模式时需要注意线程安全问题,以防止多个线程同时创建实例,导致…...
4. TypeScript 类型推断与类型组合
一、类型推断 (一) 什么是类型推断 TypeScript 的类型推断会根据变量、函数返回值、对象和数组的赋值和使用方式,自动确定它们的类型。 这一特性减少了显式类型注解的需要,在保持类型安全的同时简化了代码。通过分析上下文和初始值,TypeSc…...
