Partager via


Conserver un modèle personnalisé servant des données dans le catalogue Unity

Important

Cette fonctionnalité est en version bêta. Il n’est pas automatiquement activé pour tous les clients et toutes les fonctionnalités sont susceptibles de changer. Pour demander l’accès, contactez votre équipe de compte Azure Databricks.

Découvrez comment configurer la télémétrie des points de terminaison pour conserver les journaux OpenTelemetry, les traces et les métriques de votre modèle personnalisé servant des points de terminaison dans des tables de catalogue Unity. Utilisez les données de télémétrie persistantes pour effectuer une analyse de cause racine, surveiller l’intégrité du point de terminaison et répondre aux exigences de conformité avec les requêtes SQL standard.

Exigences

  • Vous devez activer votre espace de travail pour Unity Catalog. Le stockage par défaut (Arclight) n’est pas pris en charge.

  • Vous devez disposer des autorisations USE CATALOG, USE SCHEMA, CREATE TABLE et MODIFY sur le catalogue et le schéma du catalogue Unity de destination où sont stockés les journaux.

  • Un modèle personnalisé existant servant un point de terminaison ou des autorisations pour en créer un.

  • Votre espace de travail doit se trouver dans une région prise en charge :

    • canadacentral
    • westus
    • westus2
    • southcentralus
    • eastus
    • eastus2
    • centralus
    • northcentralus
    • swedencentral
    • westeurope
    • northeurope
    • uksouth
    • australiaeast
    • southeastasia

Étape 1 : Instrumenter votre code de modèle

Ajoutez l’instrumentation à votre code de modèle pour capturer les données de télémétrie.

  1. Ajoutez la journalisation des applications à votre modèle. La télémétrie du point de terminaison capture automatiquement la sortie Python logging standard. Aucune instrumentation du Kit de développement logiciel (SDK) OpenTelemetry n’est requise pour la journalisation de base.

    import logging
    
    class MyCustomModel(mlflow.pyfunc.PythonModel):
        def predict(self, context, model_input):
            # This log will be persisted to the <prefix>_otel_logs table
            logging.warning("Received inference request")
    
            try:
                # Your model logic here
                result = model_input * 2
                return result
            except Exception as e:
                # Error logs are also captured with severity 'ERROR'
                logging.error(f"Inference failed: {e}")
                raise e
    

    Le niveau de journalisation racine est défini sur WARNING. Consultez Résolution des problèmes pour modifier le niveau de journalisation.

  2. (Facultatif) Instrumentez des métriques et des traces personnalisées avec OpenTelemetry. Pour capturer des métriques et des traces personnalisées au-delà de la journalisation de base, ajoutez l’instrumentation du SDK OpenTelemetry à votre modèle. Développez la section suivante pour obtenir un exemple complet qui montre comment créer des compteurs, des étendues d’enregistrement et attacher des attributs personnalisés.

    Icône carrée de crochets. Exemple : Métriques personnalisées, étendues et journalisation des modèles avec OpenTelemetry

    Note

    En raison des limitations de la sérialisation du modèle, vous devez écrire votre modèle dans un fichier distinct, avant la consignation pour éviter les erreurs, comme indiqué ci-dessous à l'aide de %%writefile return_input_model.py.

    %%writefile return_input_model.py
    import os
    
    import mlflow
    from opentelemetry.exporter.otlp.proto.http.metric_exporter import OTLPMetricExporter
    from opentelemetry.exporter.otlp.proto.http.trace_exporter import OTLPSpanExporter
    from opentelemetry.metrics import get_meter, set_meter_provider
    from opentelemetry.sdk.metrics import MeterProvider
    from opentelemetry.sdk.metrics.export import PeriodicExportingMetricReader
    from opentelemetry.sdk.resources import Resource
    from opentelemetry.sdk.trace import TracerProvider
    from opentelemetry.sdk.trace.export import BatchSpanProcessor
    from opentelemetry.trace import get_tracer, set_tracer_provider
    
    # highlight-start
    # ---- OTel initialization (per-worker) ----
    resource = Resource.create({
        "worker.pid": str(os.getpid()),
    })
    
    otlp_trace_exporter = OTLPSpanExporter()
    tracer_provider = TracerProvider(resource=resource)
    tracer_provider.add_span_processor(BatchSpanProcessor(otlp_trace_exporter))
    set_tracer_provider(tracer_provider)
    
    otlp_metric_exporter = OTLPMetricExporter()
    metric_reader = PeriodicExportingMetricReader(otlp_metric_exporter)
    meter_provider = MeterProvider(metric_readers=[metric_reader], resource=resource)
    set_meter_provider(meter_provider)
    
    _tracer = get_tracer(__name__)
    _meter = get_meter(__name__)
    _prediction_counter = _meter.create_counter(
        name="prediction_count",
        description="Number of predictions made",
        unit="1"
    )
    # highlight-end
    
    
    class ReturnInputModel(mlflow.pyfunc.PythonModel):
        def load_context(self, context):
            # highlight-start
            self.tracer = _tracer
            self.prediction_counter = _prediction_counter
            # highlight-end
    
        def predict(self, context, model_input):
            # highlight-next-line
            with self.tracer.start_as_current_span("ReturnInputModel.predict") as span:
                # highlight-next-line
                span.set_attribute("input_shape", str(model_input.shape))
                # highlight-next-line
                span.set_attribute("input_columns", str(list(model_input.columns)))
                # highlight-next-line
                self.prediction_counter.add(1)
                return model_input
    
    mlflow.models.set_model(ReturnInputModel())
    
  3. Journaliser et inscrire le modèle.

    import pandas as pd
    import mlflow
    from mlflow.models import infer_signature
    
    # Prepare tabular input/output for signature (pyfunc expects DataFrame)
    input_df = pd.DataFrame({"inputs": ["hello world"]})
    output_df = input_df.copy()  # model returns input unchanged
    
    # Log the model with OpenTelemetry dependencies (using code-based logging to avoid serialization issues)
    with mlflow.start_run():
        signature = infer_signature(input_df, output_df)
    
        model_info = mlflow.pyfunc.log_model(
            name="model",
            python_model="return_input_model.py",
            signature=signature,
            input_example=input_df,
            pip_requirements=[
                "mlflow==3.1",
                # highlight-next-line
                "opentelemetry-sdk",
                # highlight-next-line
                "opentelemetry-exporter-otlp-proto-http",
            ],
        )
    
    # Register with serverless optimized deployment environment packing
    # Use Unity Catalog name: catalog.schema.model_name
    registered = mlflow.register_model(
        model_info.model_uri,
        MODEL_NAME,
        env_pack="databricks_model_serving"
    )
    

