Sprendimai, kaip atnaujinti „Apache DolphinScheduler“ iš 1.3.4 versijos į 3.1.2

1xYF9Q2MEDQRYXBY7nlDViaH7ED3-3h8367o.png


Kadangi reikia skatinti „Apache DolphinScheduler“ naujinimą darbe, mano atliktas preliminarus tyrimas rodo, kad nuo 1.3.4 iki 3.1.2 versijos gerokai patobulinti našumas ir funkcionalumas. Taigi, rekomenduojama atnaujinti.

Oficialioje naujinimo dokumentacijoje pateikiami naujinimo scenarijai. Atliekant nedidelių versijų naujinimus, pakanka paleisti scenarijų, tačiau atnaujinus kelias pagrindines versijas vis tiek gali kilti įvairių problemų. Toliau pateikiama šių problemų santrauka.

Sena versija: 1.3.4

Nauja versija: 3.1.2

Problemos kolekcija

  1. Išteklių centro klaida

Po naujovinimo naudojant išteklių centrą įvyksta klaida: IllegalArgumentException: Failed to specify server's Kerberos principal name.

Išteklių centras naudoja HDFS su įjungtu Kerberos autentifikavimu.

Sprendimas:

Redaguoti dolphinscheduler/api-server/conf/hdfs-site.xml ir pridėkite šį turinį:

<property>
    <name>dfs.namenode.kerberos.principal.pattern</name>
    <value>*</value>
</property>

2. Užduočių egzempliorių žurnalo praradimas

Po naujovinimo peržiūrint užduočių egzempliorių žurnalus atsiranda klaida, nurodanti, kad žurnalų nepavyko rasti. Patikrinus klaidos pranešimą ir naujos versijos katalogų struktūrą bei žurnalo kelius, nustatoma, kad žurnalo kelias pasikeitė.

Sprendimas: Vykdykite SQL, kad pakeistumėte žurnalo kelią

atnaujinti t_ds_task_instance set log_path=replace(log_path,'/logs/','/worker-server/logs/');

Tada nukopijuokite pradinius žurnalo failus į naują žurnalo kelią:

