Nota
O acesso a esta página requer autorização. Pode tentar iniciar sessão ou alterar os diretórios.
O acesso a esta página requer autorização. Pode tentar alterar os diretórios.
O acelerador distribuído para armazenamento na nuvem (DACS) fornece um cliente Python nativo para ler dados do Azure Blob através da cache distribuída.
Conclua Introdução ao acelerador distribuído para armazenamento na nuvem no AKS antes de utilizar este artigo.
Instale o cliente Python nativo
Instale o pacote do PyPI na imagem da sua carga de trabalho:
python3 -m pip install "dacs-client==0.1.0"
Se estiveres a atualizar um workload existente, atualiza o pin do pacote na definição da build da imagem, reconstrói e envia a imagem, e reimplementa os pods do workload com a imagem atualizada. Instalar o pacote localmente não atualiza os contentores em execução. Para comandos de build e push de imagem, veja Adicionar o cliente a uma imagem de workload.
O pacote requer Python 3.8 ou mais recente e um ambiente Linux com glibc 2.35 ou mais recente. Fornece wheels autónomas manylinux_2_35 para x86-64 e arm64, incluindo a biblioteca nativa e as suas dependências de bibliotecas partilhadas. A dependência azure-identity é instalada automaticamente.
O quickstart usa Python 3.12 em python:3.12-slim-bookworm com nós x86-64.
Verifique a instalação dentro do contentor da workload:
python3 -c "import importlib.metadata; import py_dacs_client; print(importlib.metadata.version('dacs-client'))"
O comando deve imprimir 0.1.0. O nome da distribuição é dacs-client, mas o nome de importação em Python é py_dacs_client.
Configurar o cliente
Defina ambas as variáveis de descoberta de cache em cada pod que utilize acelerador distribuído para armazenamento na cloud:
env:
- name: CACHE_DISCOVERY_URL
value: <discovery-service-hostname>
- name: CACHE_SERVER_PORT
value: "9065"
Importante
Ambas as variáveis são necessárias. Se algum deles estiver em falta, o cliente regista no registo Cache not configured. Working in Remote Blob mode only. e acede diretamente ao Armazenamento de Blobs do Azure. A operação pode ter sucesso sem usar o cache.
Utilize o nome de anfitrião do serviço de deteção para o seu recurso Cache e espaço de nomes, por exemplo, cache-sample-discovery.<namespace>.svc.cluster.local, com a porta 9065.
Configure a autenticação por Blob antes de criar o cliente. O exemplo seguinte utiliza a identidade gerida do kubelet do AKS através do Serviço de Metadados de Instância (IMDS) do nó, e não a identidade federada da carga de trabalho do AKS. Defina AZURE_CLIENT_ID como o ID do cliente da identidade do kubelet:
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"
O Pod tem de conseguir chegar ao IMDS. Para esta configuração cliente nativo, MSI_SECRET é um marcador de compatibilidade não vazio obrigatório, não um segredo ou credencial real. Não coloques credenciais nesse campo. Estas definições são específicas para esta integração; não as copie para a configuração de autenticação do Run:ai.
Para inferência apenas de leitura, conceda à identidade do kubelet o papel Storage Blob Data Reader com o âmbito do contentor do modelo. Ver Conceder acesso de leitura aos dados do modelo. Utilize Storage Blob Data Contributor apenas quando a aplicação tiver de escrever dados. Não é necessária a permissão de escrita de um uploader separado para leituras em tempo de execução.
Use este formato de caminho canónico:
az://<account>.blob.core.windows.net/<container>/<path>
A camada nativa lê a configuração quando o primeiro cliente é criado num processo. Configure o ambiente e as definições do cliente antes de criar esse cliente. Os clientes posteriores não alteram a configuração nativa já em vigor.
Compreender as falhas na cache e as leituras simultâneas
Quando vários clientes solicitam os mesmos dados em falta ao mesmo tempo, cada cliente pode recuperar os dados de forma independente do Armazenamento de Blobs do Azure. A população coordenada de cold-cache não está disponível nesta pré-visualização.
A população da cache é assíncrona. Uma leitura pode terminar antes de os seus dados estarem disponíveis na cache, pelo que duas leituras imediatas podem resultar em cache miss mesmo quando os bytes devolvidos coincidem.
Antes de grandes eventos em escala sincronizada, aqueça os blobs de modelo selecionados através do DACS antes de iniciar réplicas de inferência. Consulte Pré-carregar dados do modelo antes da implantação para um pod de aquecimento dedicado, comandos de leitura e verificação da implantação.
Uma leitura bem-sucedida pode resultar do mecanismo de contingência do Armazenamento de Blobs do Azure. Para verificar que as leituras usam DACS:
- Antes da leitura, regista
cache_server_request_counter{request_type="Download",status="Success"}, somado por todos os pods do servidor de cache para o teu recurso de Cache. Os valores do rótulo diferenciam maiúsculas de minúsculas. - Lê repetidamente o mesmo intervalo de blobs com um atraso entre leituras. O quickstart usa cinco leituras espaçadas por um segundo; esta sequência não garante que a população tenha terminado. Confirme que o número de downloads bem-sucedidos do servidor aumente e que o cliente reporta os acertos na cache. Verifique as contagens de bytes retornados e as somas de verificação para a integridade dos dados; o tempo mais rápido por si só não é prova de cache.
- Correlacione métricas de cliente e servidor com telemetria Azure Blob para distinguir o tráfego de cache das leituras de origem e do fallback.
Para comandos para recolher métricas do cliente e contadores do servidor, consulte Verificar o caminho do pedido DACS.
Use o cliente nativo
O cliente nativo fornece métodos assíncronos e as respetivas versões síncronas. Lê para buffers nativos pré-alocados. Defina MODEL_PATH para o caminho canónico az:// de um fragmento de modelo existente antes de executar o seguinte exemplo, que lê até aos primeiros 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())
Métodos comuns de leitura incluem:
| Método assíncrono | Método síncrono | Description |
|---|---|---|
get_file_size(path) |
get_file_size_sync(path) |
Obtém o tamanho, em bytes, do blob. |
get_file_stat(path) |
get_file_stat_sync(path) |
Obtenha metadados do ficheiro de modelo. |
read_blob(path, buffer, size, offset) |
read_blob_sync(...) |
Leia um intervalo de bytes num buffer pré-alocado. |
list_dir(path) |
list_dir_sync(path) |
Liste as entradas do diretório. |
get_file_handle(path, flags) |
get_file_handle_sync(...) |
Abra um manípulo reutilizável. |
release_file_handle(handle) |
release_file_handle_sync(handle) |
Feche um identificador reutilizável. |
shutdown() |
shutdown_sync() |
Liberte as ligações e emita métricas finais. |
O método assíncrono list_dir(path) devolve um iterador; use async for para consumir entradas de diretório.
Use leituras por intervalo para formatos de modelo que não precisem de todos os bytes. O acelerador distribuído para armazenamento na cloud armazena apenas os blocos que cobrem os intervalos solicitados.
Otimizar o desempenho de leitura
Ajuste em conjunto a concorrência de leitura da aplicação e o tamanho do intervalo de bytes solicitado. As melhores definições dependem do teu padrão de acesso, limites de CPU e memória do pod, largura de banda da rede do cliente e do nó de cache, e se as leituras atingem a cache ou recorrem ao Armazenamento de Blobs.
Utilize os valores desta secção como pontos de partida para benchmarks de carga de trabalho, não como recomendações de desempenho garantido. Mede o efeito deles com a tua própria carga de trabalho antes de implementares as alterações.
Ajustar concorrência
A concorrência é o número de leituras que a sua aplicação mantém em curso. Um ciclo que aguarda cada chamada read_blob antes de iniciar a seguinte é sequencial, mesmo quando utiliza a API assíncrona.
- Emitir leituras independentes de intervalo de bytes ou blob em simultâneo. Limite o número de leituras ativas com um
asyncio.Semaphoreou um número fixo de tarefas de processamento. Não crie uma tarefa para cada intervalo de um grande conjunto de dados de uma só vez. - Comece com um limite pequeno, como quatro leituras simultâneas, e compare com oito e dezasseis. Aumentar a concorrência apenas enquanto o débito melhora, sem latência, uso de memória, erros ou limitação inaceitáveis.
- O cliente nativo aceita um
concurrent.futures.Executoratravés do seuexecutorparâmetro construtor. Para controlar explicitamente o pool de threads Python, passe umThreadPoolExecutor, por exemplo,DACSCacheClient(executor=ThreadPoolExecutor(max_workers=8)). Manter uma referência ao executor, mantê-la ativa até todas as leituras terminarem e desligá-la após chamarawait client.shutdown(). - Um pool de threads maior não torna chamadas sequenciais concorrentes. Vincule tarefas de aplicação, bem como workers do executor, e use um buffer separado para cada leitura ativa.
Tenha em conta a concorrência em todos os processos de trabalho e pods. Aumentar a concorrência de cada pod durante um scale-out pode sobrecarregar os mesmos nós de cache ou aumentar downloads duplicados de Blob em falhas de cold cache.
Configurar o tamanho do bloco de cache
Defina SI_streamingChunkSize, em bytes, nos pods de aplicação para configurar o tamanho do bloco da cache. Por exemplo, a configuração seguinte usa blocos de 3 MiB:
env:
- name: SI_streamingChunkSize
value: "3145728"
Defina esta variável antes de criar o primeiro cliente num processo em execução. Reinicie os pods da aplicação depois de fazer alterações.
O tamanho padrão do bloco de cache é de 32 MiB. O argumento size de read_blob(path, buffer, size, offset) especifica o intervalo de bytes solicitado pela aplicação, não o tamanho do bloco da cache.
| Padrão de acesso | Orientações para leitura da aplicação |
|---|---|
| Leituras de um grande modelo sequencial | Compare blocos de cache maiores, tamanhos de intervalo solicitados e concorrência com limite. Altere uma definição de cada vez. |
| Leituras pequenas ou aleatórias | Solicite apenas os bytes de que a aplicação precisa. Compare blocos de cache mais pequenos para reduzir os dados obtidos fora do intervalo solicitado. |
| Caches com capacidade limitada | Meça o comportamento de ocupação e expulsão do cache em vez de estimar o uso do cache apenas com o tamanho do buffer de leitura da aplicação. |
A aplicação Budget lê buffers separadamente dos blocos de cache. Por exemplo, oito pedidos simultâneos de 4 MiB read_blob requerem 32 MiB de capacidade de buffer de leitura da aplicação, independentemente do tamanho configurado do bloco de cache. Reserve memória pod adicional para alocações nativas do cliente, trabalho em fila, objetos Python e processamento de modelos. Adquira buffers apenas após atingir o limite de concorrência e liberte cada buffer num bloco finally.
Warning
BoundedBufferManager(max_memory_limit=...) limita a capacidade do buffer de leitura da aplicação, não a memória total do cliente ou o buffer nativo de upload. Em 0.1.0, o orçamento padrão do buffer de upload assíncrono do cliente nativo é de 400 GiB. Este orçamento não é uma pré-alocação nem um limite seguro de memória Pod. Grandes leituras de cold cache podem esgotar um Pod mais pequeno. Para cargas de trabalho com restrições de memória, teste o preenchimento síncrono (SI_cacheEnableSyncUpload=true) ou um orçamento de upload assíncrono limitado (SI_cacheMaxUploadBufferSizePerProcessGB). Defina estes valores antes de criar o primeiro cliente e orçamente buffers nativos separadamente dos buffers de leitura da aplicação e dos buffers utilizados no processamento de modelos.
Meça antes de aumentar os limites
- Estabeleça uma linha de base com um conjunto de dados fixo, número de pods e limites de recursos. Medir o débito, a latência de leitura, a CPU, a memória e a utilização da rede.
- Avalie separadamente as leituras cold-cache e warm-cache. Inspect
cache_server_request_countere a telemetria do Azure Blob para distinguir o tráfego de cache do fallback direto do Blob. - Muda uma definição de cada vez: concorrência, tamanho de leitura da aplicação ou tamanho do bloco de cache. Mantenha o conjunto de dados e outras definições consistentes ao comparar resultados.
- Pare de aumentar uma configuração quando o throughput estagnar ou a latência, a pressão de recursos, os erros ou o Blob throttling aumentarem.
Para observações do lado da cache, veja Monitorizar o acelerador distribuído para armazenamento na cloud.
Lidar com erros
Todas as exceções ao DACS derivam de 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 |
O caminho do Blob ou diretório não existe. |
DACSExistsError |
Uma aplicação tenta escrever num blob existente sem a sobrescrição ativada. |
DACSAuthenticationError |
As credenciais estão em falta ou são inválidas. |
DACSPermissionError |
A identidade não tem a função Blob exigida. |
DACSTimeoutError |
Uma operação de cache ou Blob atingiu o tempo limite. |
DACSNetworkError |
O servidor de cache ou o endpoint Blob é inacessível. |
DACSInvalidInputError |
Um caminho ou argumento está mal formado. |
OperationNotSupportedError |
A interface API solicitada ainda não está implementada. |
Registo de eventos de controlo
O cliente tem controlos de registo separados para as camadas Python e nativa. Defina ambas as variáveis para suprimir a saída verbosa de ambas as camadas:
env:
- name: DACS_DATA_LOG_LEVEL
value: WARNING
- name: STORAGE_LOG_LEVEL
value: WARNING
DACS_DATA_LOG_LEVELcontrola o logging em Python.
STORAGE_LOG_LEVEL controlos do registo nativo do cliente.