BT

Diffuser les Connaissances et l'Innovation dans le Développement Logiciel d'Entreprise

Contribuez

Sujets

Sélectionner votre région

Accueil InfoQ Articles Le Protocole Direct de Sockets sous Java 7 - Ecrit une fois, exécuté partout...

Le Protocole Direct de Sockets sous Java 7 - Ecrit une fois, exécuté partout...

Favoris

Dans cet article, nous étudierons le nouveau Protocole Direct de Sockets (SDP), une avancée très intéressante récemment introduite dans le SDK Java 7. Le SDP permet à la communauté de l'Informatique Ultra Haute Performance (UHPC) d'utiliser les fonctionnalités et les mérites ubiquitaires de Java dans un but peu commun : l'accès natif à la capacité d'Accès Direct à la Mémoire à Distance (RDMA) d'InfiniBand. RDMA fournit, pour les applications à faible latence, un protocole permettant d'accéder directement à la mémoire d'autres ordinateurs sans passer par le système d'exploitation. La communauté UHPC a les plus strictes demandes en termes de faible latence non compromettante et de haut débit imaginables; il est donc naturel qu'elle ait besoin de la meilleure fonctionnalité de RDMA disponible. Avec l'introduction du Protocole Direct de Sockets sous Java 7, la communauté UHPC possède maintenant une plateforme Java lui permettant d'écrire du code applicatif qui utilise directement la puissance maximale du RDMA natif d'InfiniBand.

Avant que nous entrions dans les profondeurs du nouveau Protocole Direct de Sockets, revenons brièvement sur l'historique du réseau et des sockets en Java

