Regional haveriberedskap för Azure Databricks-kluster

Den här artikeln beskriver en arkitektur för haveriberedskap som är användbar för Azure Databricks-kluster och stegen för att utföra den designen.

Azure Databricks-arkitektur

När du skapar en Azure Databricks-arbetsyta från Azure-portalen distribueras ett hanterat program som en Azure-resurs i din prenumeration, i den valda Azure-regionen (till exempel USA, västra). Den här installationen distribueras i ett virtuellt Azure-nätverk med en nätverkssäkerhetsgrupp och ett Azure Storage-konto som är tillgängligt i din prenumeration. Det virtuella nätverket ger säkerhet på perimeternivå till Databricks-arbetsytan och skyddas via nätverkssäkerhetsgruppen. På arbetsytan skapar du Databricks-kluster genom att ange typ av arbets- och drivrutins-VM och Databricks-körningsversion. Beständiga data är tillgängliga i ditt lagringskonto. När klustret har skapats kan du köra jobb via notebook-filer, REST-API:er eller ODBC/JDBC-slutpunkter genom att koppla dem till ett specifikt kluster.

Databricks-kontrollplanet hanterar och övervakar Databricks-arbetsytemiljön. Alla hanteringsåtgärder, till exempel skapa kluster, initieras från kontrollplanet. Alla metadata, till exempel schemalagda jobb, lagras i en Azure Database och databassäkerhetskopiorna geo-replikeras automatiskt för i parkopplade regioner där de implementeras.

Databricks-arkitektur

En av fördelarna med den här arkitekturen är att användarna kan ansluta Azure Databricks till valfri lagringsresurs i sitt konto. En viktig fördel är att både beräkning (Azure Databricks) och lagring kan skalas oberoende av varandra.

Så här skapar du en topologi för regional haveriberedskap

I föregående arkitekturbeskrivning finns det ett antal komponenter som används för en stordatapipeline med Azure Databricks: Azure Storage, Azure Database och andra datakällor. Azure Databricks är beräkningen för stordatapipelinen. Det är tillfälliga till sin natur, vilket innebär att även om dina data fortfarande är tillgängliga i Azure Storage kan beräkningen (Azure Databricks-klustret) avslutas för att undvika att betala för beräkning när du inte behöver den. Beräkningskällorna (Azure Databricks) och lagringskällorna måste finnas i samma region så att jobben inte får långa svarstider.

Följ dessa krav för att skapa en egen topologi för regional haveriberedskap:

  1. Etablera flera Azure Databricks-arbetsytor i separata Azure-regioner. Skapa till exempel den primära Azure Databricks-arbetsytan i USA, östra. Skapa den sekundära haveriberedskapen för Azure Databricks-arbetsytan i en separat region, till exempel USA, västra. En lista över länkade Azure-regioner finns i Replikering mellan regioner. Mer information om Azure Databricks-regioner finns i Regioner som stöds.

  2. Använd geo-redundant lagring. Som standard lagras data som är associerade med Azure Databricks i Azure Storage och resultaten från Databricks-jobb lagras i Azure Blob Storage, så att bearbetade data är varaktiga och förblir mycket tillgängliga när klustret har avslutats. Klusterlagringen och jobblagringen finns i samma tillgänglighetszon. För att skydda mot regional otillgänglighet använder Azure Databricks-arbetsytor geo-redundant lagring som standard. Med geo-redundant lagring replikeras data till en Länkad Azure-region. Databricks rekommenderar att du behåller den geo-redundanta lagringsstandarden, men om du behöver använda lokalt redundant lagring i stället kan du ange storageAccountSkuName till Standard_LRS i ARM-mallen för arbetsytan.

  3. När den sekundära regionen har skapats måste du migrera användare, användarmappar, notebook-filer, klusterkonfiguration, jobbkonfiguration, bibliotek, lagring, init-skript och konfigurera om åtkomstkontroll. Ytterligare information beskrivs i följande avsnitt.

Regional katastrof

För att förbereda dig för regionala katastrofer måste du uttryckligen underhålla en annan uppsättning Azure Databricks-arbetsytor i en sekundär region. Se Haveriberedskap.

Våra rekommenderade verktyg för haveriberedskap är främst Terraform (för infrareplikering) och Delta Deep Clone (för datareplikering).

