Практика внедрения инструмента дифференциального тестирования для доставки активных и резервных каналов в хранилище данных реального времени.

1. История

В настоящее время уровень приоритета индикаторов доставки в реальном времени, предоставляемых хранилищами данных в реальном времени, становится все более важным. В частности, данные хранилища данных, предоставляемые нижестоящими механизмами правил, оказывают непосредственное влияние на доставку рекламы рекламных операций. Задержки или отклонения данных могут привести к прямым или косвенным потерям активов.Потеря;Судя по панораме каналов платформы управления доставкой, текущая доставка представляет собой операционный процесс с замкнутым циклом.Хранилище данных в реальном времени является ключевым узлом в канале передачи данных. Данные в реальном времени напрямую поддерживают автоматическую работу механизма правил и доставки. Ручное управление платформой управления; аварии узлов в реальном времени могут привести к сбою в нормальной работе всего канала доставки; для достижения стабильности 99,9% звена доставки необходимо улучшить стабильность и приоритетность задач звена.

135.png

Комплексный план оценки испытаний НИОКР добавляет резервную ссылку к действующей ссылке, повторяет требования к доставке и вносит итерационные изменения через резервную ссылку.После завершения модификации выполняется Diff основного и резервного каналов, чтобы гарантировать, что Diff пройдет ставка составляет 99,9%, и тогда он может выйти в Интернет.

2. План реализации

  • Подготовка данных: данные, генерируемые активными и резервными каналами, записываются в ODPS в режиме реального времени.

  • Сбор данных. Служба инструмента тестирования одновременно собирает фрагменты данных активного и резервного канала, сохраняя 2 копии данных за один и тот же период времени.

  • Снижение шума данных и разница: после того, как инструмент соберет данные, он выполнит первый этап обработки шумоподавления; основные и резервные данные начнут сравниваться и второй этап обработки шумоподавления.

  • Результат сравнения данных: Обработайте результат сравнения данных, определите разницу в каждом поле и, наконец, определите разницу в общих данных и выдайте результат.

900.jpeg

3. Настройте основные и резервные каналы связи.

230.jpeg

Объяснение ссылки в режиме реального времени: исходные данные записываются в Kafka, Flink использует данные Kafka в качестве источника данных (источник), объединяет поля атрибутов для выполнения операторской обработки (Transformatin), а результаты обработки записываются в Kafka (приемник). для следующего этапа обработки. Обработка передается в базу данных приложения через каждый узел задачи Flink.

4. Подготовка данных – нарезка данных

Срез временного окна

Разрежьте в соответствии с моментом времени тестирования и зафиксируйте данные от 0 часов дня до периода времени выполнения, чтобы гарантировать, что данные больше не обновляются.

Нарезка бизнес-сценариев

Различные бизнес-сценарии итеративно нарезаются на срезы, и поток данных доставляется для предоставления различных данных последующих сценариев. Срезы фиксируются для итерированных данных бизнес-сценария. Например: field_a='b'

5. Данные активного и резервного канала.

Проблема с дрейфом данных

Признак: поток данных постоянно обновляется.Поток данных тех же бизнес-данных обновляется до последней версии.Основная ссылка может войти в раздел дня, а резервная ссылка может войти в раздел следующего дня.

План шумоподавления: возьмите последний фрагмент данных из потока данных.

098.jpeg

Проблема с частотой обновления данных

Признак: во время процесса обновления одних и тех же бизнес-данных основная ссылка может быть обновлена ​​10 раз, данные не будут изменены в течение следующих пяти раз, а резервная ссылка будет обновлена ​​только 5 раз.

Решение для шумоподавления: возьмите N фрагментов данных из потока данных для одних и тех же бизнес-данных.

076.png

Проблема со своевременностью обновления данных

Проблемное явление: во время одного и того же процесса обновления бизнес-данных основная ссылка обновляет три данных до 11.68, 12.9 и 13.05; резервная ссылка обновляет три данных до 11.68, 12.9 и 13.1; видно, что данные обновляются в следующем время уже не то же самое.

