Questa pagina descrive come personalizzare il deployment di GKE Inference Gateway.
Questa pagina è rivolta agli esperti di networking responsabili della gestione dell'infrastruttura GKE e agli amministratori della piattaforma che gestiscono i carichi di lavoro di IA.
Per gestire e ottimizzare i carichi di lavoro di inferenza, configura le funzionalità avanzate di GKE Inference Gateway.
Comprendi e configura le seguenti funzionalità avanzate:
- Per utilizzare l'integrazione di Model Armor, configura i controlli di sicurezza e affidabilità dell'IA.
- Per visualizzare le dashboard e le metriche di GKE Inference Gateway e del server del modello e per attivare il logging delle richieste HTTP per informazioni dettagliate su richieste e risposte, configura l'osservabilità.
- Per scalare automaticamente i deployment di GKE Inference Gateway, configura la scalabilità automatica.
Configurare i controlli di sicurezza e affidabilità dell'IA
GKE Inference Gateway si integra con Model Armor per eseguire controlli di sicurezza su prompt e risposte per le applicazioni che utilizzano modelli linguistici di grandi dimensioni (LLM). Questa integrazione fornisce un ulteriore livello di applicazione delle misure di sicurezza a livello di infrastruttura che integra le misure di sicurezza a livello di applicazione. In questo modo, è possibile applicare i criteri in modo centralizzato a tutto il traffico LLM.
Il seguente diagramma illustra l'integrazione di Model Armor con GKE Inference Gateway su un cluster GKE:

Per configurare i controlli di sicurezza dell'IA, svolgi i seguenti passaggi:
Assicurati che siano soddisfatti i seguenti prerequisiti:
- Abilita il servizio Model Armor nel tuo progetto Google Cloud .
- Crea i modelli di Model Armor utilizzando la console Model Armor, Google Cloud CLI o l'API.
Assicurati di aver già creato un modello Model Armor denominato
my-model-armor-template-name-id
.Per configurare
GCPTrafficExtension
, segui questi passaggi:Salva il seguente manifest di esempio come
gcp-traffic-extension.yaml
:kind: GCPTrafficExtension apiVersion: networking.gke.io/v1 metadata: name: my-model-armor-extension spec: targetRefs: - group: "gateway.networking.k8s.io" kind: Gateway name: GATEWAY_NAME extensionChains: - name: my-model-armor-chain1 matchCondition: celExpressions: - celMatcher: request.path.startsWith("/") extensions: - name: my-model-armor-service supportedEvents: - RequestHeaders timeout: 1s googleAPIServiceName: "modelarmor.us-central1.rep.googleapis.com" metadata: 'extensionPolicy': MODEL_ARMOR_TEMPLATE_NAME 'sanitizeUserPrompt': 'true' 'sanitizeUserResponse': 'true'
Sostituisci quanto segue:
GATEWAY_NAME
: il nome del gateway.MODEL_ARMOR_TEMPLATE_NAME
: il nome del tuo modello Model Armor.
Il file
gcp-traffic-extension.yaml
include le seguenti impostazioni:targetRefs
: specifica il gateway a cui si applica questa estensione.extensionChains
: definisce una catena di estensioni da applicare al traffico.matchCondition
: definisce le condizioni in cui vengono applicate le estensioni.extensions
: definisce le estensioni da applicare.supportedEvents
: specifica gli eventi durante i quali viene invocata l'estensione.timeout
: specifica il timeout per l'estensione.googleAPIServiceName
: specifica il nome del servizio per l'estensione.metadata
: specifica i metadati dell'estensione, tra cuiextensionPolicy
e le impostazioni di sanitizzazione della richiesta o della risposta.
Applica il manifest di esempio al cluster:
kubectl apply -f `gcp-traffic-extension.yaml`
Dopo aver configurato i controlli di sicurezza dell'IA e averli integrati con il tuo gateway, Model Armor filtra automaticamente i prompt e le risposte in base alle regole definite.
Configurare l'osservabilità
GKE Inference Gateway fornisce informazioni sullo stato di integrità, sulle prestazioni e sul comportamento dei carichi di lavoro di inferenza. In questo modo puoi identificare e risolvere i problemi, ottimizzare l'utilizzo delle risorse e garantire l'affidabilità delle tue applicazioni.
Google Cloud fornisce le seguenti dashboard di Cloud Monitoring che offrono l'osservabilità dell'inferenza per GKE Inference Gateway:
- Dashboard di GKE Inference Gateway: fornisce metriche standard per il servizio LLM, come throughput di richieste e token, latenza, errori e utilizzo della cache per il
InferencePool
. Per visualizzare l'elenco completo delle metriche di GKE Inference Gateway disponibili, consulta Metriche esposte. - Dashboard del server modello: fornisce una dashboard per gli indicatori aurei del server modello. In questo modo puoi monitorare il carico e le prestazioni dei server dei modelli, ad esempio
KVCache Utilization
eQueue length
. In questo modo puoi monitorare il carico e il rendimento dei server di modelli. - Dashboard del bilanciatore del carico: genera report sulle metriche del bilanciatore del carico, ad esempio richieste al secondo, latenza di elaborazione delle richieste end-to-end e codici di stato di richiesta/risposta. Queste metriche ti aiutano a comprendere il rendimento del servizio di gestione delle richieste end-to-end e a identificare gli errori.
- Metriche Data Center GPU Manager (DCGM): fornisce metriche delle GPU NVIDIA, ad esempio le prestazioni e l'utilizzo delle GPU NVIDIA. Puoi configurare le metriche di NVIDIA Data Center GPU Manager (DCGM) in Cloud Monitoring. Per ulteriori informazioni, consulta Raccogliere e visualizzare le metriche DCGM.
Visualizza la dashboard di GKE Inference Gateway
Per visualizzare la dashboard di GKE Inference Gateway, svolgi i seguenti passaggi:
Nella console Google Cloud, vai alla pagina Monitoring.
Nel riquadro di navigazione, seleziona Dashboard.
Nella sezione Integrazioni, seleziona GMP.
Nella pagina Modelli di dashboard di Cloud Monitoring, cerca "Gateway".
Visualizza la dashboard di GKE Inference Gateway.
In alternativa, puoi seguire le istruzioni riportate nella dashboard di monitoraggio.
Configurare la dashboard di osservabilità del server del modello
Per raccogliere indicatori standard da ciascun server di modelli e capire cosa contribuisce al rendimento di GKE Inference Gateway, puoi configurare il monitoraggio automatico per i server di modelli. Sono inclusi i server di modelli come:
Per visualizzare le dashboard di integrazione:
- Raccogli le metriche dal server del modello.
Nella console Google Cloud, vai alla pagina Monitoring.
Nel riquadro di navigazione, seleziona Dashboard.
In Integrations (Integrazioni), seleziona GMP. Vengono visualizzate le dashboard di integrazione corrispondenti.
Figura: dashboard di integrazione
Per ulteriori informazioni, consulta Personalizzare il monitoraggio per le applicazioni.
Configura la dashboard di osservabilità del bilanciatore del carico
Per utilizzare il bilanciatore del carico delle applicazioni con GKE Inference Gateway, importa la dashboard seguendo questi passaggi:
Per creare la dashboard del bilanciatore del carico, crea il seguente file e salvalo come
dashboard.json
:{ "displayName": "GKE Inference Gateway (Load Balancer) Prometheus Overview", "dashboardFilters": [ { "filterType": "RESOURCE_LABEL", "labelKey": "cluster", "templateVariable": "", "valueType": "STRING" }, { "filterType": "RESOURCE_LABEL", "labelKey": "location", "templateVariable": "", "valueType": "STRING" }, { "filterType": "RESOURCE_LABEL", "labelKey": "namespace", "templateVariable": "", "valueType": "STRING" }, { "filterType": "RESOURCE_LABEL", "labelKey": "forwarding_rule_name", "templateVariable": "", "valueType": "STRING" } ], "labels": {}, "mosaicLayout": { "columns": 48, "tiles": [ { "height": 8, "width": 48, "widget": { "title": "", "id": "", "text": { "content": "### Inferece Gateway Metrics\n\nPlease refer to the [official documentation](https://github.com/kubernetes-sigs/gateway-api-inference-extension/blob/main/site-src/guides/metrics.md) for more details of underlying metrics used in the dashboard.\n\n\n### External Application Load Balancer Metrics\n\nPlease refer to the [pubic page](/load-balancing/docs/metrics) for complete list of External Application Load Balancer metrics.\n\n### Model Server Metrics\n\nYou can redirect to the detail dashboard for model servers under the integration tab", "format": "MARKDOWN", "style": { "backgroundColor": "#FFFFFF", "fontSize": "FS_EXTRA_LARGE", "horizontalAlignment": "H_LEFT", "padding": "P_EXTRA_SMALL", "pointerLocation": "POINTER_LOCATION_UNSPECIFIED", "textColor": "#212121", "verticalAlignment": "V_TOP" } } } }, { "yPos": 8, "height": 4, "width": 48, "widget": { "title": "External Application Load Balancer", "id": "", "sectionHeader": { "dividerBelow": false, "subtitle": "" } } }, { "yPos": 12, "height": 15, "width": 24, "widget": { "title": "E2E Request Latency p99 (by code)", "id": "", "xyChart": { "chartOptions": { "displayHorizontal": false, "mode": "COLOR", "showLegend": false }, "dataSets": [ { "breakdowns": [], "dimensions": [], "legendTemplate": "", "measures": [], "plotType": "LINE", "targetAxis": "Y1", "timeSeriesQuery": { "outputFullDuration": false, "prometheusQuery": "histogram_quantile(0.99, sum by(le, response_code) (rate(loadbalancing_googleapis_com:https_external_regional_total_latencies_bucket{monitored_resource=\"http_external_regional_lb_rule\",forwarding_rule_name=~\".*inference-gateway.*\"}[1m])))", "unitOverride": "ms" } } ], "thresholds": [], "yAxis": { "label": "", "scale": "LINEAR" } } } }, { "yPos": 12, "height": 43, "width": 48, "widget": { "title": "Regional", "collapsibleGroup": { "collapsed": false }, "id": "" } }, { "yPos": 12, "xPos": 24, "height": 15, "width": 24, "widget": { "title": "E2E Request Latency p95 (by code)", "id": "", "xyChart": { "chartOptions": { "displayHorizontal": false, "mode": "COLOR", "showLegend": false }, "dataSets": [ { "breakdowns": [], "dimensions": [], "legendTemplate": "", "measures": [], "plotType": "LINE", "targetAxis": "Y1", "timeSeriesQuery": { "outputFullDuration": false, "prometheusQuery": "histogram_quantile(0.95, sum by(le, response_code) (rate(loadbalancing_googleapis_com:https_external_regional_total_latencies_bucket{monitored_resource=\"http_external_regional_lb_rule\",forwarding_rule_name=~\".*inference-gateway.*\"}[1m])))", "unitOverride": "ms" } } ], "thresholds": [], "yAxis": { "label": "", "scale": "LINEAR" } } } }, { "yPos": 27, "height": 15, "width": 24, "widget": { "title": "E2E Request Latency p90 (by code)", "id": "", "xyChart": { "chartOptions": { "displayHorizontal": false, "mode": "COLOR", "showLegend": false }, "dataSets": [ { "breakdowns": [], "dimensions": [], "legendTemplate": "", "measures": [], "plotType": "LINE", "targetAxis": "Y1", "timeSeriesQuery": { "outputFullDuration": false, "prometheusQuery": "histogram_quantile(0.90, sum by(le, response_code) (rate(loadbalancing_googleapis_com:https_external_regional_total_latencies_bucket{monitored_resource=\"http_external_regional_lb_rule\",forwarding_rule_name=~\".*inference-gateway.*\"}[1m])))", "unitOverride": "ms" } } ], "thresholds": [], "yAxis": { "label": "", "scale": "LINEAR" } } } }, { "yPos": 27, "xPos": 24, "height": 15, "width": 24, "widget": { "title": "E2E Request Latency p50 (by code)", "id": "", "xyChart": { "chartOptions": { "displayHorizontal": false, "mode": "COLOR", "showLegend": false }, "dataSets": [ { "breakdowns": [], "dimensions": [], "legendTemplate": "", "measures": [], "plotType": "LINE", "targetAxis": "Y1", "timeSeriesQuery": { "outputFullDuration": false, "prometheusQuery": "histogram_quantile(0.50, sum by(le, response_code) (rate(loadbalancing_googleapis_com:https_external_regional_total_latencies_bucket{monitored_resource=\"http_external_regional_lb_rule\",forwarding_rule_name=~\".*inference-gateway.*\"}[1m])))", "unitOverride": "ms" } } ], "thresholds": [], "yAxis": { "label": "", "scale": "LINEAR" } } } }, { "yPos": 42, "height": 13, "width": 48, "widget": { "title": "Request /s (by code)", "id": "", "xyChart": { "chartOptions": { "displayHorizontal": false, "mode": "COLOR", "showLegend": false }, "dataSets": [ { "breakdowns": [], "dimensions": [], "legendTemplate": "", "measures": [], "plotType": "LINE", "targetAxis": "Y1", "timeSeriesQuery": { "outputFullDuration": false, "prometheusQuery": "sum by (response_code)(rate(loadbalancing_googleapis_com:https_external_regional_request_count{monitored_resource=\"http_external_regional_lb_rule\", forwarding_rule_name=~\".*inference-gateway.*\"}[1m]))", "unitOverride": "" } } ], "thresholds": [], "yAxis": { "label": "", "scale": "LINEAR" } } } }, { "yPos": 55, "height": 4, "width": 48, "widget": { "title": "Inference Optimized Gateway", "id": "", "sectionHeader": { "dividerBelow": false, "subtitle": "" } } }, { "yPos": 59, "height": 17, "width": 48, "widget": { "title": "Request Latency", "id": "", "xyChart": { "chartOptions": { "displayHorizontal": false, "mode": "COLOR", "showLegend": false }, "dataSets": [ { "breakdowns": [], "dimensions": [], "legendTemplate": "p95", "measures": [], "plotType": "LINE", "targetAxis": "Y1", "timeSeriesQuery": { "outputFullDuration": false, "prometheusQuery": "histogram_quantile(0.95, sum by(le) (rate(inference_model_request_duration_seconds_bucket{}[${__interval}])))", "unitOverride": "s" } }, { "breakdowns": [], "dimensions": [], "legendTemplate": "p90", "measures": [], "plotType": "LINE", "targetAxis": "Y1", "timeSeriesQuery": { "outputFullDuration": false, "prometheusQuery": "histogram_quantile(0.9, sum by(le) (rate(inference_model_request_duration_seconds_bucket{}[${__interval}])))", "unitOverride": "s" } }, { "breakdowns": [], "dimensions": [], "legendTemplate": "p50", "measures": [], "plotType": "LINE", "targetAxis": "Y1", "timeSeriesQuery": { "outputFullDuration": false, "prometheusQuery": "histogram_quantile(0.5, sum by(le) (rate(inference_model_request_duration_seconds_bucket{}[${__interval}])))", "unitOverride": "s" } } ], "thresholds": [], "yAxis": { "label": "", "scale": "LINEAR" } } } }, { "yPos": 59, "height": 65, "width": 48, "widget": { "title": "Inference Model", "collapsibleGroup": { "collapsed": false }, "id": "" } }, { "yPos": 76, "height": 16, "width": 24, "widget": { "title": "Request / s", "id": "", "xyChart": { "chartOptions": { "displayHorizontal": false, "mode": "COLOR", "showLegend": false }, "dataSets": [ { "breakdowns": [], "dimensions": [], "legendTemplate": "", "measures": [], "plotType": "LINE", "targetAxis": "Y1", "timeSeriesQuery": { "outputFullDuration": false, "prometheusQuery": "sum by(model_name, target_model_name) (rate(inference_model_request_total{}[${__interval}]))", "unitOverride": "" } } ], "thresholds": [], "yAxis": { "label": "", "scale": "LINEAR" } } } }, { "yPos": 76, "xPos": 24, "height": 16, "width": 24, "widget": { "title": "Request Error / s", "id": "", "xyChart": { "chartOptions": { "displayHorizontal": false, "mode": "COLOR", "showLegend": false }, "dataSets": [ { "breakdowns": [], "dimensions": [], "legendTemplate": "", "measures": [], "plotType": "LINE", "targetAxis": "Y1", "timeSeriesQuery": { "outputFullDuration": false, "prometheusQuery": "sum by (error_code,model_name,target_model_name) (rate(inference_model_request_error_total[${__interval}]))", "unitOverride": "" } } ], "thresholds": [], "yAxis": { "label": "", "scale": "LINEAR" } } } }, { "yPos": 92, "height": 16, "width": 24, "widget": { "title": "Request Size", "id": "", "xyChart": { "chartOptions": { "displayHorizontal": false, "mode": "COLOR", "showLegend": false }, "dataSets": [ { "breakdowns": [], "dimensions": [], "legendTemplate": "p95", "measures": [], "plotType": "LINE", "targetAxis": "Y1", "timeSeriesQuery": { "outputFullDuration": false, "prometheusQuery": "histogram_quantile(0.95, sum by(le) (rate(inference_model_request_sizes_bucket{}[${__interval}])))", "unitOverride": "By" } }, { "breakdowns": [], "dimensions": [], "legendTemplate": "p90", "measures": [], "plotType": "LINE", "targetAxis": "Y1", "timeSeriesQuery": { "outputFullDuration": false, "prometheusQuery": "histogram_quantile(0.9, sum by(le) (rate(inference_model_request_sizes_bucket{}[${__interval}])))", "unitOverride": "By" } }, { "breakdowns": [], "dimensions": [], "legendTemplate": "p50", "measures": [], "plotType": "LINE", "targetAxis": "Y1", "timeSeriesQuery": { "outputFullDuration": false, "prometheusQuery": "histogram_quantile(0.5, sum by(le) (rate(inference_model_request_sizes_bucket{}[${__interval}])))", "unitOverride": "By" } } ], "thresholds": [], "yAxis": { "label": "", "scale": "LINEAR" } } } }, { "yPos": 92, "xPos": 24, "height": 16, "width": 24, "widget": { "title": "Response Size", "id": "", "xyChart": { "chartOptions": { "displayHorizontal": false, "mode": "COLOR", "showLegend": false }, "dataSets": [ { "breakdowns": [], "dimensions": [], "legendTemplate": "p95", "measures": [], "plotType": "LINE", "targetAxis": "Y1", "timeSeriesQuery": { "outputFullDuration": false, "prometheusQuery": "histogram_quantile(0.95, sum by(le) (rate(inference_model_response_sizes_bucket{}[${__interval}])))", "unitOverride": "By" } }, { "breakdowns": [], "dimensions": [], "legendTemplate": "p90", "measures": [], "plotType": "LINE", "targetAxis": "Y1", "timeSeriesQuery": { "outputFullDuration": false, "prometheusQuery": "histogram_quantile(0.9, sum by(le) (rate(inference_model_response_sizes_bucket{}[${__interval}])))", "unitOverride": "By" } }, { "breakdowns": [], "dimensions": [], "legendTemplate": "p50", "measures": [], "plotType": "LINE", "targetAxis": "Y1", "timeSeriesQuery": { "outputFullDuration": false, "prometheusQuery": "histogram_quantile(0.5, sum by(le) (rate(inference_model_response_sizes_bucket{}[${__interval}])))", "unitOverride": "By" } } ], "thresholds": [], "yAxis": { "label": "", "scale": "LINEAR" } } } }, { "yPos": 108, "height": 16, "width": 24, "widget": { "title": "Input Token Count", "id": "", "xyChart": { "chartOptions": { "displayHorizontal": false, "mode": "COLOR", "showLegend": false }, "dataSets": [ { "breakdowns": [], "dimensions": [], "legendTemplate": "p95", "measures": [], "plotType": "LINE", "targetAxis": "Y1", "timeSeriesQuery": { "outputFullDuration": false, "prometheusQuery": "histogram_quantile(0.95, sum by(le) (rate(inference_model_input_tokens_bucket{}[${__interval}])))", "unitOverride": "" } }, { "breakdowns": [], "dimensions": [], "legendTemplate": "p90", "measures": [], "plotType": "LINE", "targetAxis": "Y1", "timeSeriesQuery": { "outputFullDuration": false, "prometheusQuery": "histogram_quantile(0.9, sum by(le) (rate(inference_model_input_tokens_bucket{}[${__interval}])))", "unitOverride": "" } }, { "breakdowns": [], "dimensions": [], "legendTemplate": "p50", "measures": [], "plotType": "LINE", "targetAxis": "Y1", "timeSeriesQuery": { "outputFullDuration": false, "prometheusQuery": "histogram_quantile(0.5, sum by(le) (rate(inference_model_input_tokens_bucket{}[${__interval}])))", "unitOverride": "" } } ], "thresholds": [] } } }, { "yPos": 108, "xPos": 24, "height": 16, "width": 24, "widget": { "title": "Output Token Count", "id": "", "xyChart": { "chartOptions": { "displayHorizontal": false, "mode": "COLOR", "showLegend": false }, "dataSets": [ { "breakdowns": [], "dimensions": [], "legendTemplate": "p95", "measures": [], "plotType": "LINE", "targetAxis": "Y1", "timeSeriesQuery": { "outputFullDuration": false, "prometheusQuery": "histogram_quantile(0.95, sum by(le) (rate(inference_model_output_tokens_bucket{}[${__interval}])))", "unitOverride": "" } }, { "breakdowns": [], "dimensions": [], "legendTemplate": "p90", "measures": [], "plotType": "LINE", "targetAxis": "Y1", "timeSeriesQuery": { "outputFullDuration": false, "prometheusQuery": "histogram_quantile(0.9, sum by(le) (rate(inference_model_output_tokens_bucket{}[${__interval}])))", "unitOverride": "" } }, { "breakdowns": [], "dimensions": [], "legendTemplate": "p50", "measures": [], "plotType": "LINE", "targetAxis": "Y1", "timeSeriesQuery": { "outputFullDuration": false, "prometheusQuery": "histogram_quantile(0.5, sum by(le) (rate(inference_model_output_tokens_bucket{}[${__interval}])))", "unitOverride": "" } } ], "thresholds": [] } } }, { "yPos": 124, "height": 16, "width": 24, "widget": { "title": "Average KV Cache Utilization", "id": "", "xyChart": { "chartOptions": { "displayHorizontal": false, "mode": "COLOR", "showLegend": false }, "dataSets": [ { "breakdowns": [], "dimensions": [], "legendTemplate": "", "measures": [], "plotType": "LINE", "targetAxis": "Y1", "timeSeriesQuery": { "outputFullDuration": false, "prometheusQuery": "sum by (name)(avg_over_time(inference_pool_average_kv_cache_utilization[${__interval}]))*100", "unitOverride": "%" } } ], "thresholds": [], "yAxis": { "label": "", "scale": "LINEAR" } } } }, { "yPos": 124, "height": 16, "width": 48, "widget": { "title": "Inference Pool", "collapsibleGroup": { "collapsed": false }, "id": "" } }, { "yPos": 124, "xPos": 24, "height": 16, "width": 24, "widget": { "title": "Average Queue Size", "id": "", "xyChart": { "chartOptions": { "displayHorizontal": false, "mode": "COLOR", "showLegend": false }, "dataSets": [ { "breakdowns": [], "dimensions": [], "legendTemplate": "", "measures": [], "plotType": "LINE", "targetAxis": "Y1", "timeSeriesQuery": { "outputFullDuration": false, "prometheusQuery": "sum by (name) (avg_over_time(inference_pool_average_queue_size[${__interval}]))", "unitOverride": "" } } ], "thresholds": [], "yAxis": { "label": "", "scale": "LINEAR" } } } }, { "yPos": 140, "height": 4, "width": 48, "widget": { "title": "Model Server", "id": "", "sectionHeader": { "dividerBelow": true, "subtitle": "The following charts will only be populated if model server is exporting metrics." } } }, { "yPos": 144, "height": 32, "width": 48, "widget": { "title": "vLLM", "collapsibleGroup": { "collapsed": false }, "id": "" } }, { "yPos": 144, "xPos": 1, "height": 16, "width": 24, "widget": { "title": "Token Throughput", "id": "", "xyChart": { "chartOptions": { "displayHorizontal": false, "mode": "COLOR", "showLegend": false }, "dataSets": [ { "breakdowns": [], "dimensions": [], "legendTemplate": "Prompt Tokens/Sec", "measures": [], "plotType": "LINE", "targetAxis": "Y1", "timeSeriesQuery": { "outputFullDuration": false, "prometheusQuery": "sum by(model_name) (rate(vllm:prompt_tokens_total[${__interval}]))", "unitOverride": "" } }, { "breakdowns": [], "dimensions": [], "legendTemplate": "Generation Tokens/Sec", "measures": [], "plotType": "LINE", "targetAxis": "Y1", "timeSeriesQuery": { "outputFullDuration": false, "prometheusQuery": "sum by(model_name) (rate(vllm:generation_tokens_total[${__interval}]))", "unitOverride": "" } } ], "thresholds": [] } } }, { "yPos": 144, "xPos": 25, "height": 16, "width": 23, "widget": { "title": "Request Latency", "id": "", "xyChart": { "chartOptions": { "displayHorizontal": false, "mode": "COLOR", "showLegend": false }, "dataSets": [ { "breakdowns": [], "dimensions": [], "legendTemplate": "p95", "measures": [], "plotType": "LINE", "targetAxis": "Y1", "timeSeriesQuery": { "outputFullDuration": false, "prometheusQuery": "histogram_quantile(0.95, sum by(le) (rate(vllm:e2e_request_latency_seconds_bucket[${__interval}])))", "unitOverride": "s" } }, { "breakdowns": [], "dimensions": [], "legendTemplate": "p90", "measures": [], "plotType": "LINE", "targetAxis": "Y1", "timeSeriesQuery": { "outputFullDuration": false, "prometheusQuery": "histogram_quantile(0.9, sum by(le) (rate(vllm:e2e_request_latency_seconds_bucket[${__interval}])))", "unitOverride": "s" } }, { "breakdowns": [], "dimensions": [], "legendTemplate": "p50", "measures": [], "plotType": "LINE", "targetAxis": "Y1", "timeSeriesQuery": { "outputFullDuration": false, "prometheusQuery": "histogram_quantile(0.5, sum by(le) (rate(vllm:e2e_request_latency_seconds_bucket[${__interval}])))", "unitOverride": "s" } } ], "thresholds": [], "yAxis": { "label": "", "scale": "LINEAR" } } } }, { "yPos": 160, "xPos": 1, "height": 16, "width": 24, "widget": { "title": "Time Per Output Token Latency", "id": "", "xyChart": { "chartOptions": { "displayHorizontal": false, "mode": "COLOR", "showLegend": false }, "dataSets": [ { "breakdowns": [], "dimensions": [], "legendTemplate": "p95", "measures": [], "plotType": "LINE", "targetAxis": "Y1", "timeSeriesQuery": { "outputFullDuration": false, "prometheusQuery": "histogram_quantile(0.95, sum by(le) (rate(vllm:time_per_output_token_seconds_bucket[${__interval}])))", "unitOverride": "s" } }, { "breakdowns": [], "dimensions": [], "legendTemplate": "p90", "measures": [], "plotType": "LINE", "targetAxis": "Y1", "timeSeriesQuery": { "outputFullDuration": false, "prometheusQuery": "histogram_quantile(0.9, sum by(le) (rate(vllm:time_per_output_token_seconds_bucket[${__interval}])))", "unitOverride": "s" } }, { "breakdowns": [], "dimensions": [], "legendTemplate": "p50", "measures": [], "plotType": "LINE", "targetAxis": "Y1", "timeSeriesQuery": { "outputFullDuration": false, "prometheusQuery": "histogram_quantile(0.5, sum by(le) (rate(vllm:time_per_output_token_seconds_bucket[${__interval}])))", "unitOverride": "s" } } ], "thresholds": [], "yAxis": { "label": "", "scale": "LINEAR" } } } }, { "yPos": 160, "xPos": 25, "height": 16, "width": 23, "widget": { "title": "Time To First Token Latency", "id": "", "xyChart": { "chartOptions": { "displayHorizontal": false, "mode": "COLOR", "showLegend": false }, "dataSets": [ { "breakdowns": [], "dimensions": [], "legendTemplate": "p95", "measures": [], "plotType": "LINE", "targetAxis": "Y1", "timeSeriesQuery": { "outputFullDuration": false, "prometheusQuery": "histogram_quantile(0.95, sum by(le) (rate(vllm:time_to_first_token_seconds_bucket[${__interval}])))", "unitOverride": "s" } }, { "breakdowns": [], "dimensions": [], "legendTemplate": "p90", "measures": [], "plotType": "LINE", "targetAxis": "Y1", "timeSeriesQuery": { "outputFullDuration": false, "prometheusQuery": "histogram_quantile(0.9, sum by(le) (rate(vllm:time_to_first_token_seconds_bucket[${__interval}])))", "unitOverride": "s" } }, { "breakdowns": [], "dimensions": [], "legendTemplate": "p50", "measures": [], "plotType": "LINE", "targetAxis": "Y1", "timeSeriesQuery": { "outputFullDuration": false, "prometheusQuery": "histogram_quantile(0.5, sum by(le) (rate(vllm:time_to_first_token_seconds_bucket[${__interval}])))", "unitOverride": "s" } } ], "thresholds": [], "yAxis": { "label": "", "scale": "LINEAR" } } } } ] } }
Per installare la dashboard in Google Cloud Armor, esegui il comando seguente:
gcloud monitoring dashboards create --project $PROJECT_ID --config-from-file=dashboard.json
Apri la pagina Monitoraggio nella console Google Cloud.
Nel menu di navigazione, seleziona Dashboard.
Seleziona la dashboard Panoramica di Prometheus per gateway ottimizzato per l'inferenza (con L7LB) dall'elenco delle dashboard personalizzate.
La sezione Bilanciatore del carico delle applicazioni esterno mostra le seguenti metriche di bilanciamento del carico:
- Latenza richiesta E2E p99 (per codice): mostra il 99° percentile della latenza delle richieste end-to-end per le richieste gestite dal bilanciatore del carico, aggregata in base al codice di stato restituito.
- Richieste (per codice): mostra il numero di richieste gestite dal bilanciatore del carico, aggregate in base al codice di stato restituito.
Configurare il logging per GKE Inference Gateway
La configurazione della registrazione per GKE Inference Gateway fornisce informazioni dettagliate su richieste e risposte, utili per la risoluzione dei problemi, la verifica e l'analisi delle prestazioni. I log di accesso HTTP registrano ogni richiesta e risposta, incluse intestazioni, codici di stato e timestamp. Questo livello di dettaglio può aiutarti a identificare i problemi, trovare gli errori e comprendere il comportamento del tuo workload di inferenza.
Per configurare la registrazione per GKE Inference Gateway, abilita la registrazione degli accessi HTTP per ciascuno dei tuoi oggetti InferencePool
.
Salva il seguente manifest di esempio come
logging-backend-policy.yaml
:apiVersion: networking.gke.io/v1 kind: GCPBackendPolicy metadata: name: logging-backend-policy namespace: NAMESPACE_NAME spec: default: logging: enabled: true sampleRate: 500000 targetRef: group: inference.networking.x-k8s.io kind: InferencePool name: INFERENCE_POOL_NAME
Sostituisci quanto segue:
NAMESPACE_NAME
: il nome dello spazio dei nomi in cui è dipiegatoInferencePool
.INFERENCE_POOL_NAME
: il nome delInferencePool
.
Applica il manifest di esempio al cluster:
kubectl apply -f logging-backend-policy.yaml
Dopo aver applicato questo manifest, GKE Inference Gateway attiva i log di accesso HTTP per il InferencePool
specificato. Puoi visualizzare questi log in
Cloud Logging. I log includono informazioni dettagliate su ogni richiesta e risposta, ad esempio l'URL della richiesta, le intestazioni, il codice di stato della risposta e la latenza.
Configura scalabilità automatica
La scalabilità automatica regola l'allocazione delle risorse in risposta alle variazioni del carico, mantenendo le prestazioni e l'efficienza delle risorse aggiungendo o rimuovendo dinamicamente i pod in base alla domanda. Per GKE Inference Gateway, questo comporta la scalabilità automatica orizzontale dei pod in ogni InferencePool
. Horizontal Pod Autoscaler (HPA) di GKE scala automaticamente i pod in base alle metriche del server di modelli come KVCache Utilization
. In questo modo, il servizio di inferenza gestisce diversi carichi di lavoro e volumi di query, gestendo al contempo in modo efficiente l'utilizzo delle risorse.
Per configurare le istanze InferencePool
in modo che vengano scalate automaticamente in base alle metriche prodotte da GKE Inference Gateway, svolgi i seguenti passaggi:
Esegui il deployment di un oggetto
PodMonitoring
nel cluster per raccogliere le metriche prodotte da GKE Inference Gateway. Per ulteriori informazioni, consulta Configurare l'osservabilità.Esegui il deployment dell'adattatore Stackdriver delle metriche personalizzate per concedere all'HPA l'accesso alle metriche:
Salva il seguente manifest di esempio come
adapter_new_resource_model.yaml
:apiVersion: v1 kind: Namespace metadata: name: custom-metrics --- apiVersion: v1 kind: ServiceAccount metadata: name: custom-metrics-stackdriver-adapter namespace: custom-metrics --- apiVersion: rbac.authorization.k8s.io/v1 kind: ClusterRoleBinding metadata: name: custom-metrics:system:auth-delegator roleRef: apiGroup: rbac.authorization.k8s.io kind: ClusterRole name: system:auth-delegator subjects: - kind: ServiceAccount name: custom-metrics-stackdriver-adapter namespace: custom-metrics --- apiVersion: rbac.authorization.k8s.io/v1 kind: RoleBinding metadata: name: custom-metrics-auth-reader namespace: kube-system roleRef: apiGroup: rbac.authorization.k8s.io kind: Role name: extension-apiserver-authentication-reader subjects: - kind: ServiceAccount name: custom-metrics-stackdriver-adapter namespace: custom-metrics --- apiVersion: rbac.authorization.k8s.io/v1 kind: ClusterRole metadata: name: custom-metrics-resource-reader namespace: custom-metrics rules: - apiGroups: - "" resources: - pods - nodes - nodes/stats verbs: - get - list - watch --- apiVersion: rbac.authorization.k8s.io/v1 kind: ClusterRoleBinding metadata: name: custom-metrics-resource-reader roleRef: apiGroup: rbac.authorization.k8s.io kind: ClusterRole name: custom-metrics-resource-reader subjects: - kind: ServiceAccount name: custom-metrics-stackdriver-adapter namespace: custom-metrics --- apiVersion: apps/v1 kind: Deployment metadata: run: custom-metrics-stackdriver-adapter k8s-app: custom-metrics-stackdriver-adapter spec: replicas: 1 selector: matchLabels: run: custom-metrics-stackdriver-adapter k8s-app: custom-metrics-stackdriver-adapter template: metadata: labels: run: custom-metrics-stackdriver-adapter k8s-app: custom-metrics-stackdriver-adapter kubernetes.io/cluster-service: "true" spec: serviceAccountName: custom-metrics-stackdriver-adapter containers: - image: gcr.io/gke-release/custom-metrics-stackdriver-adapter:v0.15.2-gke.1 imagePullPolicy: Always name: pod-custom-metrics-stackdriver-adapter command: - /adapter - --use-new-resource-model=true - --fallback-for-container-metrics=true resources: limits: cpu: 250m memory: 200Mi requests: cpu: 250m memory: 200Mi --- apiVersion: v1 kind: Service metadata: labels: run: custom-metrics-stackdriver-adapter k8s-app: custom-metrics-stackdriver-adapter kubernetes.io/cluster-service: 'true' kubernetes.io/name: Adapter name: custom-metrics-stackdriver-adapter namespace: custom-metrics spec: ports: - port: 443 protocol: TCP targetPort: 443 selector: run: custom-metrics-stackdriver-adapter k8s-app: custom-metrics-stackdriver-adapter type: ClusterIP --- apiVersion: apiregistration.k8s.io/v1 kind: APIService metadata: name: v1beta1.custom.metrics.k8s.io spec: insecureSkipTLSVerify: true group: custom.metrics.k8s.io groupPriorityMinimum: 100 versionPriority: 100 service: name: custom-metrics-stackdriver-adapter namespace: custom-metrics version: v1beta1 --- apiVersion: apiregistration.k8s.io/v1 kind: APIService metadata: name: v1beta2.custom.metrics.k8s.io spec: insecureSkipTLSVerify: true group: custom.metrics.k8s.io groupPriorityMinimum: 100 versionPriority: 200 service: name: custom-metrics-stackdriver-adapter namespace: custom-metrics version: v1beta2 --- apiVersion: apiregistration.k8s.io/v1 kind: APIService metadata: name: v1beta1.external.metrics.k8s.io spec: insecureSkipTLSVerify: true group: external.metrics.k8s.io groupPriorityMinimum: 100 versionPriority: 100 service: name: custom-metrics-stackdriver-adapter namespace: custom-metrics version: v1beta1 --- apiVersion: rbac.authorization.k8s.io/v1 kind: ClusterRole metadata: name: external-metrics-reader rules: - apiGroups: - "external.metrics.k8s.io" resources: - "*" verbs: - list - get - watch --- apiVersion: rbac.authorization.k8s.io/v1 kind: ClusterRoleBinding metadata: name: external-metrics-reader roleRef: apiGroup: rbac.authorization.k8s.io kind: ClusterRole name: external-metrics-reader subjects: - kind: ServiceAccount name: horizontal-pod-autoscaler namespace: kube-system
Applica il manifest di esempio al cluster:
kubectl apply -f adapter_new_resource_model.yaml
Per concedere all'adattatore le autorizzazioni per leggere le metriche dal progetto, esegui il seguente comando:
$ PROJECT_ID=PROJECT_ID $ PROJECT_NUMBER=$(gcloud projects describe PROJECT_ID --format="value(projectNumber)") $ gcloud projects add-iam-policy-binding projects/PROJECT_ID \ --role roles/monitoring.viewer \ --member=principal://iam.googleapis.com/projects/PROJECT_NUMBER/locations/global/workloadIdentityPools/$PROJECT_ID.svc.id.goog/subject/ns/custom-metrics/sa/custom-metrics-stackdriver-adapter
Sostituisci
PROJECT_ID
con il tuo Google Cloud ID progetto.Per ogni
InferencePool
, esegui il deployment di un'HPA simile alla seguente:apiVersion: autoscaling/v2 kind: HorizontalPodAutoscaler metadata: name: INFERENCE_POOL_NAME namespace: INFERENCE_POOL_NAMESPACE spec: scaleTargetRef: apiVersion: apps/v1 kind: Deployment name: INFERENCE_POOL_NAME minReplicas: MIN_REPLICAS maxReplicas: MAX_REPLICAS metrics: - type: External external: metric: name: prometheus.googleapis.com|inference_pool_average_kv_cache_utilization|gauge selector: matchLabels: metric.labels.name: INFERENCE_POOL_NAME resource.labels.cluster: CLUSTER_NAME resource.labels.namespace: INFERENCE_POOL_NAMESPACE target: type: AverageValue averageValue: TARGET_VALUE
Sostituisci quanto segue:
INFERENCE_POOL_NAME
: il nome delInferencePool
.INFERENCE_POOL_NAMESPACE
: lo spazio dei nomi diInferencePool
.CLUSTER_NAME
: il nome del cluster.MIN_REPLICAS
: la disponibilità minima delInferencePool
(capacità di base). L'HPA mantiene attivo questo numero di repliche quando l'utilizzo è inferiore alla soglia target dell'HPA. I carichi di lavoro ad alta disponibilità devono impostare questo valore su un valore superiore a1
per garantire la disponibilità continua durante le interruzioni dei pod.MAX_REPLICAS
: il valore che limita il numero di acceleratori da assegnare ai workload ospitati nelInferencePool
. L'HPA non aumenterà il numero di repliche oltre questo valore. Durante i periodi di picco del traffico, monitora il numero di repliche per assicurarti che il valore del campoMAX_REPLICAS
fornisca un margine sufficiente per consentire l'aumento del carico di lavoro in modo da mantenere le caratteristiche di prestazioni del carico di lavoro scelto.TARGET_VALUE
: il valore che rappresenta il target sceltoKV-Cache Utilization
per ogni server di modelli. Si tratta di un numero compreso tra 0 e 100 ed è molto dipendente dal server del modello, dal modello, dall'acceleratore e dalle caratteristiche del traffico in entrata. Puoi determinare questo valore target sperimentalmente tramite test di carico e tracciando un grafico del throughput rispetto alla latenza. Seleziona una combinazione di throughput e latenza scelta dal grafico e usa il valoreKV-Cache Utilization
corrispondente come target HPA. Devi ottimizzare e monitorare attentamente questo valore per ottenere i risultati in termini di prezzo e prestazioni che hai scelto. Puoi utilizzare i consigli di inferenza GKE per determinare automaticamente questo valore.
Passaggi successivi
- Scopri di più su GKE Inference Gateway.
- Scopri di più sul deployment di GKE Inference Gateway.
- Scopri di più sulle operazioni di implementazione di GKE Inference Gateway.
- Scopri di più sul hosting con GKE Inference Gateway.