Detaljerade migreringssteg

  1. Konfigurera databricks-kommandoradsgränssnittet på datorn

    Den här artikeln visar ett antal kodexempel som använder kommandoradsgränssnittet för de flesta automatiserade stegen, eftersom det är en lättanvänd omslutning över Azure Databricks REST API.

    Innan du utför några migreringssteg installerar du databricks-cli på din stationära dator eller en virtuell dator där du planerar att utföra arbetet. Mer information finns i Installera Databricks CLI

    pip install databricks-cli
    

    Kommentar

    Alla Python-skript som tillhandahålls i den här artikeln förväntas fungera med Python 2.7+ < 3.x.

  2. Konfigurera två profiler.

    Konfigurera en för den primära arbetsytan och en annan för den sekundära arbetsytan:

    databricks configure --profile primary --token
    databricks configure --profile secondary --token
    

    Kodblocken i den här artikeln växlar mellan profiler i varje efterföljande steg med hjälp av motsvarande arbetsytekommando. Se till att namnen på de profiler som du skapar ersätts med varje kodblock.

    EXPORT_PROFILE = "primary"
    IMPORT_PROFILE = "secondary"
    

    Du kan växla manuellt på kommandoraden om det behövs:

    databricks workspace ls --profile primary
    databricks workspace ls --profile secondary
    
  3. Migrera Microsoft Entra-ID -användare (tidigare Azure Active Directory)

    Lägg till samma Microsoft Entra-ID (tidigare Azure Active Directory) manuellt till den sekundära arbetsytan som finns på den primära arbetsytan.

  4. Migrera användarmappar och anteckningsböcker

    Använd följande Python-kod för att migrera de sandbox-användarmiljöer som innehåller den kapslade mappstrukturen och notebook-filerna per användare.

    Kommentar

    Bibliotek kopieras inte över i det här steget eftersom det underliggande API:et inte stöder dem.

    Kopiera och spara följande Python-skript i en fil och kör det på databricks-kommandoraden. Exempel: python scriptname.py

    import sys
    import os
    import subprocess
    from subprocess import call, check_output
    
    EXPORT_PROFILE = "primary"
    IMPORT_PROFILE = "secondary"
    
    # Get a list of all users
    user_list_out = check_output(["databricks", "workspace", "ls", "/Users", "--profile", EXPORT_PROFILE])
    user_list = (user_list_out.decode(encoding="utf-8")).splitlines()
    
    print (user_list)
    
    # Export sandboxed environment(folders, notebooks) for each user and import into new workspace.
    #Libraries are not included with these APIs / commands.
    
    for user in user_list:
      #print("Trying to migrate workspace for user ".decode() + user)
      print (("Trying to migrate workspace for user ") + user)
    
      subprocess.call(str("mkdir -p ") + str(user), shell = True)
      export_exit_status = call("databricks workspace export_dir /Users/" + str(user) + " ./" + str(user) + " --profile " + EXPORT_PROFILE, shell = True)
    
      if export_exit_status==0:
        print ("Export Success")
        import_exit_status = call("databricks workspace import_dir ./" + str(user) + " /Users/" + str(user) + " --profile " + IMPORT_PROFILE, shell=True)
        if import_exit_status==0:
          print ("Import Success")
        else:
          print ("Import Failure")
      else:
        print ("Export Failure")
    print ("All done")
    
  5. Migrera klusterkonfigurationerna

    När notebook-filer har migrerats kan du migrera klusterkonfigurationerna till den nya arbetsytan. Det är nästan ett helt automatiserat steg med databricks-cli, såvida du inte vill utföra selektiv klusterkonfigurationsmigrering i stället för för alla.

    Kommentar

    Tyvärr finns det ingen slutpunkt för konfiguration av skapa kluster och det här skriptet försöker skapa varje kluster direkt. Om det inte finns tillräckligt med tillgängliga kärnor i din prenumeration kan klustret misslyckas. Felet kan ignoreras så länge konfigurationen har överförts.

    Följande skript skriver ut en mappning från gamla till nya kluster-ID:n, som kan användas för jobbmigrering senare (för jobb som har konfigurerats för att använda befintliga kluster).

    Kopiera och spara följande Python-skript i en fil och kör det på databricks-kommandoraden. Exempel: python scriptname.py

    import sys
    import os
    import subprocess
    import json
    from subprocess import call, check_output
    
    EXPORT_PROFILE = "primary"
    IMPORT_PROFILE = "secondary"
    
    # Get all clusters info from old workspace
    clusters_out = check_output(["databricks", "clusters", "list",    "--profile", EXPORT_PROFILE])
    clusters_info_list = str(clusters_out.decode(encoding="utf-8")).   splitlines()
    print("Printting Cluster info List")
    print(clusters_info_list)
    
    # Create a list of all cluster ids
    clusters_list = []
    ##for cluster_info in clusters_info_list: clusters_list.append   (cluster_info.split(None, 1)[0])
    
    for cluster_info in clusters_info_list:
       if cluster_info != '':
          clusters_list.append(cluster_info.split(None, 1)[0])
    
    # Optionally filter cluster ids out manually, so as to create only required ones in new workspace
    
    # Create a list of mandatory / optional create request elements
    cluster_req_elems = ["num_workers","autoscale","cluster_name","spark_version","spark_conf","node_type_id","driver_node_type_id","custom_tags","cluster_log_conf","spark_env_vars","autotermination_minutes","enable_elastic_disk"]
    print("Printing Cluster element List")
    print (cluster_req_elems)
    print(str(len(clusters_list)) + " clusters found in the primary site" )
    
    print ("---------------------------------------------------------")
    # Try creating all / selected clusters in new workspace with same config as in old one.
    cluster_old_new_mappings = {}
    i = 0
    for cluster in clusters_list:
       i += 1
       print("Checking cluster " + str(i) + "/" + str(len(clusters_list)) + " : " +str(cluster))
       cluster_get_out_f = check_output(["databricks", "clusters", "get", "--cluster-id", str(cluster), "--profile", EXPORT_PROFILE])
       cluster_get_out=str(cluster_get_out_f.decode(encoding="utf-8"))
       print ("Got cluster config from old workspace")
       print (cluster_get_out)
        # Remove extra content from the config, as we need to build create request with allowed elements only
       cluster_req_json = json.loads(cluster_get_out)
       cluster_json_keys = cluster_req_json.keys()
    
       #Don't migrate Job clusters
       if cluster_req_json['cluster_source'] == u'JOB' :
          print ("Skipping this cluster as it is a Job cluster : " + cluster_req_json['cluster_id'] )
          print ("---------------------------------------------------------")
          continue
    
          #cluster_req_json.pop(key, None)
          for key in cluster_json_keys:
            if key not in cluster_req_elems:
             print (cluster_req_json)
             #cluster_del_item=cluster_json_keys .keys()
             cluster_req_json.popitem(key, None)
    
       # Create the cluster, and store the mapping from old to new cluster ids
    
       #Create a temp file to store the current cluster info as JSON
       strCurrentClusterFile = "tmp_cluster_info.json"
    
       #delete the temp file if exists
       if os.path.exists(strCurrentClusterFile) :
          os.remove(strCurrentClusterFile)
    
       fClusterJSONtmp = open(strCurrentClusterFile,"w+")
       fClusterJSONtmp.write(json.dumps(cluster_req_json))
       fClusterJSONtmp.close()
    
       #cluster_create_out = check_output(["databricks", "clusters", "create", "--json", json.dumps(cluster_req_json), "--profile", IMPORT_PROFILE])
       cluster_create_out = check_output(["databricks", "clusters", "create", "--json-file", strCurrentClusterFile , "--profile", IMPORT_PROFILE])
       cluster_create_out_json = json.loads(cluster_create_out)
       cluster_old_new_mappings[cluster] = cluster_create_out_json['cluster_id']
    
       print ("Cluster create request sent to secondary site workspace successfully")
       print ("---------------------------------------------------------")
    
       #delete the temp file if exists
       if os.path.exists(strCurrentClusterFile) :
          os.remove(strCurrentClusterFile)
    
    print ("Cluster mappings: " + json.dumps(cluster_old_new_mappings))
    print ("All done")
    print ("P.S. : Please note that all the new clusters in your secondary site are being started now!")
    print ("       If you won't use those new clusters at the moment, please don't forget terminating your new clusters to avoid charges")
    
  6. Migrera jobbkonfigurationen

    Om du migrerade klusterkonfigurationer i föregående steg kan du välja att migrera jobbkonfigurationer till den nya arbetsytan. Det är ett helt automatiserat steg med databricks-cli, såvida du inte vill utföra selektiv jobbkonfigurationsmigrering i stället för att göra det för alla jobb.

    Kommentar

    Konfigurationen för ett schemalagt jobb innehåller även "schemainformationen", så som standard börjar det fungera enligt konfigurerad tidsinställning så snart det migreras. Därför tar följande kodblock bort all schemainformation under migreringen (för att undvika duplicerade körningar över gamla och nya arbetsytor). Konfigurera scheman för sådana jobb när du är redo för snabb användning.

    Jobbkonfigurationen kräver inställningar för ett nytt eller ett befintligt kluster. Om du använder ett befintligt kluster försöker skriptet /koden nedan ersätta det gamla kluster-ID:t med det nya kluster-ID:t.

    Kopiera och spara följande Python-skript i en fil. Ersätt värdet för old_cluster_id och new_cluster_idmed utdata från klustermigreringen som gjordes i föregående steg. Kör den på databricks-cli-kommandoraden, till exempel python scriptname.py.

    import sys
    import os
    import subprocess
    import json
    from subprocess import call, check_output
    
    
    EXPORT_PROFILE = "primary"
    IMPORT_PROFILE = "secondary"
    
    # Please replace the old to new cluster id mappings from cluster migration output
    cluster_old_new_mappings = {"0227-120427-tryst214": "0229-032632-paper88"}
    
    # Get all jobs info from old workspace
    try:
      jobs_out = check_output(["databricks", "jobs", "list", "--profile", EXPORT_PROFILE])
      jobs_info_list = jobs_out.splitlines()
    except:
      print("No jobs to migrate")
      sys.exit(0)
    
    # Create a list of all job ids
    jobs_list = []
    for jobs_info in jobs_info_list:
      jobs_list.append(jobs_info.split(None, 1)[0])
    
    # Optionally filter job ids out manually, so as to create only required ones in new workspace
    
    # Create each job in the new workspace based on corresponding settings in the old workspace
    
    for job in jobs_list:
      print("Trying to migrate ") + job
    
      job_get_out = check_output(["databricks", "jobs", "get", "--job-id", job, "--profile", EXPORT_PROFILE])
      print("Got job config from old workspace")
    
      job_req_json = json.loads(job_get_out)
      job_req_settings_json = job_req_json['settings']
    
      # Remove schedule information so job doesn't start before proper cutover
      job_req_settings_json.pop('schedule', None)
    
      # Replace old cluster id with new cluster id, if job configured to run against an existing cluster
      if 'existing_cluster_id' in job_req_settings_json:
        if job_req_settings_json['existing_cluster_id'] in cluster_old_new_mappings:
          job_req_settings_json['existing_cluster_id'] = cluster_old_new_mappings[job_req_settings_json['existing_cluster_id']]
        else:
          print("Mapping not available for old cluster id ") + job_req_settings_json['existing_cluster_id']
          continue
    
      call(["databricks", "jobs", "create", "--json", json.dumps(job_req_settings_json), "--profile", IMPORT_PROFILE])
      print("Sent job create request to new workspace successfully")
    
    print("All done")
    
  7. Migrera bibliotek

    Det finns för närvarande inget enkelt sätt att migrera bibliotek från en arbetsyta till en annan. Installera i stället om dessa bibliotek till den nya arbetsytan manuellt. Det är möjligt att automatisera med hjälp av en kombination av DBFS CLI för att ladda upp anpassade bibliotek till arbetsytan och BIBLIOTEK CLI.

  8. Migrera Azure Blob Storage och Azure Data Lake Storage-monteringar

    Montera om alla Monteringspunkter för Azure Blob Storage och Azure Data Lake Storage (Gen 2) manuellt med hjälp av en notebook-baserad lösning. Lagringsresurserna skulle ha monterats på den primära arbetsytan och det måste upprepas på den sekundära arbetsytan. Det finns inget externt API för monteringar.

  9. Migrera init-skript för kluster

    Alla klusterinitieringsskript kan migreras från gammal till ny arbetsyta med hjälp av DBFS CLI. Kopiera först de skript som behövs från dbfs:/dat abricks/init/.. till det lokala skrivbordet eller den virtuella datorn. Kopiera sedan skripten till den nya arbetsytan på samma sökväg.

    // Primary to local
    dbfs cp -r dbfs:/databricks/init ./old-ws-init-scripts --profile primary
    
    // Local to Secondary workspace
    dbfs cp -r old-ws-init-scripts dbfs:/databricks/init --profile secondary
    
  10. Konfigurera om och använd åtkomstkontrollen igen manuellt.

    Om din befintliga primära arbetsyta är konfigurerad för att använda Premium- eller Enterprise-nivån (SKU) är det troligt att du också använder funktionen Åtkomstkontroll.

    Om du använder funktionen Åtkomstkontroll kan du manuellt tillämpa åtkomstkontrollen på resurserna igen (notebook-filer, kluster, jobb, tabeller).

Haveriberedskap för ditt Azure-ekosystem

Om du använder andra Azure-tjänster bör du även implementera metodtips för haveriberedskap för dessa tjänster. Om du till exempel väljer att använda en extern Hive-metaarkivinstans bör du överväga haveriberedskap för Azure SQL Database, Azure HDInsight och/eller Azure Database for MySQL. Allmän information om haveriberedskap finns i Haveriberedskap för Azure-program.

Nästa steg

Mer information finns i Dokumentation om Azure Databricks.