Решение для шумоподавления: потоки данных одних и тех же бизнес-данных объединяются в список, и ведущее и ведомое устройства взаимно определяют, существуют ли последние данные в списке потоков данных, перехваченных другой стороной.

099.png

Проблема несогласованных значений полей атрибутов

Признак: есть пустые символы, ноль, 0 и 0,0.Результат сравнения не удался, но фактическое бизнес-значение в порядке.

Решение для шумоподавления: разница после унифицированного преобразования.

Проблема несогласованности полей атрибутов синтаксического анализа поля сообщения активного и резервного каналов связи.

Признак: в поле сообщения хранятся данные в формате JSON. Для одного и того же фрагмента бизнес-данных поля атрибутов, соответствующие JSON, анализируемому первичной и вторичной ссылками, не полностью согласованы, и между ними существуют различия.

Решение для шумоподавления: проанализировать все поля атрибутов с помощью кода, чтобы обеспечить полный Diff.

шаблон сообщения:

{"fields_a":"20230628","fields_b":"2023-06-22 19:48:24","fields_c":"2","fields_d":"plan","fields_e":"3******","fields_f":"0.0","fields_g":"2","fields_h":"4*****","fields_i":"ext","fields_j":"binlog+odps","fields_k":"2","fields_l":"STATUS_*****","fields_m":"1********","fields_n":"孙**","fields_o":"2023-06-28T22:19:43.872"}

Конвертировать JSON:

{
        "fields_a": "20230717",
        "fields_d": "plan",
        "fields_e": "3******",
        "fields_aj": "33761.125",
        "fields_p": "37934.0",
        "fields_r": "1250.412",
        "fields_s": "1250.412",
        "fields_t": "33761.125",
        "fields_w": "33761.125",
        "fields_m": "1*********",
        "fields_v": "33761.125",
        "fields_y": "33761.125",
        "fields_n": "孙**",
        "fields_z": "1250.412",
        "fields_ai": "27",
        "fields_ak": "",
        "fields_aa": "33761.125",
        "fields_ab": "33761.125",
        "fields_ac": "33761.0",
        "fields_al": "0.1002",
        "fields_i": "***",
        "fields_j": "***",
        "fields_k": "2",
        "fields_ad": "1.0",
        "fields_ak": "37934.0",
        "fields_x": "1250.412",
        "fields_y": "0.0",
        "fields_ag": "27",
        "fields_af": "27",
        "fields_ah": "0.0",
        "fields_al": "0.0",
        "fields_am": "0.0",
        "fields_ao": "37934.0",
        "fields_ap": "37934.0",
        "fields_an": "33761.125",
        "fields_aq": "1*********",
        "fields_ae": "27",
        "fields_o": "2023-07-17T23:59:00.103",
        "fields_ar": "0.1002"
}

Вышеупомянутые пять проблем можно устранить с помощью SQL. Общий шаблон SQL для шумоподавления выглядит следующим образом:

SET odps.sql.mapper.split.size = 64;
SET odps.stage.joiner.num = 4000;
SET odps.stage.reducer.num = 1999;
CREATE TABLE table_diff AS
SELECT  a.fields_as AS fields_as_main
        ,b.fields_as AS fields_as_branch
        ,a.fields_at AS fields_at_main
        ,b.fields_at AS fields_at_branch
        ,a.fields_d AS fields_d_main
        ,b.fields_d AS fields_d_branch
        ,a.fields_i AS fields_i_main
        ,b.fields_i AS fields_i_branch
        ,a.fields_j AS fields_j_main
        ,b.fields_j AS fields_j_branch
        ,a.fields_aw AS fields_aw_main
        ,b.fields_aw AS fields_aw_branch
        ,a.fields_k_json_key AS fields_k_json_key_main
        ,b.fields_k_json_key AS fields_k_json_key_branch
        ,a.fields_k_json_key_list AS fields_k_json_key_list_main
        ,b.fields_k_json_key_list AS fields_k_json_key_list_branch
        ,CASE   WHEN a.fields_k_json_key = b.fields_k_json_key THEN 0
                WHEN b.fields_k_json_key_list RLIKE a.fields_k_json_key THEN 0
                WHEN a.fields_k_json_key_list RLIKE b.fields_k_json_key THEN 0
                ELSE 1
        END AS fields_k_json_key_diff_flag
