Zarządzanie rozproszonym akceleratorem dla przechowywania w chmurze (podgląd)

Użyj tego artykułu, aby sprawdzić stan danych w chmurze (DACS), planować pojemność, wstępnie pobierać dane modelu, skalować serwery pamięci podręcznej oraz przygotować się do konserwacji. DACS przede wszystkim przyspiesza ładowanie modelu do wnioskowania, a także może przyspieszać powtarzające się odczyty zbiorów danych do treningu.

Przed rozpoczęciem

Ustaw DACS i zapamięt podręczny, stosując Rozpocznij pracę z rozproszonym akceleratorem do przechowywania w chmurze na AKS. Wykonaj następujące polecenia w powłoce Bash z kubectl skonfigurowanym dla klastra AKS.

Ustaw przestrzeń nazw i nazwę pamięci podręcznej, którymi chcesz zarządzać:

CACHE_NAMESPACE=<cache-namespace>
CACHE_NAME=<cache-name>

Sprawdź stan DACS

Wymień zasoby pamięci podręcznej i ich status:

kubectl get cache -A -o wide

Zdrowy zasób pamięci podręcznej ma następujące cechy:

  • Stan Ready to True.
  • Aktualna liczba serwerów odpowiada pożądanej liczbie serwerów.
  • Adres URL odkrywania jest wypełniany.
  • Każdy pod cache-server jest gotowy i zaplanowany na odpowiednim węźle NVMe.

Sprawdź zasób pamięci podręcznej i powiązane zdarzenia:

kubectl get cache "$CACHE_NAME" \
  --namespace "$CACHE_NAMESPACE" \
  -o yaml

kubectl get pods \
  --namespace "$CACHE_NAMESPACE" \
  --selector app=cacheserver \
  -o wide

kubectl get events \
  --namespace "$CACHE_NAMESPACE" \
  --sort-by='.lastTimestamp'

Planowanie pojemności

Dostosuj rozmiar pamięci podręcznej do aktywnego zbioru roboczego, a nie do całkowitego rozmiaru każdego modelu lub zbioru danych w Azure Blob Storage. Do wnioskowania uwzględnij modele ładowane podczas uruchamiania i skalowania. Do treningu uwzględniaj fragmenty zbiorów danych, które pracownicy wielokrotnie czytają w różnych epokach lub zadaniach. Uwzględnij rezerwę na nowe wersje modeli, zmiany w zbiorach danych i wyparcie.

Weźmy pod uwagę następujące dane wejściowe:

  • Aktywne bajty modelu lub zbioru danych pokrywają się z oczekiwaną wersją.
  • Liczba i rozmiar lokalnych dysków NVMe na jeden węzeł cache.
  • Liczba węzłów pamięci podręcznej i przepustowość ruchu wychodzącego sieci.
  • Liczba współbieżnych czytników inferencji lub procesów roboczych szkolenia.
  • Oczekiwany współczynnik warm-hit oraz współczynnik Blob-fallback.
  • Odporność na awarie przy wymianie węzła pamięci podręcznej.

Rozproszony akcelerator do przechowywania w chmurze obsługuje do 100 węzłów. Więcej serwerów pamięci podręcznej zwiększa łączną pojemność i może zwiększyć zagregowaną przepustowość wejściową do czytnika. Sieć klienta i klastra mogą stać się czynnikami ograniczającymi zanim przepustowość NVMe zostanie wyczerpana.

Note

Dane w pamięci podręcznej są ulotne i nie są replikowane w celu zapewnienia trwałości. Przechowywać autorytatywne pliki modeli i zestawy danych w Azure Blob Storage. DACS nie zapewnia trwałego przechowywania dla wyjść treningowych ani punktów kontrolnych.

Planuj z myślą o odczytach przy zimnej pamięci podręcznej

Nowe serwery cache uruchamiają się bez danych w pamięci podręcznej. Wymiana węzłów, usuwanie i konserwacja mogą również spowodować ponowny odczyt wcześniej buforowanych danych z Azure Blob Storage. Planuj wdrożenia i zdarzenia skalowania, aby jednoczesne odczyty na zimno nie przeciążyły konta magazynu ani sieci.

