Любые идеи по развитию MyChat. Запросы на новые функции, предложения по улучшению уже работающих сервисов. Если вы знаете, что нужно добавить в MyChat — welcome!
Аватара пользователя
March Tom-Cat
Итак, начало собственно здесь и здесь

Сразу оговорюсь, админю и програмлю более 20 лет. Так что можете в меня сленгом "швыряться" по полной программе.

Итак, собственно основная проблема при мультисерверной работе - это синхронизация конфигурации серверов.
То что для синхронизации конфигураций нужен собственный протокол это понятно (без него будет просто сложно передать некоторые данные IMHO).
То что возможны коллизии при одновременном изменении конфигурации тоже понятно. На мой взгляд лучше всего здесь использовать транзакции, или SQL (и/или его механизмы).

Теперь куда я - что мешает использовать embedded SQL? Допустим тот же самый FireBird? Настраиваете БАЗЫ с конфигурацией в режиме репликации, и обственно просто пишите в базу и читаете из нее с определенным промежутком времени, либо (и/или) по команде соседнего сервера.

Вот примерно так.

Конечно я не разработчик, и не знаю всех тонкостей, но на мой взгляд предложение более-менее жизнеспособное. Даже при обрыве связи между серверами, SQL сам все сделает при её восстановлении (имеется ввиду связь и репликации между базами).
Аватара пользователя
Алексей Пикуров
Окей, начинаем швыряться :)

Embedded sql базы мы используем и так. Проблемы сливать SQL-транзакции в виде копий для slave-серверов с Master-сервера нет никакой. Наоборот - хуже.

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

На сервере №1 пользователь отправляет приватное сообщение для офлайн-юзера. Сервер кладёт его мессадж в базу данных, в базе появляется запись с автоинкрементным индексом.

На сервере №2 происходит точно такая же операция, только пользователи другие. Автоинкремент делается точно так же.

Когда начнётся репликация - будет коллизия по автоинкрементному полю. Его номер совпадёт на обоих серверах. А мессаджи и юзеры-получатели и отправители - разные.

В данном конкретном случае можно на это "забить", но есть таблицы в БД, где построены связи как раз по этим автоинкрементным полям, а это уже будет фатально.

Вообще говоря, я думаю, что вариант с "тупым" slave-сервером, на котором нельзя ничего админить, а использовать его в виде обычной розетки-заменителя коннекта, пока нет связи с Master-сервером, будет самым "мягким" решением. Как только появляется коннект с Master-сервером, Slave рубит все свои соединения и его клиенты автоматом переключаются на головной сервер.

Офлайн-сообщения, вероятно, придётся как-то передавать по протоколу межсерверного взаимодействия. Насчёт оповещений, доски объявлений и офлайн файлов - даже не знаю, возможно стоит с этим повременить, слишком сложная схема.
AlexSTAL
Алексей Пикуров писал(а):Окей, начинаем швыряться :)
Вообще говоря, я думаю, что вариант с "тупым" slave-сервером, на котором нельзя ничего админить, а использовать его в виде обычной розетки-заменителя коннекта, пока нет связи с Master-сервером, будет самым "мягким" решением.


Мне кажется, что более чем достаточно

Алексей Пикуров писал(а):Как только появляется коннект с Master-сервером, Slave рубит все свои соединения и его клиенты автоматом переключаются на головной сервер.


А что мешает постоянно быть подсоединённым к слейву? Он будет ретранслятором
Аватара пользователя
Алексей Пикуров
AlexSTAL писал(а):А что мешает постоянно быть подсоединённым к слейву? Он будет ретранслятором

Как я планирую, Slave-сервер будет иметь ограниченный функционал, он просто будет повторять тот минимум, что необходим для корректной работы клиентов. Т.е. коннект, список контактов, приватные сообщения, возможно ещё одна общая конференция и обмен файлами/картинками между пользователями. Всё.

Грубо говоря, всё то, что не требует проверки прав и сложной логики.
AlexSTAL
Алексей Пикуров писал(а):Как я планирую


Ну не знаю... Я бы всё же сделал, как с контроллерами домена ReadOnly
Все машины всегда обращаются к своему ReadOnly контроллеру, а он ретранслирует к вышестоящему при необходимости
Аватара пользователя
March Tom-Cat
Алексей Пикуров писал(а):Окей, начинаем швыряться :)

Сам напросился... :D

