国产xxxx99真实实拍_久久不雅视频_高清韩国a级特黄毛片_嗯老师别我我受不了了小说

資訊專欄INFORMATION COLUMN

[譯]Express在生產(chǎn)環(huán)境下的最佳實踐 - 性能和可靠性

Luosunce / 1273人閱讀

摘要:前言這將是一個分為兩部分,內(nèi)容是關(guān)于在生產(chǎn)環(huán)境下,跑應(yīng)用的最佳實踐。第一部分會關(guān)注安全性,第二部分則會關(guān)注性能和可靠性。關(guān)于第一部分,請參閱在生產(chǎn)環(huán)境下的最佳實踐安全性。

前言

這將是一個分為兩部分,內(nèi)容是關(guān)于在生產(chǎn)環(huán)境下,跑Express應(yīng)用的最佳實踐。第一部分會關(guān)注安全性,第二部分則會關(guān)注性能和可靠性。當(dāng)你讀這篇文章時,會假設(shè)你已經(jīng)對Node.js和web開發(fā)有所了解,并且對生產(chǎn)環(huán)境有了概念。

關(guān)于第一部分,請參閱Express在生產(chǎn)環(huán)境下的最佳實踐 - 安全性。

概覽

正如第一部分所說,生產(chǎn)環(huán)境是供你的最終用戶們所使用的,而開發(fā)環(huán)境則是供你開發(fā)和測試代碼所用。故對于和兩個環(huán)境的要求,是非常不同的。例如,在開發(fā)環(huán)境下,你不必考慮伸縮性和可靠性還有性能的問題,但這些在生產(chǎn)環(huán)境下都非常重要。

接下來,我們會將此文分為兩大部分:

需要對代碼做的事,即開發(fā)部分。

需要對環(huán)境做的事,即運維部分,

需要對代碼做的事

為了提升你應(yīng)用的性能,你可以通過:

使用gzip壓縮

禁止使用同步方法

使用中間件來提供靜態(tài)文件

適當(dāng)?shù)卮蛴∪罩?/p>

合理地處理異常

使用gzip壓縮

Gzip壓縮可以顯著地減少你web應(yīng)用的響應(yīng)體大小,從而提升你的web應(yīng)用的響應(yīng)速度。在Express中,你可以使用compression中間件來啟用gzip

var compression = require("compression");
var express = require("express");
var app = express();
app.use(compression());

對于在生產(chǎn)環(huán)境中,流量十分大的網(wǎng)站,最好是在反向代理層處理壓縮。如果這樣做,那么就不就需要使用compression了,而是需要參閱Nginxngx_http_gzip_module模塊的文檔。

禁止使用同步方法

同步方法會在它返回之前都一直阻塞線程。一次多帶帶的調(diào)用可能影響不大,但在流量非常巨大的生產(chǎn)環(huán)境中,它是不可接受的,可能會導(dǎo)致嚴(yán)重的性能問題。

雖然大多數(shù)的Node.js和其第三方庫都同時提供了一個方法的同步和異步版本,但在生產(chǎn)環(huán)境下,請總是使用它的異步版本。唯一可能例外的場景可能是,如果這個方法只在應(yīng)用初始化時調(diào)用一次,那么使用它的同步版本也是可以接受的。

如果你使用的是Node.js 4.0+ 或 io.js 2.1.0+ ,你可以在啟動應(yīng)用時附上--trace-sync-io參數(shù)來檢查你的應(yīng)用中哪里使用了同步API。更多關(guān)于這個參數(shù)的信息,你可以參閱io.js 2.1.0的更新日志。

使用中間件來提供靜態(tài)文件

在開發(fā)環(huán)境下,你可以使用res.sendFile()來提供靜態(tài)文件。但在生產(chǎn)環(huán)境下,這是不被允許的,因為這個方法會在每次請求時都會對文件系統(tǒng)進行讀取。res.sendFile()并不是通過系統(tǒng)方法sendfile實現(xiàn)的。

對應(yīng)的,你可以使用serve-static中間件來為你的Express應(yīng)用提供靜態(tài)文件。

更好的選擇則是在反向代理層上提供靜態(tài)文件。

適當(dāng)?shù)卮蛴∪罩?/b>

總得來說,為你的應(yīng)用打印日志的目的有兩個:調(diào)試和操作記錄。在開發(fā)環(huán)境下,我們通常使用console.log()console.err()來做這些事。但是,當(dāng)這些方法的輸出目標(biāo)是終端或文件時,它們是同步的,所以它們并不適用于生產(chǎn)環(huán)境,除非你將輸出導(dǎo)流至另一個程序中。