Po uruchomieniu obciążeń użyj wskaźników trafień cache-hit po stronie klienta oraz wzrostu licznika udanych żądań do serwera pamięci podręcznej, aby sprawdzić, czy odczyty korzystają z DACS. Same udane lub szybsze odczyty nie są dowodem na buforowanie, ponieważ klient może sięgnąć po Azure Blob Storage. Kroki weryfikacji znajdziesz w sekcji Verify the Request path (Weryfikacja ścieżki żądania DACS). Aby uzyskać bieżącą telemetrię, zobacz Monitor rozproszony akcelerator dla przechowywania w chmurze.

Wstępnie pobierz dane modelu przed wdrożeniem

Prefetch to opcjonalna optymalizacja na potrzeby zimnego uruchamiania i aktualizacji modeli. Odczytaj dane modelu przez DACS przed rozpoczęciem replik wnioskowania, aby ich pierwsze odczyty mogły korzystać ze współdzielonej pamięci podręcznej. Aplikacje nadal mogą odczytywać z Azure Blob Storage, gdy pamięć podręczna jest zimna; wstępne pobieranie nie jest wymagane dla poprawności.

Poniższy przykład wykorzystuje rozgrzewanie sterowane przez klienta: proces Python odczytuje każdy blob modelu przez klienta DACS. Nie wymaga to osobnego polecenia prefetch CLI.

Przygotuj zadanie rozgrzewkowe

  1. Potwierdź, że zasób cache jest gotowy i ma wystarczającą pojemność dla wybranych plików modelu. Przy aktualizacji modelu upewnij się, że podczas wdrażania jest miejsce zarówno na obecną, jak i nową wersję.
  2. Prześlij nowy model do odrębnej, wersjonowanej ścieżki Blob, takiej jak models/my-model/v2/. Zachowaj aktualną wersję dostępną, dopóki okres wdrożenia i wycofania nie dobiegnie końca.
  3. Zbuduj i wypchnij obraz klienta oraz przyznaj tożsamości kubelet dostęp do odczytu obiektów Blob zgodnie z opisem w quickstarcie. Dedykowany moduł w następnej sekcji korzysta z tego obrazu i tożsamości; nie korzysta z ukończonego modułu testowego z szybkiego startu.
  4. Użyj tej samej konfiguracji cache-chunk w kliencie rozgrzewki i czytnikach inferencji, także SI_streamingChunkSize jeśli ją nadpisujesz. Różne rozmiary chunków dają różne wpisy cache, więc ogrzewanie jednego układu nie ogrzewa innego. Zobacz Konfigurowanie rozmiaru fragmentu pamięci podręcznej.
  5. Wybierz każdy blob potrzebny do załadowania modelu, włącznie ze wszystkimi fragmentami wag. Na początku użyj niewielkiej liczby procesów roboczych używanych do wstępnego rozgrzania, aby ograniczyć ruch obiektów Blob.

Utwórz dedykowany pod do wstępnego pobierania

W tej samej sesji powłoki ustaw obraz zbudowany w szybkim starcie oraz identyfikator klienta zarządzanej tożsamości kubelet. Klaster musi być w stanie pobrać obraz kontenera. Pod pozostaje dostępny przez godzinę, żebyś mógł uruchomić i zweryfikować odczyty rozgrzewające; usuń go wcześniej po zakończeniu.

WORKLOAD_IMAGE=<registry-name>.azurecr.io/dacs-test:0.1.0
KUBELET_CLIENT_ID=<kubelet-managed-identity-client-id>
CLIENT_POD=dacs-prefetch
CACHE_DISCOVERY_URL=$(kubectl get cache "$CACHE_NAME" \
  --namespace "$CACHE_NAMESPACE" -o jsonpath='{.status.discoveryURL}')
