Geralmente, as empresas precisam que os resultados dos jobs sejam gerados antes do previsto para tomar decisões de negócios com base nesses dados o mais rápido possível. Nesse cenário, os desenvolvedores devem monitorar o status dos jobs para identificar e otimizar aqueles com execução lenta. O LogView do MaxCompute permite diagnosticar jobs com desempenho reduzido. Este tópico apresenta as causas de execuções lentas e as respectivas soluções, além de descrever como visualizar informações sobre esses jobs.
Diagnosticar um job com falha na execução
Se um job falhar durante a execução, consulte as informações de erro na aba Result do LogView. A aba Result é exibida automaticamente ao abrir o LogView de um job com falha.
Causas possíveis:
Sintaxe SQL incorreta. Nesse caso, não há grafo acíclico dirigido (DAG) nem job Fuxi, pois o job não foi enviado ao cluster de computação para execução.
Erro na função definida pelo usuário (UDF) utilizada. Visualize o DAG na aba Job Details do LogView para identificar a UDF causadora do erro. Em seguida, verifique as mensagens em StdOut ou StdError.
Outros erros. Para mais detalhes sobre outros tipos de erro, consulte Visão geral dos códigos de erro.
Diagnosticar um job com execução lenta
Estágio de compilação
Um job no estágio de compilação possui um LogView, mas sua execução ainda não começou. Com base nos substatus do job, disponíveis na aba SubStatusHistory, esse estágio divide-se em subestágios como agendamento, otimização, geração do plano de execução física e replicação de dados entre clusters. A aba SubStatusHistory lista o Code de status, a Description, o horário de início e a Latency de cada subestágio. Problemas durante a compilação geralmente indicam que o job está parado em um subestágio específico por um período prolongado. As seções a seguir descrevem as possíveis causas e soluções para jobs travados em cada subestágio.
-
Agendamento
Descrição do problema: O substatus do job é
Waiting for cluster resource. O job aguarda compilação.Causa: Recursos insuficientes no cluster de computação.
Solução: Verifique o status e os recursos necessários do cluster de computação. Se utilizar um cluster por assinatura, dimensione os recursos horizontalmente.
-
Otimização
Descrição do problema: O substatus do job é
SQLTask is optimizing query. O otimizador está ajustando o plano de execução.Causa: Plano de execução complexo. O otimizador requer muito tempo para concluir o processo.
Solução: Aguarde a conclusão da otimização. Na maioria dos casos, esse processo leva menos de 10 minutos.
-
Geração do plano de execução
Descrição do problema: O substatus do job é
SQLTask is generating execution plan.Causa 1: Leitura de dados de um número excessivo de partições.
Solução: Otimize as instruções SQL para reduzir o número de partições. Por exemplo, aplique poda de partições, filtre partições desnecessárias e divida jobs grandes em menores. Para saber como verificar a eficácia da poda de partições em instruções SQL e conhecer cenários comuns de falha, consulte Verificar se a poda de partições é eficaz.
Causa 2: Geração excessiva de arquivos pequenos. Arquivos pequenos são gerados nos seguintes cenários:
Operação incorreta ao usar comandos Tunnel para upload de dados. Por exemplo, criar uma nova
upload sessionpara cada registro carregado. Para mais informações, consulte Perguntas frequentes sobre comandos Tunnel.Execução de uma instrução
INSERT INTOem uma tabela particionada gera um novo arquivo no diretório da partition.
Soluções
Utilize a interface TunnelBufferedWriter para carregar dados de forma mais eficiente, evitando a geração excessiva de arquivos pequenos.
Mescle arquivos pequenos manualmente. Para mais detalhes, consulte Mesclar arquivos pequenos.
NotaSe houver mais de 10.000 arquivos pequenos, ative a mesclagem automática. O sistema mescla esses arquivos diariamente. No entanto, se a mesclagem automática falhar em cenários específicos, será necessário realizar a mesclagem manual.
-
Replicação de dados entre clusters
Descrição do problema:
Task rerunaparece várias vezes na aba SubStatusHistory, eFAILED: ODPS-0110141:Data version exceptionsurge na aba Result. Nesse caso, o job não falhou; ele está replicando dados entre clusters.Causa 1: Migração de dados entre clusters do projeto. Após a conclusão da migração, muitos jobs de replicação entre clusters executam durante os primeiros um ou dois dias.
Solução: Aguarde a conclusão esperada da replicação de dados entre clusters.
Causa 2: Migração de dados entre clusters do projeto, mas sem filtragem adequada das partições. Isso resulta na leitura de dados antigos de certas partições.
Solução: Filtre as partições que contêm dados antigos.
Estágio de execução
Um plano de execução é exibido na aba Job Details do LogView. O plano está incompleto e o job encontra-se no estado Running. Se um job travar nesse estágio ou demorar inesperadamente para concluir, as causas podem incluir: espera por recursos, skew de dados, execução ineficiente de UDF e inflação de dados. Esta seção descreve as características de cada caso e as respectivas soluções.
-
Espera por recursos
Sintoma: Uma instância está no estado Ready, ou algumas instâncias estão em Running enquanto outras permanecem em Ready. Observe que, se uma instância estiver em Ready mas possuir uma entrada histórica de Debug, isso pode indicar uma nova tentativa devido a falha da instância, e não espera por recursos. Na lista de instâncias Fuxi, use o SmartFilter para filtrar por status. A coluna Status mostra o estado atual de cada instância.
Solução:
-
Verifique se o status da fila é normal. Consulte a posição do job na fila verificando o
Queue lengthno LogView. O valor de Queue length está disponível no painel Basic info à esquerda do LogView. Alternativamente, verifique o uso de recursos do grupo de cotas correspondente no console do MaxCompute. No console do MaxCompute, selecione Quota management > Resource usage no menu à esquerda e visualize os gráficos de tendência de métricas como CPU resource para o grupo de cotas alvo. Se o uso de um recurso estiver próximo ou acima da cota, isso indica escassez de recursos no grupo, sendo a formação de fila esperada. A ordem de agendamento de um job depende não apenas do horário de envio e da prioridade, mas também da disponibilidade de memória ou CPU necessária. -
Visualize os jobs que utilizam o grupo de cotas.
Jobs grandes com baixa prioridade podem ter sido enviados, ou múltiplos jobs pequenos foram submetidos simultaneamente, ocupando muitos recursos. Entre em contato com o proprietário desses jobs para encerrá-los e liberar os recursos ocupados.
Altere o grupo de cotas do job para um grupo de outro projeto.
Dimensione os recursos horizontalmente. Esta solução aplica-se apenas a usuários com recursos por assinatura.
-
-
Skew de dados
Sintoma: A maioria das instâncias de uma tarefa concluiu, mas algumas instâncias "long-tail" demoram muito mais para finalizar. Essas instâncias lentas podem estar processando mais dados que as demais. No SmartFilter, verifique a contagem de Long-tails e compare as latências das instâncias na coluna Latency.
Solução: Para mais informações sobre causas comuns de skew de dados e métodos de otimização relacionados, consulte Ajuste de skew de dados.
-
Execução ineficiente de UDF
Neste tópico, UDFs referem-se a várias extensões definidas pelo usuário, incluindo funções escalares definidas pelo usuário (UDFs), funções de agregação definidas pelo usuário (UDAFs), funções com valor de tabela definidas pelo usuário (UDTFs), joins definidos pelo usuário (UDJs) e tipos definidos pelo usuário (UDTs).
Descrição: A eficiência de execução de uma tarefa é baixa e a tarefa inclui UDFs. A seguinte mensagem de erro indicando timeout na execução da UDF pode aparecer:
Fuxi job failed - WorkerRestart errCode:252,errMsg:kInstanceMonitorTimeout, usually caused by bad udf performance.Método de solução de problemas: Se uma tarefa falhar, examine o DAG na aba Job details do LogView para determinar se contém uma UDF. No DAG, uma tarefa com falha, como R4_3, aparece em vermelho. O rótulo fx no nó indica a linguagem da UDF, como ["JAVA"]. Clique duas vezes em R4_3 para abrir a visualização do operador, que mostra a cadeia de operadores de cima para baixo e lista todos os nomes de UDF usados na tarefa. No log StdOut da tarefa, o framework da UDF imprime o número de registros de entrada, registros de saída e tempo de processamento. Use esses dados para identificar problemas de desempenho. Normalmente, o
Speed(records/s)varia de centenas de milhares a milhões. Se cair para dezenas de milhares, provavelmente há um problema de desempenho. O log exibe um resumo do processamento da UDF e uma tabela estatística para cada operador (CursorId) com métricas como OutputCount, InnerTime e Speed(records/s).Solução: Se ocorrer um problema de desempenho, utilize o método abaixo para solucionar e otimizar o desempenho.
-
Verifique se há erros na UDF.
Em casos específicos, o problema de desempenho é causado por um valor de dado específico. Por exemplo, ocorre um loop infinito quando um determinado valor aparece. O MaxCompute Studio permite baixar amostras específicas de dados de uma tabela e usá-las localmente para solução de problemas. Para mais informações, consulte Java UDFs e Python UDF no manual de desenvolvimento do MaxCompute Studio.
-
Verifique se o nome da UDF coincide com o de uma função interna.
Uma função interna pode ser sobrescrita por uma UDF com o mesmo nome. Se uma função parecer ser interna, determine se existe uma UDF homônima capaz de sobrescrevê-la.
-
Substitua a UDF por uma função interna.
Se existirem funções internas com funcionalidades similares, evite usar UDFs. Funções internas são validadas e executadas de maneira mais eficiente. Além disso, otimizadores realizam testes de caixa branca em funções internas, permitindo mais otimizações. Para mais informações sobre o uso de funções internas, consulte Funções internas.
Substitua UDFs específicas por funções internas equivalentes, mantendo apenas as UDFs que não podem ser implementadas com funções internas.
-
Otimize o método evaluate das UDFs.
Use o método evaluate apenas nas operações necessárias relacionadas aos parâmetros. Realize operações de inicialização ou cálculos repetitivos antecipadamente, pois o método evaluate é executado repetidamente.
-
Estime o tempo necessário para executar uma UDF.
Simule localmente a quantidade de dados processada por uma instância para testar o tempo de execução da UDF. Em seguida, otimize a implementação da UDF. Por padrão, o tempo máximo de execução de uma UDF é de 30 minutos. Uma UDF deve retornar dados dentro de 30 minutos ou usar
context.progress()para reportar heartbeats. Se o tempo estimado de execução exceder 30 minutos, configure um parâmetro para especificar o timeout da UDF.Default value: 1800. Unit: seconds. Valid values: 1 to 3600. -- Specify the timeout period of a UDF. Unit: seconds. Default value: 600. -- You can manually adjust the timeout period of the UDF in the range of [0,3600]. -
Modifique parâmetros de memória.
A baixa eficiência de UDFs não se deve necessariamente à complexidade computacional. A complexidade de armazenamento também pode afetar a eficiência. Exemplos:
Estouro de memória ocorre se uma UDF realizar computação em memória ou ordenar uma grande quantidade de dados.
Memória insuficiente causa alta frequência de coleta de lixo (GC).
Modifique parâmetros de memória para contornar temporariamente os problemas acima. A otimização específica deve ser realizada conforme seus requisitos de negócio. Exemplo:
set odps.sql.udf.jvm.memory= -- Specify the maximum memory size that can be used for the JVM heap of a UDF. Default value: 1024. Unit: MB. -- You can change the value of the odps.sql.udf.jvm.memory parameter in the range of [256,12288].NotaSe uma UDF for usada, a poda de partições pode tornar-se inválida. A anotação
UdfPropertyé suportada a partir do MaxCompute V2.0. Ao definir uma UDF, use essa anotação para informar ao compilador que a UDF é determinística. Código de exemplo:@com.aliyun.odps.udf.annotation.UdfProperty(isDeterministic = true) public class AnnotatedUdf extends com.aliyun.odps.udf.UDF { public String evaluate(String x) { return x; } }Se reescrever a instrução SQL de uma UDF, você poderá usar a UDF na filtragem de partições.
-- SQL statement before rewriting SELECT * FROM t WHERE pt = udf('foo'); -- pt indicates a partition key column of t. -- SQL statement after rewriting SELECT * FROM t WHERE pt = (SELECT udf('foo')); --pt indicates a partition key column of t.
-
-
Inflação de dados
Sintoma: O volume de dados de saída de uma tarefa é muito maior que o de entrada. Por exemplo, se 1 GB de dados processados se transformar em 1 TB, o desempenho cai significativamente quando uma única instância processa esse 1 TB. Após a conclusão do job, visualize os volumes de dados de entrada e saída em I/O Records da tarefa. Se um job travar no estágio Join, verifique os logs StdOut de algumas instâncias Fuxi em estado Running. No SmartFilter, filtre por instâncias em estado Running e clique em no ícone StdOut de uma instância para ver seus logs. Se o log StdOut mostrar continuamente logs de Merge Join, isso indica que um único worker está realizando Merge Join incessantemente. Se o número de linhas de saída do Merge Join exceder 143,3 bilhões, há inflação severa de dados; verifique se a condição JOIN e a Join Key são adequadas. O log emitirá continuamente registros de Merge join cursor, e o valor do campo OutputRowCount aumentará progressivamente. Use isso para determinar o grau de inflação dos dados.
Solução:
Verifique no código: se a condição JOIN está correta, se foi escrita como produto cartesiano, se a UDTF está normal e se há geração excessiva de dados de saída.
-
Verifique se a inflação de dados é causada por agregação.
A maioria dos agregadores realiza agregação recursiva. Ao agregar dados, o agregador primeiro mescla os resultados intermediários. O volume de dados intermediários não é grande e a complexidade computacional da maioria dos agregadores é baixa. A agregação pode ser concluída rapidamente mesmo com grandes volumes de dados. Na maioria dos casos, não ocorre inflação de dados durante a agregação. No entanto, a inflação pode ocorrer nos seguintes cenários:
Ativar agregação na instrução SELECT para realizar a operação DISTINCT em diferentes dimensões. Os dados expandem a cada execução da operação DISTINCT.
Ao usar a instrução GROUPING SETS ou CUBE | ROLLUP, o tamanho dos dados de resultado intermediário pode aumentar várias vezes em relação ao original. Contudo, ao usar instruções específicas como COLLECT_LIST ou MEDIAN, todos os dados de resultado intermediário devem ser retidos, o que pode causar problemas específicos.
-
Evite inflação de dados causada por operações JOIN.
Por exemplo, ao juntar duas tabelas: a tabela esquerda contém muitos dados populacionais, mas a eficiência de processamento é alta devido ao alto paralelismo das instâncias do MaxCompute. A tabela direita é uma tabela de dimensões que registra informações sobre cada gênero, como possíveis maus hábitos. Essa tabela tem apenas dois gêneros, mas centenas de linhas correspondentes a cada um. Se juntar as tabelas por gênero, os dados da tabela esquerda podem expandir centenas de vezes. Para evitar inflação, agregue as linhas da tabela direita em duas linhas antes de realizar o join.
-
Verifique se a inflação de dados é causada pela instrução GROUPING SET. Quando executada, essa instrução expande os dados, aumentando a saída várias vezes em relação ao número de grupos. O plano de execução atual não consegue adaptar-se à instrução GROUPING SET nem alterar o grau de paralelismo das tarefas subsequentes. Configure manualmente o grau de paralelismo das tarefas subsequentes. Instruções de exemplo:
set odps.stage.reducer.num = xxx; set odps.stage.joiner.num = xxx;
Estágio de finalização
A maioria dos jobs SQL para após a conclusão dos jobs Fuxi. Porém, às vezes o progresso geral do job permanece em execução mesmo com os jobs Fuxi finalizados. No LogView, a página Job details mostra todos os estágios do job Fuxi como Terminated, mas o Status geral do job à esquerda continua Running. Nesse caso, o Progress à esquerda ainda mostra 0%. Esse fenômeno geralmente ocorre em duas situações:
O job SQL inclui múltiplos jobs Fuxi. Por exemplo, subconsultas executadas em vários estágios ou jobs de mesclagem automática de arquivos pequenos disparados devido à geração excessiva desses arquivos.
No estágio de finalização, o job SQL passa muito tempo no cluster de controle. Por exemplo, o job atualiza metadados de partições dinâmicas. A seção a seguir apresenta exemplos de cenários comuns.
-
Execução de subconsultas em múltiplos estágios
Na maioria dos casos, subconsultas do MaxCompute SQL são compiladas no mesmo DAG Fuxi. Assim, todas as subconsultas e consultas principais são concluídas por um único job Fuxi. No entanto, certas subconsultas especiais precisam ser executadas separadamente antes das consultas principais. Código de exemplo:
SELECT product, sum(price) FROM sales WHERE ds in (SELECT DISTINCT ds FROM t_ds_set) GROUP BY product;A subconsulta
SELECT DISTINCT ds FROM t_ds_setexecuta primeiro. Seu resultado é necessário para a poda de partições, otimizando o número de partições lidas pela consulta principal. Essas duas execuções são jobs Fuxi separados. O LogView exibe cada job Fuxi em uma aba distinta, como SQL_0_0_0_job_0 e SQL_0_0_1_job_1. O DAG também mostra a dependência entre múltiplos nós JOB. Basta clicar em na segunda tab para ver o status de execução do job_1. Após alternar, visualize o status atual de cada tarefa no job_1, como Running ou Waiting. -
Excesso de arquivos pequenos
O excesso de arquivos pequenos afeta principalmente o desempenho de armazenamento e computação.
Armazenamento: O excesso de arquivos pequenos aumenta a carga no Apsara Distributed File System, afetando o uso de armazenamento.
Computação: O desempenho geral de processamento é afetado porque a eficiência do MaxCompute no processamento de um único arquivo grande é superior à de múltiplos arquivos pequenos. Portanto, ao concluir um job SQL, a operação de mesclagem de arquivos pequenos é acionada automaticamente se certas condições forem atendidas, evitando que o sistema gere arquivos pequenos em excesso.
-
Se houver excesso de arquivos pequenos, instruções SELECT podem demorar muito no estágio de finalização. Ao gerar e exibir resultados de instruções SELECT, o sistema precisa abrir muitos arquivos pequenos para ler dados, um processo demorado. Para evitar que o sistema gere muitos resultados de execução, evite usar instruções SELECT. Utilize comandos Tunnel para baixar dados. Se o número de resultados não for grande, mas a quantidade de arquivos for excessiva, verifique se o parâmetro odps.merge.smallfile.filesize.threshold está configurado corretamente. Para mais informações sobre como mesclar arquivos pequenos, consulte Mesclar arquivos pequenos.
Solução: Use o LogView para verificar se um job acionou a mesclagem automática de arquivos pequenos. Assim como na execução em múltiplos estágios de subconsultas, o job de Merge também aparece em uma aba separada. Embora a MergeTask adicional para mesclagem automática aumente o tempo total de execução do job atual, ela otimiza o número e o tamanho dos arquivos gerados na tabela de resultados após a mesclagem. Isso evita pressão excessiva no sistema de arquivos e melhora o desempenho de leitura quando a tabela é usada por jobs subsequentes. O nome da aba do job de Merge é semelhante a SQL_0_0_0_merge, exibindo o progresso de execução da MergeTask.
-
Atualização de metadados em partições dinâmicas
Descrição do problema: Após a conclusão de um job Fuxi, pode ser necessário realizar operações específicas relacionadas aos metadados. Por exemplo, ao mover dados resultantes para um diretório específico e atualizar os metadados da tabela, muitas partições podem ser geradas durante o particionamento dinâmico, tornando o processo demorado. Por exemplo, a instrução
insert into ... valuesé executada na tabela particionada sales para adicionar 2.000 partições. Instrução de exemplo:INSERT INTO TABLE sales partition (ds)(ds, product, price) VALUES ('20170101','a',1),('20170102','b',2),('20170103','c',3), ...;Após a conclusão do job Fuxi, ainda leva algum tempo para atualizar os metadados da tabela. O SubStatusHistory do LogView mostra que o job está parado em
SQLTask is updating meta information. O código de status correspondente é 1260, e seu valor de Latency indica quanto tempo a atualização de metadados levou. -
Aumento no tamanho do arquivo de saída
Sintoma: O número de registros de entrada e saída é similar, mas o tamanho da saída é várias vezes maior. Em Fuxi Jobs, verifique a coluna IO bytes para comparar os tamanhos de dados de Entrada e Saída de cada tarefa. Isso ajuda a identificar o estágio onde ocorreu a inflação de tamanho.
Solução: Uma razão é a mudança na distribuição dos dados. Ao gravar dados em uma tabela, eles são compactados. O algoritmo de compactação é mais eficaz em dados repetitivos. Portanto, se dados idênticos forem organizados juntos durante a gravação, obtém-se uma alta taxa de compactação. A distribuição dos dados depende de como eles são embaralhados e ordenados durante o estágio de gravação (estágio R12 nos Fuxi Jobs). Neste exemplo, a operação SQL final é um JOIN, com a chave JOIN sendo:
on t1.query = t2.query and t1.item_id=t2.item_idAs características dos dados indicam que a maioria das colunas são atributos dos itens. Nesse caso, todas as colunas para itens com o mesmo
item_idsão idênticas. Portanto, todos os itens na consulta são ordenados aleatoriamente, causando baixa taxa de compactação. O código de exemplo a seguir mostra como modificar a sequência do join. Após a modificação, o tamanho dos dados reduziu para 1/3 do original.on t1.item_id=t2.item_id and t1.query = t2.queryApós a modificação, o tamanho dos dados reduziu para 1/3 do original.
Em outro caso, as operações de shuffle geradas por JOIN ou
GROUP BYnão contêm a coluna de ordenação mais adequada para compactação. Nesse cenário, use a cláusula ZORDER BY para ordenar os itens localmente, obtendo alta taxa de compactação com menor custo. Também é possível executar uma instruçãoDISTRIBUTED BY SORT BYpara reorganizar manualmente a distribuição dos dados. Esse método exige muito tempo de cálculo e alto uso de CPU.