LINUX.ORG.RU

Неблокирующее логирование в python2

 


1

3

Всем добрый день. Использую logging для логирования в продкшене. Но из-за нагрузки cpu подбирается к 100%, путем отладки выяснил, что больше всего тратится на IO операции. У меня все операции IO асинхронные (tornado), из синхронных только логирование (StreamHandler (stdout) и SyslogHandler) - они то и грузят cpu. Логов очень много, урезать не могу. В инете только nonblockingloghandler, но он не подходит, т.к. работает на тредах. Кто сталкивался с данной проблемой, как решал. Хотелось бы логи асинхронно писать либо вообще в другом процессе, но с наименьшими затратами на реализацию...



Последнее исправление: energyclab (всего исправлений: 1)

Если кардинально, то проблема решалась заменой железа, которое должно быть специальным. Обычные диски будут грузить систему при интенсивном вводе-выводе. Специальные диски бывают, но они дорогие. Как называются - особо не интересовался. На хороших спарках такие диски стояли. Должны быть такие и для интеля.

dave ★★★★★
()

Ты уверен что в питоновском логгере дело? Вывод на syslog и stdout сами по себе не обращаются к диску. Что говорит iotop и atop?

codeogre
()

Стандартный логгер просто делает flush на каждую запись. Переопредели logging.FileHandler.flush и сбрасывай, например, каждые 10с.

A1
()
Ответ на: комментарий от A1

у меня не FileHandler а SyslogHandler который логирует сейчас в unix сокет. Я отрубал логирование, cpu где то на уровне 5-10% (это пики). Дело в блокирующих IO операциях (любой файловый дескриптор) dave, dtm, codeogre

energyclab
() автор топика
Ответ на: комментарий от energyclab

у меня не FileHandler а SyslogHandler

Сорян, невнимательно прочитал.

который логирует сейчас в unix сокет

Покажи опции при создании хендлера, там же UDP по умолчанию, поэтому ничего блокироваться не должно.

A1
()
Ответ на: комментарий от A1

Сама функция write внутри хендлеров как я понимаю, блокирует все, пока не отработает до конца. Для python 2 проблема известна, но не решена (решение есть в python 3).

energyclab
() автор топика
Ответ на: комментарий от A1

Выхлоп профайлера покажешь? На каком там write блокируется.

A1
()
Ответ на: комментарий от A1

во-первых, в сокет внезапно пишут через write(2), во-вторых запись в UDP-сокет *может* блокироваться. не советуй пожалуйста больше ничего про сетевое программирование пока не осилишь хотя бы Стивенса.

val-amart ★★★★★
()
Ответ на: комментарий от val-amart

во-первых, в сокет внезапно пишут через write(2)

Это можно делать, но там нет семантики sendto.

во-вторых запись в UDP-сокет *может* блокироваться

Может, но это детали реализации, типа переполненного буфера. В манах про блокирование sendto (а именно он используется в SyslogHandler) ничего нет.

A1
()
Ответ на: комментарий от A1

в чем по-твоему разница между write в сокет и sendto с точки зрения ядра в контексте данной проблемы? вопрос, конечно, риторический. особенно если ты считаешь что как все устроенно на самом деле не важно, важно что тебе в мане написали.

val-amart ★★★★★
()
Ответ на: комментарий от val-amart

в чем по-твоему разница между write в сокет и sendto с точки зрения ядра в контексте данной проблемы?

А причем тут это? Ты сказал что «в сокет внезапно пишут через write(2)», что очевидно не так, пишут через sendto(2).

Для начала давай поговорим про UDP vs TCP и про блокирование. В последнем блокируется до момента пока не станет известно сколько байт приняла удаленная сторона. В первом пока операционка не положит пакет в буфер, на что можно в большинстве задач забить.

A1
()
Ответ на: комментарий от A1

цитируя тебя, «причем тут это»? у человека вполне понятная проблема. почему она возникает и как ее решить вполне понятно. человек спрашивает или есть какие-то менее трудозатратные способы, off-the-shelf solutions. ты можешь такие предложить? нет? потому что пока что от тебя исходит только информационный шум.

val-amart ★★★★★
()
Ответ на: комментарий от val-amart

у человека вполне понятная проблема. почему она возникает и как ее решить вполне понятно.

Ничего не понятно, он мычит про какие-то блокировки и cpu. У меня SyslogHandler прекрасно работает на примерно 100 записях в секунду на одной ноде. На синтетике, на одну запись уходит 60мкс.

А теперь послушаем гуру write(2) и его предсказание.

