Набор утилит для других модулей. Включает 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@AutoSerializableBufferSerializableList , 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 | Максимальное время, в течение которого сервер будет ждать завершения установления связи с другим сервером. В противном случае он будет считать последний неработающим, прекращая собственные попытки подключения, и в этом случае соединение будет перезапущено только в случае запроса от другого при его запуске. |