FROM    (
            SELECT  fields_as
                    ,fields_at
                    ,fields_d
                    ,fields_i
                    ,fields_j
                    ,fields_aw
                    ,MAX(CASE WHEN rn = 1 THEN fields_k_json_key END) AS fields_k_json_key
                    ,CONCAT_WS(',',COLLECT_SET(fields_k_json_key)) AS fields_k_json_key_list
            FROM    (
                        SELECT  *
                                ,CASE   WHEN NVL(GET_JSON_OBJECT(message,'$.fields_k'),'') = '' THEN '---'
                                        WHEN GET_JSON_OBJECT(message,'$.fields_k') IN ('0','0.0') THEN '0-0-0'
                                        ELSE GET_JSON_OBJECT(message,'$.fields_k')
                                END AS fields_k_json_key
                                ,ROW_NUMBER() OVER (PARTITION BY fields_as,fields_at,fields_d,fields_i,fields_j,fields_aw ORDER BY offset DESC ) AS rn
                        FROM    table_main
                        WHERE   pt = 20230628
                        -- AND     fields_i = 'realMetric'
                    ) 
            WHERE   rn < 6
            GROUP BY fields_as
                     ,fields_at
                     ,fields_d
                     ,fields_i
                     ,fields_j
                     ,fields_aw
        ) a
LEFT JOIN   (
                SELECT  fields_as
                        ,fields_at
                        ,fields_d
                        ,fields_i
                        ,fields_j
                        ,fields_aw
                        ,MAX(CASE WHEN rn = 1 THEN fields_k_json_key END) AS fields_k_json_key
                        ,CONCAT_WS(',',COLLECT_SET(fields_k_json_key)) AS fields_k_json_key_list
                FROM    (
                            SELECT  *
                                    ,CASE   WHEN NVL(GET_JSON_OBJECT(message,'$.fields_k'),'') = '' THEN '---'
                                            WHEN GET_JSON_OBJECT(message,'$.fields_k') IN ('0','0.0') THEN '0-0-0'
                                            ELSE GET_JSON_OBJECT(message,'$.fields_k')
                                    END AS fields_k_json_key
                                    ,ROW_NUMBER() OVER (PARTITION BY fields_as,fields_at,fields_d,fields_i,fields_j,fields_aw ORDER BY offset DESC ) AS rn
                            FROM    table_branch
                            WHERE   pt = 20230628
                            -- AND     fields_i = 'realMetric'
                            and fields_d !='group'
                        ) 
                WHERE   rn < 6
                GROUP BY fields_as
                         ,fields_at
                         ,fields_d
                         ,fields_i
                         ,fields_j
                         ,fields_aw
            ) b
ON      NVL(a.fields_as,'-00') = NVL(b.fields_as,'-00')
AND     NVL(a.fields_at,'-00') = NVL(b.fields_at,'-00')
AND     NVL(a.fields_d,'-00') = NVL(b.fields_d,'-00')
AND     NVL(a.fields_i,'-00') = NVL(b.fields_i,'-00')
AND     NVL(a.fields_j,'-00') = NVL(b.fields_j,'-00')
AND     NVL(a.fields_aw,'-00') = NVL(b.fields_aw,'-00')
;

Проблема с шумоподавлением поля

Признак: при изменении логики поля результат Diff неверен, что влияет на результат Diff.

Решение по шумоподавлению: Необходимо отказаться от логически модифицированных полей, больше не судить о логически модифицированных полях и гибко управлять ими через Java.

String[] jsonColumnListStrings = jsonColumnList.split(",");
List<String> jsonColumnLists = new ArrayList<String>();
String[] iterationColumnStrings = iterationColumn.split(",");
List<String> iterationColumnLists = Arrays.asList(iterationColumnStrings);
for (String s:jsonColumnListStrings){
    if(!iterationColumnLists.contains(s)){//判断字段是否为去噪字段
        jsonColumnLists.add(s);
    }
}

