Набор утилит для других модулей. Включает LambdaReflection
, который позволяет устанавливать и получать значения полей экземпляра или конструктора доступа через функциональные интерфейсы, созданные LambdaMetafactory
.
Библиотека абстрактной сериализации, поддерживающая любую реализацию буфера. Автоматически (де-)сериализует классы, отмеченные @AutoSerializable
состоящие из полей типов по умолчанию, реализаций Proto4jSerializable
или других членов @AutoSerializable
.
Также поддерживает наследование: сериализуемый класс может расширять другие @AutoSerializable
и в этом случае все родительские поля также станут транзитивно сериализованными.
Поля, которые следует игнорировать во время сериализации, должны быть помечены @Transient
.
Сетевая библиотека с собственной реализацией на основе UDP и настраиваемой надежностью.
Proto4jServer
и Proto4jClient
позволяют передавать данные с помощью датаграмм между сокетами.
По умолчанию любые передаваемые данные упорядочены, надежны, могут быть разбиты на несколько UDP-пакетов и объединены обратно на стороне получателя и гарантированно доставлены.
Все отправляемые UDP-пакеты имеют следующую структуру:
Вы сами выбираете, как передавать данные. Его можно настроить, указав флаги для методов отправки. Все они расположены в Proto4jPacket
. Flag
.
Доступны следующие флаги:
Имя | Ценить | Значение |
---|---|---|
CONFIRMATION | 0x01 | Отмечает, что этот пакет является индикатором успешного получения других пакетов. Требуется для надежности передачи. В общем, только для внутреннего использования. |
PARTIAL | 0x02 | Отмечает, что именно этот UDP-пакет является частью более крупного. При совместном использовании с флагом CONFIRMATION это указывает на то, что некоторая часть более крупного пакета была доставлена. |
UNORDERED | 0x04 | Отмечает, что этот пакет может быть обработан вне очереди. |
UNSIGNED_BODY | 0x08 | По умолчанию все отправленные пакеты подписываются с использованием CRC32 , но для пакетов с указанным флагом будет подписан только заголовок пакета. Это означает, что пакеты могут содержать недопустимые байты (хотя потеря данных при этом не гарантируется). |
UNRELIABLE | 0x10 | Помечает этот пакет как не требующий подтверждения. Если получатель не получил этот пакет, отправитель ничего не сделает. |
INDIVISIBLE | 0x20 | UDP-пакеты ограничены по длине, поэтому Proto4J разбивает огромные данные на несколько меньших пакетов. Этот флаг указывает, что в случае превышения лимита размера одного пакета вместо разделения будет выдано исключение. |
На этом уровне не поддерживается квитирование или проверка связи, но вы можете настроить свои собственные обработчики пакетов, используя метод Proto4jSocket
.setInitialPacketHandler(BiConsumer<C, Proto4jPacket>)
. Пакеты, поступающие в эту точку, никогда не помечаются флагами CONFIRMATION
или PARTIAL
поэтому все обрабатываемые там экземпляры Proto4jPacket
содержат точные данные, отправленные отправителем (вплоть до флага UNSIGNED_BODY
).
Кроме того, когда вы запускаете сокет, будет возвращен CompletionStage<Void>
, который может помочь вам инициировать логику связи между сокетами.
Когда вы собираетесь создать экземпляр любого сокета в Proto4J, вам необходимо передать количество рабочих потоков и потоков-обработчиков конструктору сокета.
Воркеры используются только для чтения данных из сокета.
Обработчики используются для обработки логики при появлении нового пакета.
Это интерфейс более высокого уровня по сравнению с предыдущим уровнем. Чтобы начать с ним работать, взгляните на Proto4jHighServer
и Proto4jHighClient
или их базовые реализации: BaseProto4jHighServer
и BaseProto4jHighClient
.
Когда клиент сначала взаимодействует с сервером, он инициирует установление связи . После его завершения сервер и клиент пропингуют друг друга, чтобы соединение не потерялось.
В отличие от низкого уровня , вы можете отправлять пакеты высокого уровня по сети не только манипулируя необработанными байтами, но и используя сложные объекты. Для этого создайте свой собственный класс, расширяющий EnumeratedProto4jPacket
или CallbackProto4jPacket
. Все, что вам нужно сделать, чтобы заставить его работать, — это реализовать методы write(Buffer)
и read(Buffer)
и зарегистрировать свой пакет в PacketManager
с обеих сторон.
Кроме того, существует альтернативный класс PacketHandler
, который работает с этими пакетами вместо Proto4jPacket
.
Это обычный сценарий ожидания ответа на отправленные пакеты. Эти функциональные возможности уже реализованы на этом уровне. Вы можете указать максимальное время ожидания и обрабатывать ответ так, как хотите. Это можно сделать, отправив начальный пакет с помощью HighChannel
. sendWithCallback(CallbackProto4jPacket)
.
Ниже приведен список свойств системы, которые можно использовать для влияния на внутреннее поведение модулей. Все значения времени указаны в миллисекундах.
Имя | Значение по умолчанию | Описание |
---|---|---|
proto4j.maxDatagramSize | 508 | Максимально допустимый размер датаграммы. Имейте в виду, что он учитывает весь размер UDP-пакета. |
proto4j.maxSequenceNumber | 2_000_000_000 | Максимальный порядковый номер пакета. Когда внутренний счетчик достигнет этого значения, он обнулится. |
proto4j.reliabilityThreshold | 20 | Задержка неподтвержденных (и не отмеченных флагом UNRELIABLE ) пакетов. |
proto4j.callbacksRegistryDelay | 100 | Скорость, с которой проверки реестра обратных вызовов извлекают обратные вызовы с истекшим временем ожидания. |
proto4j.callbacksInitialDelay | 500 | Это время по умолчанию, используемое всякий раз, когда пакет отправляется и ожидается, если время ожидания явно не указано. |
proto4j.highTimeout | 10_000 | Если сервер не получает никаких пакетов от клиента в течение этого времени, он отключит последнего. |
proto4j.highPingDelay | 1_000 | Если сервер указывает, что в течение этого времени не было никаких приемов или отправок клиенту, он отправит ответ последнему и ожидает ping-пакета. |
Это API более высокого уровня, чем первый . Вместо того, чтобы вручную реализовывать пакеты и их обрабатывать, вы работаете через сервисы.
Чтобы начать с ним работать, используйте RpcServer
и RpcClient
.
Сервер на этом уровне используется только для целей маршрутизации, но клиенты выступают как в качестве пользователей услуг, так и в качестве разработчиков.
Сервис состоит из интерфейса и части реализации. Как пользователь службы вы можете получить экземпляр интерфейса службы через RpcClient
.getServiceManager().getService(Class<S>)
. Все его методы будут проксированы в зарегистрированные реализации и будут выполняться удаленно.
Чтобы создать свой собственный сервис, начните с интерфейса и добавьте к нему аннотацию @Proto4jService.
Интерфейс службы может иметь методы по умолчанию и статические методы, но их тип возвращаемого значения должен быть void
, сериализуемый или CompletionStage
предыдущих типов. Кроме того, все аргументы должны быть сериализуемыми.
Сериализуемые типы:
String
и UUID
@AutoSerializable
BufferSerializable
List
, Set
и Map
сериализуемых типов Если метод должен выполняться во всех зарегистрированных реализациях службы, он должен быть помечен @Broadcast
однако такие методы могут возвращать только void
или CompletionStage<Void>
.
По умолчанию, когда вы вызываете метод, он будет выполнен в случайной реализации. Если вы хотите контролировать распределение выполнения, пометьте некоторые аргументы метода @Index
: при каждом вызове метода реализация будет выбираться на основе хэш-кода отмеченных аргументов.
Всякий раз, когда служба регистрируется, все методы преобразуются в целочисленный идентификатор. Не может быть двух методов с одним и тем же идентификатором, но такая ситуация может возникнуть. Чтобы справиться с этим, добавьте к методу аннотацию @MethodIdentifier
с явно указанным статическим идентификатором.
Когда вы уже создали интерфейс службы, теперь создайте его реализацию и зарегистрируйте ее с помощью RpcClient
.getServiceManager().registerService(Class<S>, I)
.
Распространенным сценарием является наличие интерфейса службы на двух группах клиентов, но реализация только на одном из них.
Это уровень более высокого уровня по сравнению с базовым RPC.
При создании распределенной серверной части (т. е. микросервисов) рекомендуется минимизировать количество точек отказа. В схеме, описанной в предыдущем разделе, есть только одна точка отказа — одиночный экземпляр сервера. Конклав — это набор серверов, работающих одновременно.
Все серверы Конклава подключены друг к другу, но каждый клиент подключен только к одному серверу. Запросы RPC корректно распределяются и маршрутизируются по всей сети, так что вам не придется об этом беспокоиться.
Чтобы начать работать с Conclave , взгляните на RpcConclaveServer
и RpcConclaveClient
. Чтобы создать экземпляр любого из них, вам нужно будет передать List<InetSocketAddress>
— список точек назначения всех серверов.
Что касается транспортного модуля, то в модуле RPC есть набор системных свойств.
Имя | Значение по умолчанию | Описание |
---|---|---|
proto4j.conclaveWorkers | 2 | Количество рабочих потоков, используемых каждым из внутренних клиентов сервера (которые используются для доступа к другим серверам). |
proto4j.conclaveHandlers | 2 | Количество потоков обработчиков, используемых каждым из внутренних клиентов сервера (которые используются для доступа к другим серверам). |
proto4j.conclaveTimeout | 1_000 | Максимальное время, в течение которого сервер будет ждать завершения установления связи с другим сервером. В противном случае он будет считать последний неработающим, прекращая собственные попытки подключения, и в этом случае соединение будет перезапущено только в случае запроса от другого при его запуске. |