【发布时间】:2018-07-15 19:59:58
【问题描述】:
我在我的 React 应用程序中使用 react-boilerplate(带有 react-router、sagas、express.js),在它之上我添加了 SSR 逻辑,这样一旦它接收到 HTTP 请求,它就会将反应组件呈现给基于 URL 的字符串并将 HTML 字符串发送回客户端。
当服务器端发生 react 渲染时,它还会通过 sagas 向某些 API(基于 URL 最多 5 个端点)发出fetch 请求,以在将组件实际呈现为字符串之前获取组件的数据。
如果我同时只向 Node 服务器发出多个请求,一切都很好,但是一旦我模拟了 100 多个并发请求的负载并开始处理它,然后在某个时候它会崩溃而没有任何异常的迹象。
我在尝试调试应用程序时注意到的是,一旦 Node 服务器开始处理 100 多个传入请求,它就会同时向 API 发送请求,但在停止堆叠这些请求之前不会收到任何实际响应请求。
用于服务器端渲染的代码:
async function renderHtmlDocument({ store, renderProps, sagasDone, assets, webpackDllNames }) {
// 1st render phase - triggers the sagas
renderAppToString(store, renderProps);
// send signal to sagas that we're done
store.dispatch(END);
// wait for all tasks to finish
await sagasDone();
// capture the state after the first render
const state = store.getState().toJS();
// prepare style sheet to collect generated css
const styleSheet = new ServerStyleSheet();
// 2nd render phase - the sagas triggered in the first phase are resolved by now
const appMarkup = renderAppToString(store, renderProps, styleSheet);
// capture the generated css
const css = styleSheet.getStyleElement();
const doc = renderToStaticMarkup(
<HtmlDocument
appMarkup={appMarkup}
lang={state.language.locale}
state={state}
head={Helmet.rewind()}
assets={assets}
css={css}
webpackDllNames={webpackDllNames}
/>
);
return `<!DOCTYPE html>\n${doc}`;
}
// The code that's executed by express.js for each request
function renderAppToStringAtLocation(url, { webpackDllNames = [], assets, lang }, callback) {
const memHistory = createMemoryHistory(url);
const store = createStore({}, memHistory);
syncHistoryWithStore(memHistory, store);
const routes = createRoutes(store);
const sagasDone = monitorSagas(store);
store.dispatch(changeLocale(lang));
match({ routes, location: url }, (error, redirectLocation, renderProps) => {
if (error) {
callback({ error });
} else if (renderProps) {
renderHtmlDocument({ store, renderProps, sagasDone, assets, webpackDllNames })
.then((html) => {
callback({ html });
})
.catch((e) => callback({ error: e }));
} else {
callback({ error: new Error('Unknown error') });
}
});
}
所以我的假设是,一旦它接收到过多的 HTTP 请求,就会出现问题,这反过来又会向 API 端点生成更多请求以呈现反应组件。
我注意到它会在renderAppToString() 之后为每个客户端请求阻塞事件循环 300 毫秒,因此一旦有 100 个并发请求,它会阻塞它大约 10 秒。不过我不确定这是正常的还是坏的。
是否值得尝试限制对 Node 服务器的并发请求?
我找不到关于 SSR + 节点崩溃主题的太多信息。因此,如果有人过去遇到过类似问题,我将不胜感激有关在哪里寻找问题或寻找可能的解决方案的任何建议。
【问题讨论】:
-
为什么不在客户端的主 js 文件和用户把手中使用 ReactDOM.hydrate 来返回文件作为响应。为了清楚起见,我将在下面写一个答案
-
尝试使用PM2集群处理多个并发请求。 pm2.keymetrics.io/docs/usage/cluster-mode
-
这与我们现在正在处理的问题完全相同。即使 PM2 在集群模式下运行 7 台服务器,也是同样的问题。你有没有设法解决它?
标签: node.js reactjs express server-side-rendering