0776.png

6. Анализ результатов различий

На основе SQL, синтезированного активным и резервным Diff, можно создать сравнительную таблицу результатов, а анализ результатов выполнения может определить, прошло ли выполнение или нет.

Логика анализа 1: Определите долю прохождения каждого поля сравнения

Проведите анализ исследований и разработок, в которых проанализированные поля имеют низкий процент прохождения.

Логика анализа 2. Определите долю всех полей, передающих общее количество записей.

Этот индикатор может определить, прошел ли Diff.Если он составляет 99,9%, это означает, что он прошел.

Проанализируйте образец SQL:

SELECT  round(SUM(CASE WHEN fields_k_json_key_diff_flag = 0 THEN 1 ELSE 0 END) / COUNT(1) * 100,4) AS fields_k_ratio
        ,round(SUM(CASE WHEN fields_m_json_key_diff_flag = 0 THEN 1 ELSE 0 END) / COUNT(1) * 100,4) AS fields_m_ratio
        ,round(SUM(CASE WHEN fields_e_json_key_diff_flag = 0 THEN 1 ELSE 0 END) / COUNT(1) * 100,4) AS fields_e_ratio
        ,round(SUM(CASE WHEN fields_a_json_key_diff_flag = 0 THEN 1 ELSE 0 END) / COUNT(1) * 100,4) AS fields_aratio
        ,round(SUM(CASE WHEN fields_n_json_key_diff_flag = 0 THEN 1 ELSE 0 END) / COUNT(1) * 100,4) AS fields_n_ratio
        ,round(SUM(CASE WHEN fields_p_json_key_diff_flag = 0 THEN 1 ELSE 0 END) / COUNT(1) * 100,4) AS fields_p_ratio
        ,round(SUM(CASE WHEN fields_ac_json_key_diff_flag = 0 THEN 1 ELSE 0 END) / COUNT(1) * 100,4) AS fields_ac_ratio
        ,round(SUM(CASE WHEN fields_ar_json_key_diff_flag = 0 THEN 1 ELSE 0 END) / COUNT(1) * 100,4) AS fields_ar_ratio
        ,round(SUM(CASE WHEN fields_k_json_key_diff_flag = 0 AND fields_m_json_key_diff_flag = 0 AND fields_e_json_key_diff_flag = 0 AND fields_a_json_key_diff_flag = 0 AND fields_n_json_key_diff_flag = 0 AND fields_p_json_key_diff_flag = 0 AND fields_ac_json_key_diff_flag = 0 AND fields_ar_json_key_diff_flag = 0 THEN 1 ELSE 0 END) / COUNT(1) * 100,4) AS total_ratio
        ,COUNT(1) AS total_cnt
FROM    table_diff
;

7. Сервисизация инструмента

Логика обработки серверной службы

Первичное и вторичное сравнение SQL-синтеза

Внедрите SQL-код Diff в код, управляйте нарезкой данных, шумоподавлением и другими сценариями с помощью кода, чтобы завершить тестовый синтез SQL.