Алексей Пикуров писал(а):Embedded sql базы мы используем и так. Проблемы сливать SQL-транзакции в виде копий для slave-серверов с Master-сервера нет никакой. Наоборот - хуже.

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

На сервере №1 пользователь отправляет приватное сообщение для офлайн-юзера. Сервер кладёт его мессадж в базу данных, в базе появляется запись с автоинкрементным индексом.

На сервере №2 происходит точно такая же операция, только пользователи другие. Автоинкремент делается точно так же.

Когда начнётся репликация - будет коллизия по автоинкрементному полю. Его номер совпадёт на обоих серверах. А мессаджи и юзеры-получатели и отправители - разные.

В данном конкретном случае можно на это "забить", но есть таблицы в БД, где построены связи как раз по этим автоинкрементным полям, а это уже будет фатально.

Вообще говоря, я думаю, что вариант с "тупым" slave-сервером, на котором нельзя ничего админить, а использовать его в виде обычной розетки-заменителя коннекта, пока нет связи с Master-сервером, будет самым "мягким" решением. Как только появляется коннект с Master-сервером, Slave рубит все свои соединения и его клиенты автоматом переключаются на головной сервер.

Офлайн-сообщения, вероятно, придётся как-то передавать по протоколу межсерверного взаимодействия. Насчёт оповещений, доски объявлений и офлайн файлов - даже не знаю, возможно стоит с этим повременить, слишком сложная схема.

Честно говоря не знал, что у Вас уже вшит SQL, предложение родилось как-то само и спонтанно...
Я не знаю возможностей конкрено embedded SQL'я который Вы используете, да и вообще всех embedded (лет 5 назад дошел до них, но так и не удалось опробовать). Могут возникнуть проблемы в "урезанном" функционале подобных серверов.
Поднятая Вами проблема не проста, но и не нова. В той или иной степени она решалась уже не раз.
Вот например здесь: Репликация базы данных. Евдокимов Алексей
Или совсем беспредметные, но общие рекомендации в руководстве админа: 4.10 Репликация
Но пути эти сложны и тернисты... Что мешает пойти простым путем?
Как?! :shock:
Да очень просто. Используем старший байт IDа (автоинкремента) в качестве номера сервера, в результате можем построить "сеть" с 255 серверами без "особых" проблем! :oops:
Ведь НИКОГДА ни на одном из серверов НЕ БУДЕТ ОДИНАКОВОГО IDа... :D
Аватара пользователя
March Tom-Cat
AlexSTAL писал(а):
Алексей Пикуров писал(а):Как я планирую


Ну не знаю... Я бы всё же сделал, как с контроллерами домена ReadOnly
Все машины всегда обращаются к своему ReadOnly контроллеру, а он ретранслирует к вышестоящему при необходимости

Здесь я соглашусь с Алексеем, разработчику всегда проще начинать от простого к сложному, чем начать делать все и сразу...
AlexSTAL
March Tom-Cat писал(а):
AlexSTAL писал(а):
Алексей Пикуров писал(а):Как я планирую


Ну не знаю... Я бы всё же сделал, как с контроллерами домена ReadOnly
Все машины всегда обращаются к своему ReadOnly контроллеру, а он ретранслирует к вышестоящему при необходимости

Здесь я соглашусь с Алексеем, разработчику всегда проще начинать от простого к сложному, чем начать делать все и сразу...

Млин... я вообще ничего не усложнял...
Вы откуда взялись?
Аватара пользователя
Алексей Пикуров
March Tom-Cat, я почитаю статьи по вашим линкам, спасибо. Вредно не будет.

Со старшим байтом накладка :)
1. Я не управляю механизмом автоинкрементов, этим занимается БД. Тут это железно. Можно это изменить, конечно, сделав привязку к специальному полю, но для этого надо полностью перепроектировать БД. Wrong way.
2. Старшего байта маловато, в таблице может быть значительно больше, чем 65535 записей. Там используется Cardinal. Конкретно в нашей БД. Но сути дела это не меняет всё равно. В FireBird, насколько я помню, автоинкремента нет, но есть триггер, на который можно повесить всё что душе угодно. Но, сами понимаете, взять и вот так перепрыгнуть на совершенно другую БД мы не можем.

И ещё один момент.

