Configurez la mise en cache des données Fluid pour équilibrer les performances, la stabilité et la cohérence en lecture/écriture.
Chaque section présente les configurations recommandées et des exemples YAML pour les modèles de charge de travail courants.
Quand la mise en cache des données est utile
La mise en cache profite aux charges de travail qui lisent à plusieurs reprises les mêmes données. Vérifiez si votre charge de travail correspond à ce modèle avant de configurer un système de cache.
| Modèle de charge de travail | Avantage de la mise en cache | Exemple |
|---|---|---|
| Lectures répétées des mêmes données | Élevé | Entraînement IA itérant sur un jeu de données sur plusieurs époques |
| Lectures concurrentes de fichiers partagés | Élevé | Service d'inférence chargeant un modèle partagé dans la mémoire GPU au démarrage |
| Données partagées entre les tâches | Élevé | Tâches SparkSQL traitant des données de commande référencées par plusieurs requêtes analytiques |
| Lectures uniques | Aucun | Nettoyage de données ETL ou migration de données ponctuelle |
| Charges de travail en écriture seule | Aucun | Aucune opération de lecture sur le même chemin de données |
| Accès très peu fréquent | Aucun | Le cache expire ou est évincé avant réutilisation |
Si la mise en cache s'applique à votre charge de travail, configurez les politiques ci-dessous.
Optimisation des performances
Configurez l'infrastructure (types d'instance ECS et supports de cache), ajustez les paramètres du cache et alignez la planification des Pods avec le placement du cache.
Sélectionner les types d'instance ECS pour le système de cache
Un cache distribué agrège le stockage et la bande passante sur plusieurs nœuds. Estimez les limites supérieures pour votre cluster de cache :
Capacité de cache disponible = Capacité de cache par Pod Worker x Nombre de réplicas de Pod Worker
Bande passante de cache disponible = Nombre de réplicas de Pod Worker x min{Bande passante maximale disponible du nœud ECS où s'exécute le Pod Worker, débit d'E/S du support de cache utilisé par le Pod Worker}
Bande passante théorique maximale de l'application = min{Bande passante disponible du nœud ECS où s'exécute le Pod d'application, Bande passante de cache disponible}
La bande passante réelle dépend de la bande passante disponible du nœud d'application et du modèle d'accès (séquentiel ou aléatoire). Lorsque plusieurs Pods d'application accèdent aux données simultanément, la bande passante du cache est partagée.
Exemple d'estimation
Ajoutez deux instances ecs.g7nex.8xlarge à votre cluster ACK en tant que Pods Worker de cache, chacune disposant de 100 GiB de mémoire sur un nœud distinct. Le Pod d'application s'exécute sur une instance ecs.gn7i-c8g1.2xlarge (8 vCPU, 30 GiB de mémoire, bande passante de 16 Gbps).
| Métrique | Calcul | Résultat |
|---|---|---|
| Capacité de cache disponible | 100 GiB x 2 | 200 GiB |
| Bande passante de cache disponible | 2 x min{40 Gbps, Débit d'E/S d'accès mémoire} | 80 Gbps |
| Bande passante maximale de l'application (en cas de succès du cache) | min{80 Gbps, 16 Gbps} | 16 Gbps |
Le goulot d'étranglement est la bande passante de 16 Gbps du nœud d'application, et non le cluster de cache. Pour augmenter le débit, utilisez un type d'instance à plus haute bande passante ou répartissez la charge de travail sur plusieurs Pods d'application.
Types d'instance ECS recommandés
Choisissez des types d'instance à haute bande passante pour les nœuds de cache. Utilisez la mémoire pour un débit maximal, ou des SSD locaux pour une capacité plus importante à moindre coût.
| Famille d'instances ECS | Type d'instance ECS | Configuration |
|---|---|---|
| g7nex, usage général amélioré pour le réseau | ecs.g7nex.8xlarge | 32 vCPU, 128 GiB de mémoire, bande passante de 40 Gbps |
| ecs.g7nex.16xlarge | 64 vCPU, 256 GiB de mémoire, bande passante de 80 Gbps | |
| ecs.g7nex.32xlarge | 128 vCPU, 512 GiB de mémoire, bande passante de 160 Gbps | |
| i4g, stockage SSD local | ecs.i4g.16xlarge | 64 vCPU, 256 GiB de mémoire, 2 x 1920 Go de SSD local, bande passante de 32 Gbps |
| ecs.i4g.32xlarge | 128 vCPU, 512 GiB de mémoire, 4 x 1920 Go de SSD local, bande passante de 64 Gbps | |
| g7ne, usage général amélioré pour le réseau | ecs.g7ne.8xlarge | 32 vCPU, 128 GiB de mémoire, bande passante de 25 Gbps |
| ecs.g7ne.12xlarge | 48 vCPU, 192 GiB de mémoire, bande passante de 40 Gbps | |
| ecs.g7ne.24xlarge | 96 vCPU, 384 GiB de mémoire, bande passante de 80 Gbps | |
| g8i, usage général | ecs.g8i.24xlarge | 96 vCPU, 384 GiB de mémoire, bande passante de 50 Gbps |
| ecs.g8i.16xlarge | 64 vCPU, 256 GiB de mémoire, bande passante de 32 Gbps |
Consultez Familles d'instances pour les spécifications.
Sélectionner le support de cache
Le support de cache détermine le plafond de débit d'E/S pour chaque nœud. Même si une instance ECS dispose d'une bande passante réseau élevée, un support de cache lent devient le goulot d'étranglement.
Un SSD entreprise (ESSD) ne peut souvent pas répondre aux besoins de performance des charges de travail intensives en données. Par exemple, un seul disque PL2 a un débit maximal de 750 Mo/s. Si vous utilisez un disque PL2 comme support de cache sur une instance avec une bande passante de 40 Gbps, la bande passante effective du cache est limitée à 750 Mo/s, gaspillant ainsi la capacité réseau de l'instance.
Supports de cache disponibles :
| Support de cache | **mediumtype** |
**volumeType** |
**path** |
Idéal pour |
|---|---|---|---|---|
| Mémoire | MEM | emptyDir | /dev/shm | Débit maximal ; le jeu de données tient en mémoire |
| Disque système (SSD local) | SSD | emptyDir | /var/lib/fluid/cache | Capacité plus importante à moindre coût ; cycle de vie du cache lié au Pod Worker |
| Disque de données SSD monté | SSD | hostPath | /mnt/disk1 | Disque dédié au stockage du cache |
| Plusieurs disques de données SSD | SSD | hostPath | /mnt/disk1,/mnt/disk2 | Capacité locale la plus élevée ; capacité répartie uniformément sur les disques |
Configurez le support de cache et la capacité dans spec.tieredstore sur la ressource Runtime :
Mémoire comme support de cache
spec:
tieredstore:
levels:
- mediumtype: MEM
volumeType: emptyDir
path: /dev/shm
quota: 30Gi # Cache capacity per Worker Pod replica.
high: "0.99"
low: "0.95"
Stockage local comme support de cache
Choisissez en fonction de votre configuration de disque :
Stockage sur disque système :
spec:
tieredstore:
levels:
- mediumtype: SSD
volumeType: emptyDir # emptyDir ties the cache lifecycle to the Worker Pod, preventing residual data.
path: /var/lib/fluid/cache
quota: 100Gi # Cache capacity per Worker Pod replica.
high: "0.99"
low: "0.95"
Disque de données SSD monté :
spec:
tieredstore:
levels:
- mediumtype: SSD
volumeType: hostPath
path: /mnt/disk1 # Mount path of the local SSD on the host.
quota: 100Gi # Cache capacity per Worker Pod replica.
high: "0.99"
low: "0.95"
Plusieurs disques de données SSD :
spec:
tieredstore:
levels:
- mediumtype: SSD
volumeType: hostPath
path: /mnt/disk1,/mnt/disk2 # Mount paths of the data disks on the host.
quota: 100Gi # Cache capacity per Worker Pod replica. Capacity is evenly distributed: /mnt/disk1 and /mnt/disk2 each get 50 GiB.
high: "0.99"
low: "0.95"
Les seuilshighetlowcontrôlent l'éviction du cache. Lorsque l'utilisation du cache dépasse le seuilhigh, le système de cache évince les données jusqu'à ce que l'utilisation descende au seuillow.
Configurer l'affinité de planification entre le cache et les applications
La latence réseau inter-zones entre les Pods d'application et les Pods Worker de cache dégrade les performances d'accès aux données. Déployez-les dans la même zone.
Plus précisément :
Déployez les Pods Worker de cache dans la même zone dans la mesure du possible.
Déployez les Pods d'application dans la même zone que les Pods Worker de cache dans la mesure du possible.
Concentrer tous les Pods dans une seule zone réduit la capacité de reprise après sinistre. Équilibrez les performances et la disponibilité en fonction de votre accord de niveau de service (SLA).
Définissez la zone de cache en configurant spec.nodeAffinity sur la ressource Dataset :
apiVersion: data.fluid.io/v1alpha1
kind: Dataset
metadata:
name: demo-dataset
spec:
...
nodeAffinity:
required:
nodeSelectorTerms:
- matchExpressions:
- key: topology.kubernetes.io/zone
operator: In
values:
- <ZONE_ID> # The zone to deploy cache Worker Pods in, for example, cn-beijing-i.
Cela place les Pods Worker de cache sur les nœuds de la zone spécifiée. Fluid peut également injecter automatiquement des règles d'affinité afin que les Pods d'application soient planifiés aux côtés des Pods Worker de cache. Consultez Optimiser la planification en fonction de l'affinité du cache de données.
Ajuster les paramètres de prélecture pour les lectures séquentielles de gros fichiers
Les charges de travail qui effectuent des lectures séquentielles complètes sur de gros fichiers peuvent bénéficier de paramètres de prélecture agressifs. Voici quelques exemples courants :
Entraînement IA sur des jeux de données au format TFRecord ou Tar
Chargement des fichiers de paramètres de modèle au démarrage du service d'inférence
Analytique distribuée lisant des fichiers Parquet
Une prélecture agressive augmente l'amplification des lectures. Pour les lectures aléatoires ou les petits fichiers, ces paramètres gaspillent de la bande passante sur des données inutilisées. Utilisez les valeurs par défaut pour les charges de travail mixtes ou à lecture aléatoire.
La configuration de la prélecture varie selon le runtime.
JindoRuntime
Configurez la prélecture FUSE (Filesystem in Userspace) dans spec.fuse.properties :
kind: JindoRuntime
metadata:
...
spec:
fuse:
properties:
fs.oss.download.thread.concurrency: "200"
fs.oss.read.buffer.size: "8388608"
fs.oss.read.readahead.max.buffer.count: "200"
fs.oss.read.sequence.ambiguity.range: "2147483647" # About 2 GB.
| Paramètre | Description |
|---|---|
fs.oss.download.thread.concurrency |
Nombre de threads de prélecture simultanés. |
fs.oss.read.buffer.size |
Taille d'un seul tampon de prélecture. |
fs.oss.read.readahead.max.buffer.count |
Nombre maximal de tampons pour une prélecture à flux unique. |
fs.oss.read.sequence.ambiguity.range |
Plage utilisée pour déterminer si un modèle de lecture est séquentiel. |
JuiceFSRuntime
Configurez la prélecture dans spec.fuse.options et spec.worker.options :
kind: JuiceFSRuntime
metadata:
...
spec:
fuse:
options:
buffer-size: "2048"
cache-size: "0"
max-uploads: "150"
worker:
options:
buffer-size: "2048"
max-downloads: "200"
max-uploads: "150"
master:
resources:
requests:
memory: 2Gi
limits:
memory: 8Gi
...
| Paramètre | Description |
|---|---|
buffer-size |
Taille du tampon de lecture/écriture. |
max-downloads |
Concurrence des téléchargements de prélecture. |
max-uploads |
Concurrence des téléchargements. |
fuse cache-size |
Capacité du cache local pour FUSE. |
Le paramètre cache-size: "0" désactive le cache local FUSE, qui utilise alors la mémoire du nœud comme cache de pages Linux. En cas d'échec du cache, il lit à partir du cache distribué JuiceFSRuntime Worker. Consultez la documentation JuiceFS pour un ajustement détaillé.
Optimisation de la stabilité
Les politiques suivantes traitent des risques de stabilité courants : surcharge des métadonnées, perte de données au redémarrage du Pod, plantages FUSE dus à une erreur de mémoire (OOM) et défaillances des points de montage.
Éviter de monter des répertoires contenant trop de fichiers
Le système de cache maintient les métadonnées pour chaque fichier du répertoire monté. Monter un répertoire contenant trop de fichiers (comme la racine d'un système de stockage à grande échelle) consomme une quantité excessive de mémoire et de CPU.
Montez des sous-répertoires spécifiques correspondant à votre périmètre de données. Créez des Datasets distincts pour différentes collections de données.
apiVersion: data.fluid.io/v1alpha1
kind: Dataset
metadata:
name: demo-dataset
spec:
...
mounts:
- mountPoint: oss://<BUCKET>/<PATH1>/<SUBPATH>/
name: sub-bucket
Plusieurs systèmes de cache ajoutent de la complexité opérationnelle. Choisissez la granularité appropriée en fonction de vos besoins.
| Scénario | Approche |
|---|---|
| Petit jeu de données avec peu de fichiers et forte pertinence | Un Dataset et un système de cache |
| Grand jeu de données avec de nombreux fichiers | Diviser en plusieurs Datasets par répertoire de données. Les Pods d'application peuvent monter plusieurs Datasets. |
| Plusieurs utilisateurs ou exigences d'isolation des données | Créer des Datasets éphémères par utilisateur ou tâche. Envisagez un opérateur Kubernetes pour une gestion dynamique. |
Persister les métadonnées avec un stockage durable
JindoRuntime et les systèmes de cache similaires utilisent une architecture Master-Worker. Le Pod Master stocke les métadonnées de fichiers et l'état du cache pour le stockage backend monté. Sans métadonnées persistantes, un redémarrage nécessite une reconstruction complète de l'état.
Utilisez une revendication de volume persistant (PVC) sauvegardée par un ESSD pour stocker les métadonnées de manière durable :
apiVersion: data.fluid.io/v1alpha1
kind: JindoRuntime
metadata:
name: sd-dataset
spec:
...
volumes:
- name: meta-vol
persistentVolumeClaim:
claimName: demo-jindo-master-meta
master:
resources:
requests:
memory: 4Gi
limits:
memory: 8Gi
volumeMounts:
- name: meta-vol
mountPath: /root/jindofs-meta
properties:
namespace.meta-dir: "/root/jindofs-meta"
Ici, demo-jindo-master-meta est une PVC précréée sauvegardée par un ESSD. Les métadonnées survivent aux redémarrages de Pod et migrent avec le Pod. Consultez Utiliser JindoRuntime pour persister l'état du Pod Master.
Allouer des ressources au Pod FUSE
Le Pod FUSE monte un système de fichiers FUSE sur le nœud et le monte par liaison dans le Pod d'application, exposant une interface POSIX pour lire les données distantes comme des fichiers locaux.
Pour éviter les échecs de montage liés à une erreur de mémoire (OOM), évitez de définir une limite de mémoire pour le Pod FUSE, ou définissez-la proche de la mémoire allouable du nœud :
spec:
fuse:
resources:
requests:
memory: 8Gi
# limits:
# memory: <ECS_ALLOCATABLE_MEMORY>
Si le Pod FUSE est arrêté par le tueur OOM, le point de montage du Pod d'application se rompt. Redémarrez l'application pour rétablir le montage, sauf si l'auto-réparation FUSE est activée (voir ci-dessous).
Activer l'auto-réparation FUSE
Par défaut, un plantage FUSE rend le point de montage inaccessible. Le conteneur d'application doit redémarrer pour déclencher à nouveau le montage par liaison.
Le mécanisme d'auto-réparation FUSE de Fluid récupère automatiquement l'accès au point de montage après un redémarrage FUSE sans nécessiter le redémarrage du conteneur d'application.
Pendant la fenêtre de redémarrage FUSE, le point de montage est inaccessible. L'application doit gérer les erreurs d'E/S et inclure une logique de nouvelle tentative.
L'auto-réparation FUSE présente des limitations. Activez-la uniquement lorsque le redémarrage est perturbateur, comme dans les environnements interactifs Jupyter Notebook ou VS Code.
Consultez Comment activer la capacité d'auto-récupération FUSE.
Cohérence en lecture/écriture du cache
La mise en cache introduit des défis de cohérence — une cohérence forte dégrade souvent les performances. Choisissez une politique qui correspond au modèle de lecture/écriture de votre charge de travail.
Le tableau suivant résume les cinq scénarios. Consultez chaque sous-section pour les détails de configuration.
| Scénario | Modifications des données backend | Mode d'accès | Approche de configuration |
|---|---|---|---|
| Lecture seule, données statiques | Aucune | ReadOnlyMany (par défaut) | Configuration Dataset par défaut |
| Lecture seule, modifications périodiques | Périodique (planifiée) | ReadOnlyMany | DataLoad avec politique Cron |
| Lecture seule, modifications pilotées par événements | À la demande | ReadOnlyMany | Désactiver le cache de métadonnées ; définir les délais d'expiration des métadonnées FUSE |
| Lecture/écriture, répertoires séparés | Via un chemin d'écriture séparé | ReadOnlyMany + ReadWriteMany | Deux Datasets avec différents modes d'accès |
| Lecture/écriture, même répertoire | Sur place | ReadWriteMany | Dataset unique ; backend compatible POSIX |
Scénario 1 : Données en lecture seule sans modifications backend
Quand l'utiliser : Une seule tâche d'entraînement IA lit un jeu de données fixe sur plusieurs époques. Le cache est vidé après l'entraînement.
Configuration : Fluid utilise par défaut le mode lecture seule. Utilisez la configuration Dataset par défaut ou définissez-la explicitement :
apiVersion: data.fluid.io/v1alpha1
kind: Dataset
metadata:
name: demo-dataset
spec:
...
# accessModes: ["ReadOnlyMany"] ReadOnlyMany is the default value.
Le paramètre accessModes: ["ReadOnlyMany"] empêche les écritures accidentelles dans le jeu de données pendant l'entraînement.
Scénario 2 : Données en lecture seule avec modifications backend périodiques
Quand l'utiliser : Les données métier sont collectées quotidiennement dans le stockage backend. Des tâches d'analyse nocturnes traitent les données du jour. Les résultats sont écrits directement dans le stockage backend, en contournant le cache.
Configuration : Utilisez une ressource DataLoad avec une politique Cron pour synchroniser les modifications depuis le stockage backend à intervalles réguliers :
apiVersion: data.fluid.io/v1alpha1
kind: Dataset
metadata:
name: demo-dataset
spec:
...
# accessModes: ["ReadOnlyMany"] ReadOnlyMany is the default value.
---
apiVersion: data.fluid.io/v1alpha1
kind: DataLoad
metadata:
name: demo-dataset-warmup
spec:
...
policy: Cron
schedule: "0 0 * * *" # Prefetch data at 00:00 every day.
loadMetadata: true # Sync metadata changes from backend storage during prefetch.
target:
- path: /path/to/warmup # Path in backend storage to prefetch.
Le paramètre loadMetadata: true actualise également les métadonnées lors de chaque préchargement, maintenant ainsi la cohérence du cache avec le stockage backend.
Scénario 3 : Données en lecture seule avec modifications backend pilotées par événements
Quand l'utiliser : Les utilisateurs téléversent des modèles personnalisés dans le stockage backend et les sélectionnent pour l'inférence. Le cache doit refléter les nouveaux téléversements sans attendre une synchronisation planifiée.
Configuration : Désactivez le cache de métadonnées côté serveur et définissez des délais d'expiration courts pour les métadonnées FUSE afin de forcer les vérifications du stockage backend à chaque accès.
Utilisation de JindoRuntime :
apiVersion: data.fluid.io/v1alpha1
kind: Dataset
metadata:
name: demo-dataset
spec:
mounts:
- mountPoint: <MOUNTPOINT>
name: data
path: /
options:
metaPolicy: ALWAYS # Disable server-side metadata cache.
---
apiVersion: data.fluid.io/v1alpha1
kind: JindoRuntime
metadata:
name: demo-dataset
spec:
fuse:
args:
- -oauto_cache
# Metadata timeout in seconds. Setting to 0 provides strong consistency but may greatly reduce read efficiency.
- -oattr_timeout=30
- -oentry_timeout=30
- -onegative_timeout=30
- -ometrics_port=0
Le paramètre metaPolicy: ALWAYS désactive le cache de métadonnées côté serveur, forçant chaque accès aux métadonnées à interroger directement le stockage backend.
La définition deattr_timeout,entry_timeoutetnegative_timeoutà0offre une cohérence forte mais peut réduire considérablement les performances de lecture. Une valeur de30(secondes) équilibre la fraîcheur et les performances pour la plupart des scénarios pilotés par événements.
Scénario 4 : Lecture et écriture dans des répertoires séparés
Quand l'utiliser : L'entraînement distribué à grande échelle lit les données depuis le répertoire A et écrit des points de contrôle dans le répertoire B à chaque époque. La mise en cache des écritures améliore l'efficacité des points de contrôle.
Configuration : Créez deux Datasets. Définissez l'un en lecture seule pour les données d'entraînement et l'autre en lecture-écriture pour les points de contrôle :
apiVersion: data.fluid.io/v1alpha1
kind: Dataset
metadata:
name: train-samples
spec:
...
# accessModes: ["ReadOnlyMany"] ReadOnlyMany is the default value.
---
apiVersion: data.fluid.io/v1alpha1
kind: Dataset
metadata:
name: model-ckpt
spec:
...
accessModes: ["ReadWriteMany"]
Montez les deux Datasets sur le Pod d'application :
apiVersion: v1
kind: Pod
metadata:
...
spec:
containers:
...
volumeMounts:
- name: train-samples-vol
mountPath: /data/A
- name: model-ckpt-vol
mountPath: /data/B
volumes:
- name: train-samples-vol
persistentVolumeClaim:
claimName: train-samples
- name: model-ckpt-vol
persistentVolumeClaim:
claimName: model-ckpt
Cela isole le jeu de données d'entraînement des points de contrôle. Le Dataset train-samples en lecture seule empêche les problèmes de cohérence liés à l'écriture, tandis que le Dataset model-ckpt en lecture-écriture permet les écritures mises en cache.
Scénario 5 : Lecture et écriture dans le même répertoire
Quand l'utiliser : Développement interactif, tel qu'un espace de travail Jupyter Notebook ou VS Code en ligne, où les fichiers sont fréquemment créés, modifiés et supprimés dans un répertoire partagé.
Configuration : Définissez le mode d'accès du Dataset en lecture-écriture. Utilisez un backend de stockage compatible POSIX :
apiVersion: data.fluid.io/v1alpha1
kind: Dataset
metadata:
name: myworkspace
spec:
...
accessModes: ["ReadWriteMany"]
Le paramètre ReadWriteMany permet l'accès simultané en lecture/écriture au même répertoire par plusieurs utilisateurs ou processus.