Apache DolphinScheduler 从 1.3.4 升级至3.1.2 过程中的问题记录及解决方案

点击蓝字 关注我们

58d54fdcda26aee294b86ba777ae010e.jpeg

作者 | 刘宇星,开源爱好者

摘要

Apache DolphinScheduler官方的升级文档提供了升级脚本,如果只是跨小版本的更新,那么只用执行脚本就好了,但跨多个大版本升级时依然容易出现各种问题,特此总结。

旧版本:1.3.4

新版本:3.1.2

从1.3.4升级至3.1.2版本问题列表:

  1. 升级完成后使用资源中心报错 IllegalArgumentException: Failed to specify server's Kerberos principal name

  2. 升级完成后查看任务实例的日志,报错未找到日志

  3. 升级完成后创建工作流报错

  4. 升级后任务实例列表为空

  5. 执行升级脚本的过程中报错空指针

    1. 分析日志,定位到 UpgradeDao.java 517行

    2. 分析日志,定位到 UpgradeDao.java 675行

  6. 接入LDAP后登陆失败,不知道email字段名

  7. 管理员给普通用户授权资源文件不生效

  8. kerberos过期的问题

1、升级完成后使用资源中心报错 IllegalArgumentException: Failed to specify server's Kerberos principal name

DS

资源中心使用的HDFS,开启了kerberos认证

解决方法:

编辑 dolphinscheduler/api-server/conf/hdfs-site.xml 添加以下内容

<property>
    <name>dfs.namenode.kerberos.principal.patternname>
    <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_name
        from 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_version
        left join t_ds_process_instance process on process.id=instance.process_instance_id
        where define.project_code = #{projectCode}
        <if test="startTime != null">
            and instance.start_time =]]> #{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_name
        from 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_version
        join t_ds_process_instance process
         on process.id=instance.process_instance_id
        join t_ds_process_definition define
         on define.code=process.process_definition_code
        where define.project_code = #{projectCode}
        <if test="startTime != null">
            and instance.start_time =]]> #{startTime}
        if>
  ......省略多余部分

直接用 t_ds_process_definition 关联,也有project_code字段可以用来关联过滤这里修改后就能查出数据了

5、执行升级脚本的过程中报错空指针

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);
    }
}

5.2

分析日志,定位到 UpgradeDao.java 675行

查看代码

