Search
Write a publication
Pull to refresh
0
0
Send message

Жизнь асинхронна и события по факту происходят асинхронно.

Установилось сетевое соединение - событие.

Разорвалось сетевое соединение - событие. Надо всё корректно закрыть и почистить.

Успешно закончился SSL handshake - событие, из параметров которого ещё нужно извлечь сертификат другой стороны и произвести аутентификацию, авторизацию и создать ентри в таблице сессий.

И всё это надо обработать как можно быстрее.

Что касается стоимости - часто более общее решение гораздо дешевле кучи частных. У нас всё на метаданных, весь обмен идет по набору унифицированных шин. Переход на OSGi позволил избавиться от необходимости писать кучу самопала. Один перенос парсинга XML с сервера на клиентов позволил сэкономить тучу денег на серверном оборудовании. Сейчас ещё вычистим старые реализации обработки на сервере списочных данных, которые сделаны в виде старых добрых списков в оперативной памяти, и будет совсем хорошо.

При пинге 50 мс 100 вызовов в цикле синхронного вызова функции дадут 5000 мс, а не 98 мс

Если в процессе передачи нужно обработать кучу промежуточных событий разного типа, это уже не черный ящик с синхронной функцией "удалённо обработать документ". Не говоря о том, что нужно корректно обработать случай обрыва связи и начать с нужного места дальше после восстановления связи/перезагрузки на одной или обеих сторонах.

Не так всё просто.

Каждое уведомление надо обработать и в результате обработки обновить интерфейс пользователя и данные на стороне клиента. Запросов параллельно несколько, сокеты ценные ресурсы и на клиента сокет один. По которому надо передать туда обратно кучу всего. И данные и команды. И то и то имеет приоритеты, команды обрабатываются в первую очередь. Более приоритетный документ ставит на паузу отправку менее приоритетного. Двустороння асинхронная шина (набор шин) краеугольный элемент распределенной системы и попытка спрятать её под одеяло приносит больше проблем, чем решает. Удаленный метод не должен выглядеть как локальный. Удаленный метод требует реализации формализованного двустороннего протокола обмена.

Попробуйте получить такие тайминги при вызове в цикле синхронного вызова функции

09:34:38.343 - Send MD successful
09:34:38.343 - Send MD successful
09:34:38.344 - Send MD successful
09:34:38.344 - Send MD successful
09:34:38.345 - Send MD successful
09:34:38.345 - Send MD successful
09:34:38.345 - Send MD successful
09:34:38.346 - Send MD successful
09:34:38.346 - Send MD successful
09:34:38.346 - Send MD successful
09:34:38.346 - Send MD successful
...
09:34:38.379 - Send MD successful
09:34:38.379 - Send MD successful
09:34:38.379 - Send MD successful
09:34:38.379 - Send MD successful
09:34:38.380 - Send MD successful
09:34:38.380 - Send MD successful
09:34:38.380 - Send MD successful
09:34:38.381 - Send MD successful
09:34:38.381 - Send MD successful
09:34:38.400 - ## handle response ACK from Server to Msg 7 from GUI
09:34:38.401 - ## handle response ACK from Server to Msg 8 from GUI
09:34:38.402 - ## handle response ACK from Server to Msg 9 from GUI
09:34:38.402 - ## handle response ACK from Server to Msg 10 from GUI
09:34:38.403 - ## handle response ACK from Server to Msg 11 from GUI
09:34:38.403 - ## handle response ACK from Server to Msg 12 from GUI
...
09:34:38.436 - ## handle response ACK from Server to Msg 86 from GUI
09:34:38.436 - ## handle response ACK from Server to Msg 87 from GUI
09:34:38.436 - ## handle response ACK from Server to Msg 88 from GUI
09:34:38.437 - ## handle response ACK from Server to Msg 89 from GUI
09:34:38.437 - ## handle response ACK from Server to Msg 90 from GUI
09:34:38.437 - ## handle response ACK from Server to Msg 91 from GUI
09:34:38.437 - ## handle response ACK from Server to Msg 92 from GUI
09:34:38.438 - ## handle response ACK from Server to Msg 93 from GUI
09:34:38.438 - ## handle response ACK from Server to Msg 94 from GUI
09:34:38.438 - ## handle response ACK from Server to Msg 95 from GUI
09:34:38.439 - ## handle response ACK from Server to Msg 96 from GUI
09:34:38.439 - ## handle response ACK from Server to Msg 97 from GUI
09:34:38.440 - ## handle response ACK from Server to Msg 98 from GUI
09:34:38.440 - ## handle response ACK from Server to Msg 99 from GUI
09:34:38.441 - ## handle response ACK from Server to Msg 100 from GUI

Это по обычному интернету на ширпотебовских раутерах, компьютеры в разных квартирах на разных улицах. Ещё и древний комп на i7-3770 с древним сетевым оборудованием.

Контекст размазан по ФС и памяти, Акторами не пользуемся.

