Todos os produtos
Search
Central de documentação

MaxCompute:Analisar as N principais contas de faturamento e jobs mais demorados no MaxCompute

Última atualização: Oct 10, 2026

Ao desenvolver com o MaxCompute, talvez seja necessário analisar os custos das contas e a duração dos jobs para planejar e ajustar suas tarefas com mais eficiência. Este tópico descreve como usar os metadados do MaxCompute (Information Schema) para identificar as contas com maior faturamento e os jobs que consomem mais tempo. Também é possível enviar essas informações para um grupo do DingTalk.

Contexto

Desenvolvedores de dados frequentemente usam o MaxCompute no modo padrão do DataWorks. Nesse modo, o MaxCompute registra a mesma conta raiz no Information Schema como executora da maioria dos jobs. Apenas alguns jobs são executados por usuários do Resource Access Management (RAM). Isso dificulta a análise de custos e da duração dos jobs por conta individual. O MaxCompute oferece as seguintes soluções:

  • Custos da conta: Revise os detalhes de uso na sua fatura. No entanto, esse método não vincula o uso a usuários RAM específicos. A view TASKS_HISTORY no Information Schema registra detalhes dos jobs concluídos no seu projeto do MaxCompute nos últimos 14 dias. Faça backup dos dados da TASKS_HISTORY para um projeto do MaxCompute e use-os para encontrar as principais contas de faturamento.

  • Jobs demorados: Use os dados da TASKS_HISTORY para identificar os jobs que consomem mais tempo.

Para obter mais informações sobre os recursos e limites do Information Schema, consulte Project-level Information Schema.

O processo para analisar as N principais contas de faturamento e os jobs mais demorados consiste nas etapas a seguir:

  1. Etapa 1: Obter o service Information Schema.

  2. (Opcional) Etapa 2: Conceder permissões a usuários que não sejam o proprietário do projeto.

  3. Etapa 3: Baixar e fazer backup dos metadados.

  4. Etapa 4: Criar jobs para analisar as N principais contas de faturamento e os jobs mais demorados.

  5. Etapa 5: Criar um chatbot de grupo do DingTalk e enviar informações sobre as N principais contas de faturamento e jobs mais demorados.

  6. Etapa 6: Configurar propriedades de agendamento para nós ancestrais e descendentes e executar os nós.

Etapa 1: Obter o service Information Schema

A partir de 1º de março de 2024, o MaxCompute deixou de instalar automaticamente o Information Schema no nível do projeto para novos projetos. Caso precise consultar metadados, use o Information Schema no nível do tenant para obter informações mais abrangentes. Para mais detalhes sobre como usar o Information Schema no nível do tenant, consulte Tenant-level Information Schema.

Para projetos existentes do MaxCompute, um Project Owner ou um usuário RAM com a função Super_Administrator deve instalar o pacote de permissões do Information Schema para acessar os metadados do projeto. Para saber mais sobre como conceder uma função de gerenciamento a um usuário, consulte Grant a role to a user. Instale o pacote de uma das seguintes maneiras:

Nota

Para analisar metadados de vários projetos do MaxCompute, instale o pacote de permissões do Information Schema em cada projeto. Em seguida, insira os backups de metadados de todos os projetos em uma única tabela para análise.

(Opcional) Etapa 2: Conceder permissões a usuários que não sejam o proprietário do projeto

As views no Information Schema contêm todos os dados do usuário no nível do projeto. Por padrão, o proprietário do projeto pode visualizar esses dados. Se outros usuários ou funções precisarem de acesso, autorize-os. Para mais informações, consulte Access resources across projects by using a Package.

A sintaxe para conceder autorização é a seguinte:

grant <actions> on package Information_Schema.systables to user <user_name>;
grant <actions> on package Information_Schema.systables to role <role_name>;
  • actions: A permissão a ser concedida. O valor deve ser read.

  • user_name: Uma conta Alibaba Cloud ou um usuário RAM no projeto.

    Execute o comando list users; no MaxCompute client para listar as contas de usuário.

  • role_name: Uma função no projeto.

    Execute o comando list roles; no MaxCompute client para listar os nomes das funções.