669 if (mapEntry.isPresent()) {
670                            Map.Entry<long, map> 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 effective
    ldap:
      # ldap server config
      urls: xxx
      base-dn: xxx
      username: xxx
      password: xxx
      user:
        # admin userId when you use LDAP login
        admin: xxx
        identity-attribute: xxx
        email-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 results = ctx.search(ldapBaseDn, filter.toString(), sc);
if (results.hasMore()) {
    // get the users DN (distinguishedName) from the result
    SearchResult result = results.next();
    NamingEnumeration attrs = result.getAttributes().getAll();
    while (attrs.hasMore()) {
        // Open another connection to the LDAP server with the found DN and the password
        searchEnv.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 attrs = result.getAttributes().getAll();

通过打印或调试在里面找到email字段填到配置文件里,再还原上面注释的代码,重启服务后即可正常接入LDAP登录。

7、管理员给普通用户授权资源文件不生效

经多次测试,发现普通用户只能看到所属用户为自己的资源文件,管理员授权后依然无法查看资源文件

解决办法:

文件 dolphinscheduler-api/src/main/java/org/apache/dolphinscheduler/api/permission/ResourcePermissionCheckServiceImpl.java的listAuthorizedResource()方法,将 return 的集合修改为 relationResources。

@Override
        public Set listAuthorizedResource(int userId, Logger logger) {
            List relationResources;
            if (userId == 0) {
                relationResources = new ArrayList<>();
            } else {
                // query resource relation
                List resIds = resourceUserMapper.queryResourcesIdListByUserIdAndPerm(userId, 0);
                relationResources = CollectionUtils.isEmpty(resIds) ? new ArrayList<>() : resourceMapper.queryResourceListById(resIds);
            }
            List 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版本修复了这个bughttps://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 社区迎来蓬勃发展,为了做更好用、易用的调度,真诚欢迎热爱开源的伙伴加入到开源社区中来,为中国开源崛起献上一份自己的力量,让本土开源走向全球。

6725a6a8537090e1444394eaf0276347.png

参与 DolphinScheduler 社区有非常多的参与贡献的方式,包括:

702ce1c54b24923208f7f531d8cd5ce4.png

贡献第一个PR(文档、代码) 我们也希望是简单的,第一个PR用于熟悉提交的流程和社区协作以及感受社区的友好度。

社区汇总了以下适合新手的问题列表:https://github.com/apache/dolphinscheduler/issues/5689

非新手问题列表:https://github.com/apache/dolphinscheduler/issues?q=is%3Aopen+is%3Aissue+label%3A%22volunteer+wanted%22

如何参与贡献链接:https://dolphinscheduler.apache.org/zh-cn/community/development/contribute.html

来吧,DolphinScheduler开源社区需要您的参与,为中国开源崛起添砖加瓦吧,哪怕只是小小的一块瓦,汇聚起来的力量也是巨大的。

参与开源可以近距离与各路高手切磋,迅速提升自己的技能,如果您想参与贡献,我们有个贡献者种子孵化群,可以添加社区小助手微信(Leonard-ds) ,手把手教会您( 贡献者不分水平高低,有问必答,关键是有一颗愿意贡献的心 )。

f9ae6b43d4a8177c8ea35b4001824abc.jpeg

添加社区小助手微信(Leonard-ds) 

添加小助手微信时请说明想参与贡献。

来吧,开源社区非常期待您的参与。

< 🐬🐬 >

更多精彩推荐

社区最早一批贡献者为什么还在坚持活跃?

☞优秀用户案例有奖征集 | 活动火热开启,快来投稿!

Apache DolphinScheduler 社区成功举办“小型”网友见面会,共同探讨大数据工作流引擎的发展与创新

☞DolphinScheduler×长安汽车 | 千万级数据接入能力智能网联汽车云平台引进核心调度系统

☞去年办了这么多场Meetup都没有你,2023年赶紧安排起来!

☞DolphinScheduler UI 项目启动提速 2 倍,原来是使用了 Vite!

DolphinScheduler×思科网讯:k8S整合实践,提高大数据处理效率!

我知道你在看52887ab5d79f7f453a472949596b7531.png

  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
DolphinScheduler 是一款分布式调度系统,线程数的调优对于系统的性能和稳定性非常重要。以下是一些可能有用的线程数调优建议: 1. 调整线程池大小:在 DolphinScheduler 的配置文件,可以设置各种线程池的大小。例如,可以通过更改 `executor.threads.max` 参数来增加执行器线程池的大小,从而提高任务执行的并发度。如果系统有大量的任务需要执行,那么可以适当增加线程池大小。但是,过多的线程池大小也会导致资源消耗过高,因此需要根据实际情况进行调整。 2. 调整 JVM 参数:JVM 参数的设置也会影响线程数的使用。例如,可以通过设置 `-XX:ParallelGCThreads` 参数来调整垃圾回收线程的数量,从而提高系统的垃圾回收效率。但是,需要注意的是,过多的线程数量会导致系统的 CPU 和内存消耗过高,因此需要根据实际情况进行调整。 3. 调整操作系统参数:操作系统也会影响线程数的使用。例如,可以通过设置 `ulimit` 参数来限制系统的进程数量,从而避免系统过多的线程数导致的性能问题。但是,需要注意的是,过多的限制会导致系统的并发度降低,因此需要根据实际情况进行调整。 4. 优化代码:系统代码的优化也会影响线程数的使用。例如,可以通过避免锁竞争、减少 I/O 操作等方式来提高系统的并发度和性能。但是,需要注意的是,代码的优化也需要根据实际情况进行调整,不可一概而论。 总之,线程数的调优需要根据实际情况进行调整,需要考虑系统的性能和稳定性。以上建议只是一些可能有用的方法,具体情况需要根据实际情况进行调整。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

DolphinScheduler社区

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值