Pull to refresh

Comments 33

Но что случится, если нам потребуется вывести сразу 10'000 записей?

И вот тут сразу возникает вопрос: а зачем?
Ситуации разные бывают. Экспорт данных или передача данных на обработку в другой сервис, например.
Такие вещи надо делать стримингом.
Одно другому не мешает вроде как. Сам по себе стримминг не ускорит генерацию JSON.
Сам по себе стриминг сильно меняет требования к производительности, потому что у вас затраты «размазываются».
Здесь «производительность» измеряется во времени, поэтому как затраты не «размазывай» — времени меньше не потратится. Есть задача — отдать 10 тысяч объектов и сделать это максимально быстро. Чем поможет стриминг?
Тем, что у вас будет не «сначала забрали все из БД, потом упаковали в json», а «забрали запись из БД, упаковали ее в JSON», при этом первая запись пакуется в json в то время, пока вторая забирается из БД. А в реальности у вас еще есть время передачи по каналу, и тут тоже: если вы выплюнули первую запись сразу, а не когда все сконвертировалось, то в реальности в можете достигнуть результата быстрее.

Такая вот простая параллельность.
Такое решение тоже имеет право на жизнь, но превносит дополнительную сложность, как минимум. Во-первых, принимающая сторона тоже должна поддерживать стриминг. Во-вторых, это теория, а чтобы узнать что быстрее — нужны цифры из тестов. В-третьих, может стоять задача сделать моментальный снимок данных и тянуть данные по одной записи нельзя.

Ситуация бывают разные, поэтому и решения могут быть разными. Я не утверждаю, что решение в статье, которую я перевел, подходит всем. Но и стриминг не является в данном случае 100% альтернативой, которая будет лучшей заменой для любой подобной задачи, верно?
Во-первых, принимающая сторона тоже должна поддерживать стриминг.

Нет, потому что http его поддерживает.

В-третьих, может стоять задача сделать моментальный снимок данных и тянуть данные по одной записи нельзя.

Вообще-то, с точки зрения «моментальности» ничего не меняется — как вам БД отдавала данные по определенным критериям, так и отдает. Вопрос только в том, как и когда вы начинаете их обрабатывать.

Такое решение тоже имеет право на жизнь, но превносит дополнительную сложность, как минимум.

А решение из поста — не привносит?

Во-вторых, это теория, а чтобы узнать что быстрее — нужны цифры из тестов.

Бинго. Именно поэтому сначала надо спросить «зачем», потом найти ботлнек. Обычно большая часть проблем решается еще на первом шаге.
Нет, потому что http его поддерживает.

HTTP — это протокол, а принимающая сторона — ПО, поэтому протокол может быть и поддерживает, а вот принимающая сторона может и не поддерживать. Иначе откуда взялись костыли вроде Long polling и иже с ним для браузеров?

Вообще-то, с точки зрения «моментальности» ничего не меняется — как вам БД отдавала данные по определенным критериям, так и отдает. Вопрос только в том, как и когда вы начинаете их обрабатывать.

Вообще-то, очень даже меняется. Если данные в базе изменяются, например, 20 раз в секунду, то один запрос и 1000 запросов вернут совсем разные значения.

А решение из поста — не привносит?

Привносит минимум.
HTTP — это протокол, а принимающая сторона — ПО, поэтому протокол может быть и поддерживает, а вот принимающая сторона может и не поддерживать.

Вы не понимаете, как это работает. Я говорю банально о том, что, вместо того, чтобы сконвертировать весь массив в json в памяти (допустим, это 30 секунд), а потом выплюнуть его в http-поток, по которому он будет передаваться еще 30, можно сконвертировать первую запись (0.5с) и сразу ее выплюнуть (0.5с). Если клиент умеет так читать поток, он получит данные сразу (т.е., первые данные — через 1с). Если нет — у него соберется весь массив данных (через 30,5с вместо минуты). Никаких действий со стороны клиента при этом не нужно.

Если данные в базе изменяются, например, 20 раз в секунду, то один запрос и 1000 запросов вернут совсем разные значения.

Кто вам сказал, что будет 1000 запросов? Запрос-то один, просто обрабатывается по частям.

Привносит минимум.

Если что, правильно написанный стриминг приносит не больше.