CACHE_SERVER_PORT=$(kubectl get cache "$CACHE_NAME" \
  --namespace "$CACHE_NAMESPACE" -o jsonpath='{.spec.port}')

cat <<EOF | kubectl apply -f -
apiVersion: v1
kind: Pod
metadata:
  name: $CLIENT_POD
  namespace: $CACHE_NAMESPACE
spec:
  restartPolicy: Never
  activeDeadlineSeconds: 3600
  containers:
    - name: prefetch
      image: $WORKLOAD_IMAGE
      command: ["sleep", "3600"]
      env:
        - name: CACHE_DISCOVERY_URL
          value: "$CACHE_DISCOVERY_URL"
        - name: CACHE_SERVER_PORT
          value: "$CACHE_SERVER_PORT"
        - name: AZURE_CLIENT_ID
          value: "$KUBELET_CLIENT_ID"
        - name: MSI_ENDPOINT
          value: "http://169.254.169.254/metadata/identity/oauth2/token"
        - name: MSI_SECRET
          value: "required-nonempty-value"
        - name: DACS_CPU_CORES
          value: "2"
        - name: DACS_MEMORY_MB
          value: "512"
      resources:
        requests:
          cpu: "1"
          memory: 512Mi
        limits:
          cpu: "2"
          memory: 1Gi
EOF

kubectl wait --namespace "$CACHE_NAMESPACE" \
  --for=condition=Ready "pod/$CLIENT_POD" --timeout=5m

Jeśli readery inferencji nadpisują rozmiar chunku pamięci podręcznej, dodaj to samo ustawienie do tego podu przed jego utworzeniem. W modelach, które potrzebują więcej niż godzinę na rozgrzewanie i weryfikację, wydłuż zarówno czas uśpienia, jak i activeDeadlineSeconds przed wdrożeniem.

Odczytaj wybrane obiekty blob modelu

Ustaw pełne ścieżki obiektów blob do rozgrzania. Zastąp przykładowe ścieżki plikami modelu:

MODEL_BLOBS=(
  "az://<storage-account>.blob.core.windows.net/<container>/models/my-model/v2/model-00001.safetensors"
  "az://<storage-account>.blob.core.windows.net/<container>/models/my-model/v2/model-00002.safetensors"
)

kubectl exec --namespace "$CACHE_NAMESPACE" -i "$CLIENT_POD" -- \
  python3 - "${MODEL_BLOBS[@]}" <<'PY'
import asyncio
import os
import sys

from py_dacs_client.dacs_client import DACSCacheClient
from py_dacs_client.dacs_utils import BoundedBufferManager


async def main():
    for name in ("CACHE_DISCOVERY_URL", "CACHE_SERVER_PORT"):
        if not os.environ.get(name):
            raise RuntimeError(f"Set {name} in the client pod before warming data")
    client = DACSCacheClient()
    buffers = BoundedBufferManager(max_memory_limit=64 * 1024 * 1024)
    try:
        for path in sys.argv[1:]:
            size = await client.get_file_size(path)
            offset = 0
            while offset < size:
                length = min(4 * 1024 * 1024, size - offset)
                buffer = await buffers.acquire_buffer(length)
                try:
                    count = await client.read_blob(path, buffer, length, offset)
                    if count != length:
                        raise RuntimeError(
                            f"{path}: expected {length} bytes at {offset}, got {count}"
                        )
                finally:
                    await buffers.release_buffer(buffer)
                offset += count
            print(f"Read complete: {path} ({size} bytes)", flush=True)
    finally:
        await client.shutdown()


asyncio.run(main())
PY

Proces ten odczytuje każdy wymieniony blob w całości z ograniczonymi buforami. W przeciwieństwie do próbki z quickstartu, nie zatrzymuje się po pierwszych 4 MiB. Powtarzaj polecenie dla dodatkowych grup plików w razie potrzeby.

