169 похожих чатов

Привет! Попалась небольшая статья про загрузку данных на уровне компонентов в

NextJS приложениях - https://medium.com/@A__G__B/component-level-data-fetching-in-next-js-with-srr-8d35cdc5849e
Загрузка данных на уровне компонентов обеспечивается с помощью либы https://github.com/kmoskwiak/useSSE

Оказалось, что use-sse использует подход double render (если я не ошибаюсь, его использует Appolo).
Первый рендеринг приложения на сервере позволяет собрать промисы с загрузкой данных для каждого компонента, второй рендеринг выполняется после резолва этих промисов.

Меня всегда сильно смущал такой подход - дело в том, что ReactDOMServer.renderToString и даже ReactDOMServer.renderToNodeStream работают синхронно, и соответственно блокируют event loop.

На гитхабе мне попадались заброшенные попытки форкнуть ReactDOMServer и сделать рендеринг асинхронным, выполнять его по кусочкам, как раз для предотвращения долгой блокировки event loop.

Почему это важно?
React работает быстро на сервере, но для большого дерева компонентов, renderToString может занимать условно 100ms (на примере некоторых наших приложений от 30 до 300 при больших нагрузках).

Скорее всего, это будет самая длинная синхронная операция на вашем сервере.
Фактически, эта операция - самый главный ограничитель вашего RPS на одну ноду с SSR приложением.

Если я правильно понимаю как работает нода, когда приложение получает одновременно десять запросов, с синхронными операциями по 100ms, одинадцатый запрос получит ответ минимум через секунду, т.е. они буквально станут в очередь (это все без учёта прочих асинхронных действий на сервере).
Каждый новый запрос будет ухудшать ситуацию, увеличивать время ответа следующего запроса, будет заметно больше лаг event loop.

С такими метриками, при SSR с React можно рассчитывать что одна нода потянет 10 RPS, что достаточно не серьезные нагрузки с точки зрения high load, но пока что это наша фронтовая реальность.

С учётом этих факторов, double rendering кажется чем-то невероятно дорогим.
И в будущем Server Components будут решать проблему загрузки данных на уровне компонентов.

Я очень рассчитываю на React 18 и новую архитектуру работы на сервере.
Новые механизмы для рендеринга на сервере, вместе с Suspense, больше не будут рендерить приложение в один синхронный проход, эта задача будет разделена на отдельные асинхронные задачи (одна задача на один юнит - реакт компонент), аналогично concurrent rendering на клиенте.

Если node.js вместо десятка синхронных задач по 100ms будет получать тысячу задачек по 1ms, это в разы увеличит количество запросов, которые нода может обрабатывать одновременно без существенного влияния перформанс, т.е. новые запросы будут гораздо меньше влиять на время ответа для последующих запросов.

Например, все запросы, которые будут возвращать ошибки 500 или 404, или редиректы, не будут ждать синхронную очередь, а смогут вклиниться между остальными запросами.

Из минусов при асинхронном рендеринге - увеличение RPS будет примерно одинаково по чуть-чуть замедлять ответы на все обрабатываемые запросы, в случае с синхронными рендерингом первый запрос в очереди всегда будет обработан максимально быстро.

И возможно в новом прекрасном мире SSR легче будет делать high load :)

Отдельно хочу вспомнить про кэширование.
Конечно, самое эффективное ускорение рендеринга на сервере - это его отсутствие, и в ряде случаев можно кэшировать результаты рендеринга, или даже использовать SSG.

Но в приложениях с большим количеством персонализации, скорее всего кэшировать будет просто нечего, т.к. каждый пользователь будет получать уникальный HTML.
В tramvai приложениях на tinkoff.ru мы активно кэшируем на сервере только ответы на запросы, которые не требуют персонализации.

В конце хочу порекламировать свой обзор дискуссий reactwg/react-18, в том числе там есть разбор новой архитектуры на сервере - https://superoleg39.notion.site/reactwg-react-18-3914d12cc91e430b974495bffea86472

2 ответов

35 просмотров

Для лонгридов лучше юзать telegra.ph

Konstantin-Nosov Автор вопроса

Похожие вопросы

Обсуждают сегодня

30500 за редактор? )
Владимир
47
Недавно Google Project Zero нашёл багу в SQLite с помощью LLM, о чём достаточно было шумно в определённых интернетах, которые сопровождались рассказами, что скоро всех "ибешни...
Alex Sherbakov
5
вы делали что-то подобное и как? может есть либы готовые? увидел картинку нокода, где всё линиями соединено и стало интересно попробовать то же в ddl на lua сделать. решил с ч...
Victor
8
Подскажите пожалуйста, как в CustomDrawCell(Sender: TcxCustomGridTableView; ACanvas: TcxCanvas; AViewInfo: TcxGridTableDataCellViewInfo; var ADone: Boolean); получить наз...
A Z
7
Ребят в СИ можно реализовать ООП?
Николай
33
https://github.com/erlang/otp/blob/OTP-27.1/lib/kernel/src/logger_h_common.erl#L174 https://github.com/erlang/otp/blob/OTP-27.1/lib/kernel/src/logger_olp.erl#L76 15 лет назад...
Maksim Lapshin
20
Как передать управляющий символ в открытую через CreateProcess консоль? Собсна, есть процедура: procedure TRedirectThread.WriteData(Data: OEMString); var Written: Cardinal;...
Serjone
1
Он в одиночку это дело запилил или была какая-то команда?
Aquinary
12
~ 2m21s  nix shell github:nixos/nixpkgs#stack ~  stack ghc -- --version error: … while calling the 'derivationStrict' builtin at /builtin/derivation.nix:...
Rebuild your mind.
6
Всем привет, нужна как никогда, нужна помощь с IO в загрузчике. Пишу в code16 после установки сегментных регистров, пишу вывод символа. Пробовал 2 варианта: # 1 mov $0x0E, %a...
Shadow Akira
14
Карта сайта