Ок, т.е. все сводится к тому, что мы делаем все тоже самое, только отдаем данные по кускам? Как это кардинально меняет то, что написано в статье, не понимаю. Не надо делать выборку из базы только с нужными полями? Да нет, вроде как надо. Не надо использовать хэши вместо объектов ActiveRecord? Да нет, вроде не лишняя операция. Не стоит использовать альтернативные дамперы JSON? Возможно, но нужно тестить.

В сухом остатке — вся та же самая подготовка данных, но отдача стримингом. Так? Не совсем понятно зачем мы это так долго обсуждали :)
Нет, в сухом остатке тот факт, что если сделать выборку и сериализацию новых полей и стриминг, то альтернативные дампера и хэши уже могут быть и не нужными.

Я просто исповедую принцип наименьших изменений.
Произошла путаница с терминами.

Попробую объяснить псевдокодом:
Ваш подход:
var query = DB.exec_query(...);
var result = query.get_all();
var output_string = JSON.encode(result);
write_output(output_string);


если «развернуть» методы, то увидим что под капотом происходит примерно следующее:

var query = DB.exec_query(...);

while ( var row = query.get_next() ) {
      result.push(row);
}
foreach (res_row IN result ) {
     output_string = output_string + JSON.encode(res_row);
}

write_output(output_string);


lair предлагает такой подход:

var query = DB.exec_query(...);

while ( var row = query.get_next() ) {
      write_output(
            JSON.encode( row );
      );
}


Этот подход хорош ещё тем, что занимает меньше памяти.
Но! Часто его нельзя реализовать не ломая логику используемого фреймворка.

Не только меньше памяти, но и, как уже говорилось, выиграть в TTLB.
>Чем поможет стриминг?

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

К сожалению, я не настолько хорошо с ним знаком.
Были какие-то потуги типа async-rails, но вообще придётся ждать 4.0 или держать по процессу на каждое соединение. По поводу, можно хотя бы по Thread'у, честно говоря, ничего сказать не могу, и в любом случае это адский костыль.
Всё написанное ни в коем случае не относится в общем к Ruby, а только в частности к Rails. В Sinatra такое возможно, и очень просто, уже писал чуть ниже.
Ну можно перевернуть задачу — вывести по 10 записей но 10 000 раз. На маленьких задачах тоже есть смысл экономить если у вас много клиентов.
А вы уверены, что 10 000 раз по 10 записей оптимизируются так же, как обратное?

Я вот не уверен совершенно.
Буквально на днях наткнулся на блог «How I Learned to Stop Using LINQ2SQL and Love nHibernate», перец пытается считать из базы «1.6 million records», жалуется на таймаут и говорит, что Linq2Sql дерьмо и всем надо срочно переходить на NHibernate.

После прочтения этого поста на Хабре и того блога хочется биться головой о стол и кричать — «Люди!!! Человеки!!! На хера?!!! На хера вы это делаете???!!!!» Это ж как зуб пломбировать через жопу…
а что, если все же надо? ну ок, прям сегодня мне ставили задачу и надо было 113 000 записей выдать, чуть раньше, на прошлой неделе, было 1.13 млн. и?
Ну блин, кусками же! Кусками считывайте и обрабатывайте как вам надо. А считанные куски логируйте. И если вдруг где-то произойдет разрыв, то вам не придется начинать все сначала, а начнете с разорванного места.
Была 2 раза ситуация, когда JSON-запросы были медленные и большие. Решение было довольно простое. Перенести запрос на NodeJS… 38 строчек код ускорили отклик и получение данных в 4 раза.

Я обожаю Rails, но бывают узкие места, которые можно очень просто перенести на NodeJS и никто не пострадает.
А можно вопрос — почему Node.js с его ужасной структурой, а не Sinatra, кроме того написанная на том же Ruby? (=
Вроде как sinatra нативно не поддерживает comet? И соответственно, вопросы производительности и архитектуры. Я бы лучше спросил почему node.js, а не erlang?)
JavaScript знают все Rails-разработчики. Не будет проблем при передаче проекта или введении нового человека.
У меня был опыт использования NodeJS, в отличии от Sinatra.
И мне интуитивно кажется, что NodeJS быстрее отдаст запрос, чем любой Ruby-сервер…
Спасибо за пояснение. Наверное сказываются мои привычки, почему показалось странным. Но если нодой только JSON отдавать, без какой-то бизнес-логики — решение конечно не плохое.
Ваша интуиция вас подвела. EventMachine сопоставим по производительности с нодой.
Sign up to leave a comment.

Articles