Gamme d'utilitaires pour d'autres modules. Inclut LambdaReflection
qui permet de définir et d'obtenir les valeurs de champ d'une instance ou d'accéder à un constructeur via des interfaces fonctionnelles créées par LambdaMetafactory
.
Bibliothèque de sérialisation abstraite qui prend en charge toute implémentation de tampon. (Dés)sérialise automatiquement les classes marquées avec @AutoSerializable
composées de champs de types par défaut, d'implémentations Proto4jSerializable
ou d'autres membres @AutoSerializable
.
Prend également en charge l'héritage : la classe sérialisable peut étendre d'autres @AutoSerializable
auquel cas tous les champs parents seront également sérialisés de manière transitive.
Les champs qui doivent être ignorés lors de la sérialisation doivent être annotés avec @Transient
.
Bibliothèque réseau avec implémentation personnalisée basée sur UDP et fiabilité configurable.
Proto4jServer
et Proto4jClient
vous permettent de transférer des données à l'aide de datagrammes entre sockets.
Par défaut, toutes les données transmises sont ordonnées, fiables, peuvent être divisées en plusieurs paquets UDP et recombinées côté récepteur et leur livraison est garantie.
Tous les paquets UDP envoyés ont la structure suivante :
C'est à vous de choisir comment transmettre les données. Il peut être configuré en spécifiant des indicateurs pour les méthodes d'envoi. Ils sont tous situés dans Proto4jPacket
. Flag
.
Les drapeaux suivants sont disponibles :
Nom | Valeur | Signification |
---|---|---|
CONFIRMATION | 0x01 | Indique que ce paquet est un indicateur que d'autres paquets ont été reçus avec succès. Nécessaire pour la fiabilité de la transmission. En général, pour usage interne uniquement. |
PARTIAL | 0x02 | Indique que ce paquet UDP exact fait partie d'un paquet plus grand. Lorsqu'il est utilisé conjointement avec l'indicateur CONFIRMATION il indique qu'une partie d'un paquet plus volumineux a été livrée. |
UNORDERED | 0x04 | Indique que ce paquet peut être traité dans le désordre. |
UNSIGNED_BODY | 0x08 | Par défaut, tous les paquets envoyés sont signés à l'aide de CRC32 , mais pour les paquets avec cet indicateur spécifié, seul l'en-tête d'un paquet sera signé. Cela signifie que les paquets peuvent contenir des octets invalides (même si aucune perte de données n'est toujours garantie). |
UNRELIABLE | 0x10 | Marque ce paquet comme ne nécessitant pas de confirmation. Si le destinataire ne reçoit pas ce paquet, l'expéditeur ne fera rien. |
INDIVISIBLE | 0x20 | Les paquets UDP sont limités en longueur, donc Proto4J divise les données volumineuses en plusieurs paquets plus petits. Cet indicateur indique que si le paquet dépasse la limite de taille du paquet unique, une exception sera levée au lieu d'effectuer un fractionnement. |
Aucun établissement de liaison ni ping n'est pris en charge à ce niveau, mais vous pouvez configurer vos propres gestionnaires de paquets à l'aide de la méthode Proto4jSocket
.setInitialPacketHandler(BiConsumer<C, Proto4jPacket>)
. Les paquets arrivant à ce stade ne sont jamais marqués avec des indicateurs CONFIRMATION
ou PARTIAL
, donc toutes les instances Proto4jPacket
qui y sont traitées contiennent des données exactes envoyées par l'expéditeur (jusqu'à l'indicateur UNSIGNED_BODY
).
De plus, lorsque vous démarrez le socket, un CompletionStage<Void>
sera renvoyé, ce qui peut vous aider à lancer la logique de communication entre les sockets.
Lorsque vous êtes sur le point d'instancier n'importe quel socket dans Proto4J, vous devez transmettre le montant des threads de travail et de gestionnaire au constructeur de socket.
Les travailleurs ne sont utilisés que pour lire les données du socket.
Les gestionnaires sont utilisés pour gérer la logique lorsqu'un nouveau paquet apparaît.
Il s'agit d'une interface de niveau supérieur au niveau précédent. Pour commencer à travailler avec, jetez un œil à Proto4jHighServer
et Proto4jHighClient
ou à leurs implémentations de base : BaseProto4jHighServer
et BaseProto4jHighClient
.
Lorsque le client interagit avec le serveur pour la première fois, il initie une négociation . Une fois terminé, le serveur et le client se cingleront afin de garantir que la connexion ne soit pas perdue.
Contrairement au niveau bas , vous pouvez envoyer des paquets de haut niveau sur le réseau non seulement en manipulant les octets bruts, mais également en utilisant des entités complexes. Pour ce faire, créez votre propre classe étendant EnumeratedProto4jPacket
ou CallbackProto4jPacket
. Tout ce que vous avez à faire pour que cela fonctionne est d'implémenter les méthodes write(Buffer)
et read(Buffer)
et d'enregistrer votre paquet dans PacketManager
des deux côtés.
En outre, il existe une classe alternative PacketHandler
qui fonctionne avec ces paquets au lieu des Proto4jPacket
s.
Il est courant d'attendre qu'un paquet réponde à ceux envoyés. Ces fonctionnalités sont déjà implémentées à ce niveau. Vous pouvez spécifier le temps d'attente maximum et gérer la réponse comme vous le souhaitez. Cela peut être fait en envoyant le paquet initial à l'aide de HighChannel
. méthode sendWithCallback(CallbackProto4jPacket)
.
Ce qui suit est une liste de propriétés système qui peuvent être utilisées pour affecter le comportement interne des modules. Toutes les valeurs de temps sont spécifiées en millisecondes.
Nom | Valeur par défaut | Description |
---|---|---|
proto4j.maxDatagramSize | 508 | Taille maximale autorisée du datagramme. Sachez qu'il compte la taille totale du paquet UDP. |
proto4j.maxSequenceNumber | 2_000_000_000 | Numéro de séquence maximum du paquet. Lorsque le compteur interne atteint cette valeur, il se remet à zéro. |
proto4j.reliabilityThreshold | 20 | Retard des paquets non confirmés (et non marqués du drapeau UNRELIABLE ). |
proto4j.callbacksRegistryDelay | 100 | Fréquence à laquelle les vérifications du registre des rappels récupèrent ses rappels expirés. |
proto4j.callbacksInitialDelay | 500 | C'est l'heure par défaut utilisée chaque fois qu'un paquet est envoyé et attendu lorsque l'heure d'attente n'est pas explicitement spécifiée. |
proto4j.highTimeout | 10_000 | Si le serveur ne reçoit aucun paquet du client pendant cette période, il déconnectera ce dernier. |
proto4j.highPingDelay | 1_000 | Si le serveur indique qu'il n'y a eu aucune réception ou envoi vers le client pendant cette période, il enverra la réponse à ce dernier et attendra un paquet ping. |
Il s'agit d'une API de niveau supérieur à celle de haut niveau . Au lieu d'implémenter manuellement les paquets et leur gestion, vous travaillez via des services.
Pour commencer à travailler avec, utilisez RpcServer
et RpcClient
.
Le serveur à ce niveau n'est utilisé qu'à des fins de routage, mais les clients agissent à la fois en tant qu'utilisateurs du service et en tant qu'implémenteurs.
Le service comprend des parties d’interface et d’implémentation. En tant qu'utilisateur de service, vous pouvez obtenir une instance d'interface de service via RpcClient
.getServiceManager().getService(Class<S>)
. Toutes ses méthodes seront transmises par proxy aux implémentations enregistrées et seront exécutées à distance.
Pour créer votre propre service, commencez par une interface et annotez-la avec @Proto4jService.
L'interface de service est autorisée à avoir des méthodes par défaut et statiques, mais leur type de retour doit être void
, sérialisable ou un CompletionStage
des types précédents. De plus, tous les arguments doivent être sérialisables.
Les types sérialisables sont les suivants :
String
et UUID
@AutoSerializable
BufferSerializable
List
, Set
et Map
des types sérialisables Si une méthode doit être exécutée sur toutes les implémentations de services enregistrées, elle doit être annotée avec @Broadcast
mais ces méthodes ne peuvent renvoyer que void
ou CompletionStage<Void>
.
Par défaut, lorsque vous invoquez la méthode, elle sera exécutée sur une implémentation aléatoire. Si vous souhaitez contrôler la distribution de l'exécution, marquez certains arguments de la méthode avec @Index
: chaque fois que la méthode est invoquée, l'implémentation sera sélectionnée en fonction du code de hachage des arguments marqués.
Chaque fois que le service est enregistré, toutes les méthodes sont converties en identifiant entier. Il ne peut pas y avoir deux méthodes avec le même identifiant mais une telle situation peut se produire. Pour le gérer, annotez la méthode avec @MethodIdentifier
avec un identifiant statique explicitement spécifié.
Lorsque vous avez déjà créé une interface de service, créez maintenant son implémentation et enregistrez-la à l'aide de RpcClient
.getServiceManager().registerService(Class<S>, I)
.
Le scénario courant consiste à avoir une interface de service sur deux ensembles de clients tout en ayant l'implémentation sur un seul d'entre eux.
Il s'agit d'une couche de niveau supérieur au RPC de base.
Lors de la création d'un back-end distribué (c'est-à-dire des microservices), il est recommandé de minimiser le nombre de points de défaillance. Il n'y a qu'un seul point de défaillance dans le schéma décrit dans la section précédente : une instance de serveur unique. Conclave est un ensemble de serveurs qui fonctionnent simultanément.
Tous les serveurs de Conclave sont connectés les uns aux autres mais chaque client n'est connecté qu'à un seul serveur. Les requêtes RPC sont gracieusement distribuées et acheminées sur l'ensemble du réseau afin que vous n'ayez pas à vous en soucier.
Pour commencer à travailler avec Conclave , jetez un œil à RpcConclaveServer
et RpcConclaveClient
. Pour instancier l'un d'entre eux, vous devrez transmettre une List<InetSocketAddress>
- liste des points de destination de tous les serveurs.
En ce qui concerne le module Transport , un ensemble de propriétés système est recherché dans le module RPC .
Nom | Valeur par défaut | Description |
---|---|---|
proto4j.conclaveWorkers | 2 | Nombre de threads de travail utilisés par chacun des clients internes du serveur (qui sont utilisés pour accéder à d'autres serveurs). |
proto4j.conclaveHandlers | 2 | Nombre de threads de gestionnaire utilisés par chacun des clients internes du serveur (qui sont utilisés pour accéder à d'autres serveurs). |
proto4j.conclaveTimeout | 1_000 | Temps maximum pendant lequel le serveur attendra jusqu'à ce que la négociation avec un autre serveur soit terminée. Dans le cas contraire, il considérera cette dernière comme une connexion non exécutée mettant fin à ses propres tentatives de connexion, auquel cas la connexion ne sera redémarrée qu'en cas de demande d'un autre lors de son démarrage. |