Здравствуйте! Есть задача написать некую службу, принимающую данные и складирующую их с возможностью одновременного непоследовательного чтения. И есть очень важное требование: при любых не штатных ситуациях (программные, аппаратные сбои) принятые данные должны уцелеть (принятые на данный момент времени). Запись последовательная, непрерывная по времени, частыми, но не большими объемами. Средний боевой вариант - это 1мс по 5 килобайт(фрагмент). Каждый фрагмент самодостаточен. ОГРАНИЧЕНИЯ: ОС - WinXP и выше. Бесперебойника нет. Каких либо экстра устройств с резервным питанием и памятью нет. Поясню видимые сложности: - кэширование файловой системы не всегда сбрасывает буфера на диск. - отключение кэша (WRITE_THROUGH или FlushFileBuffers) снижает производительность при частом обращении. В худшем случае программа висит, ожидая завершения обращения к винту. - в момент сброса буфферов на диск, так же может произойти отключение питания и файл (БД) будет испорчен и не обязательно в конце. Важно добиться наилучшего соотношения надежности, производительности. Бегло сделав обзор, ничего конкретного не нашел. Так что, если есть какой материал почитать, покодить, то прошу показать где взять. Безусловно, что уровень будь то простое проиложение, драйвер или еще как не важен. Важен результат или максимальное приближение к нему. Есть и своя идея как это реализовать, но хотелось бы сперва услышать Ваши. Спасибо.
1 поставить все-так бесперебойник 2 использовать СУБД Оптимально не только по надежности/производительности, но и цене
все же расчитывать на это не приходится. а есть какие либо на это расчитанные?? не слишком раздутые под мал-мальские одноядерные процы... и где почитать про их надежность именно в ситуациях выключения питания, BSOD и прочего...
PavPS Необходима надстройка над ядром, тоесть нужно перехватывать шлюзы в IDT и вручную работать с диском. В любом ином случае решение будет крайне не стабильным, даже такой вариан весьма плох - множество ситуаций есть при которых железо не будет выполнять ваш код, например железячный сброс и пр.
Спасибо. А есть ли какие прототипы, изыскания в эту сторону? Явно ведь тема беспокоила многих... Може еще идеи есть?
Без стабильного питания всё равно добиться 100% гарантии сохранности данных невозможно в принципе, но также и повышается вероятность механического повреждения носителя. Ну а насчёт сброса на диск, то Cи функция fflush по-моему это делает. В линукс ещё есть функция fsync. Конечно сбой вполне может произойти в самый неподходящий момент, тут ничего не сделаешь, нужно заново запрашивать блок. Иначе никак.
Да я бы рад, но сопутствующий софт должен работать как и раньше (всякий там офис, видео, наконец...). Вот какой вариант мне пришел на ум: Условно, каждый непрерывный промежуток времени записи назовем сессией. Считаем разовую посылку 1 килобайт. Период 10мс. (вариант штатный) Каждая сессия пишется так: Принимаются данные и пишутся в файл без WRITE_THROUGH. Размер файла ограничен размером 300 килобайт или временем 3 секунды. По истечению этого времени выполняется "flush" для этого файла, хэндл закрываем. Переоткрываем на рандом чтение. И так далее, пока не наберется цепочка из 100 открытых файлов. Как только набралась, сливаю все файлы в один файл (при этом не закрывая до этого 100 предыдущих мелких файлов), затем сбрасываю на диск буфера от полученного большого файла, жду немного и удаляю предыдущие 100 файлов, и теперь как новый источник предыдущих данных использую уже большой файл. Примечание: Каждый записываемый файл (будь то самый первый в 300 кб или дугие), естественно сопровождается контрольной суммой и в будущем инфой для восстановления. Такой подход дает возможность потерять (запороть) не более 300 записей. Естественно, период flush и граничный размер могут быть и ниже. Это еще нужно протестировать. Т.е. в приближении, любой аппаратный сбой не попортит предыдущие записи. Пожалуйста, покритикуйте, может можно улучшить? Илb другой алгоритм? PS:Если кто вдруг прочитав мой вариант понял, что изначально вопрос он мой не понял, пожалуйста, подумайте, может у вас теперь есть ответ...
Может стоит тогда попробовать (я пробовал) создать виртуальный диск в памяти (придется писать драйвер, который будет полностью эмулировать работу например FAT32 и перекачивать все это дело квантами на реальный хард, здесь правда в ядре помню с nonpaged- пулами при эмуляции FAT32 была проблема, но если использовать неболшой объем эмуляции, то и потерь намного меньше). Если чего пиши в ЛС, может тот дров откопаю у себя.
Да, но в чем приемущество? Все тот же sync нужно выполнять часто, да и так же придется синкать только модифицированную часть только, а иначе всё встанет в тормозах. Плюс я вижу только один - унифицированность работы, и не обращение внимания на способ записи данных.
PavPS На счёт количества файлов ничего подсказать пока не могу, но по поводу самой записи есть следующие соображения: 1) Файлы нужно открывать только на запись. (для чтения можно параллельно записывать в другой файл, для которого надёжность не требуется). 2) Изначально файл нужно чем-то заполнить и записывать не выходя за пределы файла. 3) Записывать только блоки выровненные по размеру кластера. При таких условиях мне кажется не будут модифицироваться структуры описывающие размещение файла, и испорченный может оказаться только записываемый в данный момент блок.
Аппаратный RAID на него блок резервного питания + ИБП на комп, если данные стоят дороже полученного решения то не вижу причин почему необходимо городить программный огород...
dag Это требует траты денег на клиентские машины, а значит дорога конкурентам, у которых может все и порушится, но изначально дешево и просто. Увы.
PavPS Второй пункт нужен чтобы системе не требовалось расширять файл и следовательно модифицировать связанные с ним структуры файловой системы. Первый пункт коненчо несколько сомнителен, но мне кажется, что чтение может задержать модифицированый блок в кеше и отложить его фактическию запись на диск. А вот по поводу блоков могу добавить, что для них нужно обязательно сделать нумерацию защищённую каким-то кодом. Причем код должен зависеть от имени файла или какого-то случайного уникльного числа(эго можно в файл положить), чтобы если файл окажется на месте какого-то старого файла, его блоки не могли быть приняты за корректные.
PavPS если у тебя данных на 10.000.000 и жаба душит потратить 20.000 на то чтобы не допустить их потерю то тогда используй избыточность размерностью которая перекроет твои траты на аппаратную избыточность, возможно стоит поставить ещё 10ток жестких дисков и писать на них в 10 потоков без использования всяких рэйдов ну или рида-соломона или xor обычный по 100 файлам в разных местах 1 - 2 дисков
Black_mirror Спасибо за пояснения, про размеры блоков. Так и сделаю, если буду применять описанный выше алгоритм... вот именно на имени файла я и хотел завязываться. плюс так же и в тело файла писать. dag Прои избыточность совершенно верно! Скорее всего сразу и надо буде вводить. Только вот она пригодится при порче последнего файла. остальные, успевшие засинкаться должны быть невредимыми. Может есть у кого еще идеи по поводу вариаций алгоритма складирования?
Зачатки идеи уже озвучили выше: Sender отправляет блок информации, временно сохраняет его у себя и ждет от Receiver'а подтверждения о получении. Как только получил - удаляет сохраненный блок. Receiver же должен уведомить Sender'а только после того, как произойдет гарантированная запись информации на диск. Так же Receiver должен помнить, что он что-то принял, чтобы в случае сбоя перезапросить информацию. При этом, если архитектура вашего проекта позволяет, то можно запретить Sender'у отправлять последующие блоки до тех пор, пока не придет подтверждение о записи последнего отправленного.