Compartilhar via


Aviso de descontinuação da tarefa Spark Submit: Guia para migração

Aviso

A tarefa Spark Submit foi preterida e a remoção pendente. O uso desse tipo de tarefa não é permitido para novos casos de uso e altamente desencorajado para clientes existentes. Consulte o Envio do Spark (herdado) para obter a documentação original desse tipo de tarefa. Continue lendo para obter instruções de migração.

Por que o Spark Submit está sendo descontinuado?

O tipo de tarefa Envio do Spark está sendo preterido devido a limitações técnicas e lacunas de recursos que não existem nas tarefas JAR, Notebook ou Python script. Essas tarefas oferecem melhor integração com os recursos do Databricks, melhor desempenho e maior confiabilidade.

Medidas de descontinuação

O Databricks está implementando as seguintes medidas em conexão com a substituição:

  • Criação restrita: somente os usuários que usaram as tarefas de Envio do Spark no mês anterior, a partir de novembro de 2025, podem criar novas tarefas de Envio do Spark . Se você precisar de uma exceção, entre em contato com o suporte da sua conta.
  • Restrições de versão do Databricks Runtime: o uso do Envio do Spark é restrito a versões existentes do Databricks Runtime e versões de manutenção. As versões existentes do Databricks Runtime com o Envio do Spark continuarão a receber versões de manutenção de segurança e bugfix até que o recurso seja desligado completamente. O Databricks Runtime 17.3+ e 18.x+ não oferecerão suporte a esse tipo de tarefa.
  • Avisos de interface do usuário: os avisos aparecem em toda a interface do usuário do Databricks quando as tarefas Spark Submit estão em uso e comunicações são enviadas aos administradores do workspace em contas de usuários existentes.

Migrar cargas de trabalho da JVM para tarefas JAR

Para cargas de trabalho JVM, migre suas tarefas de Envio do Spark para tarefas JAR. As tarefas JAR fornecem melhor suporte a recursos e integração com o Databricks.

Siga estas etapas para migrar:

  1. Crie uma nova tarefa JAR em seu trabalho.
  2. Em seus parâmetros de tarefa de Spark Submit, identifique os três primeiros argumentos. Eles geralmente seguem esse padrão: ["--class", "org.apache.spark.mainClassName", "dbfs:/path/to/jar_file.jar"]
  3. Remova o --class parâmetro.
  4. Defina o nome da classe principal (por exemplo, org.apache.spark.mainClassName) como a classe Principal para sua tarefa JAR.
  5. Forneça o caminho para o arquivo JAR (por exemplo, dbfs:/path/to/jar_file.jar) na configuração da tarefa JAR.
  6. Copie os argumentos restantes da tarefa Spark Submit para os parâmetros da tarefa JAR.
  7. Execute a tarefa JAR e verifique se ela funciona conforme o esperado.

Para obter informações detalhadas sobre como configurar tarefas JAR, consulte a tarefa JAR.

Migrar cargas de trabalho do R

Se você estiver iniciando um script R diretamente de uma tarefa Spark Submit, vários caminhos de migração estarão disponíveis.

Opção A: Usar tarefas do Notebook

Migre seu script R para um bloco de anotações do Databricks. As tarefas do notebook dão suporte a um conjunto completo de recursos, incluindo o dimensionamento automático do cluster, e fornecem uma melhor integração com a plataforma Databricks.

Opção B: inicializar scripts R de uma tarefa notebook

Use uma tarefa notebook para inicializar seus scripts R. Crie um notebook com o código a seguir e faça referência ao arquivo R como um parâmetro de trabalho. Modifique para adicionar parâmetros usados pelo script R, se necessário:

dbutils.widgets.text("script_path", "", "Path to script")
script_path <- dbutils.widgets.get("script_path")
source(script_path)

Localizar trabalhos que usam tarefas de Envio do Spark

Você pode usar os scripts python a seguir para identificar trabalhos em seu workspace que contêm tarefas de Envio do Spark. Um acesso pessoal válido ou outro token será necessário e sua URL do workspace deve ser usada.