Zweryfikować rozgrzewanie i wprowadzić model

  1. Sprawdź, czy komenda zakończyła się pomyślnie dla każdego wybranego bloba. Niepowodzenie odczytu zatrzymuje przykład; rozwiąż błędy uwierzytelniania, łączności lub ścieżki Blob przed ponowną próbą.
  2. Powtórz odczyty i potwierdź trafienia pamięci podręcznej, używając Zweryfikuj ścieżkę żądania DACS. Same udane odczyty nie dowodzą, że dane znajdują się w pamięci podręcznej, a zapełnianie pamięci podręcznej może być nadal w toku po zakończeniu odczytu.
  3. Rozpocznij niewielką liczbę replik wnioskowania, używając tych samych wersjonowanych ścieżek Blob. Potwierdź, że ładowanie modelu się powiedzie i że odczyty korzystają z pamięci podręcznej przed skalowaniem.
  4. W przypadku aktualizacji ruch na nowy model przekieruj dopiero po przejściu kontroli stanu aplikacji. Zachowaj stary model dostępny do rollbacku.

Prefetch nie przypina danych ani nie gwarantuje, że pozostaną one w pamięci podręcznej. Usuwanie elementów z pamięci podręcznej, wymiana węzłów lub zmiany topologii pamięci podręcznej mogą wymagać kolejnego rozgrzewania. Monitoruj pojemność pamięci podręcznej i ruch Blob podczas wdrażania.

Po weryfikacji usuń dedykowany pod. To działanie nie usuwa danych zapisanych w pamięci podręcznej na serwerach DACS.

kubectl delete pod "$CLIENT_POD" --namespace "$CACHE_NAMESPACE"

Przykład Python uruchamia się przez kubectl exec, więc przechwytuj dane wyjściowe terminala, aby wykryć błędy odczytu i metryki zamykania. Główny sleep proces kapsuły nie emituje tych komunikatów.

Sprawdź konfigurację magazynu pamięci podręcznej

Zasób pamięci podręcznej określa liczbę serwerów pamięci podręcznej, pojemność każdego serwera, limity zasobów, selektor węzłów oraz ścieżkę danych cache. Sprawdź aktualną konfigurację przed zmianą pojemności:

kubectl get cache "$CACHE_NAME" \
  --namespace "$CACHE_NAMESPACE" \
  -o yaml

Dla konfiguracji ścieżki hosta używanej w szybkim starcie spec.storage.hostPath.nodeCacheFolderPath musi być zgodne z punktem montażu sprawdzonym podczas weryfikacji przygotowania NVMe. Ścieżka musi wskazywać na dedykowany lokalny magazyn NVMe, a nie na dysk systemu operacyjnego. Dla przykładu konfiguracji zobacz Provisioning the cache.

Skalowanie pamięci podręcznej

Dla statycznej konfiguracji skalowania używanej w quickstarcie zmieniaj spec.scaling.static.numServers w zasobie Cache, a nie w rozszerzeniu.

Zanim zwiększysz liczbę, dodaj wystarczającą liczbę uprawnionych węzłów NVMe do puli węzłów cache. Upewnij się, że nowe węzły mają wymaganą etykietę puli węzłów oraz że ich dostępna pojemność CPU, pamięci i dysku spełniają specyfikację Cache. Zarządzany dacs-prereq DaemonSet automatycznie przygotowuje NVMe na dopasowanych węzłach. Nie instaluj kolejnego wykresu zależności.

Sprawdź, czy DaemonSet ma pod Ready na każdym nowym węźle cache, zanim zwiększysz liczbę serwerów:

kubectl rollout status daemonset/dacs-prereq --namespace kube-system --timeout=10m
kubectl get pods --namespace kube-system \
  --selector app.kubernetes.io/name=dacs-prereq --output wide

Etykietuj tylko te węzły, których lokalne dyski NVMe są dedykowane dla DACS: konfiguracja wstępna może sformatować te dyski. Zachowaj etykiety w konfiguracji puli węzłów, aby przetrwały wymianę węzłów.

Ustaw pożądaną liczbę serwerów i zaktualizuj zasób Cache. Użyj dodatniej liczby całkowitej, która pasuje do kwalifikującej się puli węzłów:

