Recuperação de desastres regionais para clusters do Azure Databricks

Este artigo descreve uma arquitetura de recuperação de desastres útil para clusters do Azure Databricks e as etapas para realizar esse design.

Arquitetura do Azure Databricks

Quando você cria um espaço de trabalho do Azure Databricks a partir do portal do Azure, um aplicativo gerenciado é implantado como um recurso do Azure em sua assinatura, na região do Azure escolhida (por exemplo, Oeste dos EUA). Este dispositivo é implementado numa Rede Virtual do Azure com um Grupo de Segurança de Rede e uma conta de Armazenamento do Azure, disponível na sua subscrição. A rede virtual fornece segurança de nível de perímetro para o espaço de trabalho Databricks e é protegida por meio do grupo de segurança de rede. Dentro do espaço de trabalho, você cria clusters Databricks fornecendo o tipo de VM de trabalho e driver e a versão de tempo de execução do Databricks. Os dados persistentes estão disponíveis na sua conta de armazenamento. Depois que o cluster é criado, você pode executar trabalhos por meio de blocos de anotações, APIs REST ou pontos de extremidade ODBC/JDBC, anexando-os a um cluster específico.

O plano de controle Databricks gerencia e monitora o ambiente de espaço de trabalho Databricks. Qualquer operação de gerenciamento, como criar cluster, será iniciada a partir do plano de controle. Todos os metadados, como trabalhos agendados, são armazenados em um Banco de Dados do Azure e os backups do banco de dados são replicados automaticamente geograficamente para regiões emparelhadas onde são implementados.

Databricks architecture

Uma das vantagens dessa arquitetura é que os usuários podem conectar o Azure Databricks a qualquer recurso de armazenamento em sua conta. Um benefício importante é que a computação (Azure Databricks) e o armazenamento podem ser dimensionados independentemente um do outro.

Como criar uma topologia regional de recuperação de desastres

Na descrição da arquitetura anterior, há vários componentes usados para um pipeline de Big Data com o Azure Databricks: Armazenamento do Azure, Banco de Dados do Azure e outras fontes de dados. O Azure Databricks é a computação para o pipeline de Big Data. É efêmero por natureza, o que significa que, enquanto seus dados ainda estão disponíveis no Armazenamento do Azure, a computação (cluster do Azure Databricks) pode ser encerrada para evitar pagar pela computação quando você não precisa dela. As fontes de computação (Azure Databricks) e armazenamento devem estar na mesma região para que os trabalhos não tenham alta latência.

Para criar sua própria topologia regional de recuperação de desastres, siga estes requisitos:

  1. Provisione vários espaços de trabalho do Azure Databricks em regiões separadas do Azure. Por exemplo, crie o espaço de trabalho principal do Azure Databricks no Leste dos EUA. Crie o espaço de trabalho secundário de recuperação de desastres do Azure Databricks em uma região separada, como West US. Para obter uma lista de regiões do Azure emparelhadas, consulte Replicação entre regiões. Para obter detalhes sobre as regiões do Azure Databricks, consulte Regiões suportadas.

  2. Use armazenamento com redundância geográfica. Por padrão, os dados associados ao Azure Databricks são armazenados no Armazenamento do Azure e os resultados dos trabalhos do Databricks são armazenados no Armazenamento de Blobs do Azure, para que os dados processados sejam duráveis e permaneçam altamente disponíveis após o término do cluster. O armazenamento de cluster e o armazenamento de tarefas estão localizados na mesma zona de disponibilidade. Para proteger contra indisponibilidade regional, os espaços de trabalho do Azure Databricks usam armazenamento com redundância geográfica por padrão. Com o armazenamento com redundância geográfica, os dados são replicados para uma região emparelhada do Azure. O Databricks recomenda que você mantenha o padrão de armazenamento com redundância geográfica, mas se precisar usar o armazenamento com redundância local, você pode definir storageAccountSkuName como no modelo ARM para o Standard_LRS espaço de trabalho.

  3. Depois que a região secundária for criada, você deverá migrar os usuários, pastas de usuário, blocos de anotações, configuração de cluster, configuração de trabalhos, bibliotecas, armazenamento, scripts de inicialização e reconfigurar o controle de acesso. Detalhes adicionais são descritos na seção a seguir.

Desastre regional

Para se preparar para desastres regionais, você precisa manter explicitamente outro conjunto de espaços de trabalho do Azure Databricks em uma região secundária. Consulte Recuperação de desastres.

Nossas ferramentas recomendadas para recuperação de desastres são principalmente Terraform (para replicação de infra) e Delta Deep Clone (para replicação de dados).

