![]() |
Модераторы: Daevaorn |
![]() ![]() ![]() |
|
drug007 |
|
|||
Бывалый ![]() Профиль Группа: Участник Сообщений: 196 Регистрация: 3.11.2011 Репутация: нет Всего: 1 |
Помогите оценить сложность создания фреймворка. Фреймворк должен позволят программисту явно описывать необходимые модели предметной области и прозрачно для программиста (неявно) расшаривать эти самые модели на всех узлах сети, где запущено данное приложение. Т.е я создал объект "автомобиль", задал его местоположение и скорость на одном узле и на остальных узлах эти данные появились без моего явного участия.
Я представляю это дело в виде фабрики, которая создает объекты заранее определенных классов и вся магия в этой фабрике заключается. С объектами работаю дальше как с обычными, без явных команд передать, засинхронизировать и т.д. Что посоветуете? Куда двигаться, что почитать. |
|||
|
||||
xvr |
|
|||
Эксперт ![]() ![]() ![]() ![]() Профиль Группа: Комодератор Сообщений: 7046 Регистрация: 28.8.2007 Где: Дублин, Ирландия Репутация: 60 Всего: 223 |
Немного похоже на DCOM. Можно с него и начать (в смысле ознакомления)
|
|||
|
||||
drug007 |
|
|||
Бывалый ![]() Профиль Группа: Участник Сообщений: 196 Регистрация: 3.11.2011 Репутация: нет Всего: 1 |
DCOM не подходит - слишком универсально. Я. правда, и не обрисовывал конкретную ситуацию. Область применения - сеть приложений, которые должны взаимодействовать друг с другом в различных сочетаниях. Например, есть узлы У1, У2 и У3 - узел У1 изменяет у себя величину В233, при этом У2 получает изменение величины В233, а У3 не заинтересован в ней и ему такие данные не нужны. Но он может быть заинтересован в других данных, которые не нужны У2. Т.е. связи между узлами довольно сложные, хотя формируются по простым алгоритмам - каждый узел избирательно подписывается на нужную ему информацию у всех нужных ему узлов. При этом все должно происходить прозрачно для программиста-пользователя фреймворка.
Лично у меня идея изобрести велосипед создать класс-фабрику, которая будет создавать базовый класс-контейнер плюс хранить в себе все данные в виде таблицы ключ-значение. Этот базовый класс-контейнер хранит в себе экземпляры другого базового класса-величины. Класс-величина преобразует свои значения в данные нижнего слоя - пары ключ-значение. Где ключом является номер узла, порядковый номер записи, идентификатор базового-класса контейнера и идентификатор базового класса-величины, а значением является собственно значение. А если в ключ добавить номер версии, то можно некоторое подобие персистентности организовать. Таким образом, возможно из пар ключ-значение данные вернуть в виде класса и класс преобразовать в пары ключ-значение. И смысл разделения на два слоя в том, что нижний слой - эти самые записи, можно передавать между узлами независимо от верхнего слоя. При чтении значения из экземпляра класса-величины происходит поиск по ключу и возврат значения. Конечно, тут издержки по времени и по памяти, но память сейчас дешевая, а скорость при необходимости можно увеличить за счет кэширования данных в критичном месте. Да, еще в основе лежит утверждение, что каждый узел генерирует уникальную информацию, не пересекающуюся с другими узлами и не конфликтующую. Т,е. если мы имеем кучу складов, то каждый склад отвечает сам за себя. А если мы хотим отгрузить со склада находясь в офисе, то должны запрос отправить складу и только после обработки складом можем реально отгружать. Таким образом (имхо, конечно) избегаются лишние блокировки - они возникают, только когда несколько запросов к одному складу. Но это ограничение накладывается не программной моделью, а самой бизнес-моделью - если поставить на один склад несколько кладовщиков и они не будут согласовывать между собой свои действия, то ничего хорошего из этого не выйдет. Покритикуйте, пожалуйста. Это сообщение отредактировал(а) drug007 - 16.1.2013, 07:09 |
|||
|
||||
xvr |
|
|||
Эксперт ![]() ![]() ![]() ![]() Профиль Группа: Комодератор Сообщений: 7046 Регистрация: 28.8.2007 Где: Дублин, Ирландия Репутация: 60 Всего: 223 |
Задача понятна, но вы подходите к ее решению не с той стороны
![]() На мой взгляд несколько усложнено. Какие типы значений предполагаются? В любом случае, прежде чем проектировать реализацию, разработайте интерфейс пользовательского уровня (в вашем случае - уровня программиста, пользователя вашего фреймворка) |
|||
|
||||
drug007 |
|
||||
Бывалый ![]() Профиль Группа: Участник Сообщений: 196 Регистрация: 3.11.2011 Репутация: нет Всего: 1 |
А интерфейса как такового и нет. В этом то и смысл фреймворка. Т.е. если я создаю класс
я максимум что делаю, объявляю мемберы через шаблон и делаю скрытым конструктор (у меня же фабрика):
Ну возможно еще геттеры/сеттеры. Вот и весь интерфейс. Все остальное должно обрабатываться автомагически в классе-фабрике. Топология сети динамическая, на первом этапе информация тупо дублируется между всеми узлами, позже добавлю управление обменом. Так как выделено два слоя, то отработкой взаимодействия на сетевом уровне можно заниматься независимо от уровня интерфейса, что одна из целей. Discovery service я планирую решать позднее, ибо вещь нужная, но независимая. Определить у кого какая информация можно на основе того, что каждый узел генерирует уникальную информацию в масштабах всей системы (это важное условие в основе моего подхода - возможно ошибочное, что и хочу обсудить), то узлы легко могут оповестить друг друга о том, какой информацией они обладают - тупо по своему номеру (узла) и идентификатору последнего сообщения. Типы значений пока предполагаю только POD. Но не вижу проблем позднее добавить поддержку указателей и классов. В конце концов можно взять библиотеку сериализации - тогда можно будет использовать все типы, поддерживаемые библиотекой, но здесь нужно на практике проверить. Это сообщение отредактировал(а) drug007 - 16.1.2013, 14:03 |
||||
|
|||||
xvr |
|
|||
Эксперт ![]() ![]() ![]() ![]() Профиль Группа: Комодератор Сообщений: 7046 Регистрация: 28.8.2007 Где: Дублин, Ирландия Репутация: 60 Всего: 223 |
Вполне нормальный интерфейс, но явно не полный. У вас в интерфейсе должно быть определено, как разделяются инстансы классов, а не их типы (т.е. не class A, а A my_class_a) Вот у инстансов и должны быть какие то идентификаторы, что бы их можно было опознать из других узлов сети. Далее, как узлы сети должны получать разделенные объекты из других узлов? Это не могут быть те же инстансы классов, что и их собственные объекты - т.е. нужно их как то отдельно именовать Пока нет, а должен быть ![]()
Это не так - вполне зависимая. Оповестить мало - что бы другой узел смог воспользоваться этой информацией, он должен о ней знать заранее (если фреймворк будет работать на этапе компиляции), либо скатываться в чистую динамику и интерпретацию информации о типах в runtime. |
|||
|
||||
drug007 |
|
|||
Бывалый ![]() Профиль Группа: Участник Сообщений: 196 Регистрация: 3.11.2011 Репутация: нет Всего: 1 |
Я это представляю через константы:
Т.е. фабрика имеет уникальный ид, контейнер имеет уникальный внутри фабрики ид и величина имеет уникальный ид внутри контейнера - втроем они составляют уникальный ид в масштабах всей системы. Фабрика(на самом деле получается не фабрика, а хранилище - так правильнее, создает динамически контейнеры через вызов makeContainer, а контейнеры внутри себя создают величины напрямую. Потом идет работа с величинами, а их изменения обрабатываются хранилищем. Взять какое-нить бинарное дерево для этого, хранить пары ключ-значение упорядоченно - т.е. добавить еще один ключ из номера хранилища и порядкового номера пары, а пару ключ-значение использовать как значение. И чтобы синхронизироваться, нужно просто обменяться данными - для какого хранилища какая последняя пара хранится. Отсюда можно легко определить какие данные куда нужно передать и делать это можно в другом потоке. Как думаете? код не компилил, не обессудьте ![]() Я имею в виду, что вполне можно позднее ее реализовать, нет? Меня, в приниципе устроит и фиксированная топология сети, но динамическая это конечно другой уровень... А я только про динамику и думаю. Честно говоря не знаю, как это можно в компайл-тайм сделать. Расскажите подробнее, пожалуйста. Это сообщение отредактировал(а) drug007 - 16.1.2013, 20:42 |
|||
|
||||
xvr |
|
|||
Эксперт ![]() ![]() ![]() ![]() Профиль Группа: Комодератор Сообщений: 7046 Регистрация: 28.8.2007 Где: Дублин, Ирландия Репутация: 60 Всего: 223 |
А как другие узлы узнают, какой именно 'уникальный ID' им нужен и с какого узла его брать? Динамика в данном контексте обозначает, что данные могут быть не только числа, а вообще любые. И их потребитель будет разбираться в рантайме с тем, что ему пришло. Это не самый удачный выбор ![]() Могут ли на узле в процессе работы программы появляться новые типы данных (и запрашиваться с других узлов новые типы)? Если нет, то обычная статическая инициализация вполне подойдет. Конкретное данное обозначается строкой (все строки в составе сети уникальны), и статическим экземпляром класса. Как то так -
Устроит? |
|||
|
||||
drug007 |
|
||||
Бывалый ![]() Профиль Группа: Участник Сообщений: 196 Регистрация: 3.11.2011 Репутация: нет Всего: 1 |
Номер узла они получают при конфигурации системы - либо из конфигурационного файла, либо от discovery service. Номера контейнера и величин определяется статически в компайл-тайм - т.е. узел знает, информация каких контейнеров и какие величины ему нужны. Если контейнер инкапсюлирует склад, то узел-офис, знающий про этот склад, знает, что ему интересно на данном складе и какие id эти позиции имеют. Если вдруг появится новая какая-то величина, id которой неизвестен узлу, то она будет отображаться как неизвестная величина, т.е. это будет ошибкой бизнес-логики, но не приложения. Новые типы данных появляться могут, но с ограничениями - чтобы появление таких типов не разрушало работоспособность системы. Т.е. например мы собрали новый билд и в нем новый тип - старые билды не должны падать общаясь с новым, а только лишь фиксировать факт получения данных, которые они не могут классифицировать. Я это вижу как складывание таких данных отдельно от остальных без выдачи фатальной ошибки, но с извещением оператора, ну и логом. Практически да. Я вообще хочу максимально разделить прикладной уровень интерфейса от реализации подсистемы репликации (назову так, к примеру). Т.е. чтобы программист вообще не вникал в то, что данные где-то находятся, с кем-то расшариваются. Т.е. он пишет код как для обычного приложения, не распределенного. Проблему кто с кем взаимодействует должен решать администратор приложения путем конфигурации. Все остальное должно происходить автоматически. Примерно так:
Как-то так... Это сообщение отредактировал(а) drug007 - 17.1.2013, 16:59 |
||||
|
|||||
xvr |
|
||||
Эксперт ![]() ![]() ![]() ![]() Профиль Группа: Комодератор Сообщений: 7046 Регистрация: 28.8.2007 Где: Дублин, Ирландия Репутация: 60 Всего: 223 |
Я имел в виду не типы, а экземпляры
Согласен. Немного по поводу кода - я бы не стал генерить классы через new. Все же С++ это не Java, в нем можно экземпляры классов делать и не на куче, даже лучше делать не на куче. Далее, все манипуляции с контейнером и конфигурацией лучше оставить внутри фреймворка - програмисту о них знать не имеет смысла. Связывать переменные SharedVar[RO] можно по их строковым именам, не привязываясь ни к каким конфиг файлам, при этом все равно где именно они находятся. В принципе SharedVar может быть сделан не только от int и string, но и от любого класса, поддерживающего стриминг (определенный набор методов) Если такая функциональность и интерфейсы устраивают, то можно переходить к проработке реализации. |
||||
|
|||||
drug007 |
|
||||||||||
Бывалый ![]() Профиль Группа: Участник Сообщений: 196 Регистрация: 3.11.2011 Репутация: нет Всего: 1 |
Экземпляры будут появляться новые однозначно, но только в предопределенном виде - как правильнее сказать не знаю, но будут массивы таких величин - размер массивов будет меняться по мере появления новых значений, но количество самих массивов меняться не будет в ходе работы приложения, только при перекомпиляции по мере развития проекта.
Имеете в виду кастомный аллокатор? Или стек?
Согласен, я на черновую просто написал для примера.
Точно так, правда пока хочу ограничиться pod-типами - без указателей и ссылок.
Вы были абсолютно правы про интерфейс - я подумал как будет работать пользователь и пришел к выводу, что без персистентности не получится адекватной работы. Смысл в том, что обмен данными между узлами асинхронный (синхронность предъявит жесткие требования к аппаратной части). А значит, возможна ситуация, когда на разных узлах разные данные и решить эту проблему можно путем версий значения - т.е. если узлу нужно произвести какие-то расчеты, для расчетов нужно, например, 3 величины. Он берет их значения, находит их время обновления, выбирает величину с наименьшим, а по остальным величинам еще раз запрашивает значения, но уже с наименьшим временем и на основании этих данных производит расчет и ему присваивает это же самое время. А это означает, что нужно продумать еще алгоритм. Правда, получается, что часть проблем я все-таки выношу из фреймворка и программист уже должен будет учитывать время обновления значения величины, но думаю, это оправдано будет в данном случае, как думаете? С эфемерными величина проще конечно было бы написать реализацию, но как тогда решить проблему рассинхронизации?
Я первоначально неправильно понял вопрос - да, фреймворк будет работать на этапе компиляции. Чистая динамика слишком уж усложнит реализацию, по крайней мере пока можно без нее обойтись. |
||||||||||
|
|||||||||||
xvr |
|
||||
Эксперт ![]() ![]() ![]() ![]() Профиль Группа: Комодератор Сообщений: 7046 Регистрация: 28.8.2007 Где: Дублин, Ирландия Репутация: 60 Всего: 223 |
Это можно учесть, введя тип разделяемой переменной - массив. Тогда новых переменных в процессе работы программы появляться не будет Я имею в виду обычные глобальные статические переменные.
Это требует наличие синхронизированного времени на всех узлах (например в виде NTP клиента), что в свою очередь требует единого сервера для задания этого самого времени. Лучше сделать так, что бы на узлах всегда присутствовали самые последние версии значений. Это можно обеспечить просто сделав взаимодействие узлов в push режиме - узел, поменявший свою переменную, немедленно рассылает ее всем заинтересованным сторонам ![]()
Я думаю, что проблема тут сложнее, чем кажется. Что считать синхронизацией значений, если учитывать то, что эти значения вырабатываются асинхронно работающими узлами? Для того, что бы вообще говорить о 'синхронизации' в любом понимании нужно иметь точку отсчета, одинаковую на всех узлах. И узлы должны знать об этом и учитывать в своей работе. Синхронизация по времени в принципе не самая удачная методика. Зачем вообще нужна синхронизация? |
||||
|
|||||
drug007 |
|
||||
Бывалый ![]() Профиль Группа: Участник Сообщений: 196 Регистрация: 3.11.2011 Репутация: нет Всего: 1 |
Это учитывает, что разделяемая переменная является массивом. А я имею в виду массив разделяемых переменных - т.е. мы на этапе компиляции будем иметь тип переменной, а их количество узнаем в рантайме. Да, там где динамического изменения нет - так лучше А у меня же возможно изменение числа контейнеров с разделяемыми переменными - причем это важный аспект. Тип данных, с которыми работает узел определен в компайл-тайме, а объем данных в рантайме.
Совершенно верно. Но я боюсь, что может получится такая ситуация - узел У1 изменил переменную П1, узел У2 изменил переменную П2, а узел У3 начал какие-то вычисления (запустил отчет, например) на основе переменной У1.П1 и У2.П2, но при этом от узла У1 пришло новое значение, а от У2 еще не успело - т.е. получится наполовину правильные расчеты. Можно поставить дело так, что У3 получив новое значение У2 заново выполняет отчет и тогда все становится действительно актуальным. И моя мысль сделать это как бы более явным с помощью временной метки - тогда узел У3 просто бы пометил свои расчеты меткой самых молодых данных. Но пишу и чувствую, как все усложняется резко с этими метками... ![]() Неправильно я использовал термин синхронизация, правильнее актуализация - т.е. получение последнего значения. |
||||
|
|||||
xvr |
|
||||
Эксперт ![]() ![]() ![]() ![]() Профиль Группа: Комодератор Сообщений: 7046 Регистрация: 28.8.2007 Где: Дублин, Ирландия Репутация: 60 Всего: 223 |
Это все равно будет массив, но динамический. Его размер может изменяться в рантайме (вместе со значением элементов)
С учетом того, что узлы работают асинхронно, вполне законным будет любой порядок вычислений: старое значение П1+новое значение П2, или новое значение П1+старое П2, или оба старых или оба новых. Например - 2 узла вырабатывают новые значения 2х переменных каждую миллисекунду, со сдвигом в 0.5ms. Когда брать 'новое' значение с обоих узлов? Тут просматривается аналогия с разделяемыми переменными в многозадачном/многопоточном окружении. Если потоки/задачи не предпринимают никаких мер по синхронизации доступа к переменным, то одновременный доступ из разных потоков/задач к общим переменным может привести к краху приложения. Так что если программист хочет что то считать, базируясь на нескольких переменных, то какая то явная синхронизация нужна, равно как и в случае обычных переменных в многопоточном приложении. Вот только синхронизация тут нужна хитрая, обычные мьютексы и семафоры не подойдут, да и на метках времени синхронизацию тоже не построишь ![]() |
||||
|
|||||
drug007 |
|
||||||
Бывалый ![]() Профиль Группа: Участник Сообщений: 196 Регистрация: 3.11.2011 Репутация: нет Всего: 1 |
я все-таки разделяю эти два момента: SharedVar<int> sv_arr1[10]; SharedVar<int[10]> sv_arr2; Ведь в первом случае мы можем индивидуально менять значение каждого элемента массива. А во-втором случае мы будем менять весь массив сразу. В принципе результат будет один и тот же, но первый вариант оптимален когда мы часто меняем элементы массива по одному, а второй когда меняем весь массив сразу.
В этом случае по идее можно и пренебречь разницей во времени, так как разница будет небольшой, даже если одно значение придет с опозданием, то ошибка будет в 0.5 мс. А вот если один узел так же быстро вырабатывает значения, а второй раз в 1 секунду и со второго узла одно значение придет с опозданием, то ошибка составит целую секунду и может быть критической. Вообще у меня впечатление, что это проблема не фреймворка должна быть, а его пользователя, так как нужно знать подробности приложения. Однако какие-то средства на этот случай во фреймворке должны быть, наверное?
Тут я думаю синхронизация как внутри процесса будет гиблым делом. Слишком разные среды. Я думаю, что эти вопросы надо выносить на уровень пользователя библиотеки, пусть у него голова болит. Т.о. нужно предоставить программисту возможность самостоятельно определять какие данные актуальны - т.е. если ему нужно определить актуальность данных пусть делает сам. Нужно какую-то метку ставить - пусть сам ставит. А задача фреймворка только расшаривать данные. Как думаете? |
||||||
|
|||||||
xvr |
|
||||||
Эксперт ![]() ![]() ![]() ![]() Профиль Группа: Комодератор Сообщений: 7046 Регистрация: 28.8.2007 Где: Дублин, Ирландия Репутация: 60 Всего: 223 |
Я имел в виду сделать специальный класс (в дополнение к SharedVar) - SharedArray. И уже в его интерфейс добавить возможность ресайза.
Угу.
Я пока вижу единственное место, где понадобится синхронизация. Это вычисления, когда переменная (назовем ее A) зависит от другой переменной (B) косвенно, через 2 других переменных (C и D) (все переменные расположены на разных узлах). В таком случае вычисление А должно происходить только тода, когда вычислятся С и D после модификации B Для реализации этого понадобится граф зависимостей и система слежения за версиями переменных. Граф можно строить динамически, но от пользователя понадобится явное описание зависимости и явная фиксация данных. Например так:
|
||||||
|
|||||||
drug007 |
|
|||
Бывалый ![]() Профиль Группа: Участник Сообщений: 196 Регистрация: 3.11.2011 Репутация: нет Всего: 1 |
Это просто у нас разный уровень подготовки - вот я и не сообразил ![]() Граф зависимости и система слежения очень хорошая идея - защелка мне понравилась. Я думаю, что два этих feature можно рассматривать как промежуточный слой между sharing system и конечным пользователем библиотеки. Т.е. достаточно продумать интерфейс и методологию их применения и можно делать реализацию нижнего уровня с небольшой оглядкой на интерфейс зависимостей и слежения за версиями. Мне еще кажется, что достаточно сделать неявное защелкивание данных - т.е. latch защелкивает данные разных версий, но при расчете использует данные одной версии, которую сама выбирает автоматически и при формировании результата просто присваивает версию, которую использовала при расчетах. Думаю, это покроет большинство областей применения и интерфейс не будет перегруженным. |
|||
|
||||
Lazin |
|
|||
![]() Эксперт ![]() ![]() ![]() ![]() Профиль Группа: Завсегдатай Сообщений: 3820 Регистрация: 11.12.2006 Где: paranoid oil empi re Репутация: 41 Всего: 154 |
Зачем писать свой фреймверк, когда можно использовать что-нибудь готовое? Во первых, такие проблемы, как правило решают с помощью БД(как правило, на этом и стоит остановиться). У меня складывается впечатление, что автор просто не дружит с БД, поэтому пытается перенести решение проблемы на знакомую территорию - программирование на с++.
Все высказавшиеся в этом топике слабо представляют себе, что такое распределенная система. Автор даже написал что оставит разработку дискавери сервиса на потом, интерфейсы классов и с++ код, с которым будет работать пользователь конечно же важнее ![]()
Может что-то еще забыл ![]() Соответственно, от ответа на первый и второй вопрос, зависят возможные варианты ответов на остальные вопросы. |
|||
|
||||
drug007 |
|
||||||||||
Бывалый ![]() Профиль Группа: Участник Сообщений: 196 Регистрация: 3.11.2011 Репутация: нет Всего: 1 |
Очень хорошо, что знающие люди подключаются к обсуждению
![]()
Согласен, но я не знаю таких.
Во-вторых, программист не лишен возможности в данном случае использовать БД - это его желание. БД может быть слишком жирной для решаемых задач. А во-первых моя задача создать фреймворк с максимально большим decoupling между пользователем фреймворка и сетевой подсистемой. Основная нагрузка по конфигурации сетевой подсистемы должна лечь на администратора приложения, не на разработчика. Именно поэтому:
Это целенаправленное решение. И именно поэтому же:
Потому что автор их себе задал. И автор их здесь не поднимает, потому что см. выше - задача разделить эти два уровня. Достичь этого предполагается за счет использования таблиц ключ-значение - они являются теми структурами данных, которые будут мигрировать из одного уровня в другой. За счет этого разработку сетевой подсистемы (а это именно то, что Lazin имеет в виду можно делать параллельно и независимо. Более того, сетевая часть будет взятая готовая - благо вот там то фреймворков хватает. Поэтому важной задачей стоит создание удобного практичного интерфейса.
Система должна быть устойчива к плохим и неустойчивым каналам связи, в том числе работать на слабом оборудования (пусть и в урезанном варианте). Архитектура приложения не должна иметь какие-либо принципиальные ограничения на среду - в идеале должно работать в любой гетерогенной среде. Конечно, на начальных этапах не все может быть реализовано, но ограничений быть не должно. Обновления должны осуществляться децентрализованно. В идеале по принципу вирусного заражения. Информация должна быть целостной всегда. Расхождения могут быть, к сожалению, скорее всего от неверной эксплуатации до злонамеренного вмешательства. Помехи и потери в каналах связи здесь рассматривать не будем - это задача коммуникационного оборудования. Этот вопрос актуальный и сложный - на данный момент он вообще никак не решается (только на уровне систем передачи данных), первоначально скорее всего будет просто обнаруживаться факт расхождения и одна или обе стороны будут просто компроментированы с игнорированием результатов от них до разрешения конфликта на уровне приложения (не фреймворка) - либо автоматический, либо вручную с участием человека concurrency control. Ordering. Этот вопрос меня сейчас мучает больше всего, мы его, кстати, обсуждали с xvr, я ориентировался на timestamp, но есть некоторые моменты, что этого недостаточно (применительно к конкретной задаче на одном из этапов ее решения) Обновление асинхронное. Если нода падает это проблема администратора этой ноды. Все узлы независимы, падения одного из них не должно сказываться на работоспособности системы. Важна именно система - отдельно сами по себе работающие узлы никакой ценности не представляют. Система дожна быть устойчива к падению узла в том плане, что узлы по мере восстановления должны продолжать работу с момента падения. Организация групп - осуществляется на двух уровня ниже и выше здесь обсуждаемого - физически группирование осуществляется на уровне сетевой подсистемы, логически - на уровне приложения. В любом случае, вопросы по сетевой подсистеме меня сейчас интересуют меньше здесь обсуждаемого интерфейса по той причине, что от если такой промежуточный интерфейс окажется нереален, нужно будет связывать между собой логику и сетевую часть, что усложнит задачу и потребует другого подхода. В качестве сетевой части я планирую использовать zeromq и zyre - пробные запуски zeromq показали обнадеживающие результаты. zyre пока не трогал, но еще более многообещающий фреймворк для распределенных приложений. В целом моя мысль изменить подход к решению задачи - не передавать сериализованное представление объекта, а перевести все данные в программе на уровень таблиц ключ-значение и передавать между узлами уже их - т.е. сетевая подсистема понятия не имеет, что она передает. А программист понятия не имеет как передаются данные, которые он обрабатывает. и только для оптимизации программисту нужно будет знать, как все дело организованно. Решить многие проблемы, в том числе озвученные выше я планирую за счет того, что каждый узел генерирует уникальные в масштабах всей системы данные - таким образом, ни одному узлу не нужно синхронизировать данные с кем-либо, он только лишь оповещает те узлы, которые подписались на его данные. Даже если такой узел умер, то данные с него, являясь уникальными, могут еще долго жить в системе, более того, возможен вариант, что узел будет восстанавливать свои данные получая их обратно с узлов, ранее подписавшихся на него. Но это все более высокий уровень. До него еще нужно дойти. ![]() Это сообщение отредактировал(а) drug007 - 19.1.2013, 15:27 |
||||||||||
|
|||||||||||
Lazin |
|
||||||||||||
![]() Эксперт ![]() ![]() ![]() ![]() Профиль Группа: Завсегдатай Сообщений: 3820 Регистрация: 11.12.2006 Где: paranoid oil empi re Репутация: 41 Всего: 154 |
Это невозможно. В рамках LAN можно сделать вид, что узлы всегда могут быть связаны с другими узлами (нет network partitioning-а), в рамках WAN так сделать уже не получится, в ad-hock сетях вообще возможно использование только gossip-подобных протоколов, со всеми вытекающими ![]()
Автор, ты не понимаешь проблемы в принципе ![]() Представим, что у нас есть 3 ноды, А, В и С. В определенный момент времени, каждый из них отправляет сообщение широковещательно, всем нодам, в результате, каждый узел получит 3 сообщения. При этом, порядок получения сообщений не гарантирован, если нода А получила сообщения в порядке (В, А, С), то это вовсе не означает, что другие ноды получили сообщения в том же порядке. Если все эти сообщения содержат информацию о том, что и как должно меняться в памяти узла, то мы в итоге получим разное состояние на разных узлах. Обычно, когда нужно распределенное общее состояние, применяют специальные алгоритмы (google: atomic broadcast, ZAB, Paxos, vector clock, lamport timestams), которые позволяют получить одинаковый порядок сообщений на разных узлах. Соответственно, если просто кидаться сообщениями, данные будут расходиться. Есть еще такая вещь, как гарантированная доставка. Твой zmq не гарантирует доставку сообщений, если сообщение потеряется, то считай что данные на разных узлах разошлись.
метки времени не помогут, так как на разных узлах, метки времени могут отличаться (даже с ntp) + время прохождения пакета. Нод А отпавил сообщение ноду В в момент времени t0, нод С тоже отправил сообщение ноду В в момент времени t1, t0 < t1. Нод В получил сообщение t1, изменил свое состояние в ответ на это сообщение, затем он получил сообщение t0, которое было сгенерировано раньше и при этом конфликтует с сообщением от ноды C. Опять же, с асинхронным обнвлением возможна только eventual consistency. Т.е. ноды могут содержать у себя устаревшие данные и операции чтения будут возвращать устаревшие данные.
Для того, чтобы сопротивляться f отказам, распределенная система должна состоять из 2*f + 1 узлов. Почему узлы могут считаться независимыми я не понимаю. В чем тогда смысл всего этого?
Вот эту таблицу лучше заменить на БД. Пускай БД занимается отказами и прочими вещами.
Я бы порекомендовал добиться сначала чего-нибудь подобного на уровне простого key-value хранилища. Там столько проблем, о которых ты даже не догадываешься. У тебя сейчас много противоречивых идей, то, что ты описал в последней цитате похоже на gossip, если это так, то обеспечить целостность данных не получится (точнее получится, но только с некоторой, достаточно высокой вероятностью). фигня какая-то Вообще я все больше и больше не понимаю - что должно в конце получиться то. Это будет набор объектов, доступных на разных нодах, или что? Какие требования к этим объектам, могут ли они друг на друга ссылаться? Короче, предлагаю не парить мозги себе и окружающим и написать mapping для какой-нибудь NoSQL Key Value БД. |
||||||||||||
|
|||||||||||||
drug007 |
|
||||||||||||||
Бывалый ![]() Профиль Группа: Участник Сообщений: 196 Регистрация: 3.11.2011 Репутация: нет Всего: 1 |
Невозможно что? Построение системы, части которой работают в зависимости от конфигурации и в LAN, и в WAN и в ad-hock сетях? В чем здесь принципиальная проблема такой категоричности?
Нет, Lazin, это ты не понимаешь, что данная проблема решается за счет того, что каждый узел генерирует уникальную информацию и ему не нужно ни с кем ее синхронизировать, он просто оповещает другие узлы об этом. Он же ее и упорядочивает - если данные приходят в разном порядке их легко упорядочить. Гарантированная доставка в zmq обеспечивается выбор reliable транспорта - не нужно выбирать udp, можно выбрать tcp, т.е. zmq надстройка над транспортом. Вот такую же абстракцию сверху zmq я и хочу создать.
одна из задач, для решения которой и продумываю интерфейс, предполагает что данные имеют метку. Например значение какого либо параметра с датчика привязаны ко времени - т.е. температура за такое-то время, за такое. поэтому получив данные, приложение все равно учитывает время и в каком порядке она получила значения температуры с точки зрения приложения не имеет значения. Отсюда возникает допущение, которое я держал в голове, но не озвучил в условии задачи - на данный момент фреймворк предназначен для обработки данных, которые используют привязку по времени, либо иной способ отличить одно значение от другого.
требование к системе работоспособность до последней капли крови - пусть даже данные устаревшие - главное, чтобы система функционировала, просто пусть показывает, что данные устаревшие.
Здесь я одно время планировал прикрутить berkeleydb или что-то в этом роде - ничего серьезнее не нужно. Привязка к конкретной базе убьет масштабируемость, а логика БД будет просто хранение.
Так я выше уровня простого хранилища даже и планирую подниматься. Для моих задач этого достаточно. gossip меня вполне устроит - система в нормальных условиях должна работать с высокой актуальностью данных, при тяжелых условиях актуальность данных может снижаться, но система должна оставаться работоспособной. Т.е. больше волнует целостность самой системы, чем данных. Недопустимо, чтобы система выдала пользователю сообщение об ошибке и выпала. Чтобы не произошло, система должна быть работоспособной. Аналогия - она не должна быть каменной стеной, которая сопротивляется внешним воздействиям и за ней тихо и спокойно, но когда такую стену ломают за ней сразу начинается бардак. Здесь же нужна система гибкая, которая может прогибаться под внешними воздействиями, но никогда не ломаться и как только воздействие прекратилось она должна восстановиться в изначальном состоянии. Это одна из плюшек системы. я, да, не совсем логично выразился. Исправил эту фразу про "звучит". ![]() но в целом эта "фигня" позволяет решать большинство вопросов из предыдущего твоего поста про распределенное приложение. рекомендую присмотреться. Я понимаю, что я действительно не разработчик распределенных систем и мои познания ограничены. Возможно я какие-то понятия путаю, более того, я знаю, что некоторые вопросы, которые у меня возникли я смогли пощупать только на практике - т.е. в реальном приложение и мне придется делать некоторые исследования. Что я, собственно и делаю. Просто у меня есть конкретная задача и я ее решаю. У моего фреймворка есть и будут ограничения. Мне не нужен блэкджек со шлюхами, мне достаточно подкидного дурака. Для дурака мне сейчас нужен интерфейс между программистом и сетевой частью. Это сообщение отредактировал(а) drug007 - 19.1.2013, 15:28 |
||||||||||||||
|
|||||||||||||||
Lazin |
|
||||
![]() Эксперт ![]() ![]() ![]() ![]() Профиль Группа: Завсегдатай Сообщений: 3820 Регистрация: 11.12.2006 Где: paranoid oil empi re Репутация: 41 Всего: 154 |
я представлял себе задачу - как задачу репликации данных между нодами, все о чем я говорил - справедливо для репликации (statemachine репликации в частности). если на всех узлах разная информация, то я не понимаю, в чем тогда глубокий смысл сего?
google - time series database |
||||
|
|||||
drug007 |
|
||||
Бывалый ![]() Профиль Группа: Участник Сообщений: 196 Регистрация: 3.11.2011 Репутация: нет Всего: 1 |
Именно это я в целом и делаю. Только вместо БД беру хэш-таблицу. И теперь хочу продумать интерфейс для маппинга данных в такую таблицу и интерфейс для передачи такой таблицы между узлами. И в этом топике мы как раз обсуждали вот этот самый первый интерфейс - когда программист работает привычным для него образом, но все данные, которыми он манипулирует прозрачно для него отображаются в таблицу ключ-значение. которая в свою очередь прозрачно для программиста расшаривается между узлами. зависимости между узлами определяет администратор приложения. В целом такая система является более технической, что ли, она не для эксплуатации в банках, это ближе к АСУ ТП. Самый яркий пример - сеть цифровой радиосвязи, в которой используются разнородные средства - КВ,УКВ, тропосферная связь, космическая. Узлы постоянно мониторят прохождение радиоволн, в зависимости от этого выстраивают связь, более того, учитывают время суток, сезон, погоду в районе конкретно радиостанции и т.д. и вот этой информацией они обмениваются. поднимать базу данных stand-alone на каждом узле это нереально. каналы плохие и неустойчивые, информация может теряться, но постоянно должны приниматься меры к ее восстановлению. а задачи такой системы будет именно в организации как можно более качественной связи с минимальным расходом ресурсов - т.е. нагрузка уменьшилась на сеть, система выключает мощные станция и переходит на более дешевые каналы и т.д. Тут не допустимо, чтобы дедлок был какой-то или система сказала, что данные устарели на пять минут и я с ними работать не буду. Т.е. целостность данных тут вообще сложно нарушить с точки зрения предметной области - данные могут устареть, но неверными они не могут быть, т.к. система передачи данных нам гарантирует, что данные либо получены, либо не получены. Возможно это прояснит нюансы. Добавлено через 10 минут и 21 секунду
не все же распределенные приложения занимаются репликацией? репликация это намного сложнее чем то, что я озвучил, согласен. и сложнее потому, что приложения не приспособлены для репликации. мы сделали одно. потом решили что надо реплицировать и начинаем решать эти вопросы. у меня же изначально приложение ориентировано на распределенность и эта ориентация проходит красной ниткой через всю систему от сетевого уровня до оператора конкретной копии приложения. Т.е человек знает, что система распределенная и ее состояние не всегда актуально, но система ему гарантирует, что всегда поставит его в известность, что какие-либо данные неактуальны. подсказка интересная, несмотря на простоту, спасибо. но в данном случае это из пушки по воробьям, отлично, да, но оправдано только на крупных узлах. если уж делать такую БД, то в качестве опции на усмотрение администратора приложения. |
||||
|
|||||
drug007 |
|
|||
Бывалый ![]() Профиль Группа: Участник Сообщений: 196 Регистрация: 3.11.2011 Репутация: нет Всего: 1 |
Соответственно, такая система умеет работать с устаревшими данным. Фактически этот момент переносится на уровень приложения. Т.е. я не скрываю от пользователя все возможные проблемы и не пытаюсь их решать до какого-то уровня, а когда не могу решить - падаю. А изначально информирую пользователя, что ситуация такая-то, принимаю меры такие-то, рекомендую сделать то-то. Т.е. система как помощник оператору, но опять же по возможности оператор должен вмешиваться только когда система не может самостоятельно решить вопрос. Это будет предъявлять более высокие требования к оператору, но и возможности такой системы выше.
|
|||
|
||||
Lazin |
|
|||
![]() Эксперт ![]() ![]() ![]() ![]() Профиль Группа: Завсегдатай Сообщений: 3820 Регистрация: 11.12.2006 Где: paranoid oil empi re Репутация: 41 Всего: 154 |
А зачем такой системе быть распределенной? Возможно ей хватит одной машины для сбора и хранения данных? Во многих современных SCADA системах, timeserices базы данных работают на одном сервере, так как они могут собирать и обрабатывать огромные объемы данных. То, что ты описал, похоже по архитектуре на некоторые современные scada системы, в которых есть сервера телемеханики, которые собирают данные с оборудования и далее, перенаправляют их в дисп. центр, в котором они ложатся в timeseries БД. Сервера телемеханики как правило обрабатывают и агрегируют данные, уменьшая нагрузку на центральный диспетчерский центр.
|
|||
|
||||
drug007 |
|
|||
Бывалый ![]() Профиль Группа: Участник Сообщений: 196 Регистрация: 3.11.2011 Репутация: нет Всего: 1 |
Здесь система управления распределенная по определению - поскольку средства связи разбросаны тут и там. Даже если сеть распалась на фрагменты, внутри фрагментов должно осуществляться управление. А с одним сервером этого не сделаешь. Поэтому программная система копирует модель системы из прикладной области.
Фактически да, это SCADA система, текущие системы именно так и организованны, но в целях выполнения требований к устойчивости, есть необходимость в распределенной системе. Геморроя больше, конечно, но возможности пошире и это расширяет круг задач, где ее можно использовать. |
|||
|
||||
drug007 |
|
|||
Бывалый ![]() Профиль Группа: Участник Сообщений: 196 Регистрация: 3.11.2011 Репутация: нет Всего: 1 |
Обновлю тему и попробую структурировать вопрос. На данный момент стоит задача разработки универсального интерфейса, позволяющего прикладному программисту разрабатывать распределенные приложения (с определенными ограничениями) с минимальными изменениями в подходе к процессу разработки.
Тут, на мой взгляд, существуют два взаимоисключающих подхода - хранить данные в программе удобным способом с точки зрения их обработки и хранить данные способом, удобным для их "расшаривания" между потоками или узлами. Например, если мы имеем несколько структур:
чтобы не мучаться, в сеттерах прописывается код, генерирующий, например, событие, по которому происходит отправка данных на другие узлы. Работоспособно, но только до того момента, пока не встает вопрос, а как быть, если в сети появляется новый узел и запрашивает все данные? можно будет "вручную" пробежаться по всем экземплярам и вызвать функцию refreshState() (имя не совсем может подходящее) которая вызывает для всех полей экземпляра код, обеспечивающий отправку данных на другие узлы. Вроде тоже работает. Правда, получается, что мы каждое поле по каждому экземпляру отправляем "единично", хотя отправить пакетом данные было бы более быстрым и простым способом, ну да не будем прежде временно оптимизировать, ибо это зло ;) А как быть, если узел запрашивает у нас не все данные, а только часть? Отправлять в запросе какие поля и каких объектов ему нужны? А если узел имеет примерно половину данных и запрашивает оставшуюся половину, то может получится немаленький запрос, сопоставимый по объему ответу плюс сам ответ на него опять будет не оптимальная штучная отправка данных. Либо данные всегда отправлять всем скопом. Таким образом, мы храним данные, в иерархии классов, как удобно с точки зрения разработки, но это усложняет передачу данных по сети. Второй вариант - хранить вообще все данные в массиве char[]. Хранить индекс на последний переданный на другие узлы байт и тогда, чтобы запросить данные, узел должен лишь передать диапазон байт, который ему интересен - механиз передачи данных по сети упрощается чрезвычайно. Но хранить все в одном массиве с точки зрения разработки - полная ерунда. Тут и возникает соблазн, создать промежуточный интерфейс, который бы позволил с одной стороны иметь привычный код, в котором доступ к данным был как привычно, в виде полей класса/структуры, переменных. А с другой стороны, чтобы данные хранились в виде некоторого упорядоченного массива в формате, удобном для передачи данных на другие узлы. Для этого предполагаю использовать хранение данных в генерализованном типовом виде - стандартной структуры DataChunk, каждая такая структура имеет уникальный идентификатор (типа индекса в массиве), который позволяет ее однозначно идентифицировать. DataChunk хранятся в структуре SharedStorage, которая и является генерализированным аналогом массива, на каждом узле используется в единственном числе, также имеет уникальный номер, который является идентификатором узла. Таким образом, зная номер SharedStorage (узла) и номер DataChunk мы можем уникально идентифицировать любые данные в масштабах всей системы. При обмене данными между узлами в запросе будет необходимо и достаточно указать только номер SharedStorage и диапазон номеров DataChunk. Это с точки зрения "сетевой" части. Что касается "прикладной" части - создаем шаблон SharedValue, который позволяет любой тип обернуть необходимыми сеттерами и геттерами. Которые при доступе/записи к переменной будет вызывать соответствующие функции SharedStorage. Так как обычно переменные группируются по какому-либо признаку, поэтому создаем ValueContainer, чья основная задача - группировать переменные SharedValue. ValueContainer имеет свой тип и свои идентификатор. Тип позволяет его наследнику выделиться среди других наследников с другим типом, а идентификатор позволяет выделиться конкретному экземпляру. Получается, что любые данные будут храниться в виде пар ключ-значение, где ключ - SharedStorage.id, ValueContainer.type, ValueContainer.id, SharedValue.id, а значение - собственно значение в виде char[]. При этом каждая такая пара ключ-значение хранится в DataChunk также в виде пары ключ-значение, но ключом уже является SharedStorage.id, DataChunk.id, а значением предыдущая пара. Немного сумбурно мне кажется, но мысль должна быть понятной. Самый сильный недостаток - большой расход памяти при работе с маленькими данными, т.к. целых два ключа - один ключ для идентификации внутри SharedStorage, а второй ключ для передачи между узлами. Т.е. если нужно сохранить булевскую переменную, то два ключа будут по размеру во много раз больше, чем само значение. С другой стороны, что сейчас эта память стоит? Критика приветствуется. xvr, у меня в качестве ключей long, поэтому 40 байт вышло - тут есть где поиграться, но при 2 байтах на все ключи эта схема не работоспособна Это сообщение отредактировал(а) drug007 - 23.1.2013, 14:04 |
|||
|
||||
xvr |
|
|||
Эксперт ![]() ![]() ![]() ![]() Профиль Группа: Комодератор Сообщений: 7046 Регистрация: 28.8.2007 Где: Дублин, Ирландия Репутация: 60 Всего: 223 |
Для передачи по сети можно отделить информацию, описывающую структуру данных от самих данных. Т.к. структура у вас в процессе работы не меняется, то ее достаточно передать один раз за сеанс. А вот данные меняются - вот именно их и надо передавать постоянно. Для того, что бы можно было определить какие данные пришли, нужно к ним прикрепить некий ID, но он не обязан совпадать с набором ValueContainer.type, ValueContainer.id. В качестве ID можно использовать пару <IP адрес отправителя, порядковый номер данных в ValueContainer на отправителе>. IP вам выдаст сетевой уровень, т.е. с данными нужно передать только индекс в контейнере. Если количество переменных на узле не превышает 65К, то достаточно 2х байт. (Если превышает - то сделать столько байтов, сколько нужно). Информация о самом ValueContainer (вместе с IP узла, где он находится) передается в процессе network discovery. Это сообщение отредактировал(а) xvr - 23.1.2013, 15:57 |
|||
|
||||
drug007 |
|
|||
Бывалый ![]() Профиль Группа: Участник Сообщений: 196 Регистрация: 3.11.2011 Репутация: нет Всего: 1 |
Да, вполне вариант. Просто я решил разбить передачу данных еще на два уровня - первый уровень организация такой сложной структуры данных локально на конкретной машине, второй уровень - оптимальная передача этих данных по сети. На первом уровне я исхожу из того, что смело жертвую объемом памяти для упрощения кода и для скорости. Поэтому структура раздутая, но ее обработка простая - передав на другой узел данные по своей схеме я гарантирую, что получив любой DataChunk любой узел сможет восстановить из него данные с полным извлечением имеющейся информации в этом DataChunk'е - т.е. мне нужно будет каких-либо дополнительных данных типа схемы данных. Схема организации данных прошита жестко в коде, т.е. ее не надо передавать (хотя это гибче, конечно, но я, честно говоря, не ставил задачу организацию взаимодействия с неизвестным узлом). Зная все id по моей схеме из куска сырых данных можно однозначно восстановить данные. Поскольку в общем случае я не могу ориентироваться на IP, я предусмотрел как можно более общую схему, пусть и избыточную. А вот в конкретном случае можно уже сжимать данные в том числе по вашей схеме. А если связь будет точка-точка то вообще адрес не нужен. Хотя здесь есть нюанс - у узла У1 могут быть данные узла У2, и У3 может потребовать эти данные у У1 (например У2 упал как раз в этот момент) - тут уже по сетевому адресу нельзя будет идентифицировать, так как передающий узел будет У1. Поэтому я думаю будет гибко сделать пусть раздутую, но гибкую структуру в памяти, а при передаче уже изменять структуру данных ну и банальное сжатие никто не отменял. |
|||
|
||||
xvr |
|
|||
Эксперт ![]() ![]() ![]() ![]() Профиль Группа: Комодератор Сообщений: 7046 Регистрация: 28.8.2007 Где: Дублин, Ирландия Репутация: 60 Всего: 223 |
По моему это перебор. Раздавать данные должен тот, кто их производит. Использование левых узлов в качестве запасного кэша данных сильно усложнит организацию системы. Похоже подошла очередь обсуждения сетевого уровня ![]() |
|||
|
||||
drug007 |
|
|||
Бывалый ![]() Профиль Группа: Участник Сообщений: 196 Регистрация: 3.11.2011 Репутация: нет Всего: 1 |
Соль в том, что использование пар ключ-значение упрощает реализацию данного подхода - в самом общем случае можно передавать между узлами все данные - они либо будут дополнять друг друга, либо дублировать. И абсолютно никакого конфликта. К сожалению четкими и конкретными требованиями похвастаться не могу, так как проект исследовательский да и учебный, прямо скажем. Нужно уделить этому время, которого пока нет. А вот на уровне пожеланий - сказать могу сейчас ![]() Лучше, конечно, это все продумать в виде четких лозунгов. А то поток сознания некий, но пока что есть то есть. |
|||
|
||||
xvr |
|
||||
Эксперт ![]() ![]() ![]() ![]() Профиль Группа: Комодератор Сообщений: 7046 Регистрация: 28.8.2007 Где: Дублин, Ирландия Репутация: 60 Всего: 223 |
Возможна сильная перегрузка сети ненужными данными. Особенно при большом количестве узлов.
Эээ, это как бы взаимоисключающие пункты ![]() |
||||
|
|||||
drug007 |
|
|||
Бывалый ![]() Профиль Группа: Участник Сообщений: 196 Регистрация: 3.11.2011 Репутация: нет Всего: 1 |
При таком подходе "в лоб" так и будет, однозначно. Но ничто не мешает позднее добавить дополнительную логику для исключения подобных вариантов. Т.е. первоначально все узлы обладают равными правами и получают одну и ту же информацию, впоследствии у каждого узла добавятся особенности и он будет потреблять и производить информацию разных типов. Мое мнение, что если первоначально реализовать возможность передачи всех данных легче потом добавить ограничение, чем изначально для каждого рода информации прописывать свой dataflow. Кстати, фактически я пытаюсь сделать dataflow платформу на самом деле, если вдуматься... Согласен, я и говорю - поток сознания, а не четкая формулировка. ![]() |
|||
|
||||
xvr |
|
|||
Эксперт ![]() ![]() ![]() ![]() Профиль Группа: Комодератор Сообщений: 7046 Регистрация: 28.8.2007 Где: Дублин, Ирландия Репутация: 60 Всего: 223 |
Ровно наоборот. Введение конфигурации dataflow возможно потребует полной переделки системы комуникации между узлами. Да и в зависимости от степени связанности узлов оптимальные методы коммуникации могут сильно отличаться |
|||
|
||||
drug007 |
|
|||
Бывалый ![]() Профиль Группа: Участник Сообщений: 196 Регистрация: 3.11.2011 Репутация: нет Всего: 1 |
Согласен, конечно. Но разве нельзя разделить их, decoupling вещь хорошая же - в начале простую систему где все расшаривается между всеми, а потом уже усложнить. Переделывать простую систему и не жалко. Плюс совместить с итерационной разработкой. Сразу задание на такую систему сделать это нереально. А разбить на этапы и помаленьку уточнять по мере эволюции? Это классно иметь сразу ТЗ, но это не всегда возможно. Я бы сейчас хотел отработать код для взаимодействия распределенной системы без привязки к коммуникационной среде. Саму логику такого взаимодействия, его достоинства и недостатки (помимо расхода памяти ![]() |
|||
|
||||
xvr |
|
|||
Эксперт ![]() ![]() ![]() ![]() Профиль Группа: Комодератор Сообщений: 7046 Регистрация: 28.8.2007 Где: Дублин, Ирландия Репутация: 60 Всего: 223 |
Это будет не переделка, а создание ее заново. ![]() Некоторые 'уточнения' могут оказаться в корне не совместимы с тем, что уже сделано ![]() Но хоть что то иметь надо, нельзя же изобретать систему по мере ее написания ![]()
Сначала определитесь с алгоритмами этой самой 'взаимодействия распределенной системы'. Для начала - в системе будет выделенный (или не выделенный) сервер, или она будет вся однородная? Узлы будут обмениваться данными напрямую или через сервер? |
|||
|
||||
drug007 |
|
|||
Бывалый ![]() Профиль Группа: Участник Сообщений: 196 Регистрация: 3.11.2011 Репутация: нет Всего: 1 |
Сеть однородная Обмен напрямую Если честно, я планирую использовать zmq в качестве сетевой платформы. Там есть такой паттерн как Clone - CloneServerи CloneClient. Они практически реализуют половину нужной мне логики, сервер расшаривает между клиентами таблицу пар ключ-значение. Я по простоте душевной предполагаю потом расширить этот паттерн и на каждом узле создавать такой сервер и клиент с целью реализации одноранговой сети. Отсюда исхожу, что нужно продумать интерфейс между приложением и таблицей ключ-значение. zmq вещь интересная, не реклама, но посмотрите код распределенного чата Я человек неискушенный, меня впечатлило. |
|||
|
||||
xvr |
|
|||
Эксперт ![]() ![]() ![]() ![]() Профиль Группа: Комодератор Сообщений: 7046 Регистрация: 28.8.2007 Где: Дублин, Ирландия Репутация: 60 Всего: 223 |
Откуда взялся сервер в однородной сети? Или у вас все узлы будут серверами? ![]()
Ага, но это уже не Clone паттерн - он предполагает 1 источник данных, который будет рассылаться на все клиенты. Кто будет этим 1 источником? И вообще, насколько я понял ZMQ это весьма навороченный транспортный уровень, т.е. с точки зрения топологии сети он недалеко ушел от чистого TCP/IP (его внутренние вкусности пока оставим за бортом - на сеть они не влияют) Поэтому вопрос остается - как будет производится построение сети из ваших узлов? Будет ли какая то точка привязки (например имя хоста, которое будет определять сеть), или все будет производится абсолютно динамически и без какой либо конфигурации? Если второе, то как будет определяться та часть сети, где узлы будут искать друг друга? PS. Сделать сеть совсем однородную (без какой либо разновидности сервера, пусть даже динамического) очень и очень проблематично, а уж сделать эффективно скорее всего вообще невозможно. |
|||
|
||||
drug007 |
|
||||||||
Бывалый ![]() Профиль Группа: Участник Сообщений: 196 Регистрация: 3.11.2011 Репутация: нет Всего: 1 |
однородная в смысле, что не будет выделенных сервера и клиентов - будет одно приложение. а внутри него будет сервер и клиент.
вот каждый узел и будет тем самым единственным - они же все уникальны у меня
Первоначально у каждого узла будет конфигурационный файл, в котором прописаны нужные ему узлы - те узлы, к которым он подключается как клиент. А другие узлы, у которых в конфиге прописан он, будет к нему как клиенты подключаться и он для них уже будет сервером - такое просто решение "в лоб". Потом уже желательна динамическая конфигурация, но это отдаленное будущее - главное вообще предусмотреть такую возможность. Ибо я согласен, что
Да я и не знаю транспорта, который бы позволил обойтись без сервера. Разве что-то вроде RS-232 ![]() |
||||||||
|
|||||||||
xvr |
|
||||||
Эксперт ![]() ![]() ![]() ![]() Профиль Группа: Комодератор Сообщений: 7046 Регистрация: 28.8.2007 Где: Дублин, Ирландия Репутация: 60 Всего: 223 |
'Каждый' не может быть 'единственным'. Для Clone патерна серверный узел должен быть ровно в 1 экземпляре. Или придется делать N штук Clone'ов, но это совсем чехол - у вас на каждом узле будут жить сервера по количеству узлов в сети, этакий multi сервер ![]()
Это тупиковый путь, при малейшем изменении сети вам придется переписать конфиги на всех узлах, причем переписать вручную ![]()
При таком подходе у вас в качестве сервера выступают конфиг файлы. Некоторое пояснение - под сервером я имел в виду узел, который хранит конфигурацию сети. Непосредственно данные передаются узлами непосредственно друг другу. Так что никакого постоянного взаимодействия узлов с сервером не происходит, и делать для него клоны явно нерентабельно. При статической конфигурации сети всем узлам достаточно знать IP сервера, собственно он и будет определять узлы, из которых состоит сеть. В случае динамической конфигурации сервером становится первый стартовавший узел, но понадобится дополнительные заточки в протоколе о том, как этот сервер будут находить другие узлы (например через broadcast в пределах сегмента сети), как выбирать сервер, если несколько узлов поднялись одновременно и как передавать функции сервера, если текущий сервер отключился от сети (например упал) |
||||||
|
|||||||
drug007 |
|
||||||
Бывалый ![]() Профиль Группа: Участник Сообщений: 196 Регистрация: 3.11.2011 Репутация: нет Всего: 1 |
Именно так - на каждом узле будет серверная часть - серверная в том плане, что к ней подключаются.
Это же на начальном этапе. Иначе можно застрять на этапе discovery service - поэтому в начале все-таки бизнес-логика, а уже потом удобства. К тому же зачем переписывать на всех узлах? Если узлу А больше не надо получать данные с узла В, но нужно с узла С - то меняется конфиг только на узле А - из него убирается В и добавляется С. Конечно это все упрощенно, но нет речи о законченной системе для полета на Марс. Главное, чтобы принципиальных ограничений не было. Поэтому вполне можно оставить так для начала:
По идее получается, что типичная сеть сервер-клиенты многократно накладывается на саму себя (с изменением сервера каждый раз) по количеству узлов в сети и получается аналог одноранговой сети. Или я где-то сильно ошибаюсь? |
||||||
|
|||||||
xvr |
|
|||
Эксперт ![]() ![]() ![]() ![]() Профиль Группа: Комодератор Сообщений: 7046 Регистрация: 28.8.2007 Где: Дублин, Ирландия Репутация: 60 Всего: 223 |
||||
|
||||
drug007 |
|
|||
Бывалый ![]() Профиль Группа: Участник Сообщений: 196 Регистрация: 3.11.2011 Репутация: нет Всего: 1 |
Они неразрывны, единое целое. Так как каждый узел генерирует уникальную информацию. Она может пересекаться с другими узлами по смыслу и содержанию, но все равно считается уникальной - например, если два датчика температуры измеряют температуру в одном и том же месте (неважно по какой причине, к примеру) то несмотря на то, что это температура по сути одна и та же, но информация с этих датчиков будет уникальной - будет включать в себя не только номер датчика, но и номер узла. Проблема отождествления информации с разных узлов ложится на приложение. Т.о. я планирую избавить приложение от нужды организовывать взаимодействие на низком уровне с другими узлами. А для отождествления что данная информация дублируется несколькими узлами у него уже будут все необходимые данные - и оно может, например, отказаться от получения данных с определенного узла. |
|||
|
||||
xvr |
|
||||
Эксперт ![]() ![]() ![]() ![]() Профиль Группа: Комодератор Сообщений: 7046 Регистрация: 28.8.2007 Где: Дублин, Ирландия Репутация: 60 Всего: 223 |
Т.е. идентификатор узла по сути входит в имя переменной. Тогда действительно координирующий сервер не нужен, но нужна какая то система сопоставления экспортируемых и импортируемых переменных. Это могут быть и конфиг файлы на каждом узле, но может быть и нечто иное - это сильно зависит от планируемого способа использования этой системы.
Это и не надо, фреймворк это должен реализовывать в любом случае. Вариант с конфиг файлами может не подойти например в таком случае -
|
||||
|
|||||
drug007 |
|
|||
Бывалый ![]() Профиль Группа: Участник Сообщений: 196 Регистрация: 3.11.2011 Репутация: нет Всего: 1 |
я планирую (опять же в начале) просто выставлять на экспорт все переменные с возможностью ограничения в дальнейшем. Потому что я опять же считаю, что выстроить обмен данными главнее, а уже потом можно этот обмен ограничивать. Потому что это большой объем работы - подобные ограничения, я думаю, ближе должны быть к уровню приложения, и в нем уже пользователь будет определять, что он хочет экспортировать, а что нет. А во фреймворке нужно будет предусмотреть средства для подобного регулирования. Но я даже пока не знаю, когда дойду до этого. ![]() Да, должны будут. А куда деваться? Динамическая реконфигурация вещь хорошая, конечно, но тоже в перспективе - ее создание усугубляет тот факт, что система становится слишком уязвимой к внешним воздействиям, в том числе злонамеренного характера. Вот как бы такая гибкость не вылезла боком-то в этом плане... |
|||
|
||||
xvr |
|
|||
Эксперт ![]() ![]() ![]() ![]() Профиль Группа: Комодератор Сообщений: 7046 Регистрация: 28.8.2007 Где: Дублин, Ирландия Репутация: 60 Всего: 223 |
Ну экспортироваться будут все перменные, это понятно. А вот какие переменные импортировать и откуда - вот в чем вопрос ![]() Не факт, сильно зависит от предметной области. Мы о ней пока ничего не знаем, может поделитесь сокровенными знаниями (если не секрет) ? |
|||
|
||||
drug007 |
|
||||
Бывалый ![]() Профиль Группа: Участник Сообщений: 196 Регистрация: 3.11.2011 Репутация: нет Всего: 1 |
Ух как далеко заходим... ![]()
Подробно пока не могу. А без деталей - это система географически распределенных датчиков и исполнительных устройств, которые могут действовать самостоятельно, но в системе их эффективность (иногда значительно) повышается. При этом система подвергается неблагоприятным внешним воздействиям как естественного, так и искусственного характера. |
||||
|
|||||
xvr |
|
||||
Эксперт ![]() ![]() ![]() ![]() Профиль Группа: Комодератор Сообщений: 7046 Регистрация: 28.8.2007 Где: Дублин, Ирландия Репутация: 60 Всего: 223 |
Все импортировать не получится. Для импорта любой переменной в клиенте должен быть инстанс соответствующего объекта (SharedVarRO), а это значит, что максимальное количество импортируемых объектов жестко задается самим клиентом, и не зависит от конфигурации сети
Это слишком общее описание. Под такое может подойди все, что угодно. Набор вручную заданных конфигов на каждом узле это обеспечит, но такое решение совершенно не manageable |
||||
|
|||||
drug007 |
|
||||
Бывалый ![]() Профиль Группа: Участник Сообщений: 196 Регистрация: 3.11.2011 Репутация: нет Всего: 1 |
Я не совсем корректно выразился - да, клиент определяет что бы он хотел получить путем создание инстансов SharedVarRO, а сервер определяет, что он ему может дать - т.е. возможна ситуация, когда клиент какие-то данные вообще не получит и инстанс SharedVarRO будет возвращаеть null вместо значения. Поскольку приложение специализированные, то количество инстансов будет задаваться на этапе разработки - определение структуры данных в приложении в рантайме вещь интересная, конечно, но это слишком накладно будет. Т.е. задача попроще стоит - на этапе разработки уже известно какие данные и от каких датчиков мы будет получать конкретный узел. Остальные узлы подписываются на показания нужных им датчиков - т.е. опять же на этапе компиляции задаются нужные инстансы. Т.о. получается, что структуру данных всей сети мы определяем в компайлтайме (не совсем уж жестко определяем - точнее сказать очерчиваем границы этой структуры), а уже в рантайме происходит заполнение этой структуры.
Согласен, это не удобно. Но возможны ситуации, когда из-за отсутствия каналов связи сеть будет распадаться на изолированные островки - если завести управление на единый сервер, то один островок останется управляемым, а остальные? Честно говоря, я всей проблемы полностью еще сам пока не представляю - в реале подобные задачи уже десятки лет решаются обычными АСУ, которые подразумевают жесткую иерархию, и смотря как они решаются (а решаются не очень) и возникла мысль сделать все по другому - изменить сам подход к решению проблемы. А раз подход новый, то и вопросов куча у самого. |
||||
|
|||||
xvr |
|
||||
Эксперт ![]() ![]() ![]() ![]() Профиль Группа: Комодератор Сообщений: 7046 Регистрация: 28.8.2007 Где: Дублин, Ирландия Репутация: 60 Всего: 223 |
Угу
В случае автоматичеси назначаемого сервера (в сегменте сети), в каждом островке образуется по серверу. Остается только предусмотреть средства, что бы эти сервера не передрались когда соединения между островками восстановится ![]() В принципе можно начать и с конфигов, и в дальнейшем это развить. |
||||
|
|||||
drug007 |
|
|||
Бывалый ![]() Профиль Группа: Участник Сообщений: 196 Регистрация: 3.11.2011 Репутация: нет Всего: 1 |
Это было бы классно, но за неимением ресурсов лучше так: |
|||
|
||||
![]() ![]() ![]() |
Правила форума "С++:Общие вопросы" | |
|
Добро пожаловать!
Если Вам понравилась атмосфера форума, заходите к нам чаще! С уважением, Earnest Daevaorn |
1 Пользователей читают эту тему (1 Гостей и 0 Скрытых Пользователей) | |
0 Пользователей: | |
« Предыдущая тема | C/C++: Общие вопросы | Следующая тема » |
|
По вопросам размещения рекламы пишите на vladimir(sobaka)vingrad.ru
Отказ от ответственности Powered by Invision Power Board(R) 1.3 © 2003 IPS, Inc. |