為了調(diào)試

如果你正在為了調(diào)試而打印日志。那么你可以使用一些專用于調(diào)試的庫如debug,用于代替console.log()。這個庫可以通過設(shè)置DEBUG環(huán)境變量來控制具體哪些信息會被打印。雖然這些方法也是同步的,但你一定不會在生產(chǎn)環(huán)境下進行調(diào)試吧?

為了操作記錄

如果你正在為了記錄應(yīng)用的活動而打印日志。那么你可以使用一些日志庫如winston或Bunyan,來替代console.log()。更多關(guān)于這兩個庫的詳情,可以參閱這里。

合理地處理異常

Node.js在遇到未處理的異常時就會退出。如果沒有合理地捕獲并處理異常,這會使你的應(yīng)用崩潰和離線。如果你使用了一個自動重啟的工具,那么你的應(yīng)用則會在崩潰后立刻重啟,而且幸運的是,Express應(yīng)用的重啟時間通常都很快。但是不管怎樣,你都想要盡量避免這種崩潰。

為了保證你合理處理異常,請遵從以下指示:

使用try-catch

使用promise

不應(yīng)該做的事

你不應(yīng)該監(jiān)聽全局事件uncaughtException。監(jiān)聽該事件將會導(dǎo)致進程遇到未處理異常時的行為被改變:進程將會忽略此異常并繼續(xù)運行。這聽上去很好,但是如果你的應(yīng)用中存在未處理異常,繼續(xù)運行它是非常危險的,因為應(yīng)用的狀態(tài)開始變得不可預(yù)測。

所以,監(jiān)聽uncaughtException并不是一個好主意,它已被官方地列為了不推薦的做法,并且以后可能會移除這個接口。我們更推薦的是,使用多進程和自動重啟。

我們同樣不推薦使用domains。它通常也并不能解決問題,并且已是一個被標(biāo)識為棄用的模塊。

使用try-catch

Try-catch是一個JavaScript語言自帶的捕獲同步代碼的結(jié)構(gòu)。使用try-catch,你可以捕獲例如JSON解析錯誤這樣的異常。

使用JSHintJSLint這樣的工具則可以讓你遠離引用錯誤或未定義變量這種隱式的異常。

一個使用try-catch來避免進程退出的例子:

// Accepts a JSON in the query field named "params"
// for specifying the parameters
app.get("/search", function (req, res) {
  // Simulating async operation
  setImmediate(function () {
    var jsonStr = req.query.params;
    try {
      var jsonObj = JSON.parse(jsonStr);
      res.send("Success");
    } catch (e) {
      res.status(400).send("Invalid JSON string");
    }
  })
});

但是,try-catch只能捕獲同步代碼的異常。但是Node.js世界主要是異步的,所以,對于大多數(shù)的異常它都無能為力。

使用promise

Promise可以通過then()處理異步代碼里的一切異常(顯式和隱式)。記得在promise鏈的最后加上.catch(next)。例子:

app.get("/", function (req, res, next) {
  // do some sync stuff
  queryDb()
    .then(function (data) {
      // handle data
      return makeCsv(data)
    })
    .then(function (csv) {
      // handle csv
    })
    .catch(next)
})
 
app.use(function (err, req, res, next) {
  // handle error
})

現(xiàn)在所有的同步代碼和異步代碼的異常都傳遞到了異常處理中間件中。

但是,仍有兩點需要提醒:

所有你的異步代碼都必須返回一個promise(除了emitter)。如果你正在使用的庫沒有返回一個promise,那么就使用一些工具方法(如Bluebird.promisifyAll())來轉(zhuǎn)換它。Event emitter(如stream)仍會造成未處理的異常。所以你必須合理地監(jiān)聽它們的error事件。例子:

app.get("/", wrap(async (req, res, next) =>; {
  let company = await getCompanyById(req.query.id)
  let stream = getLogoStreamById(company.id)
  stream.on("error", next).pipe(res)
}))

更多關(guān)于使用promise處理異常的信息,請參閱這里。

需要對環(huán)境做的事

以下是一些你可以對你的系統(tǒng)環(huán)境做的事,用于提升你應(yīng)用的性能:

NODE_ENV設(shè)置為“production”

保證你的應(yīng)用在發(fā)生錯誤后自動重啟

使用集群模式運行你的應(yīng)用

緩存請求結(jié)果

使用負載均衡

使用反向代理

NODE_ENV設(shè)置為“production”

