fgntfg
А давайте глядеть на бинарные логи от WAS? И ПЛАКАТЬ!
Snusmumriken
Тут, вот неожиданность, есть абсолютно чётко выраженные длины сообщений в тех случаях, где это необходимо. Базовым разделителем является \r\n (чтобы не совокупляться с длиной каждый раз), но если принимаемый тип — строка, то там точно указана длина. Чтобы было понятно, сколько ещё принять от этой строки, и где закончилось сообщение. Redis предназначен для поддержания соединения неограниченно долго, и в него даже можно загнать десяток сконкатенированных запросов, и получить такой же десяток сконкатенированных ответов (пайплайн).
Snusmumriken
И эта магия сделана как раз благодаря тому, что местный протокол совершенно точно и однозначно разделяет tcp-поток на отдельные сущности, вплоть до вложенных.
Snusmumriken
Можно ещё посмотреть на магию с HttpChunked.
Ты только посмотри, как люди изгаляются, только для того чтобы узнать, где сообщение заканчивается.
https://ru.wikipedia.org/wiki/Chunked_transfer_encoding
Потому что иначе это просто не сделать.
Лепикоршев
Redis - один из примеров хорошей работы с tcp потоком. А с ними редко возникают проблемы)
Snusmumriken
Хороший вопрос. Это ДОЛЖНА читать машина (слишком высокий eps для чтения человеком), но имеем то, что имеем.
Да, если посмотреть на диалог того же smtp клиента, мы тоже увидим, что все сообщения разделены, и однозначно идентифицируются даже, когда у нас идёт приём нескольких сообщений в одном.
Но факт - не все разработчики так делают. Хотя было бы здорово, если бы делали.
Нене, eps — это не повод для чтения машиной. У меня на работе где-то 4000 логирующих сообщения в секунду (на луёвом TCP, кек), и оно предназначено для человека, который сделает запрос по базе. Все логи парсятся.
Snusmumriken
Человек просто увидит что где проблема, сделает запрос по ID и получит логи которые можно прочитать. Остальное можно будет удалить.
Лепикоршев
Snusmumriken
Всё равно фигня.
Snusmumriken
Регулярки и вперёд.
Лепикоршев
Snusmumriken
Нет.
Snusmumriken
Это человек может составить регулярку чтобы найти конкретный кусочек.
Snusmumriken
Почему без конца?
Лепикоршев
Snusmumriken
Кому-то может быть норм.
Лепикоршев
Человеку должны быть доступны данные в самой удобной форме.
Лепикоршев
Для этого должно быть возможно распарсить автоматически
Snusmumriken
Это уже проблемы их организации. Главное — то, что они сделали машинонечитаемый протокол, следовательно твой пример некорректен.
Лепикоршев
Лепикоршев
Snusmumriken
Да потому что
1. он не распространён и запилен для внутренних нужд
2. он предназначен для людей, люди — немного более сложные существа чем машины
Snusmumriken
3. Даже машиной скорее всего это можно распарсить, но придётся регулярить, типа (\r\n[timestamp_regex].-\r\n[timestamp_regex])
И это извращения для сетевого протокола.
Лепикоршев
Программировать нужно не только там, где легко.
Там, где редкая узкая проприетарщина, тоже нужна автоматическая обработка.
Лепикоршев
Snusmumriken
Да нет, не становится.
Snusmumriken
Просто держишь буфер строки, отпиливаешь кусок с начала, когда там накапливается логирующее сообщение.
Лепикоршев
Лепикоршев
Только к tcp такие извращения не относятся никак. Это костыли поверх
Лепикоршев
Да, так это и обрабатывается.
Snusmumriken
Относятся напрямую, потому что внутри самого TCP отсутствуют механизмы разделения сообщений, а нам надо разделять ))
И вот тут вот — разделителем работает метка времени определённого формата или аналог )))
Видишь, мы уже нашли разделитель в протоколе, он тут есть ))))
Лепикоршев
Не нашли, потому что текст сообщения содержит внутри себя ещё несколько меток времени
Лепикоршев
Того же самого формата
Лепикоршев
Ты будешь вырезать заголовок + часть текста, потом ещё часть текста, и потом остаток текста до следующего заголовка
Snusmumriken
Ну вот отлично.
Лепикоршев
Есть начало строки, нет ни длины, ни конца
Лепикоршев
Т.е. Ты не сможешь понять, что перед домой одно длинное сообщение, а нарежешь его на несколько мелких
Snusmumriken
Ла-а-адно, просто берём не метку времени, а собственно регулярку заголовка. От текущего до следующего. Она немножко длиннее.
Лепикоршев
Snusmumriken
Да, в этом протоколе может потеряться самое последнее-распоследнее сообщение, но его можно обработать отдельно.
Snusmumriken
Сам факт в том, что у нас уже есть заголовки, и это уже офигеть как круто и позволяет делить машиной. Не однозначно (потому что последнее может сломаться)
Лепикоршев
Snusmumriken
Когда система встанет — будет последний, и его тоже надо бы обработать. Тем более что он несёт особую важность, с потенциальными причинами вставания.
Лепикоршев
Snusmumriken
А как они будут чинить, когда в последнем лого-сообщении возможно сидит ошибка, из-за которой всё упало? ))
Лепикоршев
Лепикоршев
Т. Е. Текст ошибки встретится много раньше
Snusmumriken
Ну в данном конкретном случае — ок. Всё равно черезжопский протокол, и хорошо что он у вас внутри.
Лепикоршев
Но даже в этом случае можно просто сделать прерывание по тацмауту - если tcp буфер пустой и вы вышли с тацмаутом, просто запишем все, что накопилось в буфере
Snusmumriken
Патамущта у меня на работке, все логи это как раз
[N символов длины][сжатый джысон типа такого]
Входная часть вычленяет отдельные сообщения и раскидывает на потоки, которые уже разбирают жысоны. А всё для того чтобы искать, сортировать, вычислять кол-во ворнингов и для прочей статы.
Лепикоршев
Это в общем-то не попытка найти решение лучше существующего для такой специфический ситуации =)
Это пример того, как крупные вендор типа Симантека могут забить на rfc при tcp-шной пересылке данных.
И такой "ход конём" всегда надо держать в голове. А то можно промахнуться, если исходить из "минимальный формат tcp будет содержать хотя бы длину или однозначный признаки начала-конца". Должен. Но может и не содержать.
Лепикоршев
Snusmumriken
Я писал эту систему. И формат тоже мой ))
Лепикоршев
Лепикоршев
у нас многие вещи работают как чёрный ящик
Лепикоршев
И если ли оно работает не так, как нужно, надо либо приделать свой костыль поверх, либо пытаться пинать вендора
Snusmumriken
Snusmumriken
Кстати, 25к логов/сек это довольно много. При гигабитной сети, каждое сообщение (включая заголовки TCP) должны укладываться в 5.24288 бита, иначе не пролезут в сетевуху ))
В 10-гигабитной, соответственно, 52.4288 бита.
Или принимать это счастье должно несколько машин, целый кластер для приёма логов с балансировкой на клиентской стороне (ибо одна тачка не справится).
Так что если 25к это пик, то ещё ничо так (tcp выровняет приём), но в среднем должно быть около 1-5к логов/сек, туда уже средне-длинные логи влезают.
Лепикоршев
Лепикоршев
Кстати, 25к логов/сек это довольно много. При гигабитной сети, каждое сообщение (включая заголовки TCP) должны укладываться в 5.24288 бита, иначе не пролезут в сетевуху ))
В 10-гигабитной, соответственно, 52.4288 бита.
Или принимать это счастье должно несколько машин, целый кластер для приёма логов с балансировкой на клиентской стороне (ибо одна тачка не справится).
Так что если 25к это пик, то ещё ничо так (tcp выровняет приём), но в среднем должно быть около 1-5к логов/сек, туда уже средне-длинные логи влезают.
Речь о 40г сети и таких же адаптерах. Но чтобы минимизировать нагрузку при пересылке, логи бы желательно на первом же хопе парсить и ужимать. Чтобы можно было отправить "сообщение А, количество 300 штук", а не пересылать все 300 в чистом виде.
Лепикоршев
Это возвращает нас к автоматическому парсингу и хлебушку от разрабов, которые решили, что по tcp можно передавать сообщения без разбивки.
Snusmumriken
Но изначальная фигня вопроса была в том, что в норме, все tcp-rfc-сообщенькоориентированные — написаны с учётом длин сообщенек, дабы машина могла в точности определить длину и предельно быстро распарсить, в идеале — прямым распилом:
local len, data = data:sub(1, 4), data:sub(5)
local msg, data = data:sub(1, len), data:sub(len + 1)
Лепикоршев
Но изначальная фигня вопроса была в том, что в норме, все tcp-rfc-сообщенькоориентированные — написаны с учётом длин сообщенек, дабы машина могла в точности определить длину и предельно быстро распарсить, в идеале — прямым распилом:
local len, data = data:sub(1, 4), data:sub(5)
local msg, data = data:sub(1, len), data:sub(len + 1)
Точно. И то, что вот этот замечательный порядок работы поддерживают не все.
Snusmumriken
Ну, то есть если у нас фиксированная длина текста длины сообщения — мы просто отпиливаем N символов, числофицируем, и отпиливаем от остатка то что у нас получилось. Если не фиксированная — нужен разделитель и регулярки, что хреново. Или фиксированная длина длины сообщения ))
Snusmumriken
В сишном варианте — можно смело упаковать 32-битное число в четыре октета, но на луях это не очень удобно (плюс при попытке дебага странно выглядит), поэтому именно в моём протоколе — 10 ascii-циферок. Оверхед, ну что поделать.
Лепикоршев
Snusmumriken
Ну тут оверхед ровно 6 символов. 4 символа 32-битного числа против 10 символов ascii.
Лепикоршев
Лепикоршев
Snusmumriken
(On вместо n * log(n)^2 или чего-то такого)
Snusmumriken
Это примерно прикинуто
Snusmumriken
Ну сам прикинь. В регулярке почти точно есть n, она как правило проходит по всем символам строки.
Но ещё у неё есть обработка собственно регулярной фигни, это курсор который бегает по символам и набивает в обойму то что в него подходит, сбрасывает если напоролся на неподходящую фигню и так далее. По прикидке, это где-то log(n)^2: на log(n) не тянет ибо слишком просто, но и на n^2 тоже не тянет ибо жирновато. Плюс сами регулярки имеют различную сложность: ".*" это совсем не то что "([^a-cA-F])..(\\(%w+%D+))", а ведь длина самого регулярного выражения ничем не ограничена.
Александр
Добрый день, помогите!
Snusmumriken
М?
Александр
Нужно решить задачу, ответ реализовать в Lua
Snusmumriken
Очень интересно, собеседование? : )
Александр
Именно)