nodejs express 使用 redis 存儲 session 或 Session存放到MongoDB


使用 redis 存儲 session 的好處在於: 
1.多進程間 session 可以共存 
2.網站重啟用 session 依舊還在

var express = require('express'); var RedisStore = require('connect-redis')(express.session); var app = express(); // 設置 Cookie app.use(express.cookieParser('keyboard cat')); // 設置 Session app.use(express.session({  store: new RedisStore({   host: "192.168.108.46",   port: 6379,   db: "test_session"  }),  secret: 'keyboard cat' }))

 
// monogdb連接
app.use(session({//session持久化配置 secret: "kvkenssecret", key: "kvkenskey", cookie: {maxAge: 1000 * 60 * 60 * 24 * 30},//超時時間 resave: false, saveUninitialized: true, store: new MongoStore({ db: "my_database", host: "localhost", port: 27017 }) }));
 
app.get("/", function(req, res) {
 var session = req.session;  session.count = session.count || 0;  var n = session.count++;  res.send('hello, session id:' + session.id + ' count:' + n); }); app.listen(3002); console.log('Web server has started on http://127.0.0.1:3002/');
客戶端與服務會使用一個Sessionid的Cookie值來進行客戶端和服務器端會話的匹配,這個Cookie一般是服務器端讀/寫的,並在Http請求響應的Header中的Set-Cookie屬性設置:

HTTP/1.1 200 OK
Server: nginx
Date: Wed, 14 Jan 2015 02:29:09 GMT
Content-Type: text/html
Transfer-Encoding: chunked
Proxy-Connection: Keep-Alive
Connection: Keep-Alive
Content-Encoding: gzip
Set-Cookie: sessionid=i4w3axuzyj4nwwg75y6k5us2; path=/; domain=.ourjs.com; httponly

  • path=/             表示這個cookie是設置在根目錄的。
  • httponly           屬性禁止客戶端JavaScript的訪問,防止當前會話(sessionid)被惡意的js腳本盜取
  • domain=.ourjs.com  表示將sessionid存放到主域名下,各個二級域名域名均使用此Cookie (sessionid)

注* 中間代理人攻擊,即是通過代理服務器(如無線路由)盜取你的會話Cookie(SessionID等),從而訪冒你的身份。因此Google建議網站全部采用HTTPS協議,加密傳輸內容,並提高了純HTTPS網站的權重。

使用數據庫來集中管理session,存放Session內容,並在各個子域名跨域共享Cookies (SessionID),即可實現為每一個子域分配一個獨立的node.js Web服務器,各個服務程序均可依據sessionid從數據庫中尋找到同一Session,從而實現不同Web Server中的會話同步,從而實現一定程度上的負載均衡。

要想實現完全意義的負載均衡還需要將Web服務做到完全狀態無關,不僅僅是Session,所有的中間緩存數據都要轉移到與服務器無關的緩存層中,這正是Redis最善長的地方。

但是為什么存放在Redis中要比MongoDB中好呢?


將Session存放到MongoDB


在MongoDB中是這樣存放Session的, 使用  connect-mongo  即用來將Express中的Session持久化到Mongodb的一個中間件,它也可以在 connect  上使用。

Express 4.x, 5.0 與 Connect 3.x配合使用:

var session = require('express-session');
var MongoStore = require('connect-mongo')(session);

app.use(session({
    secret: 'foo',
    store: new MongoStore(options)
}));

Express 2.x, 3.x 和 Connect 1.x, 2.x配合使用:

var MongoStore = require('connect-mongo')(express);

app.use(express.session({
    secret: 'foo',
    store: new MongoStore(options)
}));


對於 Connect 只需要將express替換成connect即可


MongoDB 是一個基於文檔的數據庫,所有數據是從磁盤上進行讀寫的。MongoDB善長的是對無模式JSON數據的查詢。

而Redis是一個基於內存的鍵值數據庫,它由C語言實現的,與Nginx/ NodeJS工作原理近似,同樣以單線程異步的方式工作,先讀寫內存再異步同步到磁盤,讀寫速度上比MongoDB有巨大的提升。因此目前很多超高並發的網站/應用都使用Redis做緩存層,普遍認為其性能明顯好於MemoryCache。當並發達到一定程度時,即可考慮使用Redis來緩存數據和持久化Session。


在NodeJS中使用Redis緩存數據


Redis ( 安裝方法 ) 數據庫采用極簡的設計思想,最新版的源碼包還不到2Mb。其在使用上也有別於一般的數據庫。


node_redis


redis驅動程序多使用  node_redis 此模塊可搭載官方的 hiredis C 語言庫 - 同樣是非阻塞的,比使用JavaScript內置的解釋器性能稍好。可選擇將hiredis 與 redis 一同安裝。

npm install hiredis redis

如果 hiredis 安裝成功, node_redis 會默認使用 hiredis, 否則會使用JavaScript的解釋器。

Redis的一個Key不僅可以對應一個String類型的值,還支持hashes, lists, sets, sorted sets, bitmaps等。

比如存/取一組Hash值,Redis中有兩個對應的 命令 

HMSET key field value [field value ...]、
為一個Key一次設置多個哈希鍵/值, 多用於JSON對象的寫入(序列化的SESSION)。

HGETALL key
讀取一個Key的所有 哈希鍵/值,多用於JSON對象讀取

這兩個命令即是在NodeJS中存取JSON對象的關鍵,

下面是node_reids中對應的例子:

var redis = require("redis"),
    client = redis.createClient();

//寫入JavaScript(JSON)對象
client.hmset('sessionid', { username: 'kris', password: 'password' }, function(err) {
  console.log(err)
})

//讀取JavaScript(JSON)對象
client.hgetall('sessionid', function(err, object) {
  console.log(object)
})


Redis沒有嚴格意義上的表名和字段名,以 Key-Value 鍵值對的方式存儲,因此一般采用 schema:key 形式做為鍵值,其中

schema:  可理解為傳統數據庫中的表名
key:    可理解為表中的主鍵

因此使用redis存放你的session時,需要一個schema前輟, 比如這個key: sessionid:i4w3axuzyj4nwwg75y6k5us2

Redis 也僅能對Key進行檢索, 尚不支持對Key所存放的Hash Key的檢索。 如要檢索到所有session,只需匹配 sessionid:* 即可, 

client.keys('session:*', function (err, keys) {
  console.log(keys)
})

有些第三方庫會支持檢索值中的Hash Key,但這不是一個原子性操作,redis本身並不提供。 

因此在采用Redis緩存與檢索數據時,要使用一些獨特的數據類型,如集合(Sets)

> sadd myset 1 2 3    //添加 1 2 3到集合myset
(integer) 3
> smembers myset      //列出集合的所有成員
1. 3
2. 1
3. 2
> sismember myset 30  //判斷30是否存在
(integer) 0           //不存在

Redis集合不允許添加相同成員。多次添加同一元素到集合中最終只會包含一個元素。多個集合之間可以進行連接/交集這樣的操作。從而實現類似傳統數據庫中索引、條件和連接查詢的效果。

# 添加 3 個用戶和信息
hmset user:1 user_name lee age 21
hmset user:2 user_name david age 25
hmset user:3 user_name chris age 25

# 維護age索引
sadd age:21 1
sadd age:25 2 3

# 維護name索引
sadd name:lee 1
sadd name:david 2
sadd name:chris 3

# 查找  age = 25 和 name = lee 的用戶
sinter age:25 name:lee
  -> 會返回一個空集合


將Session存放到Redis中


connect-reids  是一個 Redis 版的 session 存儲器,使用node_redis作為驅動。借助它即可在Express中啟用Redis來持久化你的Session.


安裝


$ npm install connect-redis

在 Express 3.x 中還需要安裝express-session 

$ npm install express-session


參數


client 你可以復用現有的redis客戶端對象, 由 redis.createClient() 創建
host   Redis服務器名
port   Redis服務器端口
socket Redis服務器的unix_socket

可選參數


ttl        Redis session TTL 過期時間 (秒)
disableTTL 禁用設置的 TTL
db         使用第幾個數據庫
pass       Redis數據庫的密碼
prefix     數據表前輟即schema, 默認為 "sess:"


使用


將express-session傳給connect-redis來啟用

var session = require('express-session');
var RedisStore = require('connect-redis')(session);

app.use(session({
    store: new RedisStore(options),
    secret: 'keyboard cat'
}));

檢驗

app.use(function (req, res, next) {
  if (!req.session) {
    return next(new Error('oh no')) // handle error
  }
  next() // otherwise continue
})


這樣你的Session就轉移到了Redis數據庫,這樣做的一個額外好處是,當你的Express服務器突然重啟后,用戶仍然可以使用當前Cookie中的SessionID從數據庫中獲取到他的會話狀態,做到會話不丟失,在一定程度上提高網站的鍵壯性。


如果你的NodeJS網站上的所有緩存數據都轉移到了Redis后,就可做到完全狀態無關,按需擴展網站的規模。








可水平擴展的NodeJS網站服務器集群(非  cluster模塊  不同,它們是相互獨立的,可分布在不同的物理服務器上),這樣的架構,對於應對超大規模並發也是有好處的。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM