Ответ 1
Факт № 0: ZeroMQ не является потокобезопасным - по определению
В то время как документация ZeroMQ и превосходная книга Pieter HINTJENS "Код, подключенный. Том 1", не забудьте напомнить об этом, когда это возможно, идея возвращения или даже совместного использования экземпляра сокета ZeroMQ среди потоков появляется время от времени. Разумеется, методы класса-экземпляра могут доставить это почти "скрытое" внутри своих внутренних методов и атрибутов, но надлежащие проектные усилия должны предотвращать любые такие побочные эффекты без каких-либо исключений, никаких оправданий.
Совместное использование, если это обоснованно поддерживается количественными фактами, может быть способом для общего экземпляра zmq.Context()
, но кристально чистая распределенная система может жить по действительно мультиагентной схеме, где каждый агент управляет собственным Context()
-engine, точно настроенный для соответствующего сочетания настроек конфигурации и производительности.
Итак, каков наилучший и эффективный способ решить эту проблему?
Никогда не используйте сокет ZeroMQ. Никогда. Даже если новейшая разработка начала обещать некоторые близкие будущие изменения в этом направлении. Это плохая привычка загрязнять любой высокопроизводительный дизайн с низкой задержкой распределенной системы с совместным использованием. Доля ничего не является лучшим дизайном для этого домена.
Да, я вижу, что мы не должны делиться сокетами между потоками, но в моем коде
как вы думаете, лучший способ разрешить это?
Да, лучший и эффективный способ решить эту проблему - никогда не делиться сокетов ZeroMQ.
Это означает, что никогда не возвращать какой-либо объект, атрибуты которого являются сокетами ZeroMQ (которые вы активно создаете и возвращаете массивным образом из класса .connect(){...}
). В вашем случае весь класс -методы, как представляется, сохраняются private
, что может сгладить проблему разрешения "других потоков" касаться экземпляров класса-приватного сокета, но тот же принцип должен быть одобрен также для всех атрибутов- уровень, чтобы быть эффективным. Наконец, это "слияние" получает ярлык и нарушается
public static SocketManager getInstance()
,
который promiscuitively предлагает любому внешнему аферу получить прямой доступ к совместному использованию частных экземпляров сокетов ZeroMQ.
Если в какой-либо документации явным образом предупреждает почти каждую главу о том, чтобы не делиться вещами, скорее не следует делиться вещами.
Итак, переконструируйте методы таким образом, чтобы SocketManager
получал больше функциональных возможностей, чем методы класса, которые будут выполнять встроенные функции must-have, чтобы явно запретить любой поток внешнего мира коснитесь экземпляра, не имеющего общего доступа, как описано в публикациях ZeroMQ.
Далее идет инвентаризация ресурсов: ваш код, кажется, пересматривает каждые 30 секунд состояние мира во всех DataCenters-of-Interest. Это фактически создает новые объекты List два раза в минуту. Хотя вы можете спекулировать java Сборщик мусора убирать все трэш, о чем больше не упоминается нигде, это не очень хорошая идея для объектов, связанных с ZeroMQ, встроенных внутри List-s из ваших предыдущих проверок повторной проверки. Объекты ZeroMQ по-прежнему ссылаются изнутри Zcontext()
- созданных в ZeroMQ Context()
-core- factory потоков ввода-вывода, которые также можно рассматривать как диспетчер ресурсов сокета-инвентаря ZeroMQ. Таким образом, все new
-созданные сокеты-экземпляры получают не только внешний дескриптор из java
-side, но и внутренний-дескриптор изнутри (Z)Context()
. Все идет нормально. Но то, что не видно нигде в коде, - это какой-либо метод, который будет деактивировать любые и все сокеты ZeroMQ в объектных экземплярах, которые были отключены от java
-side, но все же остаются ссылкой на (Z)Context()
-side. Явное выделение ресурсов из выделенных ресурсов является справедливой практикой на стороне разработки, тем больше ресурсов, которые ограничены или иным образом ограничены. Способ для этого может отличаться для { "cheap" | "дорогостоящие" затраты на такую обработку ресурсов (обработка ZeroMQ-сокетов чрезвычайно выгодна для обработки в виде небольшого "расходного/одноразового"... но это уже другая история).
Итак, добавьте также набор правильных методов повторного использования/ресурсов-демонтажа ресурсов, которые вернут общую сумму new
-созданных сокетов обратно под вашу ответственность за контроль (ваш код отвечает за количество сокетов -handlers внутри (Z)Context()
-область-ресурсы-контроль может создаваться и должен оставаться управляемым - будь то сознательно или нет).
Можно возразить, что может быть некоторая "promises" из автоматического обнаружения и (возможно, отложенная) сборка мусора, но тем не менее ваш код отвечает за правильное управление ресурсами, и даже ребята из LMAX никогда не получат такую храбрую производительность, если они полагаются на "promises" из стандартного gc. Ваша проблема хуже, чем LMAX с максимальной производительностью. Ваш код (до сих пор опубликованный) ничего не делает для .close()
и .term()
связанных с ZeroMQ ресурсов. Это - прямая невозможная практика внутри экосистемы с неконтролируемым (распределенным спросом) - потреблением. Вы должны защитить свою лодку от перегрузки за пределы, которые, как вы знаете, могут безопасно обрабатывать и динамически разгружать каждую коробку, у которой нет получателя на "противоположном берегу".
Это капитан (ваш разработчик кода) .
Не указывая явным образом матрос-менеджмент управления запасами на самом низком уровне (ZeroMQ Context()
-floor), чтобы некоторые ящики не загружались, проблема по-прежнему остается вашей. Стандартная gc
-связка команды не будет делать это "автоматически", независимо от того, что "promises" может выглядеть так, как было бы, это не так. Поэтому будьте откровенны в отношении управления ресурсами ZeroMQ, оцените коды возврата, чтобы упорядочить эти шаги, которые необходимо предпринять, и надлежащим образом обрабатывать любые и все исключения, возникающие при выполнении этих операций управления ресурсами под явным контролем кода.
Нижняя (если вообще не самая низкая достижимая) использование ресурсов - более высокие (если не самые высокие достижимые) производительность - это бонус от выполнения этой работы правильно. Ребята из LMAX - хороший пример того, что это замечательно выходит за рамки стандартного java "promises", поэтому можно учиться на ладбах лучших.
Объявленные сигнатуры подписей, а также используемые, похоже, не соответствуют:
в то время как я могу ошибаться в этом вопросе, так как большинство моих проектных усилий не находятся в java полиморфных интерфейсов вызова, похоже, в подписи есть неправильное совпадение, опубликованное как:
private List<SocketHolder> connect( Datacenters dc, // 1-st
List<String> addresses, // 2-nd
int socketType // 3-rd
) {
... /* implementation */
}
и фактический вызов метода, вызванный внутри метода connectToZMQSockets()
, просто:
List<SocketHolder> addedColoSockets = connect( entry.getValue(), // 1-st
ZMQ.PUSH // 2-nd
);