Étape 2 : Préparer la destination du catalogue Unity

Avant de créer votre point de terminaison, vérifiez que vous disposez d’un catalogue et d’un schéma prêts à recevoir les données de télémétrie. Azure Databricks crée automatiquement les tables nécessaires dans ce schéma s’ils n’existent pas déjà.

  1. Dans l’Explorateur de catalogues, accédez au catalogue et au schéma que vous souhaitez utiliser (par exemple). my_catalog.observability

Étape 3 : Activer la télémétrie de point de terminaison

Vous pouvez activer la télémétrie lors de la création d’un point de terminaison ou l’ajouter à un point de terminaison existant.

Nouveau point de terminaison

Pour activer la télémétrie dans l’interface utilisateur :

  1. Accédez à Service dans la barre latérale gauche.
  2. Cliquez sur Créer un point de terminaison de service.
  3. Dans la section Télémétrie de point de terminaison (marquée préversion), développez les options de configuration.
  4. Emplacement du catalogue Unity : sélectionnez le catalogue de destination et le schéma préparés à l’étape 2.
  5. (Facultatif) Préfixe de table : entrez un préfixe pour les tables générées. S’il est laissé vide, il n’y a pas de préfixe. Les tables sont nommées <prefix>_otel_logs, <prefix>_otel_spanset <prefix>_otel_metrics.
  6. Terminez le reste de la configuration du point de terminaison (sélection du modèle, paramètres de calcul) et cliquez sur Créer.

Pour ce faire avec l’API :

