Notatka
Dostęp do tej strony wymaga autoryzacji. Może spróbować zalogować się lub zmienić katalogi.
Dostęp do tej strony wymaga autoryzacji. Możesz spróbować zmienić katalogi.
Rozproszony akcelerator do przechowywania w chmurze (DACS) udostępnia natywnego klienta Python do odczytu danych Azure Blob przez rozproszoną pamięć podręczną.
Ukończ Rozpocznij korzystanie z rozproszonego akceleratora do przechowywania w chmurze na AKS przed użyciem tego artykułu.
Zainstaluj natywny klient Pythona
Zainstaluj pakiet z PyPI w obrazie obciążenia roboczego:
python3 -m pip install "dacs-client==0.1.0"
Jeśli aktualizujesz istniejące obciążenie robocze, zaktualizuj pin pakietu w definicji budowania obrazu, odbuduj i wypchnij obraz, a następnie ponownie wdroż pody obciążenia roboczego z tym zaktualizowanym obrazem. Instalacja pakietu lokalnie nie aktualizuje działających kontenerów. Aby uzyskać polecenia budowania i wypychania obrazu, zobacz Dodaj klienta do obrazu obciążenia roboczego.
Pakiet wymaga Python 3.8 lub nowszego oraz środowiska Linux z glibc 2.35 lub nowszym. Zapewnia samowystarczalne manylinux_2_35 wheels dla x86-64 i arm64, w tym natywną bibliotekę i jej zależności bibliotek współdzielonych. Zależność azure-identity instaluje się automatycznie.
Quickstart korzysta z Python 3.12 na python:3.12-slim-bookworm z węzłami x86-64.
Sprawdź instalację wewnątrz kontenera obciążenia roboczego:
python3 -c "import importlib.metadata; import py_dacs_client; print(importlib.metadata.version('dacs-client'))"
Polecenie musi wypisać 0.1.0. Nazwa dystrybucji to dacs-client, ale import w Python to py_dacs_client.
Konfigurowanie klienta
Ustaw obie zmienne cache-discovery na każdym podzie korzystającym z rozproszonego akceleratora dla pamięci masowej w chmurze:
env:
- name: CACHE_DISCOVERY_URL
value: <discovery-service-hostname>
- name: CACHE_SERVER_PORT
value: "9065"
Important
Obie zmienne są wymagane. Jeśli brakuje jednego z nich, klient loguje się Cache not configured. Working in Remote Blob mode only. i bezpośrednio korzysta z Azure Blob Storage. Operacja może zakończyć się bez użycia pamięci podręcznej.
Użyj nazwy hosta usługi discovery dla swojego zasobu cache i przestrzeni nazw, na przykład cache-sample-discovery.<namespace>.svc.cluster.local, z portem 9065.
Skonfiguruj uwierzytelnianie obiektu Blob przed utworzeniem klienta. Poniższy przykład wykorzystuje zarządzaną tożsamość AKS kubelet poprzez usługę Instance Metadata Service (IMDS) węzła, a nie federowaną tożsamość obciążenia AKS. Ustaw AZURE_CLIENT_ID na identyfikator klienta tożsamości kubeleta:
env:
- name: AZURE_CLIENT_ID
value: <kubelet-identity-client-id>
- name: MSI_ENDPOINT
value: "http://169.254.169.254/metadata/identity/oauth2/token"
- name: MSI_SECRET
value: "required-nonempty-value"
Pod musi być w stanie uzyskać dostęp do IMDS. W tej konfiguracji klienta natywnego MSI_SECRET jest wymaganym niepustym znacznikiem zgodności, a nie prawdziwym sekretem ani poświadczeniem. Nie umieszczaj danych uwierzytelniających w tej wartości. Te ustawienia są specyficzne dla tej integracji; nie kopiuj ich do konfiguracji uwierzytelniania Run:ai.
Dla wnioskowania tylko do odczytu należy przypisać tożsamości kubeleta rolę Storage Blob Data Reader w zakresie kontenera modelu. Zobacz Przyznawanie dostępu do odczytu danych modelu. Używaj Storage Blob Data Contributor tylko wtedy, gdy aplikacja musi zapisywać dane. Osobne uprawnienia uploadującego do zapisu nie są potrzebne do odczytu w czasie działania.
Użyj tego kanonicznego formatu ścieżki:
az://<account>.blob.core.windows.net/<container>/<path>
Natywna warstwa odczytuje konfigurację, gdy tworzony jest pierwszy klient w procesie. Skonfiguruj środowisko i ustawienia klienta przed utworzeniem tego klienta. Późniejsi klienci nie zmieniają już obowiązującej konfiguracji natywnej.
Zrozumienie chybień pamięci podręcznej i jednoczesnych odczytów
Gdy wielu klientów żąda tych samych brakujących danych jednocześnie, każdy klient może niezależnie pobrać dane z Azure Blob Storage. Skoordynowana populacja zimnych cache'ów nie jest dostępna w tej wersji zapoznawczej.
Populacja pamięci podręcznej jest asynchroniczna. Odczyt może zakończyć się zanim dane będą dostępne z pamięci podręcznej, więc dwa natychmiastowe odczyty mogą chybić nawet wtedy, gdy zwrócone bajty się zgadzają.
Przed dużymi zsynchronizowanymi zdarzeniami skalowania wstępnie załaduj wybrane bloby modelu przez DACS przed rozpoczęciem replik inferencji. Postępuj zgodnie z instrukcjami w Pobierz z wyprzedzeniem dane modelu przed wdrożeniem, aby uzyskać dedykowany pod rozgrzewkowy, zapoznać się z poleceniami odczytu i zweryfikować wdrożenie.
Udany odczyt może pochodzić dzięki mechanizmowi awaryjnemu Azure Blob Storage. Aby sprawdzić, czy odczyty używają DACS:
- Przed przeczytaniem zapisz
cache_server_request_counter{request_type="Download",status="Success"}, zsumowane we wszystkich podach serwera pamięci podręcznej dla Twojego zasobu Cache. Wartości etykiet rozróżniają wielkość liter. - Odczytuj ten sam zakres blobów wielokrotnie, z opóźnieniem między odczytami. Quickstart używa pięciu odczytów odstępowanych co sekundę; ta sekwencja nie gwarantuje, że uzupełnianie danych zostało zakończone. Potwierdź, że liczba udanych pobrań serwera rośnie i że klient zgłasza trafienia do pamięci podręcznej. Sprawdź liczbę zwróconych bajtów i sumy kontrolne pod kątem integralności danych; sam krótszy czas wykonania nie jest dowodem na buforowanie.
- Koreluj metryki klienta i serwera za pomocą telemetrii Azure Blob, aby odróżnić ruch pamięci podręcznej od odczytów z origin oraz trybu awaryjnego.
Polecenia do zbierania metryk klienta i liczników serwera można znaleźć w artykule Verify the DACS request path.
Użyj natywnego klienta
Natywny klient zapewnia metody asynchroniczne oraz ich synchroniczne odpowiedniki. Odczytuje dane do wstępnie przydzielonych natywnych buforów. Ustaw MODEL_PATH na kanoniczną ścieżkę do az:// istniejącego fragmentu modelu przed uruchomieniem następującego przykładu, który odczytuje do pierwszych 4 MiB:
import asyncio
import os
from py_dacs_client.dacs_client import DACSCacheClient
from py_dacs_client.dacs_utils import BoundedBufferManager
async def main():
path = os.environ["MODEL_PATH"]
client = DACSCacheClient()
buffers = BoundedBufferManager(max_memory_limit=64 * 1024 * 1024)
try:
size = min(await client.get_file_size(path), 4 * 1024 * 1024)
if size == 0:
print("read 0 bytes")
return
buffer = await buffers.acquire_buffer(size)
try:
bytes_read = await client.read_blob(path, buffer, size, 0)
print(f"read {bytes_read} bytes")
finally:
await buffers.release_buffer(buffer)
finally:
await client.shutdown()
asyncio.run(main())
Do popularnych metod odczytu należą:
| Metoda asynchroniczna | Metoda synchroniczna | Description |
|---|---|---|
get_file_size(path) |
get_file_size_sync(path) |
Pobierz rozmiar bloba w bajtach. |
get_file_stat(path) |
get_file_stat_sync(path) |
Pobierz metadane pliku modelu. |
read_blob(path, buffer, size, offset) |
read_blob_sync(...) |
Odczytaj zakres bajtów do wcześniej przydzielonego bufora. |
list_dir(path) |
list_dir_sync(path) |
Wyświetl zawartość katalogu |
get_file_handle(path, flags) |
get_file_handle_sync(...) |
Otwórz dojście wielokrotnego użytku. |
release_file_handle(handle) |
release_file_handle_sync(handle) |
Zamknij uchwyt do ponownego użycia. |
shutdown() |
shutdown_sync() |
Zwolnij połączenia i wyemituj końcowe metryki. |
Metoda asynchroniczna list_dir(path) zwraca iterator; użyj async for, aby iterować po wpisach katalogu.
Używaj odczytów zakresu dla formatów modeli, które nie wymagają każdego bajtu. Rozproszony akcelerator pamięci masowej w chmurze przechowuje tylko te fragmenty obejmujące żądane zakresy.
Optymalizuj wydajność odczytu
Dostosuj współbieżność odczytu aplikacji i rozmiar żądanego zakresu bajtów razem. Najlepsze ustawienia zależą od wzorca dostępu, limitów CPU i pamięci pod, przepustowości sieci klienta i węzła podręcznego oraz tego, czy odczyty trafiają do pamięci podręcznej, czy są kierowane do Blob Storage w razie braku trafienia w pamięci podręcznej.
Używaj wartości z tej sekcji jako punktów wyjścia do benchmarków obciążenia, a nie gwarantowanych zaleceń dotyczących wydajności. Mierz ich wpływ na podstawie własnego obciążenia przed wdrożeniem zmian.
Dostosuj współbieżność
Współbieżność to liczba odczytów, które aplikacja utrzymuje w toku. Pętla oczekująca na każde read_blob wywołanie przed rozpoczęciem kolejnego jest sekwencyjna, nawet gdy korzysta z asynchronicznego API.
- Wykonuj niezależne odczyty zakresów bajtów lub obiektów blob równocześnie. Ogranicz liczbę aktywnych odczytów za pomocą
asyncio.Semaphorelub stałej liczby zadań roboczych. Nie twórz naraz zadania dla wszystkich zakresów dużego zbioru danych. - Zacznij od małego limitu, na przykład czterech równoczesnych odczytów, i porównaj go z ośmioma i szesnastoma. Zwiększać współbieżność tylko wtedy, gdy przepustowość się poprawia bez nieakceptowalnych opóźnień, zużycia pamięci, błędów czy dławienia.
- Natywny klient akceptuje
concurrent.futures.Executorza pomocą parametru konstruktoraexecutor. Aby wyraźnie kontrolować pulę wątków Python, przekażThreadPoolExecutor, na przykładDACSCacheClient(executor=ThreadPoolExecutor(max_workers=8)). Zachowaj referencję do executora, utrzymuj go aktywnym do zakończenia wszystkich odczytów, a następnie zamknij go po wywołaniuawait client.shutdown(). - Większa pula wątków nie sprawia, że sekwencyjne wywołania stają się współbieżne. Przypisz zadania aplikacji oraz wątków wykonawczych i używaj osobnego bufora dla każdego aktywnego odczytu.
Uwzględnij współbieżność we wszystkich procesach roboczych i podach. Zwiększenie współbieżności każdego podu podczas skalowania w poziomie może przeciążyć te same węzły pamięci podręcznej lub zwiększyć liczbę pobrań obiektów Blob przy chybieniach zimnej pamięci podręcznej.
Konfiguruj rozmiar fragmentu pamięci podręcznej
Ustaw SI_streamingChunkSize w bajtach w podach aplikacji, aby skonfigurować rozmiar fragmentu pamięci podręcznej. Na przykład poniższe ustawienie wykorzystuje bloki 3 MiB:
env:
- name: SI_streamingChunkSize
value: "3145728"
Ustaw tę zmienną przed utworzeniem pierwszego klienta w procesie. Po zmianie ponownie uruchom pody aplikacji.
Domyślny rozmiar fragmentu pamięci podręcznej to 32 MiB. Argument size do read_blob(path, buffer, size, offset) określa żądany przez aplikację zakres bajtów, a nie rozmiar fragmentu pamięci podręcznej.
| Wzorzec dostępu | Wytyczne dotyczące odczytu aplikacji |
|---|---|
| Duży model sekwencyjny odczytuje | Porównaj większe fragmenty pamięci podręcznej, żądane rozmiary zakresu oraz ograniczoną współbieżność. Zmień jedno ustawienie naraz. |
| Małe lub losowe odczyty | Żądaj tylko bajtów potrzebnych aplikacji. Użyj mniejszych fragmentów pamięci podręcznej, aby ograniczyć pobieranie danych spoza żądanego zakresu. |
| Pamięci podręczne z ograniczoną pojemnością | Mierz zapełnienie pamięci podręcznej i zachowanie wyparcia, zamiast szacować zużycie pamięci podręcznej wyłącznie na podstawie rozmiarów buforów do odczytu aplikacji. |
Aplikacja Budget odczytuje bufory oddzielnie od fragmentów pamięci podręcznej. Na przykład osiem równoczesnych żądań 4-MiB read_blob wymaga 32 MiB pojemności bufora odczytu aplikacji, niezależnie od skonfigurowanego rozmiaru fragmentu pamięci podręcznej. Zarezerwuj dodatkową pamięć poda na alokacje pamięci klienta natywnego, kolejkowe zadania, obiekty Python oraz przetwarzanie modeli. Pobieraj bufory dopiero po osiągnięciu limitu współbieżności i zwalniaj każdy bufor w bloku finally.
Warning
BoundedBufferManager(max_memory_limit=...) ogranicza pojemność bufora odczytu aplikacji, a nie całkowitą pamięć klienta ani natywnego buforowania wysyłania. W 0.1.0, domyślny budżet asynchronicznego bufora przesyłania natywnego klienta wynosi 400 GiB. Ten budżet nie jest prealokacją ani bezpiecznym limitem pamięci Podów. Duże odczyty z zimnego cache mogą wyczerpać zasoby mniejszego Poda. Dla obciążeń ograniczonych pamięcią testuj populację synchroniczną (SI_cacheEnableSyncUpload=true) lub ograniczony asynchroniczny budżet uploadu (SI_cacheMaxUploadBufferSizePerProcessGB). Ustaw te wartości przed utworzeniem pierwszego klienta i zaplanuj zasoby dla natywnych buforów oddzielnie od buforów odczytu aplikacji oraz przetwarzania modelu.
Zmierz przed podniesieniem limitów
- Ustal punkt odniesienia z ustalonym zbiorem danych, liczbą podów i limitami zasobów. Mierz przepustowość, opóźnienia odczytu, CPU, pamięć i wykorzystanie sieci.
- Testuj odczyty cold-cache i warm-cache osobno. Sprawdź
cache_server_request_counteri telemetrię Azure Blob, aby rozróżnić ruch pamięci podręcznej od awaryjnego przejścia do bezpośredniego dostępu do obiektu Blob. - Zmieniaj jedno ustawienie na raz: współbieżność, rozmiar odczytu aplikacji lub rozmiar fragmentu pamięci podręcznej. Utrzymuj spójność zestawu danych i innych ustawień podczas porównywania wyników.
- Przestań zwiększać ustawienie, gdy przepustowość przestaje rosnąć lub zwiększają się opóźnienia, obciążenie zasobów, błędy lub dławienie usługi Blob.
Informacje dotyczące pamięci podręcznej można znaleźć w artykule Monitorowanie akceleratora rozproszonego dla magazynu w chmurze.
Zarządzanie błędami
Wszystkie wyjątki DACS wynikają z DACSError:
from py_dacs_client import DACSError, DACSNotFoundError
try:
load_model_data()
except DACSNotFoundError:
handle_missing_model()
except DACSError as error:
handle_cache_or_storage_error(error)
| Exception | Meaning |
|---|---|
DACSNotFoundError |
Ścieżka lub katalog Blob nie istnieje. |
DACSExistsError |
Aplikacja próbuje zapisać do istniejącego blobu bez włączenia nadpisania. |
DACSAuthenticationError |
Brak poświadczeń lub są one nieprawidłowe. |
DACSPermissionError |
Tożsamość nie ma wymaganej roli Blob. |
DACSTimeoutError |
Upłynął limit czasu operacji pamięci podręcznej lub obiektu Blob |
DACSNetworkError |
Serwer cache lub endpoint Blob jest nieosiągalny. |
DACSInvalidInputError |
Ścieżka lub argument ma nieprawidłową postać. |
OperationNotSupportedError |
Żądane API nie zostało jeszcze zaimplementowane. |
Sterowanie rejestrowaniem
Klient ma osobne ustawienia rejestrowania dla warstw Python i natywnych. Ustaw obie zmienne, aby tłumić szczegółowe dane wyjściowe z obu warstw:
env:
- name: DACS_DATA_LOG_LEVEL
value: WARNING
- name: STORAGE_LOG_LEVEL
value: WARNING
Element DACS_DATA_LOG_LEVEL steruje logowaniem w Pythonie.
STORAGE_LOG_LEVEL steruje rejestrowaniem klientów natywnych.