En 1995, Sun Microsystems introduisit Java au monde entier et commença immédiatement à scander le slogan mondialement connu "Java - Ecrit une fois, exécuté partout". Comme nous le savons tous, l'idée derrière cela était simple : au lieu d'écrire des applications en C++ (qui était difficiles à compiler/déployer de façon même approximativement "exécutable partout"), il était à présent possible d'écrire du code applicatif dans quelque chose appelé Java, qui compilerait/se déploierait sur une machine virtuelle (pas l'environnement sous-jacent au système d'exploitation). Cela libérat grandement le développeur d'applications Java des problèmes de portabilité, délégant exclusivement la gestion de la portabilité à la machine vituelle Java (JVM). La JVM fit cette promesse : si vous pouviez compiler/déployer du code Java qui fonctionne sur une machine virtuelle Java (pour un système d'exploitation sous-jacent précis), la plateforme garantissait que le même code fonctionnerait sur n'importe quel système d'exploitation (pour lequel une machine virtuelle Java était disponible). La compilation conditionnelle et les macros pour le pré-processeur n'étaient plus nécessaires (Vous souvenez-vous de C++ et de l'enfer de #ifdef ? La JVM libéra donc les développeurs d'applications de ce cruel fardeau).

Ce fut très utile et très bien reçu de la part de la communauté de développement d'applications. Comme nous le savons tous, Java prit vite et intensivement, adopté à l'échelle mondiale à un rythme inégalé dans l'histoire des nombreuses plateformes de langage de programmation informatique.

Au début, Sun offrait une machine virtuelle Java exécutable sous 3 systèmes d'exploitation : (1) Solaris, (2) Linux, (3) Windows. Etant donné que, quelques années plus tôt (1993), Microsoft avait livré la pile de protocole WinSOCK avec Windows, le système d'exploitation pouvait maintenant faire du réseau TCP/IP (grâce à une API complètement supportée par Microsoft). Les différents systèmes *nix faisaient (évidemment) du TCP/IP depuis les années 70. L'introduction de WinSOCK par Microsoft fut absolument essentielle pour que Java devienne ce qu'il est devenu. Sans WinSOCK, il n'aurait pas été possible de délivrer une machine virtuelle Windows supportant les APIs java.net.* et java.io.*. Sans cela, Java n'aurait pas pu construire une machine virtuelle en réseau s'exécutant sur le système d'exploitation qui monopolise les ordinateurs du monde entier. Plutôt que d'atteindre "peut-être un million" d'ordinateurs, avec Windows à présent capable de faire du TCP/IP, Java pouvait atteindre "peut-être un milliard" d'ordinateurs.

Les choses ont changé

Bien sûr, Java peut encore être "écrit une fois, exécuté partout". La portabilité est toujours la priorité centrale. Cependant, il est maintenant possible de faire beaucoup plus sur la JVM grâce à Java 7 et au Protocole Direct de Sockets. La portabilité n'est pas la seule priorité; s'accommoder des utilisations ultra-hautes performances est à présent une priorité majeure pour la machine virtuelle Java. Grâce au SDP, la JVM peut maintenant délivrer les mêmes APIs de réseau et de sockets qui accèdent directement à la puissance native d'InfiniBand, qui est beaucoup plus rapide qu'Ethernet et qui est le fournisseur désigné de la couche physique de réseau pour la communauté UHPC.

Nous allons rapidemment expliquer ce qu'est InfiniBand et comment la machine virtuelle Java 7 permet aux applications d'utiliser ses capacités natives.

Il est intéressant de prendre en compte (notamment d'un point de vue historique), que Java a décidé de délivrer le Protocole Direct de Sockets sur deux systèmes d'exploitation, et que Windows n'est pas l'un d'entre eux. Ces deux systèmes sont Solaris et Linux. Le SDP de Solaris a été la norme pour toutes les versions depuis Solaris 10. Du moment que l'on possède une carte d'interface réseau (NIC) InfiniBand, le SDP fonctionnera sans configuration. Pour Linux, le support du SDP est fournit dans la Distribution du package OpenFabrics pour les Entreprises (OFED). Pour vérifier que votre version de Linux est configurée avec les drivers de l'OFED et que vous avez un adaptateur NIC InfiniBand, écrivez simplement

egrep "^[ \t]+ib" /proc/net/dev

Si vous recevez une sortie quelconque à partir de cette commande, vous êtes prêts à utiliser le SDP de Java 7 sur ce système d'exploitation.

Il est important de noter que toutes les applications utilisant java.net.* et java.io.* continueront, évidemment, de s'exécuter sous Windows en utilisant la machine virtuelle Java 7... mais elles fonctionneront sans le Protocole Direct de Sockets (et donc en utilisant Ethernet comme fournisseur de couche physique). Cela sera aussi le cas si vous les exécutez sur une version de Windows Server possédant le support InfiniBand (via WinSOCK Direct). Encore une fois, tout continuera de tourner sous Microsoft, mais ce ne sera pas aussi rapide qu'à "certains endroits" qui ne sont pas Microsoft (i.e. *nix).

Les choses ont, effectivement, changé

Parlons à présent du pont entre l'API Java et la pile de protocoles réseau du système d'exploitation. Tout d'abord, le modèle de réseau standard d'Interconnection de Systèmes Ouverts (OSI) se présente de la façon suivante.

# Couche Protocole API du noyau du SDK Java
7 Couche applicative HTTP, FTP, SSL, etc. java.net.HttpURLConnection, javax.servlet.HttpServlet
6 Couche de présentation   Pas de vraie distinction en Java entre les couches applicative et de présentation
5 Couche de session NetBios, RCP Pas de support de la couche de session dans le noyau du SDK Java
4 Couche de transport TCP, UDP java.net.Socket, java.net.ServerSocket, java.net.Datagram
3 Couche réseau IP java.net.InetAddress
2 Couche d'accès aux données PPP Pas de support pour la couche d'accès aux données dans le noyau du SDK
1 Couche physique Ethernet, InfiniBand Pas de support pour la couche physique dans le noyau du SDK, cependant... Protocole Direct de Sockets sous Java 7 (Pont entre InfiniBand et les APIs du noyau java.net.* et java.io.* dans la machine virtuelle)

Du point de vue du modèle de couche réseau OSI, le SPD prend le code applicatif Java aussi bas niveau que possible, et fournit une passerelle directe (le 'D' de SDP) de celui-ci vers le natif et physique InfiniBand, à travers la machine virtuelle. Il fait cela sans que l'application ait besoin de changer sa façon d'utiliser les APIs du noyau java.net.* et java.io.*. En plus de cela, en configurant les points de jointure avec les drivers et les librairies de l'InfiniBand (aussi connus sous le nom de d'API de couche VERBS InfiniBand) dans la JVM, l'utilisation des API java.net.* et java.io.* - qui sont l'API Java pour la couche de transport des ressources du système d'exploitation (Couche OSI 4) - peut passer outre la traditionnelle pile de protocoles réseau (i.e. elle peut passer outre les couches 2 et 3 du modèle OSI) et accéder directement à InfiniBand (Couche OSI 1). Les conséquences sur les performances et les gains sont considérables.

Avec Java 7 et le Protocole Direct de Sockets, Java fait maintenant du RDMA (Accès Direct à la Mémoire à Distance)

Le RDMA est un moyen de déplacer les buffers entre deux processus de machine virtuelle Java (s'exécutant dans un espace d'adressage *nix) à travers un réseau. Il est différent des interfaces réseau traditionnelles, car il passe outre le système d'exploitation. Cela permet au SDP de délivrer : (1) La plus petite latence absolue, (2) La plus haut débit, (3) La plus petite consommation de CPU. En exposant le point de jointure entre Java et RDMA, le SDP permet implicitement à Java de fournir l'irrésistible capacité de "Zéro-copie". "Zéro-copie" décrit les opérations de l'ordinateur qui ne requièrent pas que le CPU copie des données d'une zone mémoire à une autre. Les versions zéro-copie des piles de protocoles réseau augmentent considérablement les performances de certaines applications et utilisent plus efficacement les ressources du système. Les performances sont améliorées en permettant au CPU de s'occuper d'autres tâches pendant que la copie de données s'effectue en parallèle à un autre endroit de la machine. En outre, les opérations zéro-copie réduisent le nombre de chronophages commutations de mode entre l'espace utilisateur et l'espace noyau. Les ressources du système sont utilisées plus efficacement que lorsque l'on utilise un CPU sophistiqué pour effectuer les vastes opérations de copie, qui sont des tâches relativement simples, ce qui est un gâchis si d'autres composants plus simples du système peuvent les effectuer. Il est important de noter que la capacité de "zéro-copie" dont nous parlons ici n'est pas celle que vous pouvez atteindre en utilisant le transferTo() de l'API java.nio.channels.FileChannel. Celle-ci est beaucoup plus performante. Avec le SDP, on utilise directement l'implémentation du protocole zéro-copie d'InfiniBand.

Commençons à représenter visuellement le Protocole Direct de Sockets dans le cadre de certaines vues typiques de déploiement Java

Le diagramme suivant illustre comment Node 1 (un writer java.net.Socket) et Node 2 (un listener java.net.ServerSocket) peuvent être déployés sur une machine virtuelle Java 7 configurée et démarrée pour supporter le SDP de façon à ce que les deux JVMs puissent échanger des buffers de données d'application d'une VM à une autre, à travers le réseau d'une InfiniBand, sans aucun appel du système d'exploitation ou invocation de services. Etonnamment, le transfert de données Java passe complètement outre chacun des sytèmes d'exploitation.

  1. L'application Java 7 Node 1 (une JVM démarrée pour utiliser le SDP), utilise l'API java.net.Socket pour écrire un bloc de données d'application à un java.net.ServerSocket listener, à travers le réseau.
  2. Etant donné que la JVM a été lancée pour utiliser le SDP, la pile TCP/IP du système d'exploitation est complètement contournée - les données d'application sont écrites directement via la capacité de RDMA d'InfiniBand (ce qui nécessite qu'InfiniBand soit le fournisseur physique de la Carte d'Interface Réseau).
  3. L'application Java 7 Node 2 (une JVM aussi démarrée pour utiliser le SDP), utilise l'API java.net.ServerSocket pour attendre l'arrivée d'un bloc de données d'application par RDMA à travers le réseau, depuis un java.net.Socket writer (ce qui nécessite qu'InfiniBand soit le fournisseur physique de la Carte d'Interface Réseau).
  4. Les données sont délivrées directement au buffer d'application de la machine virtuelle Java 7 ! Aucun système d'exploitation ou d'appel de service n'est impliqué, ni depuis le système d'exploitation de Node 1, ni depuis celui de Node 2. C'est cela la puissance du Protocole Direct de Socket sous Java 7.

Quelle est la différence logique de performance entre la même application tournant sous Java 7 avec le SDP et sous Java 6 ?

Le diagramme multi-couches ci-dessous détaille la vue de Node 2 (d'après le précédent diagramme) au travers de deux scénarios différents :

1. En utilisant Java 7 avec le SDP configuré (illustré en bas à gauche), comment la réception par Node 2 des données transmises par Node 1 transite-t-elle à travers la pile de protocoles réseau OSI et l'application Java? Combien d'étapes cela prend-il? Cela ne nécessite qu'une étape! (Voir plus bas, c'est une très bonne nouvelle pour les applications Java de l'UHPC; elle peut maintenant utiliser Java 7 pour faire ce qu'elle a à faire).

2. En utilisant Java 6 (pas de SDP, voir en bas à droite), comment la réception par Node 2 des données transmises par Node 1 transite-t-elle à travers la pile de protocoles réseau OSI et l'application Java? Combien d'étapes cela prend-il? Cela nécessite cinq étapes (Voir ci-dessous - on retrouve la pile de protocoles TCP/IP traditionnelle, pas de SDP. Cela fonctionne dans la plupart des cas, mais pas pour l'UHPC. Elle ne peut donc pas utiliser Java 6 pour ce qu'elle a à faire).

 

Comment administrer et configurer une VM Java 7 pour qu'elle utilise le Protocole Direct de Sockets?

Ce qui suit est un condensé de la section configuration de la page de tutoriel d'Oracle qui introduit le SDP sous Java 7.

Un fichier de configuration SDP est un fichier texte que la JVM lit depuis le système de fichiers local à son démarrage. Il ne comprend que deux types d'entrées. Chacun de ces types est déclaré une fois par ligne :

1. Une ligne de commentaire
2. Une ligne de règle

Un commentaire est annoncé par le caractère dièse (#) au début de la ligne, et tout ce qui suit sera ignoré.

Pour les lignes de règles de configuration, il n'y a que deux types :

1. Les règles de liaison
2. Les règles de connexion

Une règle de "liaison" indique que le protocole de transport du SDP doit être utilisé lorsqu'un socket TCP se lie à une adresse et un port qui correspondent à la règle. Une règle de "connexion" indique que le protocole de transport doit être utilisé lorsqu'un socket non-lié essaye de se connecter à une adresse et un port qui correspondent à la règle.

Grâce aux règles spécifiées dans le fichier de configuration SDP, la JVM sait exactement à quel moment remplacer la pile normale de protocoles TCP/IP par la pile de protocoles VERBS/RDMA d'InfiniBand.

Le premier mot-clé indique si c'est une règle de liaison ou de connexion. L'expression suivante spécifie soit un nom d'hôte, soit une adresse IP litérale. Lorsque l'on spécifie une adresse IP litérale, il est possible de spécifier également un préfixe, qui indique une plage d'adresses IP. La troisième, et dernière expression, est un numéro de port, ou une plage de numéros de ports.

Prenons en exemple la notation suivante dans un fichier de configuration :

# Utiliser le SDP lors de la liaison à 192.0.2.1 bind 192.0.2.1

# Utiliser le SDP lors de la connexion à tous les services d'application sur 192.0.2.1 connect 192.0.2/24 1024-*

La première règle du fichier spécifie que le SDP sera utilisé pour tous les ports (*) sur l'adresse IP locale 192.0.2.1. On ajoutera une règle de liaison pour chaque adresse locale assignée à l'adaptateur InfiniBand (Un adaptateur InfiniBand est l'équivalent d'une carte d'interface réseau (NIC) pour InfiniBand). Si on a plusieurs adaptateurs InfiniBand, on utilisera une règle de liaison pour chaque adresse assignée à ces adaptateurs.

La deuxième règle du fichier spécifie qu'à chaque connexion sur 192.0.2.* avec un port-cible 1024 ou supérieur, on utilisera le SDP. Le préfixe de l'adresse IP /24 indique que les 24 premiers bits de l'adresse IP 32-bits devront correspondre à l'adresse spécifiée. Chaque portion de l'adresse IP utilise 8 bits, donc 24 bits signifie que l'adresse doit correspondre à 192.0.2 et que le byte final peut prendre n'importe quelle valeur. La notation -* sur l'expression du port signifie "et supérieur". Une plage de ports, telle que 1024-2056, serait aussi valide et incluerait ses bornes.

Comment démarrer une machine virtuelle Java 7 pour qu'elle utilise le Protocole Direct de Sockets?

&> java \
-Dcom.sun.sdp.conf=sdp.conf \
-Djava.net.preferIPv4Stack=true \
Application.class

On notera l'utilisation d'IPv4Stack comme format de réseau au démarrage. Même si Java 7 et InfiniBand utilisent le format, plus moderne, IPv6, le mapping entre eux n'est supporté ni sur Solaris, ni sur Linux. Ainsi, on utilisera toujours la familière (et fiable) pierre angulaire IPv4 comme format de réseau pour démarrer une VM Java 7 utilisant SDP.

Quel niveau d'amélioration de performance peut-on attendre lorsque l'on exécute des applications sur une VM Java 7 utilisant SDP?

C'est, bien entendu, la question ultime ! Quel est exactement mon gain lorsque j'utilise le SDP Java 7 ? La réponse à cette question ne peut évidemment pas être déterminée dans le contexte de cet article. Le gain de performance va varier en fonction de nombreux facteurs. Comme cet article touche à sa fin, retenez que ce qui suit sera toujours vrai :

InfiniBand est considérablement plus rapide qu'Ethernet. Une étude exhaustive publiée par le Conseil Consultatif de Calcul Haute Performance délivre des métriques concrètes qui démontrent qu'InfiniBand fournit des performances à 600% meilleures en terme de faible latence, et à 370% meilleures en termes de haut débit que celles de l'Ethernet (10GE).

En outre, le SDP Java 7 utilise RDMA et la meilleure implémentation de zéro-copie. Le transfert de données contourne à 100% la pile réseau TCP/IP du système d'exploitation ainsi que tous les changements de contexte qu'implique le transport de données entre les appels du système dans l'espace d'adressage du noyau et les buffers du code applicatif, dans l'espace d'adressage utilisateur.

Tout cela est fourni avec une transparence complète de l'API du SDK Java. Il n'est pas nécessaire de changer ne serait-ce qu'une ligne d'un code utilisant java.net.* ou java.io.*.

En conclusion, malgré le fait que les choses ont beaucoup changé, la ligne directrice reste la même. Aujourd'hui, comme aux premiers jours de Java (quand la JVM se chargea du fardeau d'isoler le code applicatif des infernaux problèmes de portabilité), la JVM se charge une fois de plus du fardeau de fournir une possibilité prioritaire : cette fois, c'est le Protocole Direct de Sockets. En effet, le slogan originel de Java peut rester sensiblement le même (avec un petit ajout pour refléter ces passionnants temps modernes) : Le SDP Java 7 - Ecrit une fois, exécuté partout... et (parfois) de manière fulgurante!

A propos de l'auteur

Ben D. Cotton III est Consultant IT chez JPMorgan Chase, et utilise actuellement la technologie de grille de données Java sur une plateforme UHP Linux pour interprêter et aggréger en temps réel les risques liés aux liquidités. Il est membre de la communauté Java Process, et fait partie de deux groupes d'experts JCP qui définissent les normes des APIs de Mise en Cache (JSR-107) et de Grilles de Données Distribuées (JSR-347). Ben a été diplômé de l'Université de Rutgers en mai 1985 d'une licence en Informatique. Il a passé ses 11 premières années chez AT&T Bell Laboratories à écrire du code C++ pour supporter les analyses et les protocoles de provisionnement de nombreux réseaux propriétaires de télécommunication, et passa les 14 dernières années à écrire du code Java supportant les systèmes à faible latence de négociation informatique de revenus transactionnels/dérivés, de compensation, d'étabilissement de prix et de calcul de risques.

Evaluer cet article

Pertinence
Style

Contenu Éducatif

BT