for(String s:jsonColumnLists){
    selectSql1 = selectSql1 + " case when NVL(GET_JSON_OBJECT(message,'$." + s + "'),'')='' then '---' when get_json_object(message,'$." + s + "') in ('0','0.0') then '0-0-0' else get_json_object(message,'$." + s + "') end  AS " + s + "_json_key,";
    selectSql2 = selectSql2 + " max(case when rn =1 then " + s + "_json_key end) as " + s + "_json_key,concat_ws(',',collect_set(" + s + "_json_key)) as " + s + "_json_key_list,";
    mergeSql = mergeSql + " a." + s + "_json_key as " + s + "_json_key_main,b." + s + "_json_key as " + s + "_json_key_branch,a." + s + "_json_key_list as " + s + "_json_key_list_main,b." + s + "_json_key_list as " + s + "_json_key_list_branch,case when a." + s + "_json_key = b." + s + "_json_key then 0 when b." + s + "_json_key_list rlike a." + s + "_json_key then 0 when a." + s + "_json_key_list rlike b." + s + "_json_key then 0 else 1 end as " + s + "_json_key_diff_flag,";
}
rowNumberSql ="ROW_NUMBER() OVER (PARTITION BY fields_as,fields_at,fields_d,fields_i,fields_j,fields_aw ORDER BY offset DESC ) AS rn ";
selectSql1 = selectSql1 + rowNumberSql;
whereSql1 = whereSql1 + bizdate + " AND fields_i = 'realMetric' ";
String pretreatmentSqlMain = "";
String pretreatmentSqlBranch = "";
pretreatmentSqlBranch = selectSql2.substring(0,selectSql2.length()-1) + " from(" + selectSql1 + " from " + branchLinkTableName + whereSql1 + ")" + whereSql2 + groupSql.substring(0,groupSql.length()-1);
pretreatmentSqlMain = selectSql2.substring(0,selectSql2.length()-1) + " from(" + selectSql1 + " from " + masterLinkTableName + whereSql1 + ")" + whereSql2 + groupSql.substring(0,groupSql.length()-1);
mergeSql = mergeSql.substring(0,mergeSql.length()-1) + " from (" + pretreatmentSqlMain + ")a left join (" + pretreatmentSqlBranch + ")b " + joinSql.substring(0,joinSql.length()-3) + ";";
SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyyMMddHHmmss");
String dateStr = simpleDateFormat.format(new Date());
this.resultDataCreateSql = "set odps.sql.mapper.split.size=64;set odps.stage.joiner.num=4000;set odps.stage.reducer.num=1999; create table du_temp.diff_main_branch_" + dateStr  + "_test as " + mergeSql;
log.info(resultDataCreateSql);
this.resultDataTable = "du_temp.diff_main_branch_" + dateStr  + "_test";
log.info(resultDataTable);
//合成过滤结果数据的sql
String resultSql = " select ";
String totalResultSql = "round(sum(case when ";
for(String s:jsonColumnLists){
    resultSql = resultSql + " round(sum(case when " + s + "_json_key_diff_flag = 0 then 1 else 0 end)/count(1)*100,4) as " + s + "_ratio,";
    totalResultSql = totalResultSql + " " + s + "_json_key_diff_flag = 0 and";
}
this.resultDataFiltrate = resultSql + totalResultSql.substring(0,totalResultSql.length()-3) + " then 1 else 0 end)/count(1)*100,4) as total_ratio , count(1) as total_cnt from " + this.resultDataTable + ";";
log.info(resultDataFiltrate);

Анализ отчета о результатах различий

...}
else if(testType.equals("主备diff")) {
    for (Map.Entry entry:testResultRecord.entrySet()) {
        List<String> listValue = (List<String>) entry.getValue();
        this.resultData.put(entry.getKey().toString(),listValue.get(0)) ;
        if(Double.parseDouble(listValue.get(0))< 99.9 & !entry.getKey().toString().equals("total_cnt")){
            this.failDetail.put(entry.getKey().toString(),listValue.get(0)) ;
        }
    }
    if(failDetail.size()>0){
        this.testStatus = "失败";
    }else {
        this.testStatus = "成功";
    }
}

Визуализация платформы

  • Создать задачу

27.png

  • список выполнения

84.png

  • Отчет о результатах — отображение платформы

Как показано ниже: в результате сбоя выполнения процент прохождения составляет 99,8471, что не достигает 99,99% .73.png

  • Отчет о результатах — уведомление Feishu

Вот пример:

