Auf dieser Seite wird beschrieben, wie Sie die Bereitstellung des GKE Inference Gateways anpassen.
Diese Seite richtet sich an Netzwerkexperten, die für die Verwaltung der GKE-Infrastruktur verantwortlich sind, und an Plattformadministratoren, die KI-Arbeitslasten verwalten.
Um Inferenzarbeitslasten zu verwalten und zu optimieren, konfigurieren Sie die erweiterten Funktionen des GKE Inference Gateway.
Informationen zu den folgenden erweiterten Funktionen und deren Konfiguration:
- Wenn Sie die Model Armor-Integration verwenden möchten, konfigurieren Sie die Sicherheits- und Sicherheitsprüfungen für KI.
- Wenn Sie Messwerte und Dashboards für GKE Inference Gateway und Modellserver aufrufen und HTTP-Zugriffsprotokolle für detaillierte Informationen zu Anfragen und Antworten aktivieren möchten, konfigurieren Sie die Beobachtbarkeit.
- Wenn Sie Ihre GKE Inference Gateway-Bereitstellungen automatisch skalieren möchten, konfigurieren Sie die automatische Skalierung.
Sicherheits- und Risikoprüfungen für KI konfigurieren
Das GKE Inference Gateway lässt sich in Model Armor einbinden, um Sicherheitsprüfungen für Prompts und Antworten für Anwendungen durchzuführen, die Large Language Models (LLMs) verwenden. Diese Integration bietet eine zusätzliche Sicherheitsebene auf Infrastrukturebene, die die Sicherheitsmaßnahmen auf Anwendungsebene ergänzt. Dadurch wird die zentrale Anwendung von Richtlinien auf den gesamten LLM-Traffic ermöglicht.
Das folgende Diagramm zeigt die Integration von Model Armor mit dem GKE Inference Gateway in einem GKE-Cluster:

So konfigurieren Sie Sicherheitsprüfungen für KI:
Prüfen Sie, ob die folgenden Voraussetzungen erfüllt sind:
- Aktivieren Sie den Model Armor-Dienst in Ihrem Google Cloud -Projekt.
- Erstellen Sie die Model Armor-Vorlagen mit der Model Armor-Konsole, der Google Cloud CLI oder der API.
Sie müssen bereits eine Model Armor-Vorlage mit dem Namen
my-model-armor-template-name-id
erstellt haben.So konfigurieren Sie die
GCPTrafficExtension
:Speichern Sie das folgende Beispielmanifest als
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'
Ersetzen Sie Folgendes:
GATEWAY_NAME
: der Name des Gateways.MODEL_ARMOR_TEMPLATE_NAME
: der Name Ihrer Vorlage für die Modellabdeckung.
Die Datei
gcp-traffic-extension.yaml
enthält die folgenden Einstellungen:targetRefs
: Gibt das Gateway an, auf das diese Erweiterung angewendet wird.extensionChains
: definiert eine Kette von Erweiterungen, die auf den Traffic angewendet werden sollen.matchCondition
: definiert die Bedingungen, unter denen die Verlängerungen angewendet werden.extensions
: Hier werden die anzuwendenden Erweiterungen definiert.supportedEvents
: Gibt die Ereignisse an, bei denen die Erweiterung aufgerufen wird.timeout
: Gibt das Zeitlimit für die Verlängerung an.googleAPIServiceName
: Gibt den Dienstnamen für die Erweiterung an.metadata
: Gibt die Metadaten für die Erweiterung an, einschließlich derextensionPolicy
-Einstellungen und der Einstellungen für die Bereinigung von Prompts oder Antworten.
Wenden Sie das Beispielmanifest auf Ihren Cluster an:
kubectl apply -f `gcp-traffic-extension.yaml`
Nachdem Sie die Sicherheitsprüfungen für KI konfiguriert und in Ihr Gateway eingebunden haben, filtert Model Armor automatisch Prompts und Antworten anhand der definierten Regeln.
Beobachtbarkeit konfigurieren
Das GKE Inference Gateway bietet Einblicke in den Zustand, die Leistung und das Verhalten Ihrer Inferenzarbeitslasten. So können Sie Probleme erkennen und beheben, die Ressourcennutzung optimieren und die Zuverlässigkeit Ihrer Anwendungen sicherstellen.
Google Cloud bietet die folgenden Cloud Monitoring-Dashboards, die die Beobachtbarkeit von Inferenzen für das GKE-Inferenz-Gateway ermöglichen:
- GKE Inference Gateway-Dashboard: Bietet wichtige Messwerte für das LLM-Serving, z. B. Anfrage- und Tokendurchsatz, Latenz, Fehler und Cache-Auslastung für die
InferencePool
. Eine vollständige Liste der verfügbaren GKE Inference Gateway-Messwerte finden Sie unter Zugängliche Messwerte. - Modellserver-Dashboard: Bietet ein Dashboard für goldene Signale des Modellservers. So können Sie die Auslastung und Leistung der Modellserver wie
KVCache Utilization
undQueue length
im Blick behalten. So können Sie die Auslastung und Leistung der Modellserver im Blick behalten. - Load Balancer-Dashboard: Hier werden Messwerte vom Load Balancer angezeigt, z. B. Anfragen pro Sekunde, End-to-End-Anfrageausführungslatenz und Statuscodes für Anfragen und Antworten. Mit diesen Messwerten können Sie die Leistung der End-to-End-Anfrageauslieferung nachvollziehen und Fehler erkennen.
- Data Center GPU Manager-Messwerte (DCGM): Hier finden Sie Messwerte von NVIDIA-GPUs, z. B. zur Leistung und Auslastung von NVIDIA-GPUs. Sie können NVIDIA Data Center GPU Manager-Messwerte (DCGM) in Cloud Monitoring konfigurieren. Weitere Informationen finden Sie unter DCGM-Messwerte erfassen und ansehen.
GKE Inference Gateway-Dashboard aufrufen
So rufen Sie das GKE Inference Gateway-Dashboard auf:
Rufen Sie in der Google Cloud Console die Seite Monitoring auf.
Wählen Sie im Navigationsbereich die Option Dashboards aus.
Wählen Sie im Bereich Integrationen die Option GMP aus.
Suchen Sie auf der Seite Dashboard-Vorlagen für Cloud Monitoring nach „Gateway“.
Rufen Sie das GKE-Dashboard für Inferenz-Gateways auf.
Alternativ können Sie der Anleitung unter Monitoring-Dashboard folgen.
Dashboard zur Beobachtbarkeit des Modellservers konfigurieren
Wenn Sie Golden-Signale von jedem Modellserver erfassen und nachvollziehen möchten, was zur Leistung des GKE Inference Gateways beiträgt, können Sie die automatische Überwachung für Ihre Modellserver konfigurieren. Dazu gehören unter anderem folgende Modellserver:
So rufen Sie die Integrations-Dashboards auf:
- Messwerte von Ihrem Modellserver erfassen
Rufen Sie in der Google Cloud Console die Seite Monitoring auf.
Wählen Sie im Navigationsbereich die Option Dashboards aus.
Wählen Sie unter Integrationen die Option GMP aus. Die entsprechenden Integrations-Dashboards werden angezeigt.
Abbildung: Integrationsdashboards
Weitere Informationen finden Sie unter Überwachung für Anwendungen anpassen.
Load Balancer-Dashboard für die Observability konfigurieren
Wenn Sie den Application Load Balancer mit dem GKE-Inferenz-Gateway verwenden möchten, importieren Sie das Dashboard. Gehen Sie dazu so vor:
Erstellen Sie zum Erstellen des Load Balancer-Dashboards die folgende Datei und speichern Sie sie als
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" } } } } ] } }
Führen Sie den folgenden Befehl aus, um das Dashboard in Google Cloud Armor zu installieren:
gcloud monitoring dashboards create --project $PROJECT_ID --config-from-file=dashboard.json
Öffnen Sie in der Google Cloud Console die Seite Monitoring.
Wählen Sie im Navigationsmenü Dashboards aus.
Wählen Sie in der Liste der benutzerdefinierten Dashboards das Dashboard Inference Optimized Gateway (with L7LB) Prometheus Overview aus.
Im Abschnitt Externer Application Load Balancer werden die folgenden Load Balancing-Messwerte angezeigt:
- End-to-End-Anfragelatenz p99 (nach Code): Der 99. Perzentil der End-to-End-Anfragelatenz für Anfragen, die vom Load Balancer verarbeitet werden, aggregiert nach zurückgegebenem Statuscode.
- Anfrage(n) (nach Code): Die Anzahl der Anfragen, die vom Load Balancer verarbeitet werden, nach zurückgegebenem Statuscode zusammengefasst.
Logging für GKE Inference Gateway konfigurieren
Wenn Sie das Logging für das GKE Inference Gateway konfigurieren, erhalten Sie detaillierte Informationen zu Anfragen und Antworten. Das ist nützlich für die Fehlerbehebung, Prüfung und Leistungsanalyse. In HTTP-Zugriffsprotokollen werden alle Anfragen und Antworten erfasst, einschließlich Headern, Statuscodes und Zeitstempeln. Diese Detailebene kann Ihnen helfen, Probleme zu erkennen, Fehler zu finden und das Verhalten Ihrer Inferenzarbeitslasten zu verstehen.
Wenn Sie Logging für das GKE-Inference-Gateway konfigurieren möchten, aktivieren Sie die HTTP-Zugriffsprotokollierung für jedes Ihrer InferencePool
-Objekte.
Speichern Sie das folgende Beispielmanifest als
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
Ersetzen Sie Folgendes:
NAMESPACE_NAME
: der Name des Namespace, in dem IhreInferencePool
bereitgestellt wird.INFERENCE_POOL_NAME
ist der Name desInferencePool
.
Wenden Sie das Beispielmanifest auf Ihren Cluster an:
kubectl apply -f logging-backend-policy.yaml
Nach der Anwendung dieses Manifests aktiviert das GKE Inference Gateway HTTP-Zugriffsprotokolle für die angegebene InferencePool
. Sie können diese Logs in Cloud Logging aufrufen. Die Protokolle enthalten detaillierte Informationen zu jeder Anfrage und Antwort, z. B. die Anfrage-URL, Header, den Antwortstatuscode und die Latenz.
Autoscaling konfigurieren
Beim Autoscaling wird die Ressourcenzuweisung aufgrund von Lastschwankungen angepasst. So bleiben Leistung und Ressourceneffizienz erhalten, da Pods je nach Bedarf dynamisch hinzugefügt oder entfernt werden. Beim GKE-Inference-Gateway bedeutet das horizontales Autoscaling von Pods in jeder InferencePool
. Der horizontale Pod-Autoscaler (HPA) von GKE skaliert Pods automatisch anhand von Messwerten für Modellserver wie KVCache Utilization
. So kann der Inferenzdienst unterschiedliche Arbeitslasten und Abfragevolumen bewältigen und gleichzeitig die Ressourcennutzung effizient verwalten.
So konfigurieren Sie InferencePool
-Instanzen, damit sie basierend auf Messwerten, die vom GKE Inference Gateway generiert werden, automatisch skaliert werden:
Stellen Sie ein
PodMonitoring
-Objekt im Cluster bereit, um Messwerte zu erfassen, die vom GKE Inference Gateway generiert werden. Weitere Informationen finden Sie unter Observability konfigurieren.Stellen Sie den Stackdriver-Adapter für benutzerdefinierte Messwerte bereit, um der HPA Zugriff auf die Messwerte zu gewähren:
Speichern Sie das folgende Beispielmanifest als
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
Wenden Sie das Beispielmanifest auf Ihren Cluster an:
kubectl apply -f adapter_new_resource_model.yaml
Führen Sie den folgenden Befehl aus, um dem Adapter Berechtigungen zum Lesen von Messwerten aus dem Projekt zu erteilen:
$ 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
Ersetzen Sie
PROJECT_ID
durch Ihre Google Cloud Projekt-ID.Stellen Sie für jede
InferencePool
ein HPA bereit, das in etwa so aussieht: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
Ersetzen Sie Folgendes:
INFERENCE_POOL_NAME
ist der Name desInferencePool
.INFERENCE_POOL_NAMESPACE
: der Namespace desInferencePool
.CLUSTER_NAME
ist der Name des Clusters.MIN_REPLICAS
: die Mindestverfügbarkeit derInferencePool
(Basiskapazität). Der HPA hält diese Anzahl von Replikaten aufrecht, wenn die Auslastung unter dem HPA-Zielgrenzwert liegt. Bei hochverfügbaren Arbeitslasten muss dieser Wert über1
liegen, um die Verfügbarkeit bei Pod-Störungen aufrechtzuerhalten.MAX_REPLICAS
: Der Wert, der die Anzahl der Beschleuniger begrenzt, die den imInferencePool
gehosteten Arbeitslasten zugewiesen werden müssen. Die HPA erhöht die Anzahl der Replikate nicht über diesen Wert hinaus. Beobachten Sie während Spitzenzeiten den Wert des FeldsMAX_REPLICAS
, um sicherzustellen, dass die Arbeitslast skaliert werden kann, um die gewünschten Leistungsmerkmale zu erreichen.TARGET_VALUE
: der Wert, der das ausgewählte ZielKV-Cache Utilization
pro Modellserver darstellt. Dieser Wert liegt zwischen 0 und 100 und hängt stark vom Modellserver, vom Modell, vom Accelerator und von den Eigenschaften des eingehenden Traffics ab. Sie können diesen Zielwert experimentell durch Lasttests bestimmen und einen Graphen mit Durchsatz und Latenz aufzeichnen. Wählen Sie in der Grafik eine Kombination aus Durchsatz und Latenz aus und verwenden Sie den entsprechendenKV-Cache Utilization
-Wert als HPA-Ziel. Sie müssen diesen Wert optimieren und genau beobachten, um die gewünschten Preis-Leistungs-Ergebnisse zu erzielen. Sie können diesen Wert automatisch mithilfe der GKE-Empfehlungen für die Inferenz ermitteln.
Nächste Schritte
- Weitere Informationen zum GKE-Inference-Gateway
- Weitere Informationen zum Bereitstellen von GKE Inference Gateway
- Weitere Informationen zum Roll-out von GKE Inference Gateway
- Weitere Informationen zum Bereitstellen mit GKE Inference Gateway