前言:
負載均衡用的是NLB,微軟的方案不太靠譜,舉個例子吧,AB兩台服務器負載出C,如果用戶訪問訪問C之后分配的是A,那么如果A掛了,是不會自動切換到B的。據說后來還有一種NLB的方案可以實現,也不想再試了。
背景:
這里主要是以圖片資源為主,以下是可能存在的場景:
1、同一台服務器上,部署了多個與業務相關的站點,同樣要用到統一的圖片資源(比如接口和后台這兩個業務系統,后台上傳了圖片,接口必須能獲取到這些圖片數據,同樣,反過來也是一樣)
2、使用了負載均衡(這里是微軟的NLB方案(強烈不建議使用微軟的方案),同樣也有很多負載均衡方案,比如nginx等),多個站點同時有圖片操作,那么最后每個站點都要同步進行顯示。
3、上面兩點都是基於Web的方案,那么如果出現WinForm這種,我需要保存文件到一個共享文件夾時的場景。
具體操作:
1、針對上面第1點,對應的解決方案是在IIS新建虛擬目錄實現,且新建的虛擬目錄在代碼操作上和真實目錄一致。
效果類似如下:

實質上,上面web1中的upload是真實存在的文件夾,而web2上是虛擬目錄,但是最終出來的效果都是一樣的,操作如下:


這里可以指向本機文件夾,也可以是局域網共享的文件夾,如果是需要賬號密碼的文件夾,可以設置【連接為(C)...】配置。不過一般我們只要本機就夠了。
接下來我們來代碼操作一下:web1上上傳了圖片,試下web2訪問一下,然后web2上傳了圖片,試下web1的訪問。注意:我這里直接使用一套代碼部署兩個站點,然后看下是否能達到操作虛擬目錄時,代碼是一致的。
前台:

后台代碼:

操作1:先部署到web1上,這個站點是有真實文件夾Upload的,完成通過。
操作2:部署到web2上,這個站點沒有真實文件夾Upload的,還是上面那份代碼:

一切正常!
2、針對上面第2點,那么就要配置同一個內網的文件夾共享。但是代碼還是上面的一份,只不過web.config上需要配置共享賬號。
具體操作:
1)在A服務器添加User1的賬號,密碼為123456;同時也在B服務器添加User1的賬號,密碼為123456;注意,這里兩台服務器上的賬號密碼都是一致的。



2)配置A服務器上的Upload文件夾為共享,並添加User1用戶進入共享權限

並添加安全的用戶User1的權限

重要一步,在A服務器和B服務器上設置這個文件夾的權限:“C:\Windows\Microsoft.NET\Framework64\v4.0.30319\Temporary ASP.NET Files”的權限

經過測試,如果不加這一步,會出現編譯不通過的問題。
3)在A服務器和B服務器上新建web站點,其中A服務器上的Upload文件夾為真實文件夾,但是B服務器上的Upload文件夾為虛擬文件夾,並指向A服務器的Upload共享文件夾



4)在代碼上,需要配置web.config,添加賬戶模擬設置
<system.web> <identity impersonate="true" userName="User1" password="123456"/> </system.web>

5)進行部署並測試,先部署A服務器,看運行效果


成功,有文件存在。
再來部署B服務器,看運行效果

可以看出,也是成功的上傳的

上圖中的10.18.66.101為A服務器的內網IP
3、針對上面第3點進行測試,那么就要用到在程序中模擬域帳戶進行登錄操作,這種方式同時也是兼容Web方案的,只不過Web方案本身提供更優的解
代碼實現:
using System; using System.Collections.Generic; using System.IO; using System.Linq; using System.Runtime.InteropServices; using System.Security.Principal; using System.Text; namespace ConsoleApplication_Test { internal static class WinLogonHelper { /// <summary> /// 模擬windows登錄域 /// </summary> [DllImport("advapi32.DLL", SetLastError = true)] public static extern int LogonUser(string lpszUsername, string lpszDomain, string lpszPassword, int dwLogonType, int dwLogonProvider, ref IntPtr phToken); } class Program { static void Main(string[] args) { IntPtr admin_token = default(IntPtr); WindowsIdentity wid_admin = null; WindowsImpersonationContext wic = null; //在程序中模擬域帳戶登錄 if (WinLogonHelper.LogonUser("User1", "10.18.66.101", "123456", 9, 0, ref admin_token) != 0) { using (wid_admin = new WindowsIdentity(admin_token)) { using (wic = wid_admin.Impersonate()) { System.IO.File.Create(@"\\10.18.66.101\Upload\test.txt"); } } } } } }
這里還是用User1賬號,密碼123456的用戶去登錄10.18.66.101這台機器,實質上是用模擬域登錄。
登錄完之后,然后就進行文件操作,記得,這個操作也像我們操作共享文件一樣,帶上IP這些。如“\\10.18.66.101\Upload\test.txt”,小技巧,前面加了@符號。
測試效果
將控制台部署到B服務器

效果也是成功的。
總結:
0、模擬域帳戶之后,就有了模擬用戶的權限,這里千萬要注意安全!
1、通過Web方案和WinForm方案,都可以實現局域網內的文件來回交換。
2、假設A服務器在杭州,B服務器在北京,那么要組建內網,可以直接用VPN方案,Windows下搭建PPTP,這里我提供阿里雲的的搭建方案:http://www.cnblogs.com/EasonJim/p/5361943.html
3、還有一種第三方的方案,購買又拍雲這類型的cdn方案,提供統一的接口和訪問地址,那么完全解決,都是多個程序統一一個路徑進行上傳的思路。
4、如果用了負載均衡的方案,在程序上如果用了Session的也要做相應的處理,比如StateServer方案。
5、極力反對使用微軟的NLB方案
參考:
http://www.cnblogs.com/yukaizhao/archive/2010/06/12/c-sharp-windowsimpersonationcontext.html
http://www.cnblogs.com/dudu/archive/2012/03/27/asp_net_share_folder.html
測試代碼:
后話:
這篇文章是我在13年給一家摩托車公司做抽獎的時候涉及到的配置,當時網絡上對於這類配置比較少,且都是不太可行的,由於用的是微軟的NLB負載均衡方案,所以在項目實施上效果也非常不理想。