NODE_ENV環(huán)境變量指明了應(yīng)用當(dāng)前的運行環(huán)境(開發(fā)或生產(chǎn))。你可以做的為你的Express提升性能的最簡單的事情之一,就是將NODE_ENV設(shè)置為“production”。

NODE_ENV設(shè)置為“production”將使Express

緩存視圖模板

緩存CSS文件

生成更簡潔的錯誤信息

如果你想寫環(huán)境相關(guān)的代碼,你可以通過process.env.NODE_ENV來獲取運行時NODE_ENV的值。不過需要注意的,檢查環(huán)境變量的值會造成少許的性能損失,所以不要有太多這類操作。

你可能已經(jīng)習(xí)慣了SHELL中設(shè)置環(huán)境變量,例如使用export.bash_profile文件。但是你不應(yīng)該在你的生產(chǎn)服務(wù)器上這么做。你應(yīng)該使用操作系統(tǒng)的初始化系統(tǒng)(systemdsystemd)。下一個章節(jié)將會更詳細的講述初始化系統(tǒng),但是由于設(shè)置NODE_ENV是如此的重要以及簡單,所以我們在這里就列出它:

當(dāng)使用Upstart時,請在任務(wù)文件中使用env關(guān)鍵字。例子:

# /etc/init/env.conf
 env NODE_ENV=production

更多信息,請參閱這里。

當(dāng)使用systemd時,請在你的單元文件中使用Environment指令。例子:

# /etc/systemd/system/myservice.service
Environment=NODE_ENV=production

更多信息,請參閱這里。

如果你正在使用StrongLoop Process Manager,你也可以參閱這篇文章。

保證你的應(yīng)用在發(fā)生錯誤后自動重啟

在生產(chǎn)環(huán)境下,你一定不希望你的應(yīng)用離線。所以你需要保證在你的應(yīng)用發(fā)生錯誤時或你的服務(wù)器自身崩潰時,你的應(yīng)用可以自動重啟。雖然你可能不期望它們的發(fā)生,但是我們需要更現(xiàn)實得預(yù)防它們,可以通過:

使用一個進程管理員(process manager)庫來重啟你的應(yīng)用

當(dāng)你的操作系統(tǒng)崩潰時,使用它提供的初始化系統(tǒng)來重啟你的進程管理員。

Node.js應(yīng)用在遇到未處理異常時就會退出。你的首要任務(wù)是保證你的代碼的測試健全并且合理地處理了所有的異常。但是如有萬一,請準(zhǔn)備一個機制來確保它的自動重啟。

使用進程管理員(process manager)

在開發(fā)環(huán)境下,你可以簡單地使用node server.js這樣的命令來啟動你的應(yīng)用。當(dāng)時在生產(chǎn)環(huán)境下這么做將是不被允許的。如果應(yīng)用崩潰了,在你手動重啟它之前,它都會處于離線狀態(tài)。為了保證你應(yīng)用的自動重啟,請使用一個進程管理員,它可以幫助你管理正在運行的應(yīng)用。

除了保證你的應(yīng)用的自動重啟,一個進程管理員還可以使你:

獲取當(dāng)前運行環(huán)境的性能表現(xiàn)和資源消耗情況。

自動地修改環(huán)境設(shè)置

管理集群(StrongLoop PMpm2

Node.js世界里比較流行的進程管理員有:

StrongLoop Process Manager

PM2

Forever

更多的它們之間的比較,你可以參閱這里。關(guān)于它們?nèi)叩暮喗?,你可以參閱這篇文章。

使用一個初始化系統(tǒng)

接下來要保證的就是,在你的服務(wù)器重啟時,你的應(yīng)用也會相應(yīng)的重啟。盡管我們認為我們的服務(wù)器是十分穩(wěn)定的,但它們?nèi)杂袙斓舻目赡堋K詾榱吮WC在你的服務(wù)器時重啟時你的應(yīng)用也會重啟,請使用你操作系統(tǒng)內(nèi)建的初始化系統(tǒng)。如今比較主流的是systemdUpstart

以下是通過你的Express應(yīng)用來使用初始化系統(tǒng)的兩種方法:

將你的應(yīng)用運行于一個進程管理員中,然后將進程管理員設(shè)置為系統(tǒng)的一個服務(wù)。這個是比較推薦的做法。

直接通過初始化系統(tǒng)運行你的應(yīng)用。這個方法更為簡單,但你卻享受不到進程管理員帶來的福利。

Systemd

Systems是一個linux系統(tǒng)的服務(wù)管理員。大多數(shù)的linux發(fā)行版都將它作為默認的初始化系統(tǒng)。

