На сервере в памяти хранятся данные, по запросу клиента изменяются, рассылаются другим клиентам. Данные небольшие и операции относительно простые, поэтому все работает быстро и надежно.
Но эти данные нужно сначала достать из базы данных, а потом как-то сохранить. И здесь начинаются тормоза. В частности, сохранение графа объектов происходит в общем случае дольше, чем интервал между соседними изменениями данных (пользователь довольно быстро кликает мышью по кнопке, либо несколько пользователей одновременно). В итоге сервер параллельно сохраняет в базе несколько слегка разных версий одного и того же набора данных, что в худшем случае приводит к дедлокам транзакций. Как в такой ситуации правильно организовать загрузку и сохранение данных? Загружать один раз и держать в памяти как можно дольше? Сохранять как можно реже, когда данные никто не трогает?
Не могу придумать простое решение, по которому сразу можно было бы сказать, что оно работает, и не терзаться сомнениями вида "а что, если?" Как вообще принято делать? Задача выглядит абсолютно стандартной, но что-то ничего толкового не гуглится.
Re: Сохранение данных в БД в 3-звенной архитектуре
Здравствуйте, alesterre, Вы писали:
A>Как в такой ситуации правильно организовать загрузку и сохранение данных?
Декомпозиция. Читать/сохранять не весь "граф объектов", а по частям. Пока объем изменений в единицу времени остается небольшим, и сохранение будет быстрым.
A>Не могу придумать простое решение, по которому сразу можно было бы сказать, что оно работает, и не терзаться сомнениями вида "а что, если?"
Таких не бывает. У каждого подхода есть свои проблемы и свои "если". Например, при мелкой декомпозиции необходимо поддерживать согласованность частей. Возможно, придется их версионировать.
A>Как вообще принято делать? Задача выглядит абсолютно стандартной
Задача пока никак не выглядит. Мокажи свою модель данных, для начала.
Re: Сохранение данных в БД в 3-звенной архитектуре
Здравствуйте, alesterre, Вы писали:
A>На сервере в памяти хранятся данные, по запросу клиента изменяются, рассылаются другим клиентам. Данные небольшие и операции относительно простые, поэтому все работает быстро и надежно.
A>Но эти данные нужно сначала достать из базы данных, а потом как-то сохранить. И здесь начинаются тормоза. В частности, сохранение графа объектов происходит в общем случае дольше, чем интервал между соседними изменениями данных (пользователь довольно быстро кликает мышью по кнопке, либо несколько пользователей одновременно). В итоге сервер параллельно сохраняет в базе несколько слегка разных версий одного и того же набора данных, что в худшем случае приводит к дедлокам транзакций. Как в такой ситуации правильно организовать загрузку и сохранение данных? Загружать один раз и держать в памяти как можно дольше? Сохранять как можно реже, когда данные никто не трогает?
A>Не могу придумать простое решение, по которому сразу можно было бы сказать, что оно работает, и не терзаться сомнениями вида "а что, если?" Как вообще принято делать? Задача выглядит абсолютно стандартной, но что-то ничего толкового не гуглится.
Если у вас есть Stateful модель на сервере, которая напрямую ложится в базу, то сохранять нужно её из отдельного потока по таймеру, останавливая на это время все обновления.
Это конечно плохо, потому что не масштабируется. True путь это сделать модель отдельно, а базу отдельно. Базу оптимизировать под запись, модель собирать из базы, изменения пишутся и в модель и в базу сразу, ответ пользователю отдается из модели.
Если прикрутить распределенный кеш, то можно еще и несколько серверов поставить.
Re[2]: Сохранение данных в БД в 3-звенной архитектуре
Здравствуйте, wildwind, Вы писали:
W>Здравствуйте, alesterre, Вы писали:
A>>Как в такой ситуации правильно организовать загрузку и сохранение данных? W>Декомпозиция. Читать/сохранять не весь "граф объектов", а по частям. Пока объем изменений в единицу времени остается небольшим, и сохранение будет быстрым.
То есть, все-таки в общем случае стараются сохранять данные сразу же (если нет веских причин этого не делать)?
A>>Не могу придумать простое решение, по которому сразу можно было бы сказать, что оно работает, и не терзаться сомнениями вида "а что, если?" W>Таких не бывает. У каждого подхода есть свои проблемы и свои "если". Например, при мелкой декомпозиции необходимо поддерживать согласованность частей. Возможно, придется их версионировать.
Эх, жаль. Еще и версионирование. А если пользователи редко открывают одни и те же данные, можно обойтись блокировками? Заблокировать расписание целиком на время сохранения и изменения.
A>>Как вообще принято делать? Задача выглядит абсолютно стандартной W>Задача пока никак не выглядит. Покажи свою модель данных, для начала.
Из таблицы Schedule загружается одна строчка (одно расписание) и за ней тянется все остальное. В целом расписание загружается из базы за 1-1.5 секунды. К сожалению, полностью декомпозировать изменения затруднительно, потому что, например, иногда бывает нужно сдвинуть несколько десятков точек (таблица SchedulePoint) на указанное количество минут, при этом нужно пересчитать параметры работы (таблица Work), в которую они входят.
У меня есть мысль перенести обработку вовсе на клиента. Пусть ему отправляется все расписание целиком со всеми необходимыми связями, прямо там редактируется и результат время от времени отправляется на сервер, где сохраняется и рассылается другим подписчикам (у кого это расписание открыто). С одной стороны, бизнес-логика переезжает на клиента, что не очень хорошо (но и не слишком плохо). С другой стороны, скорость работы будет максимальной. Бизнес-логику можно (как мне кажется) затолкать внутрь сущностей (self-tracking entities). Самое приятное — вместо кучи разных мелких операций в контракте сервера будет только две — загрузить расписание и сохранить расписание.
Re[2]: Сохранение данных в БД в 3-звенной архитектуре
G>Если у вас есть Stateful модель на сервере, которая напрямую ложится в базу, то сохранять нужно её из отдельного потока по таймеру, останавливая на это время все обновления. G>Это конечно плохо, потому что не масштабируется. True путь это сделать модель отдельно, а базу отдельно. Базу оптимизировать под запись, модель собирать из базы, изменения пишутся и в модель и в базу сразу, ответ пользователю отдается из модели. G>Если прикрутить распределенный кеш, то можно еще и несколько серверов поставить.
Спасибо, есть о чем подумать. Экспериментальное сохранение по таймеру я уже даже сделал — через полторы секунды после последнего изменения данных — но только для части данных (где тормоза наиболее чувствительны), поэтому были проблемы с простым и надежным блокированием. Подумаю насчет сохранения всей модели целиком. Масштабирование текущему проекту точно не нужно, но мне интересно и в целом тоже, как вообще делают (тем более что масштабирование — один из классических плюсов трехзвенки, и без него ее смысл несколько снижается.).
Re: Сохранение данных в БД в 3-звенной архитектуре
Здравствуйте, alesterre, Вы писали:
A>На сервере в памяти хранятся данные, по запросу клиента изменяются, рассылаются другим клиентам. Данные небольшие и операции относительно простые, поэтому все работает быстро и надежно.
A>Но эти данные нужно сначала достать из базы данных, а потом как-то сохранить. И здесь начинаются тормоза. В частности, сохранение графа объектов происходит в общем случае дольше, чем интервал между соседними изменениями данных (пользователь довольно быстро кликает мышью по кнопке, либо несколько пользователей одновременно). В итоге сервер параллельно сохраняет в базе несколько слегка разных версий одного и того же набора данных, что в худшем случае приводит к дедлокам транзакций.
Очевидно должно быть версирование данных и оптимистические блокировки.
A>Как в такой ситуации правильно организовать загрузку и сохранение данных? Загружать один раз и держать в памяти как можно дольше? Сохранять как можно реже, когда данные никто не трогает?
Непонятно. А если сервер упадёт, то все изменения в памяти просто теряются? И такое допусимо?
A>Не могу придумать простое решение, по которому сразу можно было бы сказать, что оно работает, и не терзаться сомнениями вида "а что, если?" Как вообще принято делать? Задача выглядит абсолютно стандартной, но что-то ничего толкового не гуглится.
У меня был опыт с некой подобной системой, тоже некие расписания. Как у нас оно работало: на сервере БД. На клиентах — клоны БД. Клиенты рисуют и отображают информацию только из локальной БД, не делая никаких запросов серверу. Когда юзер делает какое-то действие, оно отсылается серверу, сервер делает изменения, используя данные серверной БД и отсылает изменённые записи всем клиетам, клиенты применяют эти дельты на свои локальные БД.
Получилось довольно неплохо — не требуется мощного/надёжного сервера, система устойчива к тормозным сетям и даже может работать в Read Only режиме при отсутствии сети. Одна была сложность — это права доступа, если клиент не имеет права видеть все данные, то надо как-то хитро определять какому клиенту что можно отправлять, а что нет.
ЗЫЖ Привет, УдГУ!
но это не зря, хотя, может быть, невзначай
гÅрмония мира не знает границ — сейчас мы будем пить чай
Re[3]: Сохранение данных в БД в 3-звенной архитектуре
Здравствуйте, alesterre, Вы писали:
A>Здравствуйте, wildwind, Вы писали:
W>>Здравствуйте, alesterre, Вы писали:
A>>>Как в такой ситуации правильно организовать загрузку и сохранение данных? W>>Декомпозиция. Читать/сохранять не весь "граф объектов", а по частям. Пока объем изменений в единицу времени остается небольшим, и сохранение будет быстрым.
A>То есть, все-таки в общем случае стараются сохранять данные сразу же (если нет веских причин этого не делать)?
Я бы сказал наоборот, в общем случае стараются лишний раз не дергать БД без веских причин.
A>>>Не могу придумать простое решение, по которому сразу можно было бы сказать, что оно работает, и не терзаться сомнениями вида "а что, если?" W>>Таких не бывает. У каждого подхода есть свои проблемы и свои "если". Например, при мелкой декомпозиции необходимо поддерживать согласованность частей. Возможно, придется их версионировать.
A>А если пользователи редко открывают одни и те же данные, можно обойтись блокировками? Заблокировать расписание целиком на время сохранения и изменения.
Еще на время чтения. Можно. Получится пессимистическая блокировка.
A>Эх, жаль. Еще и версионирование.
Это не так уж страшно, как может показаться. Версионирование может быть реализовано на уровне СУБД, например.
A>>>Как вообще принято делать? Задача выглядит абсолютно стандартной W>>Задача пока никак не выглядит. Покажи свою модель данных, для начала.
A>http://i.imgur.com/9yB8IbOs.png
М-да, мало что понятно, да еще с таким написанием.
A>Из таблицы Schedule загружается одна строчка (одно расписание) и за ней тянется все остальное. В целом расписание загружается из базы за 1-1.5 секунды. К сожалению, полностью декомпозировать изменения затруднительно, потому что, например, иногда бывает нужно сдвинуть несколько десятков точек (таблица SchedulePoint) на указанное количество минут, при этом нужно пересчитать параметры работы (таблица Work), в которую они входят.
А сколько времени занимает сохранение, если никто не мешает? Возможно, достаточно просто его оптимизировать, прежде чем решаться на более радикальные изменения.
С другой стороны, схема данных на первый взгляд выглядит не очень и нуждается в нормализации. Возможно, это и будет той самой необходимой оптимизацией
A>У меня есть мысль перенести обработку вовсе на клиента. Пусть ему отправляется все расписание целиком со всеми необходимыми связями, прямо там редактируется и результат время от времени отправляется на сервер, где сохраняется и рассылается другим подписчикам (у кого это расписание открыто). С одной стороны, бизнес-логика переезжает на клиента, что не очень хорошо (но и не слишком плохо). С другой стороны, скорость работы будет максимальной. Бизнес-логику можно (как мне кажется) затолкать внутрь сущностей (self-tracking entities). Самое приятное — вместо кучи разных мелких операций в контракте сервера будет только две — загрузить расписание и сохранить расписание.
Тоже вариант.
Re[3]: Сохранение данных в БД в 3-звенной архитектуре
On 01.02.2013 14:07, alesterre wrote: > Самое приятное — вместо кучи > разных мелких операций в контракте сервера будет только две — загрузить > расписание и сохранить расписание.
А если 2 пользователя меняют его "одновременно"? Один из них никогда не
узнает что его изменения затёрты или второй не сможет сохраниться?