Icône carrée de crochets. Activer la télémétrie à l’aide de l’API
curl -X POST -H "Authorization: Bearer <your-token>" \
https://<workspace-url>/api/2.0/serving-endpoints \
-d '{
  "name": "my-custom-logging-endpoint",
  "config": {
    "served_entities": [
      {
        "name": "my-model",
        "entity_name": "my-model",
        "entity_version": "1",
        "workload_size": "Small",
        "scale_to_zero_enabled": true
      }
    ],
    "telemetry_config": {
      "table_names": {
        "logs_table": "my_catalog.observability.custom_endpoint_logs",
        "metrics_table": "my_catalog.observability.custom_endpoint_metrics",
        "traces_table": "my_catalog.observability.custom_endpoint_spans"
      }
    }
  }
}'

Point de terminaison existant

Note

La mise à jour déclenche un nouveau déploiement. Les modifications prennent effet une fois le déploiement terminé.

Pour activer la télémétrie dans l’interface utilisateur :

  1. Dans la page d’affichage du point de terminaison, dans le volet droit, sous la section Télémétrie du point de terminaison , cliquez sur Ajouter.
  2. Emplacement du catalogue Unity : sélectionnez le catalogue de destination et le schéma préparés à l’étape 2.
  3. (Facultatif) Préfixe de table : entrez un préfixe pour les tables générées. S’il est laissé vide, il n’y a pas de préfixe. Les tables sont nommées <prefix>_otel_logs, <prefix>_otel_spanset <prefix>_otel_metrics.
  4. Cliquez sur Mettre à jour.

Étape 4 : Vérifier et interroger les données de télémétrie

Une fois que le point de terminaison a reçu le trafic, les flux de données de télémétrie s'écoulent vers les tables de catalogue Unity configurées.

  1. Accédez à l’Explorateur de catalogues ou à l’Éditeur SQL.

  2. Recherchez la table nommée <prefix>_otel_logs dans votre schéma configuré.

  3. Exécutez une requête pour vérifier que les données circulent :

    SELECT * FROM <catalog>.<schema>.<prefix>_otel_logs
    LIMIT 10;
    

Interroger les données de télémétrie

Les exemples suivants montrent les requêtes courantes.

Pour afficher le schéma complet d’une table de télémétrie, exécutez :

DESCRIBE TABLE <catalog>.<schema>.<prefix>_otel_logs;

Utilisez ces colonnes pour filtrer et mettre en corrélation les données de télémétrie :

  • timestamp
  • severity_text
  • body
  • trace_id
  • span_id
  • attributes — carte qui contient des métadonnées spécifiques à l’événement.

Vérifier les erreurs au cours de la dernière heure

SELECT
  timestamp,
  severity_text,
  body,
  attributes
FROM <catalog>.<schema>.<prefix>_otel_logs
WHERE
  severity_text = 'ERROR'
  AND timestamp > current_timestamp() - INTERVAL 1 HOUR
ORDER BY timestamp DESC;

Résolution des problèmes

Journaux non apparents dans la table : Le niveau de journalisation racine est par défaut réglé sur WARNING pour diminuer la surcharge. Pour capturer les journaux de gravité inférieure, modifiez le niveau dans votre code de modèle :

class MyModel(mlflow.pyfunc.PythonModel):
    def load_context(self, context):
        root = logging.getLogger()
        root.setLevel(logging.DEBUG)
        for handler in root.handlers:
            handler.setLevel(logging.DEBUG)

Limites

Les limites suivantes s’appliquent aux données de télémétrie de point de terminaison :

  • L’évolution du schéma sur la table cible n’est pas prise en charge.

  • Seules les tables Delta gérées sont prises en charge. Le stockage externe et le stockage par défaut Arclight ne sont pas pris en charge.

  • L’emplacement de la table doit se trouver dans la même région que votre espace de travail.

  • Seuls les noms de tables avec des lettres ASCII, des chiffres et des traits de soulignement sont pris en charge.

  • La recréation d’une table cible n’est pas prise en charge.

  • Seule la durabilité de la zone de disponibilité unique (single-az) est prise en charge.

  • La livraison est au moins une fois. Un accusé de réception du serveur signifie que l'enregistrement est présent dans la table Delta et est permanent.

  • Les enregistrements doivent être inférieurs à 10 Mo chacun.

  • Les demandes doivent être inférieures à 30 Mo chacune.

  • Les lignes de log doivent faire moins de 1 Mo chacune.

  • La latence de télémétrie se dégrade au-delà de 2500 QPS.

  • Les journaux d’activité apparaissent dans la table catalogue Unity quelques secondes après leur émission.