Passos de migração detalhados

  1. Configurar a interface de linha de comando Databricks no seu computador

    Este artigo mostra vários exemplos de código que usam a interface de linha de comando para a maioria das etapas automatizadas, já que é um wrapper fácil de usar na API REST do Azure Databricks.

    Antes de executar qualquer etapa de migração, instale o databricks-cli em seu computador desktop ou em uma máquina virtual onde você planeja fazer o trabalho. Para obter mais informações, consulte Instalar a CLI do Databricks

    pip install databricks-cli
    

    Nota

    Espera-se que todos os scripts python fornecidos neste artigo funcionem com Python 2.7+ < 3.x.

  2. Configure dois perfis.

    Configure um para o espaço de trabalho primário e outro para o espaço de trabalho secundário:

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

    Os blocos de código neste artigo alternam entre perfis em cada etapa subsequente usando o comando de espaço de trabalho correspondente. Certifique-se de que os nomes dos perfis criados sejam substituídos em cada bloco de código.

    EXPORT_PROFILE = "primary"
    IMPORT_PROFILE = "secondary"
    

    Você pode alternar manualmente na linha de comando, se necessário:

    databricks workspace ls --profile primary
    databricks workspace ls --profile secondary
    
  3. Migrar usuários do Microsoft Entra ID (anteriormente Azure Ative Directory)

    Adicione manualmente os mesmos usuários do Microsoft Entra ID (anteriormente Azure Ative Directory) ao espaço de trabalho secundário que existe no espaço de trabalho primário.

  4. Migrar as pastas de usuário e blocos de anotações

    Use o seguinte código python para migrar os ambientes de usuário em área restrita, que incluem a estrutura de pastas aninhadas e blocos de anotações por usuário.

    Nota

    As bibliotecas não são copiadas nesta etapa, pois a API subjacente não oferece suporte a elas.

    Copie e salve o seguinte script python em um arquivo e execute-o em sua linha de comando Databricks. Por exemplo, 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. Migrar as configurações de cluster

    Depois que os blocos de anotações forem migrados, você poderá, opcionalmente, migrar as configurações de cluster para o novo espaço de trabalho. É quase uma etapa totalmente automatizada usando databricks-cli, a menos que você queira fazer a migração seletiva de configuração de cluster em vez de para todos.

    Nota

    Infelizmente, não há nenhum ponto de extremidade de configuração de cluster de criação, e esse script tenta criar cada cluster imediatamente. Se não houver núcleos suficientes disponíveis na sua assinatura, a criação do cluster poderá falhar. A falha pode ser ignorada, desde que a configuração seja transferida com êxito.

    O script a seguir fornecido imprime um mapeamento de IDs de cluster antigas para novas, que podem ser usadas para migração de trabalho posteriormente (para trabalhos configurados para usar clusters existentes).

    Copie e salve o seguinte script python em um arquivo e execute-o em sua linha de comando Databricks. Por exemplo, 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. Migrar a configuração de trabalhos

    Se você migrou configurações de cluster na etapa anterior, pode optar por migrar configurações de trabalho para o novo espaço de trabalho. É uma etapa totalmente automatizada usando databricks-cli, a menos que você queira fazer a migração seletiva de configuração de trabalho em vez de fazê-lo para todos os trabalhos.

    Nota

    A configuração para um trabalho agendado também contém as informações de "agendamento", portanto, por padrão, começará a funcionar de acordo com o tempo configurado assim que for migrado. Assim, o bloco de código a seguir remove todas as informações de agendamento durante a migração (para evitar execuções duplicadas em espaços de trabalho antigos e novos). Configure as agendas para esses trabalhos assim que estiver pronto para a substituição.

    A configuração do trabalho requer definições para um cluster novo ou existente. Se estiver usando um cluster existente, o script /código abaixo tentará substituir o ID de cluster antigo pelo novo ID de cluster.

    Copie e salve o seguinte script python em um arquivo. Substitua o valor de e new_cluster_id, pela saída da migração de old_cluster_id cluster feita na etapa anterior. Execute-o na linha de comando databricks-cli, por exemplo, 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. Migrar bibliotecas

    Atualmente, não há uma maneira simples de migrar bibliotecas de um espaço de trabalho para outro. Em vez disso, reinstale essas bibliotecas no novo espaço de trabalho manualmente. É possível automatizar usando a combinação de DBFS CLI para carregar bibliotecas personalizadas para o espaço de trabalho e bibliotecas CLI.

  8. Migrar o armazenamento de blob do Azure e as montagens do Armazenamento do Azure Data Lake

    Remonte manualmente todos os pontos de montagem do armazenamento de Blob do Azure e do Armazenamento do Azure Data Lake (Gen 2) usando uma solução baseada em notebook. Os recursos de armazenamento teriam sido montados no espaço de trabalho primário e isso deve ser repetido no espaço de trabalho secundário. Não há API externa para montagens.

  9. Migrar scripts de inicialização de cluster

    Qualquer script de inicialização de cluster pode ser migrado do antigo para o novo espaço de trabalho usando a CLI DBFS. Primeiro, copie os scripts necessários para sua área de dbfs:/dat abricks/init/.. trabalho local ou máquina virtual. Em seguida, copie esses scripts para o novo espaço de trabalho no mesmo caminho.

    // 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. Reconfigure e reaplique manualmente o controle de acesso.

    Se o espaço de trabalho principal existente estiver configurado para usar a camada Premium ou Enterprise (SKU), é provável que você também esteja usando o recurso Controle de Acesso.

    Se você usar o recurso Controle de Acesso, reaplique manualmente o controle de acesso aos recursos (Blocos de Anotações, Clusters, Trabalhos, Tabelas).

Recuperação de desastres para seu ecossistema do Azure

Se você estiver usando outros serviços do Azure, certifique-se de implementar práticas recomendadas de recuperação de desastres para esses serviços também. Por exemplo, se você optar por usar uma instância externa do metastore do Hive, considere a recuperação de desastres para o Banco de Dados SQL do Azure, o Azure HDInsight e/ou o Banco de Dados do Azure para MySQL. Para obter informações gerais sobre recuperação de desastres, consulte Recuperação de desastres para aplicativos do Azure.

Próximos passos

Para obter mais informações, consulte a documentação do Azure Databricks.