1、前言&回顧html
在上篇文章Session分佈式共享 = Session + Redis + Nginx中,好多同窗留言問了我好多問題,其中印象深入的有:nginx掛了怎麼辦?採用Redis的Session方案與微軟Session方案相比,有什麼優點呢?Cookie也能夠取代Session的,採用Redis的Session方案優點在哪裏?Nginx的iphash方式究竟是什麼?MachineKey有啥用?Net Core怎樣實現?linux
那會兒看到你們的提問,個人回答也只是從應用層面回答,基本上的回答能夠總結爲:「別人這麼作了,解決了這個問題,我用這個方法也解決了這個問題,原理請看連接。」很慚愧的說,那時的我並無徹底理解他真正的優點在哪裏,只是憑着直覺和經驗知道這樣作比較好,知道當一部分東西不可控時候,將其解耦、可視化、集羣就可讓一個系統更加健壯,但沒有一個理論支撐。通過最近一段時間的查閱資料和閱讀書籍,對此有了深入理解,本文將從網站架構的可用性角度對這種Session共享進行分析和講解,並用.net core再次實現這種架構模式。(Session分佈式共享的net core版,由於工做沒有機會應用到生產環境,過往經驗就更別提了,因此只是研究性的,請你們注意,但園子裏早有大牛寫出了相關文章,本文結束會將相關文章貼出)nginx
2、網站可用性--Session管理web
可用性是網站架構中很是重要的一環,什麼是可用性,說的簡單些,就是用戶隨時隨地打開這個網站,這個網站都能打開,而且裏面的功能都能用。若是可用性不高會出現什麼狀況?你們想象一下春節在12306搶票的情景,網站各類崩潰,你們保準會想:要是有別的方式能買到票,我纔不用12306這個破網站呢。這個例子有點極端,由於業務場景比較極端,固然,這種現象也不光是網站可用性這一環出了問題。可是一個網站三天兩頭打不開,要麼是點開了裏面的頁面處處是報錯頁面和操做無反應,你還會用這個網站麼?我相信咱們在瀏覽網站時候,只要不像12306這種壟斷業務的網站,出現不可用的狀況,咱們必定會離開尋找其餘相似的網站。redis
Session管理是網站可用性的內容之一,你們都知道Http是無狀態請求,即沒法追蹤上次Http請求的相關信息,可是業務中大量須要將Http變爲有狀態請求,Session就隨之產生了,但是在分佈式網站設計中,無狀態請求才能實現網站的橫向拓展(增減應用服務器),所以又與Session相矛盾,由於Session信息若是存儲在網站應用服務器的緩存中,加臺服務器就不能用了,所以將Session解耦是解決此問題的關鍵,下面介紹網站常見的Session管理手段。算法
一、Session複製數據庫
Session複製是最先企業應用系統使用較多的一種服務集羣Session管理機制,開啓Session複製功能,便是在集羣中的幾臺服務器之間同步Session對象,Java中好像JBoss有這個功能,.Net暫不知道。json
優點:Session信息讀取快,實現簡單。ubuntu
缺點:集羣規模較大時,服務器之間Session複製會佔用服務器資源和網絡資源,最後系統會不堪重負。windows
二、Session綁定
Session綁定的方式,通常軟/硬均衡負載服務器都會提供此功能,例如:上篇文章Nginx的IPhash方式,均衡負載服務器利用Hash算法將同一IP分配到同一臺服務器上,即Session綁定在某臺特定服務器上,保證Session總能在這臺服務器上得到,又稱做爲會話黏滯。
缺點:若是某臺服務器宕機,那麼這臺服務器上面的Session也就不存在了,用戶請求切換到其餘服務器上由於沒有Session而出錯。
三、利用Cookie記錄Session
經過Cookie記錄Session信息是大部分網站採用的方法,這種方式只要Cookie不濫用,也是很是好很是成熟的方案。Cookie記錄Session就是把一些狀態信息放到了客戶端,每次請求都要傳輸到服務器。
優點:這種方法簡單易實現,可用性高,支持服務器橫向拓展,方案成熟
缺點:安全性問題,Cookie有大小限制,並且每次請求傳輸Cookie會影響性能
四、Session服務器
Session服務器的方式管理Session,是一種很是好的解決方案,由於Session是爲了業務須要Http狀態而產生,而分佈式網站設計中提倡Http無狀態,爲了知足這一設計,Session服務器是將有狀態的Session信息與無狀態的應用服務器相分離,再針對不一樣服務器的不一樣特性進行設計。例如:咱們將Session信息存入到Redis中,那麼Redis的集羣配置、穩定性設置都有不少好的解決方案,若是將Session存入到Memcache,那麼Memcache的集羣配置、穩定性設置也會有不少成熟案例。這樣咱們就將一些問題簡單化,若是咱們單獨應用.Net的Session,咱們須要瞭解更多.Net深層次的東西並加以改造來保證其可用和穩定,越深層的東西越須要時間和閱歷,而若是將Session存儲介質轉移到Redis中,Redis集羣方案、管理工具都很是成熟,只須要配置配置就解決了Session的問題,何樂而不爲呢。
優點:可用性高、安全性高、伸縮性好、性能高、信息大小無限制
3、.Net Core+Redis+Nginx實現Session分佈式共享
一、前期準備&環境
(1)Vs2017 (2).Net Core 1.1 (3) Win 7 (4)ubuntu 16.04
二、.Net Core簡介
隨着互聯網的發展,在當今中國市場(外國不大清楚)開源、跨平臺是衡量一門語言、技術好壞的重要指標之一,微軟爲了推進.Net開源及跨平臺,.Net Core隨之誕生。
詳見大牛的文章:.NET Core與.NET Framework、Mono之間的關係
下面說說.Net Core給個人初步的感覺:
1).Net Core並無顛覆以前C#語法
通俗講就是以前說中國話(C#),如今仍是說中國話,只是說話的環境變了。
2).Net Core由於剛起步,API變了或者少了不少
通俗講就是說話環境變了,並且裏面有好多你沒見過的東西,你不知道用什麼官方詞語來描述,由於官方正在找相關詞來描述這些新東西。
3)脫離IIS,跨平臺
通俗講就是微軟老媽爲了避免讓咱們到了新環境餓着,怕離開如今這個環境(Windows+IIS)以後不知道怎麼生存。因而,教會了咱們語言(C#),給了咱們掙錢的工具(.Net Core+Kestrel),說了一句「去吧孩子,本身奮鬥去吧,稍等,別忘了把這張Visa卡帶上(.Net Core SDK),我會按期給你打錢的。」
4)NuGet愈來愈重要
NuGet通過幾年的發展,愈來愈成熟,.Net Core開源組件獲取的主要方法,經過NuGet能夠下載各類中間件和組件,並且方便快捷(除了有時候斷網,可是可使用國內鏡像),NuGet就像微軟老媽給我們的一個通信錄,並告訴我們,若是你在某些方面須要幫助的時候,能夠經過NuGet找到你的七大姑八大姨來幫忙。
三、拓撲圖
根據以前文章中成功的經驗,簡單改造一下,中間一個Windows系統和一個Ubuntu系統承載着.Net Core程序,有人會問Windows那個咋不來個IIS啊,我要說的是.Net Core實行走出去的原則,基本脫離IIS,若是IIS上面想部署.Net Core程序的話,須要安裝一樣的應用程序,而且站點配置的應用程序池也要變成「無託管代碼」。
四、開發.Net Core程序使用Session
4-一、建立一個Web程序
用Vs2017建立一個.Net Core的Web應用程序,且這個應用程序不包含身份驗證信息
建立完以下
4-二、.Net Core調用Session
.Net Core使用Session,須要引用相關Session的NuGet包,網上一查,發現.Net Core的官方Session組件相似一箇中間件,而且官方支持Redis。
注意:.Net Core的Mvc不能直接使用Session,若是你在程序裏面寫了個HttpContext.Session就會出現以下錯誤:Session has not been configured for this application or request.
4-2-一、Microsoft.AspNetCore.Session
.Net Core使用Session必須安裝Microsoft.AspNetCore.Session,他的NuGet包安裝以下圖:
4-2-二、修改Startup.cs讓Session可用
在相應位置加入高亮代碼services.AddSession(); app.UseSession();
public void ConfigureServices(IServiceCollection services) { // Add framework services. services.AddMvc(); services.AddSession(); }
public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory) { loggerFactory.AddConsole(Configuration.GetSection("Logging")); loggerFactory.AddDebug(); if (env.IsDevelopment()) { app.UseDeveloperExceptionPage(); app.UseBrowserLink(); } else { app.UseExceptionHandler("/Home/Error"); } app.UseStaticFiles(); app.UseSession(); app.UseMvc(routes => { routes.MapRoute( name: "default", template: "{controller=Home}/{action=Index}/{id?}"); }); }
4-2-三、Session寫入和讀取
Session的讀取方式,與.Net有所不一樣,寫法以下,而且Session的HttpContext.Session.SetString或者HttpContext.Session.Set方法分別支持字符串和Byte數組,因此複雜實體須要轉化成Json存入Session中。
【Session 寫入方法】
HttpContext.Session.SetString("key", "strValue");
【Session 讀取方法】
HttpContext.Session.GetString("key")
五、Session存儲介質更換爲Redis
5-一、首先配置Redis
詳細配置方式見:Session分佈式共享 = Session + Redis + Nginx
redis-server redis.windows.conf
詳細配置方式見:Session分佈式共享 = Session + Redis + Nginx
5-二、安裝Microsoft.Extensions.Caching.Redis.Core
NuGet中搜索Microsoft.Extensions.Caching.Redis.Core並安裝,此NuGet包是對Caching的拓展,便可以更換Caching存儲介質
5-三、appsettings.json配置Redis鏈接字符串
appsettings.json配置Redis鏈接字符串(至關於web.config裏面配置appsetting節點),注意:添加位置要在Logging上面,不然讀不到,添加代碼爲下面的高亮部分
{
"Data": "RedisConnection",
"ConnectionStrings": {
"RedisConnection": "192.168.8.138:6379"
},
"Logging": { "IncludeScopes": false, "LogLevel": { "Default": "Warning" } } }
5-四、Startup.cs的ConfigureServices方法中添加引用
public void ConfigureServices(IServiceCollection services) { // Add framework services. services.AddMvc(); services.AddDistributedRedisCache(option =>//redis 數據庫鏈接字符串
{
頁面運行HttpContext.Session.GetString("key"),而後用Redis管理工具RedisDesktopManager查詢Session是否入庫。
5-五、發佈前指定IP和端口(重要)
若是你沒有看這個步驟,繼續下面發佈步驟,等你發佈時候,你會發現一個尷尬的問題,就是你用IP訪問不了你的網站,用localhost能夠訪問,.Net Core默認是5000端口,端口占用也會讓你的網站訪問不了。
只須要在Program.cs中添加高亮代碼便可,細心地人已經看到.UseUrls(new string[] { }) 傳入的是個數組,那麼這裏定義多個網站,當你執行時候dotnet命令時候,多個網站都會啓動。
public static void Main(string[] args) { var host = new WebHostBuilder()//增長處,*號表示ip
.UseKestrel() .UseContentRoot(Directory.GetCurrentDirectory()) .UseIISIntegration() .UseStartup<Startup>() .UseApplicationInsights() .Build(); host.Run(); }
六、.Net Core 發佈
6-一、Windows安裝.Net Core發佈環境[10.2.107.100]
1)安裝Windows Server Hosting (x64 & x86),至關於IIS,注意安裝時候請聯網(好像是自動下載sdk,具體沒仔細研究)。
2)輸入dotnet命令驗證,若是「報’dotnet’不是內部或者外部命令」請找到「C:\Program Files\dotnet」文件夾中的dotnet.exe,用cmd來調用dotnet.exe來運行,或者添加系統環境變量(window中cmd命令能夠節省在編寫命令時候能夠.exe,即命令dotnet就是dotnet.exe)
【坑1】
在win7下提示一下錯誤:Failed to load the dll from [C:\Program Files\dotnet\host\fxr\1.0.1\hostfxr.dll], HRESULT: 0x80070057
解決方法:
須要安裝補丁:KB2533623
下載地址以下:
https://support.microsoft.com/en-us/kb/2533623
【坑2】
注意.net Core版本,本文主要是用的.net Core 1.1.1開發的,下面兩個截圖是版本按錯了出的錯誤信息
6-二、Ubuntu安裝.Net Core發佈環境[10.2.107.46]
Ubuntu安裝.Net Core官方寫的很詳細了,照着作便可,千萬別抵觸Linux系統,抵觸的話那就別用.Net Core了,若是不知道Ubuntu和Linux的關係的話請百度。
最後驗證dotnet命令是否可使用。
6-三、發佈網站
在項目上右鍵->發佈…
點擊發布按鈕,生成的文件以下(SessionTest爲應用程序名)
好了,有了這些文件,咱們只須要把這些文件扔到服務器上就成了,可是怎麼啓動呢?經過查詢,網上說只要用dotnet命令就成。繼續實踐…
說明:個人項目叫作生成了這個爲主要的dll,也是程序的入口。
你們都知道.Net Core是跨平臺的,不一樣系統的服務器環境配置好了,網上查詢說是使用dotnet命令啓動網站,那麼能夠推斷出幾個平臺的dotnet命令是同樣的。
6-3-一、Windows啓動.Net Core網站[10.2.107.100:7201]
啓動.Net Core網站的命令很簡單,安裝好發佈環境的應用程序,C:\Program Files\dotnet目錄以下(若是dotnet命令不能用,能夠直接調用dotnet.exe這個應用程序。)
將生成好的網站複製到服務器上
cmd命令找到PublishOutput
cd C:\PublishOutput
dotnet運行網站命令
成功之後(以後再編譯運行,會提示下面截圖)
訪問http://10.2.107.100:7201/(若是一臺機子有多個網卡多個IP,其餘IP的7201端口也是個獨立網站)
6-3-二、Ubuntu啓動.Net Core網站[10.2.107.46:7201]
想辦法將發佈的程序複製到Ubuntu上面去,我測試使用的VBox虛擬機。
具體方法傳送門:virtualbox中ubuntu和windows共享文件夾設置
七、Nginx配置
7-一、網站端口修改
nginx.conf配置修改
listen 80; 改爲 listen 81; 由於通常都被80都被使用。
server { listen 81; ……
}
7-二、增長負載均衡
nginx.conf中添加upstream節點
} server { ..... }
7-三、location節點修改
location / { root html; index index.aspx 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; }
7-四、Nginx啓動命令
C:\server\nginx-1.0.2>start nginx
或
C:\server\nginx-1.0.2>nginx.exe
7-五、Nginx從新載入命令
C:\server\nginx-1.0.2>nginx.exe -s reload
4、黎明前的黑暗-MachineKey
本覺得作了上述準備和相關代碼編寫,就可以實現Session共享了,結果我想的太簡單了,應用程序發佈後並不能實現Session共享,難道分佈式共享下Session須要特殊處理?.Net我是怎麼實現的,它們的方法應該方法相似。我忽然想到了MachineKey這個東西,以前在.Net版本分佈式共享時候須要添加這個東西,評論也有人問我什麼要加MachineKey。後來只能搜索.Net Core Machinekey關鍵詞,找到了如下幾篇文章作參考。
ASP.NET Core 數據保護(Data Protection)
坎坷路:ASP.NET Core 1.0 Identity 身份驗證(中集)
此問題屬於數據安全問題,微軟在開發.Net Core中延續了以前的設計,採用數據保護(Data Protection)方式對一些內部數據進行加密解密設計,如:Session、Cookie等(遠不止這些)。這樣能夠保證數據的真實性、完整性、機密性、隔離性。數據安全必然離不開加解密算法,你們想一下以前.Net的WebFrom中的ViewState,它最終解析到Html頁面是個hidden標籤裏面有一串很複雜的字符串,這個字符串是被數據保護(Data Protection)機制加密過的。Session也同樣,你們能夠看看Session存到Redis中啥樣,見下圖:
數據保護(Data Protection)有個特性是隔離性,你們能夠想象一下,數據保護核心是加密解密,常見的加密方式有對稱加密和非對稱加密,上一篇作分佈式共享時候,兩臺機子拷貝了一樣的MahcineKey,那麼他的內部加密猜想好像是對稱加密,MachineKey直譯中文爲「機器鑰匙」在聯想隔離性,那麼能夠推斷出來不一樣機子密鑰是不一樣的,那麼MachineKey的做用是統一不一樣機子的密鑰。(吐血中…….這個只是個猜想,詳細原理請參考專業文章)
一、提取.Net Core的MachineKey
.Net Core的MachineKey存儲是以key-xxxx-xxxx-xxxx-xxxx.xml的形式存儲的,那如何提取這個xml信息呢?
Startup.cs的ConfigureServices添加下圖高亮代碼
public void ConfigureServices(IServiceCollection services) {//抽取key-xxxxx.xml
services.AddDataProtection().PersistKeysToFileSystem(new DirectoryInfo(@"D:\XML"));
services.AddSession(); services.AddDistributedRedisCache(option => { //redis 數據庫鏈接字符串 option.Configuration = Configuration.GetConnectionString("RedisConnection"); //redis 實例名 option.InstanceName = "master"; }); services.AddMvc(); }
查看D:\Xml裏的xml文件
二、重寫IXmlRepository接口固定Key
在項目中添加CustomXmlRepository.cs類,其中keyContent中填寫key.xml內容,注意:裏面的幾個時間(如今還不能肯定expirationDate對項目是否有影響),有人問我KeyContent可否從文件裏讀,回答是能夠,可是ubuntu的文件路徑保準不是Windows的d:\之類的,須要使用Linux的寫法,因此乾脆字符串來的快。
using Microsoft.AspNetCore.DataProtection.Repositories; using Microsoft.AspNetCore.Http; using System; using System.Collections.Generic; using System.IO; using System.Linq; using System.Threading.Tasks; using System.Xml.Linq; namespace SessionTest { public class CustomXmlRepository : IXmlRepository { private readonly string keyContent = @"<?xml version='1.0' encoding='utf-8'?> <key id='9108538d-9ea4-45fb-a690-438c8d788619' version='1'> <creationDate>2017-04-27T06:15:07.2194692Z</creationDate> <activationDate>2017-04-27T06:15:07.1844647Z</activationDate> <expirationDate>2017-07-26T06:15:07.1844647Z</expirationDate> <descriptor deserializerType='Microsoft.AspNetCore.DataProtection.AuthenticatedEncryption.ConfigurationModel.AuthenticatedEncryptorDescriptorDeserializer, Microsoft.AspNetCore.DataProtection, Version=1.1.1.0, Culture=neutral, PublicKeyToken=adb9793829ddae60'> <descriptor> <encryption algorithm='AES_256_CBC' /> <validation algorithm='HMACSHA256' /> <masterKey p4:requiresEncryption='true' xmlns:p4='http://schemas.asp.net/2015/03/dataProtection'> <!-- Warning: the key below is in an unencrypted form. --> <value>HOz58FE6STtDHlMo2ZONoPgPTOOjRPikRWXmHOwNDS5o6NPb4hlgl/DxXUhat66soovBUFy1APXCQ4z30DDPyw==</value> </masterKey> </descriptor> </descriptor> </key>"; public virtual IReadOnlyCollection<XElement> GetAllElements() { return GetAllElementsCore().ToList().AsReadOnly(); } private IEnumerable<XElement> GetAllElementsCore() { yield return XElement.Parse(keyContent); } public virtual void StoreElement(XElement element, string friendlyName) { if (element == null) { throw new ArgumentNullException(nameof(element)); } StoreElementCore(element, friendlyName); } private void StoreElementCore(XElement element, string filename) { } } }
修改Startup.cs文件中的ConfigureServices方法加載自定義的CustomXmlRepository類
public void ConfigureServices(IServiceCollection services) { ////抽取key-xxxxx.xml //services.AddDataProtection() // .PersistKeysToFileSystem(new DirectoryInfo(@"D:\XML")); services.AddSingleton<IXmlRepository, CustomXmlRepository>();services.AddDataProtection(configure =>
{ configure.ApplicationDiscriminator = "newP.Web";
}); services.AddSession(); services.AddDistributedRedisCache(option => { //redis 數據庫鏈接字符串 option.Configuration = Configuration.GetConnectionString("RedisConnection"); //redis 實例名 option.InstanceName = "master"; }); services.AddMvc(); }
5、實現效果演示
演示效果說明
本機127.0.0.1也爲10.2.107.100,由於電腦性能有限,沒有弄windows虛擬機,只弄了10.2.107.46這臺Linux虛擬機。
MachineKey的這個實現思路也能夠用到.Net Core的身份驗證上。
UNC文件也能夠實現Session共享方式
原理就是Windows和Linux經過文件共享和掛載的方式Key.xml共享一個文件,可是總以爲有點怪怪的,共享文件會不會被別人惡意篡改,因此最後採用重寫的方式實現。
對UNC方式感興趣的請看:搭建分佈式 ASP.NET Core Web
但願經過本文,讓你們對網站的可用性中有個簡單認識,並瞭解到Session存入Redis中的優點。本文介紹的網站可用性內容中的冰山一角,還有許多知識須要咱們去學習和積累。
.Net Core版本的Session分佈式共享,讓咱們對.Net Core有了初步瞭解,.Net Core的高性能、跨平臺、開源,讓許多人改變了對.Net的見解,可是.Net Core在中國市場的路還有很長要走,我認爲.Net Core並非扭轉.Net語言在中國市場佔有率的銀彈。真正的銀彈也許是咱們這些每天寫程序的.Neter,即便是微軟大量宣傳.Net Core、成功案例漫天飛,咱們不去學習、不去了解新知識,咱們最終會被淘汰。語言只是工具,只有經過不斷學習和努力,將知識消化、吸取並最終分享給別人纔會有最大的收穫,咱們在十字路口迷茫之時,爲什麼不去學習新的知識和方法提高自身的經驗和閱歷。我常常會跟別人說,工做前幾年最重要的不是知識,而是你作事的風格和爲目標鍥而不捨的信念,俗話說「江山易改,本性難移」,若是很差的工做態度和方法變成了你的工做習慣,即便換了語言、換了工做甚至轉了行,都會對你的職業發展有很大影響。好的習慣必定要堅持,有些事堅持一天能夠、堅持兩天能夠、可是堅持三個月以上,卻變成了沒法完成的任務,更別提幾年了,「不積跬步,無以致千里」,只有堅持天天去磨練本身才能有所成長,由於我知道我不是天才,須要後天的努力才能成長。
「踏踏實實作人,認認真真作事」我堅信本身的努力,必定會有回報的,只是如今尚未抓住機遇。最後,向那些奮鬥在一線使用.Net Core開發的人員致敬。
以上總結是我熬的味道濃郁的心靈雞湯,可話說啥時候能改掉我工做外的拖延症啊,這篇文章一直拖拖拖,論文一直拖拖拖,學英語拖拖拖,還有好多事要作可一直也是拖拖拖,悲劇啊。。。忽然發現鴨梨山大啊,壞習慣很差改啊!請你們引覺得戒!固然別作工做狂,身體健康更重要,有時間多陪陪家裏人。
我的觀點,有可能由於知識和閱歷的緣由,分析片面,請多諒解。
7、參考文章
ASP.NET Core 使用 Redis 和 Protobuf 進行 Session 緩存
.NET Core與.NET Framework、Mono之間的關係
virtualbox中ubuntu和windows共享文件夾設置
坎坷路:ASP.NET Core 1.0 Identity 身份驗證(中集)
轉載https://www.cnblogs.com/newP/archive/2017/05/02/6689863.html的博客