anonymous
()
Ответ на: комментарий от A1

Ты сказал что «в сокет внезапно пишут через write(2)», что очевидно не так, пишут через sendto(2).

Это, конечно, оффтопик, но через write(2) тоже пишут.

Для начала давай поговорим про UDP vs TCP и про блокирование. В последнем блокируется до момента пока не станет известно сколько байт приняла удаленная сторона.

Хм. Можно спросить об источнике этого знания?

tailgunner ★★★★★
()
Ответ на: комментарий от tailgunner

он разумеется имеет ввиду windowing. формулировка у него так же разумеется абсолютно неверная.

val-amart ★★★★★
()
Ответ на: комментарий от tailgunner

Это, конечно, оффтопик, но через write(2) тоже пишут.

Где я с этим спорил?

Хм. Можно спросить об источнике этого знания?

Ты конечно можешь придраться к мелочам, но тогда странно что тебя write напряг. Пойнт в том что в случае TCP мы ждем сеть, а в UDP нет.

anonymous
()
Ответ на: комментарий от val-amart

лол

Про синтетику ты конечно решил промолчать. Я знаю что это мало. Но готов поспорить что у ТС и такого нет. До сих пор жду твоего информативного поста, который решит проблему ТС.

anonymous
()
Ответ на: комментарий от anonymous

Это, конечно, оффтопик, но через write(2) тоже пишут.

Где я с этим спорил?

Ну началось... а где я сказал, что ты с этим спорил?

Пойнт в том что в случае TCP мы ждем сеть

В общем случае - нет.

tailgunner ★★★★★
()
Ответ на: комментарий от tailgunner

любая отправка сообщения либо запись в файл в любом случае сводится к вызову системной функции write, которая блокирует я до тех пор, пока не запишет все в дескриптор (будь то файловый или сокетный дескриптор)... Другое дело использование selectо-подобных механизмов (select, poll, epoll), где ты просто указываешь флаги, при каких событиях тебе нужно «слетать» с этих функций. Сама полезная работа делается ОС, а процесс либо спит, либо обрабатывает другие полезные события (которые тоже сидят на селектоподных вызовах)... Модуль logging не умеет работать на к.л. event_loop, в исходниках явно есть

    def emit(self, record):
        """
        Emit a record.
        The record is formatted, and then sent to the syslog server. If
        exception information is present, it is NOT sent to the server.
        """
        try:
            msg = self.format(record)
            if self.ident:
                msg = self.ident + msg
            if self.append_nul:
                msg += '\000'

            # We need to convert record level to lowercase, maybe this will
            # change in the future.
            prio = '<%d>' % self.encodePriority(self.facility,
                                                self.mapPriority(record.levelname))
            prio = prio.encode('utf-8')
            # Message is a string. Convert to bytes as required by RFC 5424
            msg = msg.encode('utf-8')
            msg = prio + msg
            if self.unixsocket:
                try:
                    self.socket.send(msg)
                except OSError:
                    self.socket.close()
                    self._connect_unixsocket(self.address)
                    self.socket.send(msg)
            elif self.socktype == socket.SOCK_DGRAM:
                self.socket.sendto(msg, self.address)
            else:
                self.socket.sendall(msg)
        except Exception:
            self.handleError(record)

т.е. пока пишется запись в ДЕСКРИПТОР (а в *nix филосовия - all is file - т.е. всегда на любую запись вызывается системный write) весь процесс ждет. Меня это не устраивает, нагрузка выросла так, что нужно уменьшать кол-во блокирующих IO операций, 100 сообщений в секунду - слишком медленно...

energyclab
() автор топика
Ответ на: комментарий от energyclab

любая отправка сообщения либо запись в файл в любом случае сводится к вызову системной функции write, которая блокирует я до тех пор, пока не запишет все в дескриптор

Допустим, я расшифровал, что ты имеешь в виду...

Другое дело использование selectо-подобных механизмов (select, poll, epoll)

...но ты не упомянул одну мелочь - select-подобные механизмы предназначены для работы на _нескольких_ дескрипторах. У логгера дескриптор один - что и как ты собираешься выиграть?

all is file

Ага, один большой файл. На Небесной Дискете.

tailgunner ★★★★★
()
Ответ на: комментарий от energyclab

100 rps для сети это вообще ниочем, даже на raspberry pi. Операция write не заблокируется пока есть доступная пакмять в буффере на отправку, можешь попробовать покрутить sysctl ключи для net.mem и net.unix.

Вообще проблема скорее всего в чем то другом, так что лучше включай профайлер.

codeogre
()
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.