реклама на сайте
подробности

 
 
> Буферирование потока данных в файл, Идеи, критика
DeadMoroz
сообщение Nov 3 2012, 13:21
Сообщение #1


Местный
***

Группа: Свой
Сообщений: 211
Регистрация: 3-02-05
Пользователь №: 2 391



Здравствуйте!
Имеется система на Линуксе. Примерная логика части программы такова:
программа получает постоянный поток данных от FPGA (64 байта/мс * 12 каналов), если при этом установлено соединение (100Мбит изернет) с GUI, то весь поток должен передаваться туда. Если соединения нет, то поток должен писаться в файл на HDD (EXT3\4). Размер файла может быть до 170Гбайт на канал (30 дней), 12 файлов соответственно. Данные из потока должны передаваться последовательно, т.е. перестановка недопустима. В данный момент собираюсь реализовать это следующим образом:
1) для каждого из каналов создать/открыть файл размером 230Мбайт (1 час данных), отобразить файл в память с mmap().
2) писать данные в файл в независимости от состояния соединения с GUI как в ФИФО буфер.
3) если соединение установлено - читать данные из файла как из ФИФО буфера, при этом файл не будет превышать первоначального/текущего размера.
4) если соединения нет, продолжать писать в файл, при достижении максимального размера, увеличивать размер файла опять на 230Мбайт (1 час) и делать mremap().
По этой реализации у меня такие вопросы:
1) будет ли это достаточно быстро работать (mmap|mremap)?
2) насколько это все надежно (питание может пропасть в произвольный момент), как делать сброс буфера на диск (как fflush)?
3) что лучше один файл на 30 дней или куча файлов (например 1 час) с точки зрения надежности и быстродействия?
4) какие есть альтернативные варианты?

P.S. Это мой первый проект под Линукс. Подобное ранее не делал. Система на TI OMAPL-138, 128MB DDR, SATA HDD.
Go to the top of the page
 
+Quote Post
 
Start new topic
Ответов
kurtis
сообщение Nov 5 2012, 09:44
Сообщение #2


Местный
***

Группа: Свой
Сообщений: 466
Регистрация: 21-06-05
Пользователь №: 6 205



1. В чем вы видите преимущество использования mmap() перед write()/read()?
2. sync() сливает содержимое буферов ядра, в буфер устройства. Но это никак не влияет на надежность, т.к. если данные попали в буфер устройства, то не факт что они попали на физический носитель.
3. Зависит от способа обработки. Если вам нужно 1 раз построить график по данным и больше ничего не делать, то 1 файл вполне пойдет. Но если вам вдруг нужно будет посмотреть что было 23 мая, в 15 часов 12 минут, то искать вы будете долго. Я бы делал за каждый час.

Я бы сначала вообще ничего не писал, а попробовал бы все сделать на баше. Если будет тормозить (а я не думаю что будет тормозить), то тогда уже думать дальше.
Go to the top of the page
 
+Quote Post
vshemm
сообщение Nov 7 2012, 17:43
Сообщение #3


Частый гость
**

Группа: Участник
Сообщений: 167
Регистрация: 15-08-07
Пользователь №: 29 803



Цитата(kurtis @ Nov 5 2012, 13:44) *
2. sync() сливает содержимое буферов ядра, в буфер устройства. Но это никак не влияет на надежность, т.к. если данные попали в буфер устройства, то не факт что они попали на физический носитель.


Увы, данное ложное утверждение повлекло за собой бла бла бла, а не обсуждение. Дело в том,
что sync() не только сбрасывает ядерные буфера в устройство, но еще дает команду устройству
сбросить свои кеши. Но есть два нюанса.

Первый - устройство может обмануть и сказать что кеши сброшены, хотя это не так (не говоря
уже о том, что такой команды для данного типа устройств может не быть). Например,
спецификация ATA определяет команду FLUSH_CACHE (0xe7) как mandatory, но это не мешает
дешевым/кривым дискам врать. Плюс, кеши могут сбрасываться в измененном порядке, алгоритмы
внутреннего хранения данных могут накладывать свой отпечаток и т.д. - это тоже важно.

Второй нюанс заключается в том, что sync() сбрасывает ядерные буфера на уровне блочных устройств,
а ведь еще могут быть буфера ФС и даже в пользовательском пространстве существует буферизация. Для
решения этой проблемы есть fflush().

Таким образом, чтобы данные файла гарантированно оказались на диске (не кривом), нужно выполнить
комбинацию fwrite(); fflush(); fsync(); Несложно заметить, что это не решает проблему ТС, т.к.
пропадание питания во время этой последовательности может привести (и приведет) к порче данных/ФС.

Поэтому единственным выходом является использование специальных файловых систем (журналируемых или
log-based). Например, те же ext3/ext4 позволяют журналировать не только метаданные, но и данные,
хоть и с потерей производительности (причем практически двукратной, т.к. данные сначала пишутся
в журнал, а потом еще раз в "обычное" место; впрочем, некоторые ФС - ZFS, Btrfs, .. - используют
COW и данные пишутся один раз, но у них присутствуют другие недостатки). Для совсем "голых" устройств
есть jffs2, logfs и т.д.

Разумеется, эти ФС требуют, чтобы диски умели честно сбрасывать свои кеши. Диски с вращающимися
блинами также любят переупорядочивать запись кешей чтобы лишний раз не гонять головки. Но для ФС
порядок записи данных и метаданных очень важен, поэтому с этим тоже нужно бороться (курим маны на
ext3/4, термин barrier).

Для SSD (и других девайсов на флеше типа Compact Flash) все еще печальнее из-за статического
wear-leveling`а и прочих наворотов вроде представления данных как сжатого архива внутри девайса
(поэтому на некоторых новых контроллерах SSD рекомендуется не использовать TRIM во избежание
потери производительности/повышения износа).

Подобные проблемы не решаются на уровне ОС, т.к. все это делается прозрачно для нее внутри логики
девайсов. Ушлые производители об этом знают, поэтому выпускают линейки "надежных" power-safe дисков
(втридорога, разумеется), а в потребительскую продукцию внедрять новые технологии не спешат wink.gif

В двух словах примерно так...

Возвращаясь к вопросам ТС.
1. mmap() не будет быстрее read/write, т.к. все пойдет через один механизм (VFS и page cache).
2. Следует использовать журналируемую ФС и правильные диски. Неплохим стартом будет ext3/4 с
журналированием данных + HDD поддерживающий спецификацию ATA8 и выше.
3. Лучше делать много файлов из расчета что при сбое потеряются данные последнего файла. Т.е. если
вы готовы потерять последнюю минуту - делайте файлы на каждую минуту на каждый канал. Если вы вообще
не готовы терять данные - тоже решается, но сложнее.
Также старайтесь всегда дописывать данные в файл (append) а не писать в середину.

Вопрос как записать "важный для системы параметр размером ну в 256 байт" чаще решается иными методами.
Например, "голый" (т.е. без внутренней логики) NAND + logfs, а если параметр небольшой - то EEPROM
или вообще FRAM с зиллионом циклов чтения/записи + правильная структура хранения данных (т.е. вообще
без ФС). Батарейка/ИБП тоже вариант, да.
Go to the top of the page
 
+Quote Post



Reply to this topicStart new topic
1 чел. читают эту тему (гостей: 1, скрытых пользователей: 0)
Пользователей: 0

 


RSS Текстовая версия Сейчас: 26th August 2025 - 19:59
Рейтинг@Mail.ru


Страница сгенерированна за 0.01331 секунд с 7
ELECTRONIX ©2004-2016