web-dev-qa-db-ja.com

単一ホストNode.js運用アプリに適したセッションストアとは何ですか?

NodeのExpress w/Connectミドルウェアを使用しています。 Connectのメモリセッションストアは本番環境に適合しません。

Warning: connection.session() MemoryStore is not designed for a production environment, as it will leak memory, and obviously only work within a single process.

大規模な展開では、mongoまたはredisが理にかなっています。

しかし、実稼働環境の単一ホストアプリに適したソリューションは何ですか?

67
Nils

これを見て一日を過ごした。ここに私が発見したオプションがあります。 1秒あたりの要求は、ローカルマシンのab -n 100000 -c 1 http://127.0.0.1:9778/を介して実行されます。

  • セッションなし-高速(438 req/sec)
  • cookieSession :外部サービスを必要とせず、速度にわずかな影響(311リクエスト/秒)-最速、セッションはCookieで期限切れになります(maxAgeでカスタマイズ)
  • connect-redis :redisサーバーが必要、速度に大きな影響(redis2goおよびredisgreenで4 req/sec)-mongoよりも高速で、しばらくするとセッションが削除されます(ttlでカスタマイズ)
  • connect-mongo -mongodbサーバーが必要、速度への影響が大きい(mongohqで2 req/sec)-redisより遅く、セッションをクリーンアップするために手動clear_intervalを設定する必要がある

CookieSessionに使用したcoffeescriptは次のとおりです。

server.use express.cookieSession({
    secret: appConfig.site.salt
    cookie: maxAge: 1000*60*60
})

Redisに使用するコーヒースクリプトは次のとおりです。

RedisSessionStore ?= require('connect-redis')(express)
redisSessionStore ?= new RedisSessionStore(
    Host: appConfig.databaseRedis.Host
    port: appConfig.databaseRedis.port
    db: appConfig.databaseRedis.username
    pass: appConfig.databaseRedis.password
    no_ready_check: true
    ttl: 60*60  # hour
)
server.use express.session({
    secret: appConfig.site.salt
    cookie: maxAge: 1000*60*60
    store: redisSessionStore
})

これがmongoの私のcoffeescriptです:

server.use express.session({
    secret: appConfig.site.salt
    cookie:
        maxAge: 100*60*60
    store: new MongoSessionStore({
        db: appConfig.database.name
        Host: appConfig.database.Host
        port: appConfig.database.port
        username: appConfig.database.username
        password: appConfig.database.password
        auto_reconnect: appConfig.database.serverOptions.auto_reconnect
        clear_interval: 60*60  # hour
    })
})

もちろん、リモートのredisおよびmongoデータベースは、ローカルの同等のものよりも遅くなります。 ローカルの同等のものを機能させることができませんでした。特に、ホストされたリモートの選択肢と比較して、インストールとメンテナンスの時間は投資したいと思ったものよりもはるかに大きかったので、他の人にも当てはまるため、これらのホストされたリモートデータベースサービスが最初に存在する理由!

ローカルデータベースのベンチマークについては、 @ Mustafa's answer を参照してください。

誰かに喜んで この回答を編集 ミックスにローカルデータベースベンチマークを追加してください。

83
balupton

受け入れられた答えはリモートホストに接続するだけなので、ローカルホストよりも常に遅いことは明らかです。自宅の次のコンピューターであっても、そのコンピューターから読み取るのにミリ秒かかりますが、ローカルメモリはナノ秒しかかかりません。ローカルにインストールされたサーバーを使用してそれらを比較する必要があります。

ここに私のローカルPCからの結果があります:ご覧のとおり、redisは高負荷下でインメモリとほぼ同じくらい高速です。これらのテストコードが利用できるレポのクローンを作成できます。 https://github.com/mustafaakin/express-session-store-benchmark