DESIRED_SERVERS=3

kubectl patch cache "$CACHE_NAME" \
  --namespace "$CACHE_NAMESPACE" \
  --type merge \
  --patch "{\"spec\":{\"scaling\":{\"static\":{\"numServers\":$DESIRED_SERVERS}}}}"

Sprawdź liczbę serwerów pożądanych i aktualnych, aż będą zgodne, a następnie zweryfikuj gotowość i rozmieszczenie podów:

kubectl get cache "$CACHE_NAME" --namespace "$CACHE_NAMESPACE" -o wide

kubectl wait \
  --namespace "$CACHE_NAMESPACE" \
  --for=condition=Ready \
  "cache/$CACHE_NAME" \
  --timeout=10m

kubectl get pods \
  --namespace "$CACHE_NAMESPACE" \
  --selector app=cacheserver \
  -o wide

Lista podów obejmuje wszystkie serwery cache w przestrzeni nazw. Jeśli przestrzeń nazw zawiera wiele zasobów Cache, użyj referencji właściciela poda, aby zidentyfikować serwery dla pamięci podręcznej, którą zmieniasz. Przed kontynuacją potwierdź, że liczba serwerów odpowiada żądanej liczbie i że wszystkie serwery są gotowe na odpowiednich węzłach NVMe.

Aby przeskalować w dół, zmniejsz liczbę serwerów cache i poczekaj na uzgadnianie przed usunięciem węzłów kwalifikujących się do usunięcia. Planuj na wypadek chybień pamięci podręcznej i dodatkowego ruchu obiektów Blob, gdy utracone zostaną buforowane fragmenty.

Przygotuj się na ulepszenia

Przed zmianą wersji:

  1. Sprawdź wymagania kompatybilności docelowej wersji oraz obsługiwaną ścieżkę aktualizacji. Nie zakładaj, że dowolne wersje podglądowe obsługują uaktualnienia w miejscu.
  2. Zapisz status pamięci podręcznej, liczbę serwerów, pojemność, zarządzanego rozszerzenia currentVersion oraz wersje klienta obciążenia. Pobierz szczegóły rozszerzenia, wybierając Zweryfikuj rozszerzenie.
  3. Sprawdź kompatybilność między zainstalowanym wydaniem rozszerzenia, wymaganiami NVMe, konfiguracją pamięci podręcznej i klientami. Nowszy publiczny chart lub pakiet kliencki nie oznacza, że zarządzane rozszerzenie zostało zaktualizowane.
  4. Potwierdź, że autorytatywne pliki modeli i zestawy danych są dostępne w Azure Blob Storage.
  5. Zaplanuj aktualizację w okresie, gdy repopulacja cache nie przeciąży konta Bloba.

Zarządzaj cyklem życia controllera za pomocą rozszerzenia DACS i stosuj obsługiwaną procedurę aktualizacji dla docelowej wersji. Nie aktualizuj bezpośrednio bazowego wydania Helm rozszerzenia, nie instaluj innego kontrolera obok niego ani nie stosuj do DACS instrukcji aktualizacji sterownika woluminu trwałego. Planuj każdą migrację z istniejącej instalacji ręcznej osobno.

Po konserwacji potwierdź gotowość rozszerzenia i kontrolera, postępując zgodnie z Verify the extension, a następnie powtórz kontrole stanu pamięci podręcznej w tym artykule.

Nie polegaj na tym, że dane w pamięci podręcznej przetrwają aktualizację. Pozwalać na ponowne uzupełnienie danych z Azure Blob Storage przy kolejnych odczytach.

Usuń DACS

Usunięcie pamięci podręcznej nie usuwa plików modeli źródłowych ani zestawów danych w Azure Blob Storage. Zatrzymaj lub przekonfiguruj obciążenia zależne od pamięci podręcznej przed jej usunięciem.

Informacje o kolejności czyszczenia i poleceniach znajdują się w artykule Usuń rozproszony akcelerator dla magazynu w chmurze.

Następne kroki