Exemplo:

grant read on package Information_Schema.systables to user RAM$Bob@aliyun.com:user01;

Etapa 3: Baixar e fazer backup dos metadados

Crie uma tabela de backup de metadados no seu projeto do MaxCompute e agende uma tarefa recorrente para gravar os metadados nela. As etapas a seguir mostram um exemplo com o cliente do MaxCompute:

  1. Faça login no MaxCompute client e execute o comando a seguir para criar uma tabela de backup de metadados.

    -- project_name is the name of your MaxCompute project.
    CREATE TABLE if NOT EXISTS <project_name>.information_history
    (
        task_catalog STRING
        ,task_schema STRING
        ,task_name STRING
        ,task_type STRING
        ,inst_id STRING
        ,`status` STRING
        ,owner_id STRING
        ,owner_name STRING
        ,result STRING
        ,start_time DATETIME
        ,end_time DATETIME
        ,input_records BIGINT
        ,output_records BIGINT
        ,input_bytes BIGINT
        ,output_bytes BIGINT
        ,input_tables STRING
        ,output_tables STRING
        ,operation_text STRING
        ,signature STRING
        ,complexity DOUBLE
        ,cost_cpu DOUBLE
        ,cost_mem DOUBLE
        ,settings STRING
        ,ds STRING
    );
  2. Acesse a interface do DataWorks Data Studio, crie um nó ODPS SQL (information_history) e configure o agendamento temporizado para gravar dados periodicamente na tabela de backup information_history. Em seguida, clique em no ícone Save no canto superior esquerdo para salvar o nó.

    Para mais informações, consulte Create an ODPS SQL node.

    O código a seguir mostra um exemplo de comando para executar no nó ODPS SQL:

    -- project_name is the name of the MaxCompute project.
    use <project_name>;
    insert into table <project_name>.information_history select * from information_schema.tasks_history where ds ='datetime1';

    ${datetime1} é um parâmetro de agendamento do DataWorks. À direita do nó ODPS SQL, clique em Scheduling Configuration. Na seção Basic Properties, defina o Parameter como datetime1=${yyyymmdd}.

    Nota

    Para analisar metadados de vários projetos do MaxCompute simultaneamente, crie múltiplos nós ODPS SQL. Configure cada nó para gravar os metadados de um projeto diferente na mesma tabela de backup.

Etapa 4: Criar jobs para analisar as N principais contas de faturamento e os jobs mais demorados