cp -r {old_dolphinscheduler_directory}/logs/[1-9]* {new_dolphinscheduler_directory}/worker-server/logs/*

3. Klaida kuriant darbo eigą po atnaujinimo

Klaidos pranešimas rodo, kad pradinės pirminių raktų reikšmės yra t_ds_process_definition_log ir t_ds_process_definition yra nenuoseklūs. Šių reikšmių sinchronizavimas išsprendžia problemą.

Sprendimas: Vykdykite šį SQL

-- Get the auto-increment value of the primary key
select AUTO_INCREMENT FROM information_schema.TABLES WHERE TABLE_SCHEMA = 'dolphinscheduler' AND TABLE_NAME = 't_ds_process_definition' limit 1;

-- Use the result of the above SQL to execute the following
alter table dolphinscheduler_bak1.t_ds_process_definition_log auto_increment = {max_id};

4. Ištuštinkite užduočių egzempliorių sąrašą po atnaujinimo

Patikrinę SQL užklausą dolphinscheduler-dao/src/main/resources/org/apache/dolphinscheduler/dao/mapper/TaskInstanceMapper.xmlnustatyta, kad užklausos užduoties egzemplioriaus SQL pateikia nuorodas į t_ds_task_definition_log lentelė, bet sujungimo sąlyga define.code=instance.task_code nesutampa.

Atsižvelgiant į būklę define.project_code = #{projectCode}sujungimas su t_ds_task_definition_log daugiausia skirtas filtravimui pagal projectCode. Pakeiskite SQL taip:

Sprendimas:

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 <![CDATA[ >= ]] > #{startTime}
    </if>

Tiesiogiai prisijungus prie t_ds_process_definitionkuriame taip pat yra project_code filtravimo lauką, užklausa pateiks teisingus duomenis.

5. Nulinės rodyklės išimtis vykdant atnaujinimo scenarijų

(1) Išanalizuokite žurnalą ir suraskite problemą 517 eilutėje UpgradeDao.java

  1. Originalus kodas:
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                    }

Problema ta processDefinitionMap.get(jsonNodeDefinitionId.asInt()) grąžina nulį. Pridėkite nulinį patikrinimą, o jei nulinis, užregistruokite atitinkamą informaciją, kad galėtumėte peržiūrėti vėliau.

Sprendimas:

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) Išanalizuokite žurnalą ir suraskite problemą eilutėje 675 in UpgradeDao.java

Originalus kodas:

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                        }

Problema ta processCodeTaskNameCodeEntry.getValue().get(depTasks) grąžina nulį. Prieš priskirdami reikšmę, modifikuokite logiką, kad patikrintumėte, ar nėra nulio, ir užregistruokite atitinkamą informaciją.

Sprendimas:

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. Prisijungimo klaida po LDAP integravimo, neaiškus el. pašto lauko pavadinimas

Konfigūruokite LDAP integravimą api-server/conf/application.yaml

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

Norėdami sėkmingai integruoti LDAP, laukai urls, base-dn, username, password, identityir email turi būti teisingai užpildytas. Jei el. pašto lauko pavadinimas nežinomas, iš pradžių palikite jį tuščią.

Pradėję paslaugą pabandykite prisijungti naudodami LDAP vartotoją.

Sprendimas: LDAP autentifikavimo kodas yra dolphinscheduler-api/src/main/java/org/apache/dolphinscheduler/api/security/impl/ldap/LdapService.java viduje ldapLogin() metodas

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 result
    SearchResult 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 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();
        }
    }
}

Trečioji eilutė filtruoja pagal nurodytą el. pašto atributo lauką. Laikinai pakomentuokite šią eilutę:

// sc.setReturningAttributes(new String[]{ldapEmailAttribute});

Iš naujo paleiskite kodą; Dešimtoje eilutėje bus pateikti visi laukai:

NamingEnumeration<? extends Attribute> attrs = result.getAttributes().getAll();

Spausdindami arba derindami nustatykite teisingą el. pašto lauką ir atitinkamai atnaujinkite konfigūracijos failą. Tada panaikinkite kodo komentarą ir iš naujo paleiskite paslaugą, kad sėkmingai integruotumėte LDAP prisijungimą.

7. Administratoriaus ištekliaus failo autorizacija neveikia nuolatiniams vartotojams

Po kelių bandymų nustatyta, kad įprasti vartotojai gali matyti tik jiems priklausančius išteklių failus. Administratoriaus autorizacija nepadaro failų matomų.

Sprendimas:

Viduje listAuthorizedResource metodas ResourcePermissionCheckServiceImpl.java failas, esantis adresu dolphinscheduler-api/src/main/java/org/apache/dolphinscheduler/api/permission/pakeiskite grąžinimo kolekciją į relationResources:

@Override
        public Set<Integer> listAuthorizedResource(int userId, Logger logger) {
            List<Resource> relationResources;
            if (userId == 0) {
                relationResources = new ArrayList<>();
            } else {
                // query resource relation
                List<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()); // Fixed the issue that the resource file authorization was invalid
//            return ownResourceList.stream().map(Resource::getId).collect(toSet());
        }

Patikrinkite naujos versijos pakeitimų žurnalą ir sužinokite, kad ši klaida buvo ištaisyta 3.1.3 versijoje: GitHub PR #13318

8. „Kerberos“ galiojimo pabaigos problemos

„Kerberos“ sukonfigūruotas su bilieto galiojimo laiku, todėl HDFS ištekliai išteklių centre po tam tikro laikotarpio tampa nepasiekiami. Geriausias sprendimas yra pridėti logikos periodiniam kredencialų atnaujinimui.

Sprendimas:

Įtraukite šį metodą CommonUtils.javaesantis adresu dolphinscheduler-service/src/main/java/org/apache/dolphinscheduler/service/utils/:

/**
 * Periodically update credentials
 */
private static void startCheckKeytabTgtAndReloginJob() {
    // Periodically update credentials daily
    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.");
}

Tada iškvieskite šį metodą loadKerberosConfmetodas prieš grąžinant 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();  // Call here
        return true;
    }
    return false;
}

Šiame straipsnyje visų pirma įrašomos problemos, su kuriomis susiduriama naujovinimo proceso metu, ir siekiama padėti bendruomenei, kuri susiduria su panašiais iššūkiais.



Source link

Draugai: - Marketingo agentūra - Teisinės konsultacijos - Skaidrių skenavimas - Fotofilmų kūrimas - Miesto naujienos - Šeimos gydytojai - Saulius Narbutas - Įvaizdžio kūrimas - Veidoskaita - Nuotekų valymo įrenginiai - Teniso treniruotės - Pranešimai spaudai -