Имя требования выполнения: Active-backup Diff-521 Исполнитель: *** Тип выполнения: Active-backup Diff Номер выполнения: 20230628204636 Имя таблицы ссылок резервного копирования: table_main Имя таблицы основной ссылки выполнения: table_branch Раздел таблицы ссылок резервного копирования: 20230628 Подробности результата выполнения таблица: table_diff Сводка сведений о результатах выполнения:fields_am_ratio:99.9958fields_z_ratio:99.9826fields_af_ratio:99.9856fields_ba_ratio:99.9964fields_al_ratio:99.9915fields_ad_ratio:99.9873fields_r_ratio:99.9826fields_aa_ratio:99.99 06 полей_ai_ratio:99,9856 полей_v_ratio:99,9917 полей_ak_ratio:99,9909 полей_m_ratio:99,9969 полей_ak_ratio:99,9945 полей_bb_ratio :99.9964 fields_bc_ratio:99.9957 fields_bd_ratio:99.9954 fields_ae_ratio:99.9856 fields_be_ratio:99.9952 fields_bf_ratio:99.9955 fields_t_ratio:99.9917
fields_ag_ratio:99.9856 fields_p_ratio:99.9909 fields_bg_ratio:99.9948 fields_a_ratio:99.9969 fields_d_ratio:99.9969 fields_x_ratio:99.9826 fields_an_ratio:99.9917
fields_ap_ratio:99.9909 fields_ar_ratio:99.9915 fields_y_ratio:99.9917 fields_bh_ratio:99.9955 fields_aj_ratio:99.9916 fields_bi_ratio:99.987 fields_ac_ratio:99.9908 fields_s_ratio:99.9826 fields_ab_ratio:99.9906 fields_i_ratio:99.9969 fields_bj_ratio:99.9951 fields_ah_ratio:99.9959
fields_k_ratio:99.9969
fields_e_ratio:99.9969 fields_bk_ratio:99.9962 fields_bl_ratio:99.8748 fields_al_ratio:99.9958 fields_j_ratio:99.9969
fields_bm_ratio:99.9951 fields_n_ratio: 99,9969fields_ao_ratio:99,9909fields_w_ratio:99,9906fields_bn_ratio:99,9965fields_bo_ratio:99,9912fields_bcrate_ratio:99,987fields_y_ratio:99,9958 Сводные данные активных и резервных результатов выполнения различий: total_ratio:99,8471 total_cnt:71 42 59
Подробности об ошибке результата выполнения:
fields_bl_ratio :99.8748
total_ratio:99.8471% Результат выполнения статус: не удалось

8. Процесс доступа и выпуска активных и резервных инструментов сравнения.

Когда развернутая резервная линия наконец пройдет проверку активных и резервных инструментов Diff, она будет подключена к сети. В настоящее время это эквивалентно резервной производственной линии.

Для последующих итераций версий, если требования проверяются инструментом Diff перед подключением к сети, они будут соответствовать онлайн-требованиям.

68.jpeg

9. Резюме

Вычисления в реальном времени отличаются от автономных хранилищ данных. Стабильность и точность данных трудно контролировать. Сложные ссылки не могут гарантировать качество общих данных посредством простого тестирования. Форма двухканального Diff может лучше гарантировать данные в реальном времени. во время итераций.качество.

Для реализации активного и резервного Diff: самой большой проблемой часто является то, что шум данных очень велик, что требует технических средств для уменьшения шума, чтобы обеспечить точность и надежность результатов сравнения данных.

* Текст/Шию

Автор этой статьи принадлежит Dewu Technology. Другие интересные статьи можно найти на официальном сайте Dewu Technology.

Перепечатка без разрешения Dewu Technology строго запрещена, в противном случае будет наступать юридическая ответственность в соответствии с законом!

Broadcom объявила о прекращении существующей партнерской программы VMware . Сайт B дважды выходил из строя, инцидент Tencent "3.29" первого уровня... Подводя итоги десяти крупнейших инцидентов с простоями в 2023 году, выпущен Vue 3.4 "Slam Dunk", Yakult подтвердил утечку данных 95G MySQL 5.7, Moqu, Li Tiaotiao... Подведение итогов проектов и веб-сайтов с открытым исходным кодом, которые будут «остановлены» в 2023 году. Официально выпущен «Отчет разработчиков открытого исходного кода Китая за 2023 год». Оглядываясь назад на IDE 30 лет назад: только TUI, яркий цвет фона…… Официально выпущена Julia 1.10 Выпущена Rust 1.75.0 NVIDIA выпустила GeForce RTX 4090 D специально для продажи в Китае
{{o.name}}
{{м.имя}}

рекомендация

отmy.oschina.net/u/5783135/blog/10568112
рекомендация