Gama de utilidades para otros módulos. Incluye LambdaReflection
que permite establecer y obtener valores de campo de una instancia o acceder al constructor a través de interfaces funcionales creadas por LambdaMetafactory
.
Biblioteca de serialización abstracta que admite cualquier implementación de búfer. (Des)serializa automáticamente las clases marcadas con @AutoSerializable
que constan de campos de tipos predeterminados, implementaciones Proto4jSerializable
u otros miembros @AutoSerializable
.
También admite herencia: la clase serializable puede extender otras @AutoSerializable
en cuyo caso todos los campos principales también se serializarán transitivamente.
Los campos que deben ignorarse durante la serialización deben anotarse con @Transient
.
Biblioteca de redes con implementación personalizada basada en UDP con confiabilidad configurable.
Proto4jServer
y Proto4jClient
le permiten transferir datos utilizando datagramas entre sockets.
De forma predeterminada, todos los datos transmitidos son ordenados, confiables, pueden dividirse en varios paquetes UDP y combinarse nuevamente en el lado del receptor y se garantiza su entrega.
Todos los paquetes UDP que se envían tienen la siguiente estructura:
Es su elección seleccionar cómo transmitir los datos. Se puede configurar especificando indicadores para los métodos de envío. Todos están ubicados en Proto4jPacket
. Flag
.
Las siguientes banderas están disponibles:
Nombre | Valor | Significado |
---|---|---|
CONFIRMATION | 0x01 | Marca que este paquete es un indicador de que otros paquetes se han recibido correctamente. Requerido para la confiabilidad de la transmisión. En general, sólo para uso interno. |
PARTIAL | 0x02 | Marca que este paquete UDP exacto es parte de uno más grande. Cuando se usa junto con el indicador CONFIRMATION , indica que se ha entregado una parte de un paquete más grande. |
UNORDERED | 0x04 | Marca que este paquete se puede manejar fuera de orden. |
UNSIGNED_BODY | 0x08 | De forma predeterminada, todos los paquetes enviados se firman utilizando CRC32 , pero para los paquetes con ese indicador especificado solo se firmará el encabezado del paquete. Esto significa que los paquetes pueden contener bytes no válidos (aunque todavía no se garantiza ninguna pérdida de datos). |
UNRELIABLE | 0x10 | Marca este paquete como que no requiere confirmación. En caso de que el receptor no reciba este paquete, el remitente no hará nada al respecto. |
INDIVISIBLE | 0x20 | Los paquetes UDP tienen una longitud limitada, por lo que Proto4J divide datos enormes en varios paquetes más pequeños. Este indicador indica que en caso de que el paquete exceda el límite de tamaño del paquete único, se generará una excepción en lugar de realizar la división. |
En este nivel no se admite ningún protocolo de enlace ni ping, pero puede configurar sus propios controladores de paquetes utilizando el método Proto4jSocket
.setInitialPacketHandler(BiConsumer<C, Proto4jPacket>)
. Los paquetes que llegan a este punto nunca se marcan con indicadores CONFIRMATION
o PARTIAL
, por lo que todas las instancias Proto4jPacket
manejadas allí contienen datos exactos enviados por el remitente (hasta el indicador UNSIGNED_BODY
).
Además, cuando inicie el socket, se devolverá un CompletionStage<Void>
que puede ayudarlo a iniciar la lógica de comunicación entre sockets.
Cuando esté a punto de crear una instancia de cualquier socket en Proto4J, debe pasar la cantidad de subprocesos de trabajo y controlador al constructor del socket.
Los trabajadores solo se utilizan para leer datos del socket.
Los controladores se utilizan para manejar la lógica cuando aparece un nuevo paquete.
Esta es una interfaz de nivel superior al nivel anterior. Para comenzar a trabajar con él, eche un vistazo a Proto4jHighServer
y Proto4jHighClient
o sus implementaciones básicas: BaseProto4jHighServer
y BaseProto4jHighClient
.
Cuando el cliente interactúa con el servidor al principio, inicia un protocolo de enlace . Una vez completado, el servidor y el cliente harán ping entre sí para garantizar que no se pierda la conexión.
A diferencia del nivel bajo , puede enviar paquetes de alto nivel a través de la red no solo manipulando bytes sin formato sino también utilizando entidades complejas. Para hacerlo, cree su propia clase que extienda EnumeratedProto4jPacket
o CallbackProto4jPacket
. Todo lo que tiene que hacer para que funcione es implementar los métodos de write(Buffer)
y read(Buffer)
y registrar su paquete en PacketManager
en ambos lados.
Además, existe una clase PacketHandler
alternativa que funciona con esos paquetes en lugar de Proto4jPacket
s.
Es un escenario común esperar que algún paquete responda a los enviados. Esta funcionalidad ya está implementada en este nivel. Puede especificar el tiempo máximo de espera y manejar la respuesta de la forma que desee. Esto se puede hacer enviando el paquete inicial usando HighChannel
. Método sendWithCallback(CallbackProto4jPacket)
.
La siguiente es una lista de propiedades del sistema que se pueden utilizar para afectar la forma en que los módulos se comportan internamente. Todos los valores de tiempo se especifican en milisegundos.
Nombre | Valor predeterminado | Descripción |
---|---|---|
proto4j.maxDatagramSize | 508 | Tamaño máximo de datagrama permitido. Tenga en cuenta que cuenta todo el tamaño del paquete UDP. |
proto4j.maxSequenceNumber | 2_000_000_000 | Número de secuencia máximo del paquete. Cuando el contador interno alcance este valor se pondrá a cero. |
proto4j.reliabilityThreshold | 20 | Retraso de paquetes no confirmados (y no marcados con el indicador UNRELIABLE ). |
proto4j.callbacksRegistryDelay | 100 | Velocidad a la que las comprobaciones del registro de devoluciones de llamadas recuperan las devoluciones de llamadas con tiempo de espera agotado. |
proto4j.callbacksInitialDelay | 500 | Es el tiempo predeterminado que se utiliza cada vez que se envía un paquete y se espera cuando el tiempo de espera no se especifica explícitamente. |
proto4j.highTimeout | 10_000 | Si el servidor no recibe ningún paquete del cliente durante tanto tiempo, desconectará este último. |
proto4j.highPingDelay | 1_000 | Si el servidor indica que no hubo recepciones ni envíos al cliente durante ese tiempo, enviará la respuesta a este último y esperará un paquete de ping. |
Esta es una API de nivel superior a la de alto nivel . En lugar de implementar paquetes manualmente y su manejo, trabaja a través de servicios.
Para comenzar a trabajar con él, use RpcServer
y RpcClient
.
El servidor en este nivel solo se utiliza con fines de enrutamiento, pero los clientes actúan como usuarios e implementadores del servicio.
El servicio consta de partes de interfaz y de implementación. Como usuario del servicio, puede obtener una instancia de la interfaz del servicio a través de RpcClient
.getServiceManager().getService(Class<S>)
. Todos sus métodos se enviarán a implementaciones registradas y se ejecutarán de forma remota.
Para crear su propio servicio, comience con una interfaz y anótela con @Proto4jService.
Se permite que la interfaz de servicio tenga métodos predeterminados y estáticos, pero su tipo de retorno debe ser void
, serializable o CompletionStage
de los tipos anteriores. Además, todos los argumentos deben ser serializables.
Los tipos serializables son los siguientes:
String
y UUID
@AutoSerializable
BufferSerializable
List
, Set
y Map
de tipos serializables Si un método debe ejecutarse en todas las implementaciones de servicios registradas, debe anotarse con @Broadcast
sin embargo, dichos métodos solo pueden devolver void
o CompletionStage<Void>
.
De forma predeterminada, cuando invoque el método, se ejecutará en una implementación aleatoria. Si desea controlar la distribución de la ejecución, marque algunos de los argumentos del método con @Index
: siempre que se invoque el método, la implementación se seleccionará en función del código hash de los argumentos marcados.
Siempre que se registra el servicio, todos los métodos se convierten a un identificador entero. No puede haber dos métodos con el mismo identificador pero puede ocurrir tal situación. Para manejarlo, anote el método con @MethodIdentifier
con un identificador estático especificado explícitamente.
Cuando ya haya creado una interfaz de servicio, ahora cree su implementación y regístrela usando RpcClient
.getServiceManager().registerService(Class<S>, I)
.
El escenario común es tener una interfaz de servicio en dos conjuntos de clientes pero tener la implementación en solo uno de ellos.
Esta es una capa de nivel superior a la RPC básica.
Al crear un back-end distribuido (es decir, microservicios), es una buena práctica minimizar la cantidad de puntos de falla. Sólo hay un punto de falla en el esquema descrito en la sección anterior, que es la instancia de servidor único. Cónclave es un conjunto de servidores que funcionan simultáneamente.
Todos los servidores de Conclave están conectados entre sí, pero cada cliente solo está conectado a un único servidor. Las consultas RPC se distribuyen y enrutan elegantemente por toda la red para que usted no tenga que preocuparse por ello.
Para comenzar a trabajar con Conclave , eche un vistazo a RpcConclaveServer
y RpcConclaveClient
. Para crear una instancia de cualquiera de ellos, deberá pasar una List<InetSocketAddress>
: lista de los puntos de destino de todos los servidores.
En cuanto al módulo de Transporte , hay un conjunto de propiedades del sistema que se buscan en el módulo RPC .
Nombre | Valor predeterminado | Descripción |
---|---|---|
proto4j.conclaveWorkers | 2 | Número de subprocesos de trabajo utilizados por cada uno de los clientes internos del servidor (que se utilizan para acceder a otros servidores). |
proto4j.conclaveHandlers | 2 | Número de subprocesos de controlador utilizados por cada uno de los clientes internos del servidor (que se utilizan para acceder a otros servidores). |
proto4j.conclaveTimeout | 1_000 | Tiempo máximo que el servidor esperará hasta que finalice el protocolo de enlace con otro servidor. De lo contrario, considerará este último como no en ejecución y finalizará sus propios intentos de conexión, en cuyo caso la conexión sólo se reiniciará en caso de que otra persona lo solicite al iniciarse. |