O campo settings na view TASKS_HISTORY registra informações do agendador ou do usuário em formato JSON, incluindo useragent, bizid, skynet_id e skynet_nodename. Use o campo settings para encontrar o usuário RAM que criou o job. Assim, você pode usar a tabela de backup para identificar as N principais contas de faturamento e os jobs mais demorados. Siga as etapas abaixo:

  1. Faça login no MaxCompute client e crie uma tabela de detalhes de usuários RAM chamada user_ram. Essa tabela registrará as contas e IDs de conta a serem analisados.

    O código a seguir mostra um exemplo de comando:

    CREATE TABLE if NOT EXISTS <project_name>.user_ram
    (
        user_id STRING
        ,user_name STRING
    );
  2. Crie uma tabela de detalhes chamada cost_topn para registrar os detalhes das N principais contas de faturamento.

    O código a seguir mostra um exemplo de comando:

    CREATE TABLE if NOT EXISTS <project_name>.cost_topn
    (
        cost_sum DECIMAL(38,5)
        ,task_owner STRING
    )
    partitioned BY 
    (
        ds STRING
    );
  3. Crie uma tabela de detalhes chamada time_topn para registrar os detalhes dos N jobs mais demorados.

    O código a seguir mostra um exemplo de comando:

    CREATE TABLE if NOT EXISTS <project_name>.time_topn
    (
        inst_id STRING
        ,cost_time BIGINT
        ,task_owner STRING
    )
    partitioned BY 
    (
        ds STRING
    );
  4. Acesse a interface do DataWorks Data Studio. Crie um nó ODPS SQL (topn) e configure o agendamento temporizado para gravar periodicamente os dados estatísticos da tabela cost_topn na tabela user_ram. Em seguida, clique em no ícone Save no canto superior esquerdo para salvar o nó.

    Para mais informações, consulte Create an ODPS SQL node.

    O código a seguir mostra um exemplo de comando para executar no nó ODPS SQL:

    -- Enable data type 2.0. For more information about data type 2.0, see Data type editions.
    SET odps.sql.decimal.odps2=true;
    
    -- Write metadata to the cost_topn and time_topn tables. user_id is the account ID. You can find the account ID on your personal information page.
    INSERT INTO TABLE <project_name>.cost_topn PARTITION (ds = '${datetime1}')
    SELECT   
        NVL(cost_sum,0) cost_sum
        ,CASE WHEN a.task_owner='<user_id>' OR a.task_owner='<user_id>' OR a.task_owner='<user_id>' THEN b.user_name 
              ELSE a.task_owner 
         END task_owner 
    FROM    (
                SELECT  inst_id
                        ,owner_name
                        ,task_type
                        ,a.input_bytes
                        ,a.cost_cpu
                        ,a.status
                        ,CASE    WHEN a.task_type = 'SQL' THEN CAST(a.input_bytes/1024/1024/1024 * a.complexity * 0.3 AS DECIMAL(18,5) )
                                 WHEN a.task_type = 'SQLRT' THEN CAST(a.input_bytes/1024/1024/1024 * a.complexity * 0.3 AS DECIMAL(18,5) )
                                 WHEN a.task_type = 'CUPID' AND a.status='Terminated' THEN CAST(a.cost_cpu/100/3600 * 0.66 AS DECIMAL(18,5) ) 
                                 ELSE 0 
                         END cost_sum
                        ,a.settings
                        ,GET_JSON_OBJECT(settings, "$.SKYNET_ONDUTY") owner
                        ,CASE    WHEN GET_JSON_OBJECT(a.settings, "$.SKYNET_ONDUTY") IS NULL THEN owner_name 
                                 ELSE GET_JSON_OBJECT(a.settings, "$.SKYNET_ONDUTY") 
                         END task_owner
                FROM    information_history
                WHERE   ds = '${datetime1}'
            ) a
    LEFT JOIN <project_name>.user_ram b
    ON      a.task_owner = b.user_id;
    
    INSERT INTO TABLE <project_name>.time_topn PARTITION(ds = '${datetime1}')
    SELECT  inst_id
            ,cost_time
            ,CASE    WHEN a.task_owner='<user_id>' OR a.task_owner='<user_id>' OR a.task_owner='<user_id>' THEN b.user_name 
                     ELSE a.task_owner 
             END task_owner
    FROM    (
                SELECT  inst_id
                        ,task_type
                        ,status
                        ,DATEDIFF(a.end_time, a.start_time, 'ss') AS cost_time
                        ,CASE    WHEN GET_JSON_OBJECT(a.settings, "$.SKYNET_ONDUTY") IS NULL THEN owner_name 
                                 ELSE GET_JSON_OBJECT(a.settings, "$.SKYNET_ONDUTY") 
                         END task_owner
                FROM    <project_name>.information_history a
                WHERE   ds = '${datetime1}'
            ) a
    LEFT JOIN <project_name>.user_ram b
    ON      a.task_owner = b.user_id;
    Nota

    No exemplo, task_type = 'SQL' representa um job SQL, task_type = 'SQLRT' representa um job de aceleração de consulta e task_type = 'CUPID' representa um job Spark. Para analisar outros jobs faturáveis, como MapReduce ou Mars, adicione linhas de código baseadas em suas fórmulas de faturamento. Para mais informações sobre faturamento, consulte Compute pricing (pay-as-you-go).

    ${datetime1} é um parâmetro de agendamento do DataWorks. À direita do nó ODPS SQL, clique em Scheduling Configuration. Na seção Basic Properties, defina o Parameter como datetime1=${yyyymmdd}.

