應該如何設置針對高需求應用程序的node.js堆棧?

[英]How should a node.js stack for a high demand application be setup?


I'm currently working on a Node.js stack application used by over 25000 people, we're using Sails.js framework in particular and we got MongoDB Application is running at a EC2 instance with 30GB of RAM, databse is running on a Mongolab AWS based cluster in same zone the EC2 is. We even got an Elastic Cache Redis instance with 1.5GB for storage.

我目前正在研究超過25000人使用的Node.js堆棧應用程序,我們特別使用Sails.js框架,我們得到的MongoDB應用程序運行在具有30GB RAM的EC2實例上,數據庫運行在Mongolab上EC2所在的同一區域中基於AWS的集群。我們甚至有一個1.5GB的Elastic Cache Redis實例用於存儲。

So the main and huge problem we're facing is LATENCY. When we reach a peak of concurrent users requesting application we're getting multiple timeouts and sails application reaching over 7.5GB of RAM, HTTP requests to API take longer than 15 seconds (which is unacceptable) and when even get 502 and 504 responses sent by nginx.

因此,我們面臨的主要和巨大問題是延遲。當我們達到請求應用程序的並發用戶的峰值時,我們得到多個超時和風帆應用程序達到超過7.5GB的RAM,對API的HTTP請求需要超過15秒(這是不可接受的),甚至得到502和504響應發送nginx的。

I can notice Mongo write operations as our main latency issue, however even GET requests take long when a demand peak is present. I can't access production servers, I only got a keymetrics monitoring tool by pm2 (which is actually great) and New Relic alerts.

我可以注意到Mongo寫入操作是我們的主要延遲問題,但是當存在需求峰值時,即使GET請求也需要很長時間。我無法訪問生產服務器,我只有pm2(實際上很棒)和New Relic警報的keymetrics監控工具。

So, I'd like to know some roadmap to cope these issues, maybe more detailed information should be offered, so far I can say application seems stable when not much users are present.

所以,我想知道一些應對這些問題的路線圖,也許應該提供更詳細的信息,到目前為止,我可以說當沒有太多用戶時,應用程序看起來很穩定。

What are main factors and setup to consider?

要考慮哪些主要因素和設置?

So far I know what I should do, but I'm not sure about details or the hows.

到目前為止,我知道我應該做些什么,但我不確定細節或方法。

IMHO:

  1. Cache as much as possible.
  2. 盡可能緩存。

  3. Delay MongoDB write operations.
  4. 延遲MongoDB寫操作。

  5. Separate Mongo databases with higher write demand.
  6. 具有更高寫入需求的單獨Mongo數據庫。

  7. Virtualize?
  8. Tune up node setups.
  9. 調整節點設置。

On optimising code, I've posted another stackoverflow question with one example of code patterns I'm following.

在優化代碼時,我發布了另一個stackoverflow問題,其中包含一個我正在遵循的代碼模式示例。

What are your advise and opinion for production applications?

您對生產應用有何建議和意見?

3 个解决方案

#1


3  

Basically most of main points are already present in answers. I'll just summarise them.

基本上大多數要點已經存在於答案中。我只是總結一下。

To optimize your application you could do several main things.

要優化您的應用程序,您可以執行幾項主要操作。

  1. Try to move form node.js to io.js it still have a bit better performance and latest cutting edge updated. (But read carefully about experimental features). Or at least from node.js v10 to v12. There was lot of performance optimisations.

    嘗試將表單node.js移動到io.js它仍然有更好的性能和最新的前沿更新。 (但仔細閱讀有關實驗性功能的信息)。或者至少從node.js v10到v12。有很多性能優化。

  2. Avoid using synchronous functions that uses I/O operations or operating with big amount of data.

    避免使用使用I / O操作或使用大量數據的同步函數。

  3. Switch from one node process to clustering system.

    從一個節點進程切換到集群系統。

  4. Check your application to memory leaks. I'm using memwatch-next for node.js v12 and memwatch for node.js v10

    檢查應用程序是否存在內存泄漏。我正在使用node.js v12的memwatch-next和node.js v10的memwatch

  5. Try to avoid saving data to global variables

    盡量避免將數據保存到全局變量

  6. Use caching. For data that should be accessible globally you could use Redis or Memcached is also a great store.

    使用緩存。對於應該可以全局訪問的數據,您可以使用Redis或Memcached也是一個很棒的商店。

  7. Avoid of using async with Promises. Both libs are doing same things. So no need to use both of them. (I saw that in your code example).

    避免與Promise使用異步。兩個庫都在做同樣的事情。所以不需要同時使用它們。 (我在你的代碼示例中看到了這一點)。

  8. Combine async.waterfall with async.parallel methods where it could be done. For example if you need to fetch some data from mongo that is related only to user, you could fetch user and then in parallel fetch all other data you need.

    將async.waterfall與async.parallel方法結合起來可以完成。例如,如果您需要從僅與用戶相關的mongo中獲取某些數據,則可以獲取用戶,然后並行獲取所需的所有其他數據。

  9. If you are using sails.js make sure that it's in production mode. (I assume you already did this)

    如果您使用sails.js,請確保它處於生產模式。 (我假設你已經這樣做了)

  10. Disable all hooks that you don't need. In most cases grunt hook is useless.And if you don't need Socket.io in your application - disable it using .sailsrc file. Something like:

    禁用所有不需要的掛鈎。在大多數情況下,grunt hook是無用的。如果你的應用程序中不需要Socket.io - 使用.sailsrc文件禁用它。就像是:

    { "generators": { "modules": {} }, "hooks": { "grunt": false, "sockets": false } }

    {“generators”:{“modules”:{}},“hooks”:{“grunt”:false,“sockets”:false}}