一個systems服務(wù)的配置文件也被稱為一個單元文件,有一個.service后綴。以下是一個直接管理Node.js應(yīng)用的例子:

[Unit]
Description=Awesome Express App
 
[Service]
Type=simple
ExecStart=/usr/local/bin/node /projects/myapp/index.js
WorkingDirectory=/projects/myapp
 
User=nobody
Group=nogroup
 
# Environment variables:
Environment=NODE_ENV=production
 
# Allow many incoming connections
LimitNOFILE=infinity
 
# Allow core dumps for debugging
LimitCORE=infinity
 
StandardInput=null
StandardOutput=syslog
StandardError=syslog
Restart=always
 
[Install]
WantedBy=multi-user.target

更多關(guān)于systemd的信息,請參閱這里。

Upstart

Upstart是一個大多數(shù)linux發(fā)行版都可用的系統(tǒng)工具,用于在系統(tǒng)啟動時啟動任務(wù)和服務(wù),在系統(tǒng)關(guān)閉時停止它們,并且監(jiān)控它們。你可以先將你的Express應(yīng)用或進程管理員配置為一個服務(wù),然后Upstart會自動地在系統(tǒng)重啟后重啟它們。

一個Upstart服務(wù)被定義在一個任務(wù)配置文件中,有一個.conf后綴。下面的例子展示了如何創(chuàng)建一個名為“myapp”的任務(wù),且應(yīng)用的入口是/projects/myapp/index.js

/etc/init/下創(chuàng)建一個名為myapp.conf的文件:

# When to start the process
start on runlevel [2345]
 
# When to stop the process
stop on runlevel [016]
 
# Increase file descriptor limit to be able to handle more requests
limit nofile 50000 50000
 
# Use production mode
env NODE_ENV=production
 
# Run as www-data
setuid www-data
setgid www-data
 
# Run from inside the app dir
chdir /projects/myapp
 
# The process to start
exec /usr/local/bin/node /projects/myapp/index.js
 
# Restart the process if it is down
respawn
 
# Limit restart attempt to 10 times within 10 seconds
respawn limit 10 10

注意:這個腳本要求Upstart 1.4 或更新的版本,支持于Ubuntu 12.04-14.10。

除了自動重啟你的應(yīng)用,Upstart還為你提供了以下命令:

start myapp – 手動啟動應(yīng)用

restart myapp – 手動重啟應(yīng)用

stop myapp – 手動退出應(yīng)用

更多關(guān)于Upstart的信息,請參閱這里。

使用集群模式運行你的應(yīng)用

在多核的系統(tǒng)里,你可以通過啟動一個進程集群來成倍了提升你應(yīng)用的性能。一個集群運行了你的應(yīng)用的多個實例,理想情況下,一個CPU核對應(yīng)一個實例。這樣,便可以在多個實例件進行負載均衡。

值得注意的是,由于應(yīng)用實例跑在不同的進程里,所以它們并不分享同一塊內(nèi)存空間。因為,應(yīng)用里的所有對象都是本地的,你不可以在應(yīng)用代碼里維護狀態(tài)。不過,你可以使用如redis這樣的內(nèi)存數(shù)據(jù)庫來存儲session這樣的數(shù)據(jù)和狀態(tài)。

在集群中,一個工作進程的崩潰不會影響到其他的工作進程。所以除了性能因素之外,多帶帶工作進程崩潰的相互不影響也是另一個使用集群的好處。一個工作進程崩潰后,請確保記錄下日志,然后重新通過cluster.fork()創(chuàng)建一個新的工作進程。

使用Node.jscluster模塊

Node.js提供了cluster模塊來支持集群。它使得一個主進程可以創(chuàng)建出多個工作進程。但是,比起直接使用這個模塊,許多的庫已經(jīng)為你封裝了它,并提供了更多自動化的功能:如node-pm或cluser-service。

緩存請求結(jié)果

另一個提升你應(yīng)用性能的途徑是緩存請求的結(jié)果,這樣一來,對于同一個請求,你的應(yīng)用就不必做多余的重復(fù)動作。

使用一個如VarnishNginx這樣的緩存服務(wù)器可以極大地提升你應(yīng)用的響應(yīng)速度。

使用負載均衡

不論一個應(yīng)用優(yōu)化地多么好,一個多帶帶的實例總是有它的負載上限的。一個很好的解決辦法就是將你的應(yīng)用跑上多個實例,然后在它們之前加上一個負載均衡器。