Etapa 5: Criar um chatbot de grupo do DingTalk e enviar informações sobre as N principais contas de faturamento e jobs mais demorados

As etapas a seguir mostram como criar um chatbot de grupo do DingTalk e enviar informações sobre as N principais contas de faturamento e os jobs mais demorados. O exemplo usa o cliente DingTalk para PC.

  1. Crie um chatbot de grupo do DingTalk.

    1. Selecione o grupo desejado do DingTalk e clique em no ícone 1 no canto superior direito.

    2. No painel Group Settings, clique em Smart Group Assistant.

    3. No painel Smart Group Assistant, clique em Add Robot.

    4. Na seção Add Robot da caixa de diálogo Group Robot, clique em no ícone Add.

    5. Na caixa de diálogo Group Robot, clique em Custom.

    6. Na caixa de diálogo Robot Details, clique em Add.

    7. Na caixa de diálogo Add Robot, edite as informações do robô.

      Nome da propriedade

      Regras de configuração

      Foto de perfil

      Clique em no ícone 编辑 no canto inferior direito da foto de perfil para editá-la.

      Nome do robô

      Insira um nome para o robô.

      Configurações de segurança

      Configure as definições de segurança necessárias (selecione pelo menos uma), marque I have read and agree to the "Custom Robot Service and Disclaimer" e clique em Finish.

      Existem três tipos de configurações de segurança:

      • Custom Keywords: Defina até 10 palavras-chave.

      • Add Signature: Selecione Add Signature para obter a chave do robô.

      • IP Address (Range): Apenas solicitações provenientes do intervalo de endereços IP especificado serão processadas.

    8. Na caixa de diálogo Add Robot, copie a URL Webhook gerada. Em seguida, clique em Finish.

      Importante

      Mantenha a URL do Webhook segura. Não a publique em sites externos. Uma URL vazada pode causar riscos de segurança.

  2. Use o IntelliJ IDEA para criar um projeto Maven e compilar o programa Java que envia mensagens para o grupo do DingTalk. Após a compilação, um pacote JAR será gerado.

    Para mais informações sobre como usar o IntelliJ IDEA, clique em Help no canto superior direito da interface do IntelliJ IDEA.

    1. Configure as dependências do Pom.

      O código a seguir mostra as dependências do Pom.

      <?xml version="1.0" encoding="UTF-8"?>
      <project xmlns="http://maven.apache.org/POM/4.0.0"
               xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
               xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
          <modelVersion>4.0.0</modelVersion>
      
          <groupId>DingTalk_Information</groupId>
          <artifactId>DingTalk_Information</artifactId>
          <version>1.0-SNAPSHOT</version>
          <dependencies>
              <dependency>
                  <groupId>com.aliyun.odps</groupId>
                  <artifactId>odps-sdk-core</artifactId>
                  <version>0.35.5-public</version>
              </dependency>
              <dependency>
                  <groupId>log4j</groupId>
                  <artifactId>log4j</artifactId>
                  <version>1.2.15</version>
                  <exclusions>
                      <exclusion>
                          <groupId>com.sun.jmx</groupId>
                          <artifactId>jmxri</artifactId>
                      </exclusion>
                      <exclusion>
                          <groupId>com.sun.jdmk</groupId>
                          <artifactId>jmxtools</artifactId>
                      </exclusion>
                      <exclusion>
                          <groupId>javax.jms</groupId>
                          <artifactId>jms</artifactId>
                      </exclusion>
                  </exclusions>
              </dependency>
              <dependency>
                  <groupId>com.aliyun</groupId>
                  <artifactId>alibaba-dingtalk-service-sdk</artifactId>
                  <version>1.0.1</version>
              </dependency>
              <dependency>
                  <groupId>com.aliyun.odps</groupId>
                  <artifactId>odps-jdbc</artifactId>
                  <version>3.0.1</version>
                  <classifier>jar-with-dependencies</classifier>
              </dependency>
          </dependencies>
          <build>
              <plugins>
                  <plugin>
                      <groupId>org.apache.maven.plugins</groupId>
                      <artifactId>maven-assembly-plugin</artifactId>
                      <version>2.4.1</version>
                      <configuration>
                          <!-- get all project dependencies -->
                          <descriptorRefs>
                              <descriptorRef>jar-with-dependencies</descriptorRef>
                          </descriptorRefs>
                          <!-- MainClass in mainfest make a executable jar -->
                          <archive>
                              <manifest>
                                  <mainClass>com.alibaba.sgri.message.test</mainClass>
                              </manifest>
                          </archive>
                      </configuration>
                      <executions>
                          <execution>
                              <id>make-assembly</id>
                              <!-- bind to the packaging phase -->
                              <phase>package</phase>
                              <goals>
                                  <goal>single</goal>
                              </goals>
                          </execution>
                      </executions>
                  </plugin>
              </plugins>
          </build>
      </project>
    2. Desenvolva o programa Java e gere o pacote JAR topn_new.jar.

      O código a seguir mostra um exemplo em Java:

      package com.alibaba.sgri.message;
      import java.io.IOException;
      import java.util.concurrent.atomic.AtomicInteger;
      import com.aliyun.odps.Instance;
      import com.aliyun.odps.Odps;
      import com.aliyun.odps.OdpsException;
      import com.aliyun.odps.account.Account;
      import com.aliyun.odps.account.AliyunAccount;
      import com.aliyun.odps.data.ResultSet;
      import com.aliyun.odps.task.SQLTask;
      import com.dingtalk.api.DefaultDingTalkClient;
      import com.dingtalk.api.DingTalkClient;
      import com.dingtalk.api.request.OapiRobotSendRequest;
      import com.dingtalk.api.response.OapiRobotSendResponse;
      import com.taobao.api.ApiException;
      
      public class test {
      
          public static void main(String[] args) throws ApiException {
              if (args.length < 1) {
                  System.out.println("Please enter the date parameter.");
                  System.exit(0);
              }
              System.out.println("Start reading data.");
              DingTalkClient client = new DefaultDingTalkClient(
                      "<Your chatbot's Webhook URL>");
              OapiRobotSendRequest request = new OapiRobotSendRequest();
              request.setMsgtype("markdown");
              OapiRobotSendRequest.Markdown markdown = new OapiRobotSendRequest.Markdown();
              // The date here is used as a parameter.
              markdown.setText(getContent(args[0]));
              markdown.setTitle("Top N jobs by consumption");
              request.setMarkdown(markdown);
              OapiRobotSendResponse response = client.execute(request);
              System.out.println("Message sent successfully.");
          }
      
          /**
           * Read from ODPS to get the data to send.
           */
      
          public static String getContent(String day) {
              Odps odps = createOdps();
              StringBuilder sb = new StringBuilder();
              try {
                  //==================Billing accounts=====================
                  String costTopnSql = "select sum(cost_sum)cost_sum,task_owner from cost_topn where ds='" + day + "' " + "group by task_owner order by cost_sum desc limit 5;";
                  Instance costInstance = SQLTask.run(odps, costTopnSql);
                  costInstance.waitForSuccess();
                  ResultSet costTopnRecords = SQLTask.getResultSet(costInstance);
                  sb.append("<font color=#FF0000 size=4>").append("Top N Billing Accounts (").append(day).append(
                          ")[Calculated based on Alibaba Cloud pay-as-you-go billing]").append("</font>").append("\n\n");
                  AtomicInteger costIndex = new AtomicInteger(1);
                  costTopnRecords.forEach(item -> {
                      sb.append(costIndex.getAndIncrement()).append(".").append("Account:");
                      sb.append("<font color=#2E64FE>").append(item.getString("task_owner")).append("\n\n").append("</font>");
                      sb.append("  ").append(" ").append("Cost:").append("<font color=#2E64FE>").append(item.get("cost_sum"))
                              .append(" CNY").append(
                              "</font>").append("\n\n")
                              .append("</font>");
                  });
                  //==================Time-consuming jobs=====================
                  String timeTopnSql = "select * from time_topn where ds='" + day + "' ORDER BY cost_time DESC limit 5;";
                  Instance timeInstance = SQLTask.run(odps, timeTopnSql);
                  timeInstance.waitForSuccess();
                  ResultSet timeTopnRecords = SQLTask.getResultSet(timeInstance);
                  sb.append("<font color=#FF8C00 size=4>").append("Top N Time-consuming Jobs (").append(day).append(")")
                          .append("\n\n").append("</font>");
                  AtomicInteger timeIndex = new AtomicInteger(1);
                  timeTopnRecords.forEach(item -> {
                      sb.append(timeIndex.getAndIncrement()).append(".").append("Job:");
                      sb.append("<font color=#2E64FE>").append(item.getString("inst_id")).append("\n\n").append("</font>");
                      sb.append("   ").append("Account:").append("<font color=#2E64FE>").append(item.getString("task_owner")).append("\n\n").append("</font>");
                      sb.append("   ").append("Duration:").append("<font color=#2E64FE>").append(item.get("cost_time"))
                              .append("s").append(
                              "</font>").append("\n\n");
                  });
              } catch (OdpsException | IOException e) {
                  e.printStackTrace();
              }
              return sb.toString();
          }
      
          /**
           * Create an ODPS object.
           */
          public static Odps createOdps() {
              String project = "<project_name>";
              // An Alibaba Cloud account AccessKey has permissions to access all APIs. This poses a high security risk. We strongly recommend that you create and use a RAM user to make API calls or perform O&M. To create a RAM user, log on to the RAM console.
      		// This example shows how to store the AccessKey ID and AccessKey secret in environment variables. You can also store them in a configuration file as needed.
      		// We strongly recommend that you do not hard-code the AccessKey ID and AccessKey secret in your code. This can lead to key leakage.
      		String accessId = System.getenv("ALIBABA_CLOUD_ACCESS_KEY_ID");
      		String accessKey = System.getenv("ALIBABA_CLOUD_ACCESS_KEY_SECRET");
              String endPoint = "http://service.odps.aliyun.com/api";
              Account account = new AliyunAccount(accessId, accessKey);
              Odps odps = new Odps(account);
              odps.setEndpoint(endPoint);
              odps.setDefaultProject(project);
              return odps;
          }
      }
    3. Envie o pacote topn_new.jar gerado como um resource do MaxCompute.

      Para mais informações, consulte Create and use MaxCompute resources.

  3. Crie um nó Shell chamado dingsend, referencie o pacote topn_new.jar e configure um agendamento recorrente.

    Para mais informações, consulte Shell node.

    O código a seguir mostra um exemplo de comando para executar no nó Shell:

    java -jar  topn_new.jar  $1

    $1 é um parâmetro de agendamento do DataWorks. À direita do nó Shell, clique em Scheduling Configuration. Na seção Basic Properties, defina o Parameter como ${yyyymmdd}.

Etapa 6: Configurar propriedades de agendamento para nós ancestrais e descendentes e executar os nós

No painel de fluxo de negócios, conecte os nós information_history, topn e dingsend para criar dependências. Configure as propriedades de reexecução e as dependências de nós ancestrais para cada nó. Após concluir a configuração, clique com o botão direito em um nó e selecione Run Node.

Para mais informações sobre como configurar dependências, consulte Configure same-cycle scheduling dependencies.

Para mais detalhes sobre como configurar nós ancestrais e descendentes, consulte Configure node context.

Referências

Suporte online

Se tiver dúvidas ou sugestões ao usar o MaxCompute, envie um ticket para entrar em contato com o suporte técnico.