负载均衡下的资源文件配置/多站点下的资源文件夹共享(Windows IIS)
前言:
负载均衡用的是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负载均衡方案,所以在项目实施上效果也非常不理想。