Opção A: verificação rápida (execute esta primeiro; somente para trabalhos persistentes)

Esse script verifica apenas trabalhos persistentes (criados por meio /jobs/create ou pela interface da Web) e não inclui trabalhos efêmeros criados por meio /runs/submitde . Esse é o método recomendado primário para identificar o uso do Spark Submit porque ele é muito mais rápido.

#!/usr/bin/env python3
"""
Requirements:
    databricks-sdk>=0.20.0

Usage:
    export DATABRICKS_HOST="https://your-workspace.cloud.databricks.com"
    export DATABRICKS_TOKEN="your-token"
    python3 list_spark_submit_jobs.py

Output:
    CSV format with columns: Job ID, Owner ID/Email, Job Name

Incorrect:
    export DATABRICKS_HOST="https://your-workspace.cloud.databricks.com/?o=12345678910"
"""

import csv
import os
import sys
from databricks.sdk import WorkspaceClient
from databricks.sdk.errors import PermissionDenied


def main():
    # Get credentials from environment
    workspace_url = os.environ.get("DATABRICKS_HOST")
    token = os.environ.get("DATABRICKS_TOKEN")

    if not workspace_url or not token:
        print(
            "Error: Set DATABRICKS_HOST and DATABRICKS_TOKEN environment variables",
            file=sys.stderr,
        )
        sys.exit(1)

    # Initialize client
    client = WorkspaceClient(host=workspace_url, token=token)

    # Scan workspace for persistent jobs with Spark Submit tasks
    # Using list() to scan only persistent jobs (faster than list_runs())
    print(
        "Scanning workspace for persistent jobs with Spark Submit tasks...",
        file=sys.stderr,
    )
    jobs_with_spark_submit = []
    total_jobs = 0

    # Iterate through all jobs (pagination is handled automatically by the SDK)
    skipped_jobs = 0
    for job in client.jobs.list(expand_tasks=True, limit=25):
        try:
            total_jobs += 1
            if total_jobs % 1000 == 0:
                print(f"Scanned {total_jobs} jobs total", file=sys.stderr)

            # Check if job has any Spark Submit tasks
            if job.settings and job.settings.tasks:
                has_spark_submit = any(
                    task.spark_submit_task is not None for task in job.settings.tasks
                )

                if has_spark_submit:
                    # Extract job information
                    job_id = job.job_id
                    owner_email = job.creator_user_name or "Unknown"
                    job_name = job.settings.name or f"Job {job_id}"

                    jobs_with_spark_submit.append(
                        {"job_id": job_id, "owner_email": owner_email, "job_name": job_name}
                    )
        except PermissionDenied:
            # Skip jobs that the user doesn't have permission to access
            skipped_jobs += 1
            continue

    # Print summary to stderr
    print(f"Scanned {total_jobs} jobs total", file=sys.stderr)
    if skipped_jobs > 0:
        print(
            f"Skipped {skipped_jobs} jobs due to insufficient permissions",
            file=sys.stderr,
        )
    print(
        f"Found {len(jobs_with_spark_submit)} jobs with Spark Submit tasks",
        file=sys.stderr,
    )
    print("", file=sys.stderr)

    # Output CSV to stdout
    if jobs_with_spark_submit:
        writer = csv.DictWriter(
            sys.stdout,
            fieldnames=["job_id", "owner_email", "job_name"],
            quoting=csv.QUOTE_MINIMAL,
        )
        writer.writeheader()
        writer.writerows(jobs_with_spark_submit)
    else:
        print("No jobs with Spark Submit tasks found.", file=sys.stderr)


if __name__ == "__main__":
    main()

Opção B: verificação abrangente (mais lenta, inclui trabalhos efêmeros dos últimos 30 dias)

Se você precisar identificar os trabalhos efêmeros criados por meio /runs/submit, use esse script mais exaustivo. Esse script verifica todas as execuções de trabalho dos últimos 30 dias em seu workspace, incluindo trabalhos persistentes (criados via /jobs/create) e trabalhos efêmeros. Esse script pode levar horas para ser executado em workspaces grandes.

