Partilhar via


Persistir o modelo personalizado que serve dados para o Unity Catalog

Importante

Este recurso está em versão Beta. Não está ativado automaticamente para todos os clientes e a funcionalidade está sujeita a alterações. Para solicitar acesso, contacte a equipa da sua conta Azure Databricks.

Aprenda a configurar a telemetria dos endpoints para persistir os logs, rastres e métricas do OpenTelemetry desde o seu modelo personalizado que serve os endpoints para as tabelas do Unity Catalog. Utilize os dados de telemetria persistentes para realizar análise de causa raiz, monitorizar a saúde dos endpoints e cumprir os requisitos de conformidade com consultas SQL padrão.

Requisitos

  • Seu espaço de trabalho deve estar habilitado para o Catálogo Unity. O armazenamento padrão (Arclight) não é suportado.

  • Deve ter USE CATALOG, USE SCHEMA, CREATE TABLE, e MODIFY permissões no catálogo e esquema do Unity Catalog de destino onde os registos estão armazenados.

  • Um endpoint de serviço do modelo personalizado existente ou permissões para criar um.

  • O seu espaço de trabalho deve estar numa região suportada:

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

Passo 1: Instrumente o seu código de modelo

Adicione instrumentação ao seu código de modelo para captar telemetria.

  1. Adicione registo de aplicações ao seu modelo. A telemetria do ponto final capta automaticamente a saída padrão do Python logging. Não é necessária instrumentação OpenTelemetry SDK para registos básicos.

    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
    

    O nível de root logging é definido para WARNING. Consulte Resolução de Problemas para alterar o nível de registo.

  2. (Opcional) Instrumente métricas e traços personalizados com OpenTelemetry. Para capturar métricas e traços personalizados para além do registo básico, adicione instrumentação do SDK OpenTelemetry ao seu modelo. Expanda a secção seguinte para um exemplo completo que mostra como criar contadores, registar spans e anexar atributos personalizados.

    Ícone quadrado entre parênteses. Exemplo: métricas personalizadas, spans e registo de modelos com OpenTelemetry

    Observação

    Devido a limitações na serialização do modelo, deve escrever o seu modelo num ficheiro separado antes de fazer o log, para evitar erros, como mostrado abaixo usando %%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. Registe e regista o modelo.

    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"
    )
    

Passo 2: Preparar o destino do Catálogo Unity

Antes de criar o seu endpoint, certifique-se de que tem um catálogo e um esquema prontos para receber os dados de telemetria. O Azure Databricks cria automaticamente as tabelas necessárias neste esquema, caso ainda não existam.

  1. No Explorador de Catálogo, navegue até ao catálogo e ao esquema que pretende usar (por exemplo, my_catalog.observability).

Passo 3: Ativar a telemetria do endpoint

Podes ativar a telemetria ao criar um novo endpoint ou adicioná-lo a um já existente.

Novo ponto final

Para ativar a telemetria na interface:

  1. Navegue para Serviço na barra lateral esquerda.
  2. Clique em Criar terminal de serviço.
  3. Na secção Telemetria de Endpoints (marcada como Prévia), expanda as opções de configuração.
  4. Localização do Catálogo Unity: Selecione o Catálogo e o Esquema de destino preparados no passo 2.
  5. (Opcional) Prefixo de tabela: Introduza um prefixo para as tabelas geradas. Se ficar em branco, não há prefixo. As tabelas são chamadas <prefix>_otel_logs, <prefix>_otel_spans, e <prefix>_otel_metrics.
  6. Complete o resto da configuração do endpoint (seleção do modelo, definições de computação) e clique em Criar.

Para fazer isto com a API:

Ícone quadrado entre parênteses. Ativar a telemetria usando a 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"
      }
    }
  }
}'

Ponto final existente

Observação

A atualização desencadeia uma nova implementação. As alterações entram em vigor assim que a implantação termina.

Para ativar a telemetria na interface:

  1. Na página de visualização do endpoint, no painel do lado direito, na secção de telemetria do endpoint , clique em Adicionar.
  2. Localização do Catálogo Unity: Selecione o Catálogo e o Esquema de destino preparados no passo 2.
  3. (Opcional) Prefixo de tabela: Introduza um prefixo para as tabelas geradas. Se ficar em branco, não há prefixo. As tabelas são chamadas <prefix>_otel_logs, <prefix>_otel_spans, e <prefix>_otel_metrics.
  4. Clique em Atualizar.

Passo 4: Verificar e consultar dados de telemetria

Depois de o endpoint receber tráfego, os dados de telemetria fluem para as tabelas do Catálogo Unity configuradas.

  1. Vai ao Explorador de Catálogos ou ao Editor SQL.

  2. Localiza a tabela nomeada <prefix>_otel_logs no teu esquema configurado.

  3. Execute uma consulta para verificar se os dados estão a fluir:

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

Consultar dados de telemetria

Os exemplos seguintes mostram consultas comuns.

Para visualizar o esquema completo de qualquer tabela de telemetria, execute:

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

Use estas colunas para filtrar e correlacionar dados de telemetria:

  • timestamp
  • severity_text
  • body
  • trace_id
  • span_id
  • attributes — um mapa que contém metadados específicos de cada evento.

Verificar se há erros na última hora

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;

Troubleshooting

Os registos não aparecem na tabela: O nível de registo de raiz tem por padrão WARNING para reduzir a sobrecarga. Para capturar registos de menor gravidade, altere o nível no seu código de modelo:

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)

Limitações

Os seguintes limites aplicam-se à telemetria do ponto final:

  • A evolução de esquemas na tabela alvo não é suportada.

  • Apenas as tabelas Delta geridas são suportadas. O armazenamento externo e o armazenamento padrão do Arclight não são suportados.

  • A localização da mesa deve estar na mesma região do seu espaço de trabalho.

  • Apenas são suportados nomes de tabelas com letras, dígitos e sublinhados ASCII.

  • Não é suportado recriar uma tabela de alvo.

  • Apenas a durabilidade de zona de disponibilidade única (single-az) é suportada.

  • A entrega é garantida pelo menos uma vez. Um reconhecimento do servidor significa que o registo é duradouro e está na tabela Delta.

  • Os registos devem ter menos de 10 MB cada.

  • Os pedidos devem ter menos de 30 MB cada.

  • As linhas logarítmicas devem ter menos de 1 MB cada.

  • A latência de telemetria degrada-se para além de 2500 QPS.

  • Os registos aparecem na tabela do Catálogo Unity alguns segundos após serem emitidos.