Concurrency: 1
none       4484.86 [#/sec] 
memory     2144.15 [#/sec] 
redis      1891.96 [#/sec] 
mongo      710.85 [#/sec] 
Concurrency: 10
none       5737.21 [#/sec] 
memory     3336.45 [#/sec] 
redis      3164.84 [#/sec] 
mongo      1783.65 [#/sec] 
Concurrency: 100
none       5500.41 [#/sec] 
memory     3274.33 [#/sec] 
redis      3269.49 [#/sec] 
mongo      2416.72 [#/sec] 
Concurrency: 500
none       5008.14 [#/sec] 
memory     3137.93 [#/sec] 
redis      3122.37 [#/sec] 
mongo      2258.21 [#/sec] 

セッションで使用されるページは非常に単純なページです。

app.get("/", function(req,res){
    if ( req.session && req.session.no){
        req.session.no = req.session.no + 1;
    } else {
        req.session.no = 1;
    }
    res.send("No: " + req.session.no);
});

Redisストア設定:

app.use(express.session({
    store: new RedisStore({
        Host: 'localhost',
        port: 6379,
        db: 2,
        }),
    secret: 'hello'
}));

Mongoストアの構成:

app.use(express.cookieParser());
app.use(express.session({
    store: new MongoStore({
        url: 'mongodb://localhost/test-session'
    }),
    secret: 'hello'
}));
69
Mustafa

別の良いオプションはmemcachedです。 memcachedを再起動するとセッション状態は失われますが、それを行う理由はほとんどありません。アプリサーバーを再起動した場合でも、キャッシュを常に実行したままにすることができます。セッションデータへのアクセスは事実上瞬時であり、memcachedは、与えられた(適切な)量のメモリで問題なく実行されます。そして、memcachedのクラッシュ(Linux上)は見たことがありません。

https://github.com/elbart/node-memcache

Memcachedに関する一般的な留意事項:

  • キャッシュキーに空白を含めないでください
  • 使用する名前空間プレフィックスを含めて、キャッシュキーの最大長があることに注意してください。キャッシュキーが長すぎる場合は、代わりに一方向ハッシュを使用します。

これらのどちらもセッションストレージの問題ではありません。一般化されたキャッシングのみ。

9
kgilpin

connect-mongo を使用してMongoDBセッションストアにアクセスしました。

_npm install connect-mongo_でインストールし、既存のMemoryStoreを置き換えます

app.use(express.session({ store: new MongoStore({ db: 'some-database' }) }));

セッションのデータベース側を自動的に管理します。

6
greenimpala

ローカル開発にもRedisを使用します。これは、Nodeアプリケーションを再起動してもセッションを保存し、ブラウザーセッションのログインを維持します。Redisはデフォルトでセッションをメモリに保存します。 (ノードアプリと一緒に画面で実行するだけです)構成で異なるデータベースまたはセッション値を使用するだけであれば、複数のアプリケーションをサポートできます。

5
Timothy Meade

私は自分でnode.jsを調査していますが、セッションオブジェクトに多くの情報を保存する必要がない場合は、安全なCookieを調べることをお勧めします。

セキュアCookieは、ブラウザが各リクエストとともに保存および転送するCookieの一部としてセッション情報を保存します。ユーザーが有効なCookieを偽造できないように暗号化されています。

利点は、サーバーで状態を維持する必要がないことです。このソリューションは拡張性が高く、実装が簡単です。

欠点は、最大約4KBしか保存できず、データがeveryリクエストでサーバーに送信されることです(ただし、複数の架空のドメインを指すことができますたとえば、公開されている静的コンテンツにその荷物を押し付けないようにします)。

Webを検索すると、node.jsのセキュアCookieの実装が少なくとも2つあるようです。しかし、どのように生産準備が整っているのかわかりません:

https://github.com/benadida/node-client-sessions/blob/master/lib/client-sessions.js

https://github.com/caolan/cookie-sessions

3
nimrodm

これは古い質問であることに感謝しますが、同様の問題の解決策を探しているときに出くわしました。 Linuxのセッションストレージにmemcachedを使用することを既に決めていました( connect-memcached を使用)が、Windowsで実行する機能も必要でした。単一プロセスノードアプリのメモリ内セッションストレージを見つけようとしてしばらく費やしました。 RedisとMemcachedはWindowsでは十分にサポートされていないようで、インストールの複雑さをさらに増やしたくありません。

別のStack Overflowスレッドで session-memory-store を見つけました。これは見た目は良いですが、依存関係のサイズが大幅に増加しました。

最後に、 memorystoreexpress-sessionのドキュメントにありました。名前がデフォルトのMemoryStoreと似ているため、もともと見逃していましたが、まさに私が探していたものです。

リークのない高速セッションのフル機能のMemoryStoreモジュール!

現在、クラスターで実行する場合は(Linuxのみ)connect-memcachedを使用し、単一のプロセスを実行する場合は(LinuxまたはWindowsで)memorystoreを使用しています。

私が最初にやったように他の誰かがメモリストアを紛失するという間違いを犯した場合に備えて、これを別の答えとして投稿する価値があると思いました。

2
davidm_uk

https://github.com/llambda/express-session-benchmarks でベンチマークを確認してください。異なるセッション実装の比較を示しています。

1
llambda