nginx+nodejs
2016-06-17 23:21nginx+nodejs 相關文章
在之前的這篇文章在ExpressJS(NodeJS)中設置二級域名跨域共享Cookie中提及將Session存放到Mongodb中,其中有很多講解的不是很詳細。
我們為什么要把Session存放到數據中,以及又為什么要在子域名間跨域共享Cookie呢?
Session與Cookie的關系
客戶端與服務會使用一個Sessionid的Cookie值來進行客戶端和服務器端會話的匹配,這個Cookie一般是服務器端讀/寫的,並在Http請求響應的Header中的Set-Cookie屬性設置:
HTTP/1.1200OK
Server:nginx
Date:Wed,14Jan201502:29:09GMT
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.jsWeb服務器,各個服務程序均可依據sessionid從數據庫中尋找到同一Session,從而實現不同WebServer中的會話同步,從而實現一定程度上的負載均衡。
要想實現完全意義的負載均衡還需要將Web服務做到完全狀態無關,不僅僅是Session,所有的中間緩存數據都要轉移到與服務器無關的緩存層中,這正是Redis最善長的地方。
但是為什么存放在Redis中要比MongoDB中好呢?
將Session存放到MongoDB
在MongoDB中是這樣存放Session的,使用connect-mongo即用來將Express中的Session持久化到Mongodb的一個中間件,它也可以在connect上使用。
Express4.x,5.0與Connect3.x配合使用:
varsession=require('express-session');Express2.x,3.x和Connect1.x,2.x配合使用:
varMongoStore=require('connect-mongo')(express);對於Connect只需要將express替換成connect即可
MongoDB是一個基於文檔的數據庫,所有數據是從磁盤上進行讀寫的。MongoDB善長的是對無模式JSON數據的查詢。
而Redis是一個基於內存的鍵值數據庫,它由C語言實現的,與Nginx/NodeJS工作原理近似,同樣以單線程異步的方式工作,先讀寫內存再異步同步到磁盤,讀寫速度上比MongoDB有巨大的提升。因此目前很多超高並發的網站/應用都使用Redis做緩存層,普遍認為其性能明顯好於MemoryCache。當並發達到一定程度時,即可考慮使用Redis來緩存數據和持久化Session。
在NodeJS中使用Redis緩存數據
Redis (安裝方法) 數據庫采用極簡的設計思想,最新版的源碼包還不到2Mb。其在使用上也有別於一般的數據庫。
node_redis
redis驅動程序多使用node_redis 此模塊可搭載官方的hiredisC語言庫-同樣是非阻塞的,比使用JavaScript內置的解釋器性能稍好。可選擇將hiredis與redis一同安裝。
npminstallhiredisredis如果hiredis安裝成功,node_redis會默認使用hiredis,否則會使用JavaScript的解釋器。
Redis的一個Key不僅可以對應一個String類型的值,還支持hashes,lists,sets,sortedsets,bitmaps等。
比如存/取一組Hash值,Redis中有兩個對應的命令
HMSETkeyfieldvalue[fieldvalue...]、
為一個Key一次設置多個哈希鍵/值,多用於JSON對象的寫入(序列化的SESSION)。
HGETALLkey
讀取一個Key的所有哈希鍵/值,多用於JSON對象讀取
這兩個命令即是在NodeJS中存取JSON對象的關鍵,
下面是node_reids中對應的例子:
varredis=require("redis"),Redis沒有嚴格意義上的表名和字段名,以 Key-Value 鍵值對的方式存儲,因此一般采用 schema:key 形式做為鍵值,其中
schema:可理解為傳統數據庫中的表名
key: 可理解為表中的主鍵
因此使用redis存放你的session時,需要一個schema前輟, 比如這個key: sessionid:i4w3axuzyj4nwwg75y6k5us2
Redis也僅能對Key進行檢索,尚不支持對Key所存放的HashKey的檢索。如要檢索到所有session,只需匹配sessionid:* 即可,
client.keys('session:*',function(err,keys){有些第三方庫會支持檢索值中的HashKey,但這不是一個原子性操作,redis本身並不提供。
因此在采用Redis緩存與檢索數據時,要使用一些獨特的數據類型,如集合(Sets)
>saddmyset123//添加123到集合mysetRedis集合不允許添加相同成員。多次添加同一元素到集合中最終只會包含一個元素。多個集合之間可以進行連接/交集這樣的操作。從而實現類似傳統數據庫中索引、條件和連接查詢的效果。
#添加3個用戶和信息將Session存放到Redis中
connect-reids 是一個Redis版的session 存儲器,使用node_redis作為驅動。借助它即可在Express中啟用Redis來持久化你的Session.
安裝
$npminstallconnect-redis在Express3.x中還需要安裝express-session
$npminstallexpress-session參數
client你可以復用現有的redis客戶端對象,由redis.createClient()創建
hostRedis服務器名
portRedis服務器端口
socketRedis服務器的unix_socket
可選參數
ttlRedissessionTTL過期時間(秒)
disableTTL禁用設置的TTL
db使用第幾個數據庫
passRedis數據庫的密碼
prefix數據表前輟即schema,默認為"sess:"
使用
將express-session傳給connect-redis來啟用
varsession=require('express-session');檢驗
app.use(function(req,res,next){這樣你的Session就轉移到了Redis數據庫,這樣做的一個額外好處是,當你的Express服務器突然重啟后,用戶仍然可以使用當前Cookie中的SessionID從數據庫中獲取到他的會話狀態,做到會話不丟失,在一定程度上提高網站的鍵壯性。
如果你的NodeJS網站上的所有緩存數據都轉移到了Redis后,就可做到完全狀態無關,按需擴展網站的規模。