1. 程式人生 > >nginx+redis實現session共享 .NET分布式架構

nginx+redis實現session共享 .NET分布式架構

serve 1.4 應用程序 mode itl provider disco rtu htaccess

上兩篇文件介紹了如何安裝和封裝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 Apaches document root
        # concurs with nginxs 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分布式架構