Все ответные данные приходят на один обработчик, а варианты начинаются с примитивных типов наподобие подтверждения приема фрагмента в виде примитивного массива, варианты контекста и обработки сильно разные. Служебные сообщения системы передачи обрабатываются по своему, сообщения прикладных сервисов по своему.

При двух встречных асинхронных потоках в каждом направлении запись следующего фрагмента начинается по локальному событию успешного окончания записи в сокет предыдущего. Когда предыдущий запрос даже до сервера провайдера не добрался.

Такое поведение нельзя получить, вызывая в цикле вызов "запрос-ответ" с ожиданием результата каждого вызова.

Цикл запрос-ответ не катит, добавлять задержку к каждому запросу недопустимо.

Прелесть двух встречных асинхронных потоков в том, что можно в каждую сторону отсылать данные с максимальной пропускной способностью.

Примитивные способы грамотного Заказчика не устраивают.

Так просто не получается.

Отправитель производит отправку записью множества фрагментов по одному за один вызов. С некоторой задержкой начинает поступать обратный поток посредством множества асинхронных вызовов. Так что отправитель не может заснуть ни на отправке, ни на приёме.

Запрос не посылается за один раз, при такой организации работать невозможно при больших объемах. И результатов множество - подтверждение приема каждого фрагмента, уведомление в приеме всего документа с ЭЦП и только потом приходят результаты запроса. Логика обработки каждого типа результата разная. И не факт, что пользователь не выключит компьютер до того, как придет ответ.

И там, и там. На БД или ФС долго, в ОЗУ ненадежно.

Хотим попробовать Optane Persistent Memory с возможностью побайтовой адресации.

Пока сбоев нет, можно пользоваться данными в ОЗУ, в случае сбоя надо синхронизировать данные на обеих сторонах. Так как всё асинхронно, а по сети ненадежно, надо определить, с какого места продолжать после сбоя. Отдельным запросом по UID документа запрашивается сколько байт записано на сервере, отправитель продолжает отправку с нужного места. Самое сложное в том, что все ответные данные на сетевом уровне приходят на один и тот же метод обработчика, только на разные экземпляры, и надо понять, какой обработчик дальше вызвать.

Два это минимум. Только ответных минимум три.

Один - отправка подтверждения приема фрагмента.

Другой - отправка уведомления в приеме документа, на которое наложена ЭЦП системы.

Третий - отправка результатов обработки.

Все формируются разными сервисами. Второй и третий запускаются на обработку параллельно.

Без возни с событиями не получится, ответные данные приходят асинхронно в совершенно другом потоке и обработчике.

Синхронный вызов загоняет в парадигму «запрос-ответ». Проблема в том, что понятие функции, с которой мы все начинали учить программирование, совершенно неадекватно реальным процессам обработки в сети. Там по факту два встречных асинхронных потока (как минимум) и число событий в обеих направлениях неодинаково и заранее не всегда известно.

Конкретный пример — передача большого документа на примере таможенной декларации. В реальных системах (не буду называть конкретную, но это из реальной жизни) встречается такая дичь, что диву даешься. Пользователь нажимает кнопку приёма или отправки и весь интерфейс виснет. Что происходит, вообще непонятно. Или скорость низкая, но передача идет и надо ждать, или процесс завис и надо перегружаться. Диагностики ноль. Никакой loom тут не поможет.

По сути, надо иметь гранулярность уровня sub-method, когда внутри одного метода (прием или передача документа) асинхронно происходит куча другой обработки, причем, в обе стороны.

Записали очередной массив байтов в сокет. С какой скоростью он будет физически передаваться (или не передаваться) в данный момент, зависит от массы внешних факторов, так что надежный вариант ждать события успешного окончания записи в сокет или сбоя. Каждое надо обработать. При успехе обновить интерфейс пользователя, чтобы человек видел, как идет процесс. Даже это в своём потоке. Также нужно обеспечить дросселирование, чтобы не писать в сокет быстрее, чем физическая линия способна передать данные. Недопустимо ждать подтверждения приема на каждый фрагмент, пока первый фрагмент в пути, могут быть отправлены несколько следующих. Буфер свободен — пишем следующий фрагмент.

Параллельно вызываются обработчики приема ответных данных, как минимум, подтверждение приема фрагментов, чтобы пользователь видел, что серверная часть работает.

В общем случае может возникнуть набор разных асинхронных событий. Не вижу способа избавиться от асинхронности и сохранить эффективность.

Два встречных асинхронных потока событий это не набор пар запрос/ответ.

В серьезных системах при приеме последнего фрагмента нужно сделать кучу работы — собрать объект/документ до кучи, проверить его ЭЦП, сформировать заверенное ЭЦП системы уведомление в приёме документа, отправить его по ответному каналу отправителю, записать в реестры входящих/исходящих, при этом никакой обработки даже не начиналось. Потом найти обработчик и передать ему документ на обработку. Это тоже асинхронный процесс, на некоторые документы ещё должен человек посмотреть. Для многих сценариев синхронная парадигма неприменима даже при нулевой стоимости потока.

Нужен контекст более высокого уровня, с помощью которого можно всё собрать вместе.


Information

Rating
Does not participate
Registered
Activity