nginx+redis實現session共享 .NET分布式架構
上兩篇文件介紹了如何安裝和封裝redis 本篇主要是記錄下怎麽實現 nginx+redis實現session共享
目前session問題點
又愛又恨的Session
剛接觸程序開發的人一定愛死Session了,因為Session讓Http從無狀態變成有狀態了,頁面之間傳值、用戶相關信息、一些不變的數據、甚至於查出來的DataTable也可以放進去,取值的時候只需要Session[Key]即可,真是方便極了。Session真是個利器,人擋殺人佛擋殺佛,但任何事物被封為利器基本也是雙刃劍,Session的許多問題我們不得不去面對。
【常見問題請見下圖】
我相信一見到這個問題,老程序員都會心裏一哆嗦,Session是導致這個原因之一,大家也會想到這個情景,“我去,是不是Session又丟了,讓用戶重新登錄”,事故報告中會填寫:.NET規定,用戶登陸後長時間沒操作導致的。解決方案為:把Session時間調到9999。
結果該發生的還是繼續發生著,Session照樣丟失。
【常見Session丟失原因】
1、Session超時,用戶打開頁面,頁面長時間不操作會導致此原因
2、IIS應用程序池回收,或者重啟
3、Web.Config修改,即IIS應用程序池重啟
4、dll被替換或者動態頁面修改,即IIS應用程序池重啟
5、殺毒軟件對.config文件進行掃描,可能會導致IIS應用程序池回收
6、用戶瀏覽器禁用cookie
7、其他原因
其他原因有點不負責,但是好多程序員無法查明是什麽原因導致Session丟失,但Session丟失我歸結為兩大類,一個是數據的Key丟了,一個是Session內容數據庫的丟了,大家這樣就好理解了,用戶瀏覽器禁用cookie一定是Key沒了。IIS應用程序池回收必定會導致Session的內容緩存表丟失,當然還有一些其他原因。
3、解決Session丟失的漫長路
解決過Session丟失的都會用到這幾種方法
1、InProc:將Session存到進程內。
2、StateServer:將Session存到獨立的狀態服務中(Asp.Net State Service)。
3、SqlServer:將Session存到SqlServer中。
4、Cookieless:設置客戶端Session存儲的方式。
用了這些方法之後,有的是該丟還丟,有的是穩定了速度卻慢了。
下面一步步實現nginx+redis 代替session
redis 前面我們已經安裝好了
1.下載nginx。
地址:http://nginx.org/download/nginx-1.9.9.zip
2.編寫bat文件操作 nginx
cls @ECHO OFF SET NGINX_PATH=D: SET NGINX_DIR="D:\Test\nginx-1.9.3\" color 0a TITLE Nginx 管理程序 Power By Ants (http://leleroyn.cnblogs.com) GOTO MENU :MENU CLS ECHO. ECHO. * * * * Nginx 管理程序 Power By Ants (http://leleroyn.cnblogs.com) * * * ECHO. * * ECHO. * 1 啟動Nginx * ECHO. * * ECHO. * 2 關閉Nginx * ECHO. * * ECHO. * 3 重啟Nginx * ECHO. * * ECHO. * 4 退 出 * ECHO. * * ECHO. * * * * * * * * * * * * * * * * * * * * * * * * ECHO. ECHO.請輸入選擇項目的序號: set /p ID= IF "%id%"=="1" GOTO cmd1 IF "%id%"=="2" GOTO cmd2 IF "%id%"=="3" GOTO cmd3 IF "%id%"=="4" EXIT PAUSE :cmd1 ECHO. ECHO.啟動Nginx...... IF NOT EXIST %NGINX_DIR%nginx.exe ECHO %NGINX_DIR%nginx.exe不存在 %NGINX_PATH% cd %NGINX_DIR% IF EXIST %NGINX_DIR%nginx.exe start nginx.exe ECHO.OK PAUSE GOTO MENU :cmd2 ECHO. ECHO.關閉Nginx...... taskkill /F /IM nginx.exe > nul ECHO.OK PAUSE GOTO MENU :cmd3 ECHO. ECHO.關閉Nginx...... taskkill /F /IM nginx.exe > nul ECHO.OK GOTO cmd1 GOTO MENU
3.配置nginx
#user nobody; worker_processes 1; #error_log logs/error.log; #error_log logs/error.log notice; #error_log logs/error.log info; #pid logs/nginx.pid; events { worker_connections 1024; } http { include mime.types; default_type application/octet-stream; #log_format main ‘$remote_addr - $remote_user [$time_local] "$request" ‘ # ‘$status $body_bytes_sent "$http_referer" ‘ # ‘"$http_user_agent" "$http_x_forwarded_for"‘; #access_log logs/access.log main; sendfile on; #tcp_nopush on; #keepalive_timeout 0; keepalive_timeout 65; upstream Jq_one { server 10.110.1.42:1100; server 10.110.1.42:1101; } #gzip on; server { listen 1108; server_name localhost; #charset koi8-r; #access_log logs/host.access.log main; location / { root html; index index.html index.htm; #其中jq_one 對應著upstream設置的集群名稱 proxy_pass http://Jq_one; #設置主機頭和客戶端真實地址,以便服務器獲取客戶端真實IP proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; } #error_page 404 /404.html; # redirect server error pages to the static page /50x.html # error_page 500 502 503 504 /50x.html; location = /50x.html { root html; } # proxy the PHP scripts to Apache listening on 127.0.0.1:80 # #location ~ \.php$ { # proxy_pass http://127.0.0.1; #} # pass the PHP scripts to FastCGI server listening on 127.0.0.1:9000 # #location ~ \.php$ { # root html; # fastcgi_pass 127.0.0.1:9000; # fastcgi_index index.php; # fastcgi_param SCRIPT_FILENAME /scripts$fastcgi_script_name; # include fastcgi_params; #} # deny access to .htaccess files, if Apache‘s document root # concurs with nginx‘s one # #location ~ /\.ht { # deny all; #} } # another virtual host using mix of IP-, name-, and port-based configuration # #server { # listen 8000; # listen somename:8080; # server_name somename alias another.alias; # location / { # root html; # index index.html index.htm; # } #} # HTTPS server # #server { # listen 443 ssl; # server_name localhost; # ssl_certificate cert.pem; # ssl_certificate_key cert.key; # ssl_session_cache shared:SSL:1m; # ssl_session_timeout 5m; # ssl_ciphers HIGH:!aNULL:!MD5; # ssl_prefer_server_ciphers on; # location / { # root html; # index index.html index.htm; # } #} }
其重要註意 upstream Jq_one { server 10.110.1.42:1100; server 10.110.1.42:1101; } 一定要放在HTTP{}中 否則nginx無法啟動。
4.啟動Nginx成功後,搭建自己的兩個網站 發布到iis
我這裏搭建的事一個webapi 一個 webmvc 註意 redis test 這幾個字 這是我用redis 代替session 存儲的值。
5.詳解搭建站點註意事項
首先 通過nuget下載 RedisSessionProvider/StackExchange.Redis
修改兩個站點的webconfig
<system.web> <!--redis session 共享--> <sessionState mode="Custom" customProvider="RedisSessionProvider"> <providers> <add name="RedisSessionProvider" type="RedisSessionProvider.RedisSessionStateStoreProvider, RedisSessionProvider" /> </providers> </sessionState> </system.web>
在Global.asax文件中註冊redis session共享
protected void Application_Start() { //redis 實現session 共享 StackExchange.Redis.ConfigurationOptions redisConfigOpts = StackExchange.Redis.ConfigurationOptions.Parse("127.0.0.1:6379"); RedisSessionProvider.Config.RedisConnectionConfig.GetSERedisServerConfig = (HttpContextBase context) => { return new KeyValuePair<string, StackExchange.Redis.ConfigurationOptions>( "DefaultConnection", redisConfigOpts); }; AreaRegistration.RegisterAllAreas(); GlobalConfiguration.Configure(WebApiConfig.Register); FilterConfig.RegisterGlobalFilters(GlobalFilters.Filters); RouteConfig.RegisterRoutes(RouteTable.Routes); BundleConfig.RegisterBundles(BundleTable.Bundles); }
註冊時的redis服務器地址和端口,可以通過配置的方式存儲和獲取。
註冊完成後 下面測試使用redis session
public ActionResult Index() { ViewBag.Title = "Home Page"; Session["test"] = "redis test"; ViewBag.session = Session["test"].ToString(); return View(); }
存儲 Session["test"] = "redis test";
讀取 Session["test"].ToString();
打開網頁時 redis 會接受到存儲的數據
6.測試nginx+redis+session
mvc網站
F5 刷新幾次
webapi 網站
成功!!!
nginx+redis實現session共享 .NET分布式架構