Another hooks that could be disabled are: i18n, csrf, cors. BUT only if you don't use them in your system.

另一個可能被禁用的鈎子是:i18n,csrf,cors。但前提是您不在系統中使用它們。

  1. Disable useless globalisation. In config/globals.js. I assume _, async, services could be disabled by default. Just because Sails.js uses old version of lodash and async libraries and new versions has much better performance.

    禁用無用的全球化。在config / globals.js中。我假設默認情況下可以禁用_,async,services。僅僅因為Sails.js使用舊版本的lodash和異步庫,新版本具有更好的性能。

  2. Manually install lodash and async into Sails.js project and use new versions. (look point 11)

    手動將lodash和async安裝到Sails.js項目中並使用新版本。 (看點11)

  3. Some "write to mongo" operations could be made after returning result to user. For example: you can call res.view() method that will send response to user before Model.save() BUT code will continue running with all variables, so you could save data to mongo DB. So user wouldn't see delay during write operation.

    在將結果返回給用戶之后,可以進行一些“寫入mongo”操作。例如:您可以調用res.view()方法,該方法將在Model.save()之前向用戶發送響應。但是BUT代碼將繼續運行所有變量,因此您可以將數據保存到mongo DB。因此用戶在寫操作期間不會看到延遲。

  4. You could use queues like RabbitMQ to perform operations that require lot of resources. For example: If you need to store big data collection you could send it to RabbitMQ and return response to user. Then handle this message in "background" process ad store data. It will also can help you with scaling your application.

    您可以使用像RabbitMQ這樣的隊列來執行需要大量資源的操作。例如:如果您需要存儲大數據集合,您可以將其發送到RabbitMQ並將響應返回給用戶。然后在“后台”流程廣告商店數據中處理此消息。它還可以幫助您擴展應用程序。

#2


3  

Firstly, ensure that you are not using synchronous I/O. If you can run on io.js, there is --trace-sync-io flag (iojs --trace-sync-io server.js) that will warn you if you use synchronous code with the following console warning: WARNING: Detected use of sync API.

首先,確保您沒有使用同步I / O.如果您可以在io.js上運行,則會有--trace-sync-io標志(iojs --trace-sync-io server.js),如果您使用具有以下控制台警告的同步代碼,它將發出警告:警告:檢測到使用同步API。

Secondly, find out why your RAM usage goes so high. If it's because of lots of data loaded into memory (XML parsing, large amount of data returned from MongoDB, etc), you should consider using streams. V8 garbage collection (Google's JavaScript VM used in Node.js / io.js) may cause slowdown if your memory usage goes very high. More here: Node.js Performance Tip of the Week: Managing Garbage Collection and Node.js Performance Tip of the Week: Heap Profiling

其次,找出你的RAM使用率如此之高的原因。如果是因為大量數據被加載到內存中(XML解析,從MongoDB返回的大量數據等),您應該考慮使用流。如果您的內存使用率非常高,V8垃圾收集(在Node.js / io.js中使用的Google的JavaScript VM)可能會導致速度減慢。更多信息:Node.js本周性能提示:管理垃圾收集和Node.js本周性能提示:堆分析

Thirdly, experiment with Node.js clustering and MongoDB sharding.

第三,嘗試Node.js聚類和MongoDB分片。

Lastly, check if you using or can switch to MongoDB 3.x. We've observed some significant performance gains just by upgrading from 2.x to 3.x.

最后,檢查您是否使用或可以切換到MongoDB 3.x.通過從2.x升級到3.x,我們觀察到了一些顯着的性能提升。

#3


2  

For Mongodb you can use mongtop to see which databases are contested, 2.2+ uses per database locks, if database has write heavy workload reads will be affected as mongodb is using writer greedy locks

對於Mongodb,您可以使用mongtop查看哪些數據庫有爭議,每個數據庫鎖定使用2.2+,如果數據庫已寫入,則工作負載讀取將會受到影響,因為mongodb正在使用writer greedy locks

And for node.js you could check if there are any sort of event loop delays which could explain API request delays

對於node.js,您可以檢查是否存在任何類型的事件循環延遲,這可以解釋API請求延遲

(function getEventLoopDelay() {
    var startTime = Date.now();
    setTimeout(function() {
        console.log(Math.max(Date.now() - startTime - 1000, 0));
        getEventLoopDelay();
    }, 100);
})();

注意!

本站翻译的文章,版权归属于本站,未经许可禁止转摘,转摘请注明本文地址:https://www.itdaan.com/blog/2015/08/01/7259937eb6d966a83f5aa80e77908cf1.html



 
粤ICP备14056181号  © 2014-2021 ITdaan.com