一個負載均衡器通常是一個反向代理,它接受負載,并將其均勻得分配給各個實例或服務(wù)器。你可以通過NginxHAProxy十分方便地架設(shè)一個負載均衡器。

使用了負載均衡后,你可以保證每個請求都根據(jù)它的來源被設(shè)置了獨特session id。當(dāng)然,你也可以使用如Redis這樣的內(nèi)存數(shù)據(jù)庫來存儲session。更多詳情,可以參閱這里。

負載均衡是一個相當(dāng)復(fù)雜的話題,更加細致的討論已超過了本文的范疇。

使用反向代理

一個反向代理被設(shè)置與web應(yīng)用之前,用于支持各類對于請求的操作,如將請求發(fā)送給應(yīng)用,自動處理錯誤頁,壓縮,緩存,提供靜態(tài)文件,負載均衡,等等。

在生產(chǎn)環(huán)境中,這里推薦將Express應(yīng)用跑在NginxHAProxy之后。

最后

原文鏈接:https://strongloop.com/strongblog/best-practices-for-express-in-production-part-two-performance-and-reliability/

文章版權(quán)歸作者所有,未經(jīng)允許請勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。

轉(zhuǎn)載請注明本文地址:http://specialneedsforspecialkids.com/yun/86261.html

相關(guān)文章

  • []Express生產(chǎn)環(huán)境下的最佳實踐 - 安全性

    摘要:前言這將是一個分為兩部分,內(nèi)容是關(guān)于在生產(chǎn)環(huán)境下,跑應(yīng)用的最佳實踐。潛在的攻擊者可以通過它們進行針對性的攻擊。 前言 這將是一個分為兩部分,內(nèi)容是關(guān)于在生產(chǎn)環(huán)境下,跑Express應(yīng)用的最佳實踐。第一部分會關(guān)注安全性,第二部分最會關(guān)注性能和可靠性。當(dāng)你讀這篇文章時,假設(shè)你已經(jīng)對Node.js和web開發(fā)有所了解,并且對生產(chǎn)環(huán)境有了概念。 概覽 生產(chǎn)環(huán)境,指的是軟件生命循環(huán)中的某個階段。...

    Forelax 評論0 收藏0
  • multipages-generator今日發(fā)布?!媽媽再也不用擔(dān)心移動端h5網(wǎng)站搭建了!

    摘要:本文適合的讀者現(xiàn)在在手淘,京東,今日頭條,美柚等過億用戶的手機中的,都常見網(wǎng)頁,他們有更新快,靈活,便于分享和傳播的特性。這里有他們中的幾個的例子手淘,美柚。 本文適合的讀者??????? 現(xiàn)在在手淘,京東,今日頭條,美柚等過億用戶的手機app中的,都常見h5網(wǎng)頁,他們有更新快,靈活,便于分享和傳播的特性。這里有他們中的幾個h5的例子:(手淘,美柚)。這些app中都嵌者數(shù)以百計,千計的...

    xavier 評論0 收藏0
  • multipages-generator今日發(fā)布?!媽媽再也不用擔(dān)心移動端h5網(wǎng)站搭建了!

    摘要:本文適合的讀者現(xiàn)在在手淘,京東,今日頭條,美柚等過億用戶的手機中的,都常見網(wǎng)頁,他們有更新快,靈活,便于分享和傳播的特性。這里有他們中的幾個的例子手淘,美柚。 本文適合的讀者??????? 現(xiàn)在在手淘,京東,今日頭條,美柚等過億用戶的手機app中的,都常見h5網(wǎng)頁,他們有更新快,靈活,便于分享和傳播的特性。這里有他們中的幾個h5的例子:(手淘,美柚)。這些app中都嵌者數(shù)以百計,千計的...

    Kerr1Gan 評論0 收藏0
  • multipages-generator今日發(fā)布?!媽媽再也不用擔(dān)心移動端h5網(wǎng)站搭建了!

    摘要:本文適合的讀者現(xiàn)在在手淘,京東,今日頭條,美柚等過億用戶的手機中的,都常見網(wǎng)頁,他們有更新快,靈活,便于分享和傳播的特性。這里有他們中的幾個的例子手淘,美柚。 本文適合的讀者??????? 現(xiàn)在在手淘,京東,今日頭條,美柚等過億用戶的手機app中的,都常見h5網(wǎng)頁,他們有更新快,靈活,便于分享和傳播的特性。這里有他們中的幾個h5的例子:(手淘,美柚)。這些app中都嵌者數(shù)以百計,千計的...

    doodlewind 評論0 收藏0

發(fā)表評論

0條評論

最新活動
閱讀需要支付1元查看
<