Даже если мы придумаем, как синхронизировать базы данных. Я о нём вскользь упоминал. Есть онлайновые структуры в памяти, это сложные системы кешей и много других данных, которые мы вынуждены хранить в памяти для скорости работы. База данных используется только как место для хранения данных, которые можно потерять в случае внезапного отключения сервера (падение, отключение питания, BSOD и т.п.) и для хранения всех настроек. Мы стараемся обращаться к ней настолько редко, насколько это вообще возможно. Причина - падение быстродействия. На серверах, где находятся многие сотни онлайн-пользователей, это становится заметно очень быстро.

Поэтому все настройки вычитываются в память в специальные оптимизированные структуры при старте сервера.

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

Я искренне хочу сделать онлайн-линковку, как в IRC, но, максимум, на что могу сейчас пойти - это тот вариант, что я описал выше, с "тупым" Slave-сервером, без ретрансляции. IRC, к сожалению, на порядки проще по своему функционалу и устройству, там это возможно, но в MyChat - нет.
Аватара пользователя
March Tom-Cat
AlexSTAL писал(а):Млин... я вообще ничего не усложнял...

А я не говорю что Вы усложняете, я говорю как проще (на мой взгляд)...

AlexSTAL писал(а):Вы откуда взялись?

Как бы я автор темы... :oops:
Аватара пользователя
March Tom-Cat
Алексей Пикуров писал(а):March Tom-Cat, я почитаю статьи по вашим линкам, спасибо. Вредно не будет.

Со старшим байтом накладка :)
2. Старшего байта маловато, в таблице может быть значительно больше, чем 65535 записей. Там используется Cardinal. Конкретно в нашей БД. Но сути дела это не меняет всё равно. В FireBird, насколько я помню, автоинкремента нет, но есть триггер, на который можно повесить всё что душе угодно. Но, сами понимаете, взять и вот так перепрыгнуть на совершенно другую БД мы не можем.

Да конечно, это я все понимаю, как и то что любые телодвижения в ту или иную сторону потребуют трудозатрат.
Даже если исключить коллизии просто передача настройки с одного сервера на другой уже не такая и простая задача, особенно если произведена очередная выгрузка "пачки" пользователей из AD.
Однако рекомендую поразмышлять над старшим байтом. Ведь вместо простого "INSERT ...." можно воспользоваться хранимой процедурой (конечно если используемый Вами SQL поддерживает их), тогда одним из параметров можно будет передать и номер сервера.
Если я все правильно понял, то Cardinal это 8 байт (64 бита), и тогда под автоинкремент остается 10^18, т.е. очень много. А вот если это 4 байта (32 бита), то это действительно может быть проблемой, под данные остаются 24 бита или чуть больше 16 000 000 элементов.
Но опять таки можно не использовать все 8 бит. Можно ограничится 4 битами, это уже дает 16 серверов и резко расширяет количество данных (более 268 000 000 элементов).
Однако производительность при вставке новых элементов упадет, возможно даже существенно.

Алексей Пикуров писал(а):И ещё один момент.

Даже если мы придумаем, как синхронизировать базы данных. Я о нём вскользь упоминал. Есть онлайновые структуры в памяти, это сложные системы кешей и много других данных, которые мы вынуждены хранить в памяти для скорости работы. База данных используется только как место для хранения данных, которые можно потерять в случае внезапного отключения сервера (падение, отключение питания, BSOD и т.п.) и для хранения всех настроек. Мы стараемся обращаться к ней настолько редко, насколько это вообще возможно. Причина - падение быстродействия. На серверах, где находятся многие сотни онлайн-пользователей, это становится заметно очень быстро.

Поэтому все настройки вычитываются в память в специальные оптимизированные структуры при старте сервера.

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

Я искренне хочу сделать онлайн-линковку, как в IRC, но, максимум, на что могу сейчас пойти - это тот вариант, что я описал выше, с "тупым" Slave-сервером, без ретрансляции. IRC, к сожалению, на порядки проще по своему функционалу и устройству, там это возможно, но в MyChat - нет.

Есть еще один вариант, но боюсь он внесет еще большие трудности как по обслуживанию, так и по реализации, да и вопросов по нему возникает довольно много, но все равно озвучу.
Можно сделать тройственную систему, по образу client-server, только немного расширить: client-server-server. Но в данном случае придется использовать один сервер без клиентов, чисто под управление остальными серверами. И это, наверное, самая простая проблема из всех остальных.
А по поводу кэшей и всех остальных данных, тут боюсь много не насоветую - нужно знать подробности...

P.S. На самом деле задача из разряда "Это же просто сделать!"... А вот когда до реализации дело доходит... :shock: