однопоточный программный продукт весьма активной сетевой работой
работает через обертку вокруг epoll
программа ресурсоемкая и в то же время в больших объемах пишет лог файлы в формате CSV (несколько штук)
то есть размер буффера для единичной операции записи — строка 200-250 байт
таргет платформа — linux Fedora Core 4
Нужно:
проанализировать подходы к эффективной запись в лог-файлы
в том числе с использованием асинхронной записи.
Лично мне кажется, что замена текущей (весьма медленной и корявой) имплементации "fopen-fwrite-fclose на каждую строку"
на имплементацию с постоянно открытым файлом, буффером в ~64Кб и периодическим сбросом на диск вполне будет достаточно
(по крайней мере судя по замерам — в 30-40 раз быстрее)
Но для очистки совести и успокоения начальства, надо протеститровать и асинхронную работу.
Собственно возникают вопросы:
1. каким образом это можно (нужно) организовать?
2. нашел упоминание о поддержке aio на уровне ядра в ядрах 2.6.х, но к сожалению не нашел вразумительной информации об этом. Работает ли это вообще? какие есть подводные камни?
3. можно ли это сделать как-то иначе?
буду благодарен если в меня бросят ссылкой с более или менее подробной информацией по эьтому вопросу.
Здравствуйте, rip_someday, Вы писали:
_>Нужно:
_>проанализировать подходы к эффективной запись в лог-файлы _>в том числе с использованием асинхронной записи. _>Лично мне кажется, что замена текущей (весьма медленной и корявой) имплементации "fopen-fwrite-fclose на каждую строку" _>на имплементацию с постоянно открытым файлом, буффером в ~64Кб и периодическим сбросом на диск вполне будет достаточно _>(по крайней мере судя по замерам — в 30-40 раз быстрее)
Адназначна ДА! Делать окрытие файлов для записи строки в лог это УЖОС! Конечно же файлы нада держать вседа открытыми! Правда в случае fopen/fwrite/fclose делать свой буфер не есь хорошо... он уже там есть (и его размером мона поиграца еси я все прально помню из info по libc)! Собственный буфер имеет смысл при low level I/O -- open/write/close... и лучше его сделать побольше! -- порядка 1.5М (зависит конечно от скорости заполнения буфера и того насколько страшно потерять нефлашеный лог в случае непредвиденных обстоятельств -- но основной смысл в том что писать нада риальна МНОГО -- контроллеры винчей порой имеют кэш 8 и более М -- нет повода стеснять себя килобайтами...
_>Но для очистки совести и успокоения начальства, надо протеститровать и асинхронную работу.
давным давно (када дизайнилась одна мега прога тоже пишущая на диск гигабайтами всяких данных) я почитал про это и решил забить -- точной причины не вспомню... но тяжелый осадок от прочтения остался -- толи там недоделано чивота, толи черезчур сложно... не помню
НО есть разхумееца другой выход! -- см. ниже
_>Собственно возникают вопросы: _>1. каким образом это можно (нужно) организовать? _>2. нашел упоминание о поддержке aio на уровне ядра в ядрах 2.6.х, но к сожалению не нашел вразумительной информации об этом. Работает ли это вообще? какие есть подводные камни? _>3. можно ли это сделать как-то иначе?
конечно! оставь работу с логами на долю того кто под это заточен! -- а имена syslog демон
означеная мегапрога генерила порядка 1Г (или даже больше -- точную цыфру не вспомню -- но РИАЛЬНА ДОФИГА) зипаных логов в день -- не все сислоги такое выдерживают.. но есь один который более менее работал в подобных условиях -- это был syslogng
твоя задача используя функцию syslog(3) писать все что тебе там хочеца в ОДИН источник -- пусь syslogовские фильтры позднее потом разбираются чо куда распихивать и как ротейтить... -- возможно даже передавать это куданить на специально выделенный сервер (как вот было у нас в кластере -- ибо спамить хотели многие демоны а лазить по куче тачек грепать ихние логи абломно)
для упрощения работы мона сделать iostreamный syslog класс -- буишь стрелочками фигачить себе в syslog и не парица
_>буду благодарен если в меня бросят ссылкой с более или менее подробной информацией по эьтому вопросу.
Я бы делал по отдельному процессу (или треду, дело вкуса) под каждый записываемый файл, общался бы через fifo.
Запись тоже производил бы через poll/select, буферизуя входящие данные (так можно управлять размером этого буфера).
Никаких iostream/stdio, только open/write/close. open, понятно, один раз, close тоже, посередине пользоваться, например, fdatasync.
Здравствуйте, Dair, Вы писали:
D>Я бы делал по отдельному процессу (или треду, дело вкуса) под каждый записываемый файл, общался бы через fifo.
а я бы не стал так делать -- врядли скорость постепления логерских строк такова что эти threadы будут работать без простоев...
IMHO достаточно одного thread'a который буит владеть буферами и открытыми файлами и флашить на диск переполненные буферы (либо по таймауту -- ибо еси в буфер ничо не поступает и он не полный его тоже нада както записать
D>Запись тоже производил бы через poll/select, буферизуя входящие данные (так можно управлять размером этого буфера).
IMHO не нада усложнять себе жысть играми с неблокирующимся I/O... write(buffer, 1.5M); буит вполне достаточно!
D>Никаких iostream/stdio, только open/write/close. open, понятно, один раз, close тоже, посередине пользоваться, например, fdatasync.
IMHO выбор за тобой -- избавившись от постоянного открытия файлов у тя все буит "летать"! дальнейшие оптимизации нада делать _только_ на основании профайлерных данных -- не нада бежать впереди поезда...
PS: персонально мой солюшин былбы в использовании syslog...
Здравствуйте, zaufi, Вы писали:
Z>Здравствуйте, rip_someday, Вы писали:
_>>Нужно:
_>>проанализировать подходы к эффективной запись в лог-файлы _>>в том числе с использованием асинхронной записи. _>>Лично мне кажется, что замена текущей (весьма медленной и корявой) имплементации "fopen-fwrite-fclose на каждую строку" _>>на имплементацию с постоянно открытым файлом, буффером в ~64Кб и периодическим сбросом на диск вполне будет достаточно _>>(по крайней мере судя по замерам — в 30-40 раз быстрее)
Z>Адназначна ДА! Делать окрытие файлов для записи строки в лог это УЖОС! Конечно же файлы нада держать вседа открытыми! Правда в случае fopen/fwrite/fclose делать свой буфер не есь хорошо... он уже там есть (и его размером мона поиграца еси я все прально помню из info по libc)! Собственный буфер имеет смысл при low level I/O -- open/write/close...
я так и сделал, ну не совсем же я дурак все-таки
Z> и лучше его сделать побольше! -- порядка 1.5М (зависит конечно от скорости заполнения буфера и того насколько страшно потерять нефлашеный лог в случае непредвиденных обстоятельств -- но основной смысл в том что писать нада риальна МНОГО -- контроллеры винчей порой имеют кэш 8 и более М -- нет повода стеснять себя килобайтами...
в принципе размер буффера можно подобрать потом, даже лучше сделать конфигурируемым.
_>>3. можно ли это сделать как-то иначе?
Z>конечно! оставь работу с логами на долю того кто под это заточен! -- а имена syslog демон Z>означеная мегапрога генерила порядка 1Г (или даже больше -- точную цыфру не вспомню -- но РИАЛЬНА ДОФИГА) зипаных логов в день -- не все сислоги такое выдерживают.. но есь один который более менее работал в подобных условиях -- это был syslogng
спасибо за идею, возможно имеет смысл.
кстати необходимая интенсивность записи может измеряться сотнями метров в час.
Re[3]: Ассинхронный вывод в лог
От:
Аноним
Дата:
20.04.06 11:01
Оценка:
Здравствуйте, rip_someday, Вы писали:
_>спасибо за идею, возможно имеет смысл. _>кстати необходимая интенсивность записи может измеряться сотнями метров в час.
Yea! тада и думать вопчем не чиво ! -- syslog the best way!
rip_someday wrote:
> В общем стоит передо мной такая задача > > Дано: > > однопоточный программный продукт весьма активной сетевой работой > работает через обертку вокруг epoll > программа ресурсоемкая и в то же время в больших объемах пишет лог файлы > в формате CSV (несколько штук) > то есть размер буффера для единичной операции записи — строка 200-250 байт > таргет платформа — linux Fedora Core 4 > > Нужно: > > проанализировать подходы к эффективной запись в лог-файлы > в том числе с использованием асинхронной записи. > Лично мне кажется, что замена текущей (весьма медленной и корявой) > имплементации "fopen-fwrite-fclose на каждую строку" > на имплементацию с постоянно открытым файлом, буффером в ~64Кб и > периодическим сбросом на диск вполне будет достаточно > (по крайней мере судя по замерам — в 30-40 раз быстрее) > Но для очистки совести и успокоения начальства, надо протеститровать и > асинхронную работу. > > Собственно возникают вопросы: > 1. каким образом это можно (нужно) организовать? > 2. нашел упоминание о поддержке aio на уровне ядра в ядрах 2.6.х, но к > сожалению не нашел вразумительной информации об этом. Работает ли это > вообще? какие есть подводные камни? > 3. можно ли это сделать как-то иначе?
Твой IO поток не должен блокироваться, поэтому, на мой взгляд, хорошим решением
будет circular buffer, как у printk. Т.е. IO поток сбрасывает строки в
циклический буфер в память, никогда при этом не блокируясь, и сигнализирует этот
факт подходящим механизмом межпотокового взаимодействия (например,
semaphore.release()). Другой поток или лучше другой процесс тупо в блокирующем
режиме пишет данные из циклического буфера на диск или ждет на семафоре, когда
писать нечего. Если буфер находится в shared memory и запись производится другим
процессом, даже если процесс, который пишет в буфер, погибает, другой процесс
запишет в файл все, что записал в память погибший процесс.
Если потоков всего два: один пишет в буфер, другой читает, то можно сделать
буфер вообще lock free.
Здравствуйте, MaximE, Вы писали:
ME>Твой IO поток не должен блокироваться, поэтому, на мой взгляд, хорошим решением ME>будет circular buffer, как у printk. Т.е. IO поток сбрасывает строки в ME>циклический буфер в память, никогда при этом не блокируясь, и сигнализирует этот ME>факт подходящим механизмом межпотокового взаимодействия.
+1
Добавлю что, так как IO поток не должен блокироваться, его размер должен быть достаточен, чтобы свести количество выделений памяти для увеличения буфера при его полном заполнени.
Здравствуйте, Андрей Коростелев, Вы писали:
АК>Здравствуйте, MaximE, Вы писали:
ME>>Твой IO поток не должен блокироваться, поэтому, на мой взгляд, хорошим решением ME>>будет circular buffer, как у printk. Т.е. IO поток сбрасывает строки в ME>>циклический буфер в память, никогда при этом не блокируясь, и сигнализирует этот ME>>факт подходящим механизмом межпотокового взаимодействия.
АК>+1 АК>Добавлю что, так как IO поток не должен блокироваться, его размер должен быть достаточен, чтобы свести количество выделений памяти для увеличения буфера при его полном заполнени.
Я предлагаю выделять память под циклический буфер лишь однажды (как это сделано в ядре линукс). Если поток, пишущий на диск не поспевает, старые записи в буфере будут затираться новыми.