Nous souhaitons améliorer les coûts d'exécution d'un pipeline Apache Beam spécifique (SDK Python) dans GCP Dataflow.

Nous avons construit un pipeline Apache Beam gourmand en mémoire, qui nécessite environ 8,5 Go de RAM pour être exécuté sur chaque exécuteur. Un grand modèle de machine learning est actuellement chargé dans une méthode de transformation DoFn.setup afin que nous puissions précalculer les recommandations pour quelques millions d'utilisateurs.

Les types de machines GCP Compute Engine existants ont soit un ratio mémoire / vCPU inférieur à ce dont nous avons besoin (jusqu'à 8 Go de RAM par processeur virtuel), soit une proportion beaucoup plus élevée (24 Go de RAM par processeur virtuel): https://cloud.google.com/compute/docs/machine-types#machine_type_comparison

Nous avons réussi à exécuter ce pipeline en utilisant le type de machine GCP m1-ultramem-40. Cependant, l'utilisation du matériel - et par conséquent, les coûts - étaient sous-optimaux. Ce type de machine a un ratio de 24 Go de RAM par processeur virtuel. Lors de son utilisation pour exécuter ledit pipeline, les VM utilisaient moins de 36% de la mémoire disponible - mais, comme prévu, nous avons tout payé.

Lors de la tentative d'exécution du même pipeline à l'aide d'un type de machine custom-2-13312 (2 vCPU et 13 Go de RAM), Dataflow s'est écrasé, avec l'erreur:

   Root cause: The worker lost contact with the service.

Lors de la surveillance des instances Compute Engine exécutant la tâche Dataflow, il était clair qu'elles manquaient de mémoire. Dataflow a essayé de charger le modèle en mémoire deux fois - une fois par processeur virtuel - mais la mémoire disponible était suffisante pour un seul.

Si nous pouvions informer Apache Beam / Dataflow qu'une transformation particulière nécessite une quantité spécifique de mémoire, le problème serait résolu. Mais nous n'avons pas réussi à trouver un moyen d'y parvenir.

L'autre solution à laquelle nous pourrions penser était d'essayer de modifier le ratio d'exécuteurs Dataflow par VM Compute Engine. Cela nous permettrait de trouver un ratio dans lequel nous gaspillerions le moins de vCPU possible tout en respectant les besoins en mémoire du pipeline. Lors de l'utilisation du type de machine custom-2-13312 mentionné précédemment, nous avons tenté d'exécuter le pipeline à l'aide des configurations suivantes:

  1. --number_of_worker_harness_threads=1 --experiments=use_runner_v2
  2. --experiments=no_use_multiple_sdk_containers --experiments=beam_fn_api
  3. --sdk_worker_parallelism=1

Lors de l'utilisation de (1), nous avons réussi à avoir un seul thread, mais Dataflow a engendré deux processus exécuteurs Python par VM. Cela a entraîné le crash du pipeline car il y avait une tentative de chargement du modèle en mémoire deux fois alors qu'il y avait suffisamment d'espace pour un seul.

Lors de l'utilisation de (2), un seul processus Python était généré par machine virtuelle, mais il s'exécutait en utilisant deux threads. Chacun de ces threads a essayé de charger le modèle et la machine virtuelle manque de mémoire. L'approche (3) a eu un résultat très similaire à (1) et (2).

Il n'a pas été possible de combiner plusieurs de ces configurations.

Y aurait-il un (ensemble de) configuration (s) qui nous permettrait de contrôler le nombre d'exécuteurs de Dataflow par VM?

Existe-t-il d'autres alternatives à la réduction des coûts que nous pourrions ne pas avoir?

6
Tatiana Al-Chueyr 2 sept. 2020 à 15:35

2 réponses

Meilleure réponse

Nous travaillons sur des solutions à long terme à ces problèmes, mais voici un correctif tactique qui devrait éviter la duplication du modèle que vous avez vue dans les approches 1 et 2:

Partagez le modèle dans une machine virtuelle entre les nœuds de calcul, pour éviter qu'il ne soit dupliqué dans chaque nœud de calcul. Utilisez l'utilitaire suivant (https: // github .com / apache / beam / blob / master / sdks / python / apache_beam / utils / shared.py), qui est disponible immédiatement dans Beam 2.24 Si vous utilisez une version antérieure de Beam, copiez uniquement shared.py dans votre projet et utilisez-le comme code utilisateur.

3
Sergei 9 sept. 2020 à 00:21

Je ne pense pas qu'en ce moment il y ait une option pour contrôler le nombre d'exécuteurs par VM, il semble que le plus proche que vous y arriviez soit en utilisant l'option (1) et en supposant un exécuteur Python par cœur.

Option 1)

--number_of_worker_harness_threads=1 --experiments=use_runner_v2

Pour compenser le ratio CPU-mem dont vous avez besoin, je vous suggère d'utiliser machines personnalisées avec mémoire étendue. Cette approche devrait être plus rentable.

Par exemple, le coût de l'exécution d'un seul exécuteur et d'un seul thread sur une machine n1-standard-4 (4 processeurs - 15 Go) sera environ 30% plus cher que d'exécuter la même charge de travail avec un custom-1-15360-ext ( 1 CPU - 15 Go) machine personnalisée.

2
Tlaquetzal 3 sept. 2020 à 22:34