web-dev-qa-db-fra.com

Comment exécuter Spark code dans Airflow?

Bonjour les gens de la Terre! J'utilise Airflow pour planifier et exécuter des tâches Spark. Tout ce que j'ai trouvé à ce moment-là est python DAGs que Airflow peut gérer).
Exemple DAG:

spark_count_lines.py
import logging

from airflow import DAG
from airflow.operators import PythonOperator

from datetime import datetime

args = {
  'owner': 'airflow'
  , 'start_date': datetime(2016, 4, 17)
  , 'provide_context': True
}

dag = DAG(
  'spark_count_lines'
  , start_date = datetime(2016, 4, 17)
  , schedule_interval = '@hourly'
  , default_args = args
)

def run_spark(**kwargs):
  import pyspark
  sc = pyspark.SparkContext()
  df = sc.textFile('file:///opt/spark/current/examples/src/main/resources/people.txt')
  logging.info('Number of lines in people.txt = {0}'.format(df.count()))
  sc.stop()

t_main = PythonOperator(
  task_id = 'call_spark'
  , dag = dag
  , python_callable = run_spark
)

Le problème est que je ne suis pas bon en Python et que certaines tâches sont écrites en Java. Ma question est de savoir comment exécuter Spark Java jar in python DAG? Ou peut-être qu'il y a une autre façon de le faire? J'ai trouvé spark submit: http: // spark.Apache.org/docs/latest/submitting-applications.html
Mais je ne sais pas comment tout connecter ensemble. Peut-être que quelqu'un l'a utilisé auparavant et a un exemple de travail. Merci pour votre temps!

29
Ruslan Lomov

Vous devriez pouvoir utiliser BashOperator. En gardant le reste de votre code tel quel, importez les packages de classe et de système requis:

from airflow.operators.bash_operator import BashOperator

import os
import sys

définir les chemins requis:

os.environ['SPARK_HOME'] = '/path/to/spark/root'
sys.path.append(os.path.join(os.environ['SPARK_HOME'], 'bin'))

et ajoutez l'opérateur:

spark_task = BashOperator(
    task_id='spark_Java',
    bash_command='spark-submit --class {{ params.class }} {{ params.jar }}',
    params={'class': 'MainClassName', 'jar': '/path/to/your.jar'},
    dag=dag
)

Vous pouvez facilement l'étendre pour fournir des arguments supplémentaires à l'aide de modèles Jinja.

Vous pouvez bien sûr ajuster cela pour un scénario non-Spark en remplaçant bash_command avec un modèle adapté à votre cas, par exemple:

bash_command = 'Java -jar {{ params.jar }}'

et en ajustant params.

18
user6910411

Airflow à partir de la version 1.8 (publiée aujourd'hui), a

Code SparkSQLHook - https://github.com/Apache/incubator-airflow/blob/master/airflow/contrib/hooks/spark_sql_hook.py

Code SparkSubmitHook - https://github.com/Apache/incubator-airflow/blob/master/airflow/contrib/hooks/spark_submit_hook.py

Notez que ces deux nouveaux opérateurs Spark/hooks sont dans la branche "contrib" à partir de la version 1.8 donc pas (bien) documentés.

Vous pouvez donc utiliser SparkSubmitOperator pour soumettre votre code Java pour Spark.

20
Tagar

Il existe un exemple d'utilisation de SparkSubmitOperator pour Spark 2.3.1 sur kubernetes (instance de minikube):

"""
Code that goes along with the Airflow located at:
http://airflow.readthedocs.org/en/latest/tutorial.html
"""
from airflow import DAG
from airflow.operators.bash_operator import BashOperator
from airflow.contrib.operators.spark_submit_operator import SparkSubmitOperator
from airflow.models import Variable
from datetime import datetime, timedelta

default_args = {
    'owner': '[email protected]',
    'depends_on_past': False,
    'start_date': datetime(2018, 7, 27),
    'email': ['[email protected]'],
    'email_on_failure': False,
    'email_on_retry': False,
    'retries': 1,
    'retry_delay': timedelta(minutes=5),
    # 'queue': 'bash_queue',
    # 'pool': 'backfill',
    # 'priority_weight': 10,
    'end_date': datetime(2018, 7, 29),
}

dag = DAG(
    'tutorial_spark_operator', default_args=default_args, schedule_interval=timedelta(1))

t1 = BashOperator(
    task_id='print_date',
    bash_command='date',
    dag=dag)

print_path_env_task = BashOperator(
    task_id='print_path_env',
    bash_command='echo $PATH',
    dag=dag)

spark_submit_task = SparkSubmitOperator(
    task_id='spark_submit_job',
    conn_id='spark_default',
    Java_class='com.ibm.cdopoc.DataLoaderDB2COS',
    application='local:///opt/spark/examples/jars/cppmpoc-dl-0.1.jar',
    total_executor_cores='1',
    executor_cores='1',
    executor_memory='2g',
    num_executors='2',
    name='airflowspark-DataLoaderDB2COS',
    verbose=True,
    driver_memory='1g',
    conf={
        'spark.DB_URL': 'jdbc:db2://dashdb-dal13.services.dal.bluemix.net:50001/BLUDB:sslConnection=true;',
        'spark.DB_USER': Variable.get("CEDP_DB2_WoC_User"),
        'spark.DB_PASSWORD': Variable.get("CEDP_DB2_WoC_Password"),
        'spark.DB_DRIVER': 'com.ibm.db2.jcc.DB2Driver',
        'spark.DB_TABLE': 'MKT_ATBTN.MERGE_STREAM_2000_REST_API',
        'spark.COS_API_KEY': Variable.get("COS_API_KEY"),
        'spark.COS_SERVICE_ID': Variable.get("COS_SERVICE_ID"),
        'spark.COS_ENDPOINT': 's3-api.us-geo.objectstorage.softlayer.net',
        'spark.COS_BUCKET': 'data-ingestion-poc',
        'spark.COS_OUTPUT_FILENAME': 'cedp-dummy-table-cos2',
        'spark.kubernetes.container.image': 'ctipka/spark:spark-docker',
        'spark.kubernetes.authenticate.driver.serviceAccountName': 'spark'
        },
    dag=dag,
)

t1.set_upstream(print_path_env_task)
spark_submit_task.set_upstream(t1)

Le code utilisant des variables stockées dans des variables Airflow: enter image description here

De plus, vous devez créer une nouvelle connexion spark ou éditer 'spark_default' existant avec un dictionnaire supplémentaire {"queue":"root.default", "deploy-mode":"cluster", "spark-home":"", "spark-binary":"spark-submit", "namespace":"default"}: enter image description here

10
CTiPKA