Lors de l'achat de stockage, l'accent est généralement mis sur les médias, mais il peut être encore plus important de considérer également les méthodes d'accès. Vous devrez prendre en compte les protocoles de stockage lors de la conception et de l’acquisition de l’infrastructure, en particulier lorsque vous abandonnez le stockage existant pour migrer vers le stockage objet natif dans le cloud. Cependant, le stockage objet s'appuie sur l'API S3 pour les communications, tandis que les charges de travail existantes s'appuient sur POSIX, l'interface du système d'exploitation portable qui fournit un ensemble de normes développées dans les années 1980 pour permettre aux applications d'être portables entre les systèmes d'exploitation Unix. Il y a de fortes chances que la plupart des entreprises disposent d'applications en service depuis des décennies, développées pour fonctionner sur POSIX. Il est également probable que les ingénieurs soient déjà conscients des mauvaises performances de POSIX.
Cela étant dit, lorsque vous disposez de systèmes existants qui ne peuvent ingérer des données que dans un certain format ou à partir d'une certaine source, vos options peuvent être limitées et vous n'avez peut-être pas d'autre choix que d'implémenter un protocole obsolète ou de réécrire votre code. Par exemple, si vous ne pouvez ingérer qu'à partir d'un disque local avec un système de fichiers et non avec des API RESTful accessibles via le réseau, vous devez d'abord rendre ces données disponibles sur le disque avant que votre application puisse les utiliser. Cependant, l'utilisation d'un magasin d'objets comme système de fichiers a un certain nombre de conséquences négatives graves en termes de performances, de compatibilité, d'intégrité des données et de sécurité.
Montrons cela avec quelques tests réels à l'aide d'un petit utilitaire appelé s3fs-fuse . Cet utilitaire vous permet de monter un compartiment S3 en tant que système de fichiers local. Il signifie S3 (Simple Storage Service) File System - FUSE (Filesystem in Userspace). Il s'agit d'un projet open source qui exploite l'interface FUSE (Filesystem in Userspace) pour présenter une interface de type système de fichiers à S3.
Une fois qu'un compartiment S3 est monté à l'aide s3fs-fuse
, vous pouvez interagir avec le compartiment comme s'il s'agissait d'un système de fichiers local. Cela signifie que vous pouvez utiliser des opérations de fichiers régulières (telles que lire, écrire, déplacer, etc.) sur les fichiers de votre compartiment. Cela semble incroyablement pratique et nous pouvons affirmer que cela simplifie le développement d'applications. Mais par nature, le stockage d'objets et les systèmes de fichiers présentent des différences fondamentales qui affecteront le compartiment s3 monté en tant que système de fichiers.
Prenons un moment pour prendre du recul par rapport à l'utilitaire s3fs-fuse
pour discuter des véritables raisons pour lesquelles traiter le stockage d'objets comme un système de fichiers est loin d'être optimal. Le problème est bien plus important que s3fs-fuse
et inclut d'autres utilitaires tels que Mountpoint basé sur Rust pour Amazon S3 , un client de fichiers qui traduit les appels d'API du système de fichiers local en appels d'API d'objet S3. La première raison est que tous ces utilitaires s'appuient sur POSIX pour les opérations du système de fichiers. POSIX est inefficace et n'a jamais été conçu pour travailler avec des fichiers très volumineux sur le réseau.
La vitesse des systèmes basés sur POSIX diminue à mesure que la demande, en particulier la demande simultanée, augmente. Lorsque les grandes organisations ont besoin de stocker et d’accéder à des océans de données pour l’apprentissage profond, l’IA et d’autres cas d’utilisation gourmands en données, POSIX n’a pas la capacité ni l’évolutivité nécessaires pour répondre à ces demandes. Même si les baies 100 % Flash ont conservé POSIX dans le jeu, l'évolutivité et les API RESTful (les caractéristiques du cloud) sont comme la kryptonite.
Pour cette raison, exécuter POSIX sur un magasin d'objets n'est pas optimal. Jetons un coup d'œil à quelques-unes des raisons pour lesquelles :
Performances : l'interface POSIX FS est intrinsèquement centrée sur les IOPS. Ils sont bavards, coûteux et difficiles à mettre à l’échelle. L'API RESTful S3 résout ce problème en transformant les IOPS en un problème de débit. Le débit est plus facile et moins coûteux à mettre à l’échelle. C’est pourquoi le stockage objet est performant à grande échelle. La superposition de POSIX sur S3 ne sera pas évolutive car POSIX est trop bavard pour être exécuté sur une interface HTTP RESTful.
Sémantique : étant donné que les opérations sur les objets sont atomiques et immuables, il n'existe aucun moyen de garantir l'exactitude de la cohérence. Cela signifie que vous pouvez perdre les données non validées en cas de crash ou rencontrer des problèmes de corruption en cas de montages partagés.
Intégrité des données : les écritures ou toute mutation dans un fichier n'apparaîtront pas dans l'espace de noms tant qu'ils ne seront pas validés. Cela signifie que l'accès simultané sur les montages partagés ne verra pas les modifications. Ce n’est pas utile pour un accès partagé.
Contrôle d'accès : les autorisations POSIX et les ACL sont primitives et incompatibles avec la manière dont l'API S3 gère les politiques de gestion des identités et des accès. Il n'est pas possible d'implémenter en toute sécurité la gestion des accès POSIX sur les principales API S3.
POSIX manque également de la plupart des fonctionnalités que les développeurs aiment dans S3, telles que le chiffrement au niveau objet, la gestion des versions, l'immuabilité – celles-ci n'ont tout simplement pas d'équivalent dans le monde POSIX et rien n'est capable de les traduire.
Ces exemples illustrent le problème et ses implications. Pour commencer, nous utiliserons ce fichier CSV qui fait environ 10 Go et comporte 112 lignes.
Remarque : Nous supposerons que s3fs-fuse
est déjà installé et que vous avez monté l'un des compartiments du stockage d'objets dans votre système de fichiers. Sinon, suivez les instructions ici .
Dans ces exemples, nous supposerons que le nom du bucket est test-bucket et que le nom du fichier est taxi-data.csv se trouve dans le répertoire /home/user/ et que s3fs-fuse bucket
est monté dans /home/user/test-bucket/.
Nous allons d'abord essayer quelque chose de simple et essayer de copier le fichier CSV dans notre compartiment de test à l'aide des commandes mc et d'enregistrer le temps nécessaire
time mc cp /home/user/taxi-data.csv minio/test-bucket/taxi-data.csv
Cela ne devrait pas prendre beaucoup de temps et le fichier doit être copié dans notre bucket. Essayons maintenant de faire la même chose avec s3fs-fuse
time cp /home/user/taxi-data.csv /home/user/test-bucket/taxi-data.csv
Temps qu'il a fallu pendant les tests
real 1m36.056s user 0m14.507s sys 0m31.891s
Dans mon cas, je n'ai pu copier le fichier que partiellement dans le bucket et l'opération a échoué avec l'erreur suivante
cp: error writing '/home/user/test-bucket/taxi-data.csv': Input/output error cp: failed to close '/home/user/test-bucket/taxi-data.csv': Input/output error
Après plusieurs essais, c'est réussi
real 5m3.661s user 0m0.053s sys 2m35.234s
Comme vous pouvez le constater, en raison du nombre d'appels API que l'utilitaire doit effectuer et de la surcharge générale des opérations, l'utilitaire devient instable et la plupart des opérations ne se terminent même pas.
Nous vous avons montré un exemple simple cp
, qui peut avoir été convaincant ou non, car avouons-le, vous pourriez penser que time cp
est assez rudimentaire.
Donc, pour ceux qui ont besoin de plus de preuves empiriques, écrivons un extrait Python pour tester cela. Nous allons faire un exemple simple de Pandas avec à la fois s3fs-fuse
et le package python s3fs
, et voir l'impact sur les performances.
import timeit import os import fsspec import s3fs import pandas as pd # Write a dummy CSV file to test-bucket df = pd.DataFrame({"column1": ["new_value1"], "column2": ["new_value2"]}) df.to_csv("s3://test-bucket/data/test-data.csv", index=False) def process_s3(): # add fsspec for pandas to use `s3://` path style and access S3 buckets directly fsspec.config.conf = { "s3": { "key": os.getenv("AWS_ACCESS_KEY_ID", "minioadmin"), "secret": os.getenv("AWS_SECRET_ACCESS_KEY", "minioadmin"), "client_kwargs": { "endpoint_url": os.getenv("S3_ENDPOINT", "https://play.min.io") } } } s3 = s3fs.S3FileSystem() for i in range(100): # Read the existing data print(i) df = pd.read_csv('s3://test-bucket/data/test-data.csv') # Append a new row new_df = pd.concat([df, pd.DataFrame([{"column1": f"value{i}", "column2": f"value{i}"}])], ignore_index=True) # Write the data back to the file new_df.to_csv('s3://test-bucket/data/test-data.csv', index=False) execution_time = timeit.timeit(process_s3, number=1) print(f"Execution time: {execution_time:.2f} seconds")
Temps pris pendant les tests
Execution time: 8.54 seconds
Essayons maintenant la même chose pour s3fs-fuse
import timeit import pandas as pd # Write a dummy CSV file to test-bucket df = pd.DataFrame({"column1": ["new_value1"], "column2": ["new_value2"]}) df.to_csv("s3://test-bucket/data/test-data.csv", index=False) def process_s3fs(): for i in range(100): # Read the existing data print(i) df = pd.read_csv('/home/user/test-bucket/data/test-data.csv') # Append a new row new_df = pd.concat([df, pd.DataFrame([{"column1": f"value{i}", "column2": f"value{i}"}])], ignore_index=True) # Write the data back to the file new_df.to_csv('/home/user/test-bucket/data/test-data.csv', index=False) execution_time = timeit.timeit(process_s3fs, number=1) print(f"Execution time: {execution_time:.2f} seconds")
Temps pris pendant les tests
Execution time: 9.59 seconds
Ces exemples démontrent des lectures et des écritures constantes dans des fichiers S3. Imaginez que cela soit effectué simultanément par plusieurs clients : la latence augmente considérablement.
Comme vous pouvez le constater, la différence entre l'utilisation de la traduction POSIX pour traiter les objets comme des fichiers et l'utilisation de l'API directe pour travailler avec des objets est le jour et la nuit. Il n'y a tout simplement aucune comparaison possible en matière de sécurité, de performances, d'intégrité des données et de compatibilité. MinIO dispose de SDK à intégrer à presque tous les langages de programmation populaires et peut fonctionner sur presque toutes les plates-formes telles que Kubernetes, Linux nu, les conteneurs Docker – et bien plus encore.
MinIO sécurise les objets avec un chiffrement au repos et en transit, combiné avec PBAC pour réguler l'accès et effacer le codage afin de protéger l'intégrité des données. Vous obtiendrez les meilleures performances possibles, quel que soit l'endroit où vous exécutez MinIO, car il tire parti du matériel sous-jacent (voir Sélection du meilleur matériel pour votre déploiement MinIO ) pour offrir les meilleures performances possibles. Nous avons comparé MinIO à 325 Gio/s (349 Go/s) sur les GET et à 165 Gio/s (177 Go/s) sur les PUT avec seulement 32 nœuds de SSD NVMe disponibles dans le commerce.
Il n'y a tout simplement pas besoin d'un utilitaire de système de fichiers entre MinIO et votre application ! Tout avantage que les applications héritées pourraient recevoir sera compensé par la douleur de POSIX.
Si vous avez des questions sur l'utilisation de la traduction POSIX pour votre application, n'hésitez pas à nous contacter sur Slack !
Également publié ici .