#!/usr/bin/env python3
"""
Requirements:
    databricks-sdk>=0.20.0

Usage:
    export DATABRICKS_HOST="https://your-workspace.cloud.databricks.com"
    export DATABRICKS_TOKEN="your-token"
    python3 list_spark_submit_runs.py

Output:
    CSV format with columns: Job ID, Run ID, Owner ID/Email, Job/Run Name

Incorrect:
    export DATABRICKS_HOST="https://your-workspace.cloud.databricks.com/?o=12345678910"
"""

import csv
import os
import sys
import time
from databricks.sdk import WorkspaceClient
from databricks.sdk.errors import PermissionDenied


def main():
    # Get credentials from environment
    workspace_url = os.environ.get("DATABRICKS_HOST")
    token = os.environ.get("DATABRICKS_TOKEN")

    if not workspace_url or not token:
        print(
            "Error: Set DATABRICKS_HOST and DATABRICKS_TOKEN environment variables",
            file=sys.stderr,
        )
        sys.exit(1)

    # Initialize client
    client = WorkspaceClient(host=workspace_url, token=token)

    thirty_days_ago_ms = int((time.time() - 30 * 24 * 60 * 60) * 1000)

    # Scan workspace for runs with Spark Submit tasks
    # Using list_runs() instead of list() to include ephemeral jobs created via /runs/submit
    print(
        "Scanning workspace for runs with Spark Submit tasks from the last 30 days... (this will take more than an hour in large workspaces)",
        file=sys.stderr,
    )
    runs_with_spark_submit = []
    total_runs = 0
    seen_job_ids = set()

    # Iterate through all runs (pagination is handled automatically by the SDK)
    skipped_runs = 0
    for run in client.jobs.list_runs(
        expand_tasks=True,
        limit=25,
        completed_only=True,
        start_time_from=thirty_days_ago_ms,
    ):
        try:
            total_runs += 1
            if total_runs % 1000 == 0:
                print(f"Scanned {total_runs} runs total", file=sys.stderr)

            # Check if run has any Spark Submit tasks
            if run.tasks:
                has_spark_submit = any(
                    task.spark_submit_task is not None for task in run.tasks
                )

                if has_spark_submit:
                    # Extract job information from the run
                    job_id = run.job_id if run.job_id else "N/A"
                    run_id = run.run_id if run.run_id else "N/A"
                    owner_email = run.creator_user_name or "Unknown"
                    # Use run name if available, otherwise try to construct a name
                    run_name = run.run_name or (
                        f"Run {run_id}" if run_id != "N/A" else "Unnamed Run"
                    )

                    # Track unique job IDs to avoid duplicates for persistent jobs
                    # (ephemeral jobs may have the same job_id across multiple runs)
                    key = (job_id, run_id)
                    if key not in seen_job_ids:
                        seen_job_ids.add(key)
                        runs_with_spark_submit.append(
                            {
                                "job_id": job_id,
                                "run_id": run_id,
                                "owner_email": owner_email,
                                "job_name": run_name,
                            }
                        )
        except PermissionDenied:
            # Skip runs that the user doesn't have permission to access
            skipped_runs += 1
            continue

    # Print summary to stderr
    print(f"Scanned {total_runs} runs total", file=sys.stderr)
    if skipped_runs > 0:
        print(
            f"Skipped {skipped_runs} runs due to insufficient permissions",
            file=sys.stderr,
        )
    print(
        f"Found {len(runs_with_spark_submit)} runs with Spark Submit tasks",
        file=sys.stderr,
    )
    print("", file=sys.stderr)

    # Output CSV to stdout
    if runs_with_spark_submit:
        writer = csv.DictWriter(
            sys.stdout,
            fieldnames=["job_id", "run_id", "owner_email", "job_name"],
            quoting=csv.QUOTE_MINIMAL,
        )
        writer.writeheader()
        writer.writerows(runs_with_spark_submit)
    else:
        print("No runs with Spark Submit tasks found.", file=sys.stderr)


if __name__ == "__main__":
    main()

Precisa de ajuda?

Se você precisar de ajuda adicional, entre em contato com o suporte da sua conta.