遇到的問題
對於Web程序,使用一台服務器的時候,客戶端上傳的文件一般也都是存儲在這台服務器上。但在集群環境中就行不通了,如果每個服務器都存儲自己接受到的文件,就亂套了,數據庫中明明有這個附件的記錄,卻找不到這個文件。於是,文件需要進行統一集中管理,並向集群中的服務器提供統一的路徑。
基於NFS的分布式文件存儲實現
Network File System 簡稱NFS,用人話說叫共享文件夾,可以實現分布式存儲文件。只需要在文件服務器上共享文件夾,並指定相應賬號的權限,並給Web服務器設置可以訪問共享文件夾的賬號和密碼,web服務器就可以像操作本地文件一樣操作文件服務器上的文件了。NFS下的文件訪問路徑有固定的格式,稱為UNC(Universal Naming Convention),以“\\”開頭。
要以UNC的方式訪問NFS下的文件,需要用到windows提供的兩個API:WNetAddConnection2 和 WNetCancelConnection2。WNetAddConnection2可以使用指定的賬號和密碼創建一個UNC的連接,然后程序可以直接訪問該UNC下文件。
首先創建類FileServerConnection,用於管理連接,具體代碼如下:
public class FileServerConnection
{
private string uncName;
private string username;
private string password;
/// <summary>
/// 構造器
/// </summary>
/// <param name="uncName">完整的UNC路徑</param>
/// <param name="username">訪問共享連接的用戶名</param>
/// <param name="password">訪問共享連接的密碼</param>
public FileServerConnection(string uncName, string username, string password)
{
this.uncName = uncName;
this.username = username;
this.password = password;
}
/// <summary>
/// 連接文件服務器
/// </summary>
public void Connect()
{
var netResource = new NetResource
{
Scope = ResourceScope.GlobalNetwork,
ResourceType = ResourceType.Disk,
DisplayType = ResourceDisplayType.Share,
RemoteName = this.uncName.TrimEnd('\\')
};
var result = WNetAddConnection2(netResource, password, username, 0);
if (result != 0)
throw new Win32Exception(result);
}
/// <summary>
/// 釋放連接
/// </summary>
public void Disconnect()
{
WNetCancelConnection2(this.uncName, 0, true);
}
[DllImport("mpr.dll")]
private static extern int WNetAddConnection2(NetResource netResource,
string password,
string username,
int flags);
private static extern int WNetCancelConnection2(string name, int flags, bool force);
}
FileServerConnection中所用到的幾個結構體代碼如下:
[StructLayout(LayoutKind.Sequential)]
public class NetResource
{
public ResourceScope Scope;
public ResourceType ResourceType;
public ResourceDisplayType DisplayType;
public int Usage;
public string LocalName;
public string RemoteName;
public string Comment;
public string Provider;
}
public enum ResourceScope
{
Connected = 1,
GlobalNetwork,
Remembered,
Recent,
Context
} ;
public enum ResourceType
{
Any = 0,
Disk = 1,
Print = 2,
Reserved = 8,
}
public enum ResourceDisplayType
{
Generic = 0x0,
Domain = 0x01,
Server = 0x02,
Share = 0x03,
File = 0x04,
Group = 0x05,
Network = 0x06,
Root = 0x07,
Shareadmin = 0x08,
Directory = 0x09,
Tree = 0x0a,
Ndscontainer = 0x0b
}
然后在Web程序啟動的時候,只需要創建一個FileServerConnection的實例,然后調用它的Connect方法。為了防止重復創建連接引發異常,可以Connect之前先DisConnect。具體調用代碼如下:
fsConnection= new FileServerConnection (storeRootPath, username, password); fsConnection.Disconnect(); fsConnection.Connect();
基於DFS分布式存儲方案
一台文件存儲服務器+一塊大磁盤,已經能夠應付大多數情況了。如果想要更大的存儲容量、更大的吞吐量、更安全可靠的文件部署方案,可以使用windows server上的DFS。DFS本質上還是基於文件夾共享(NFS)的,但是可以通過它來組織多太文件服務器提供統一的訪問路徑,從而支持大容量和大吞吐量。而且,可以配置把同一份文件存儲在不同的服務器上,一台掛掉之后,文件仍然不會丟失;DFS還可以和活動目錄集成,即使根服務器掛掉,仍然不影響服務器使用,從而 保證文件存儲的可靠性。Windows Server下DFS的安裝和使用參考:
http://technet.microsoft.com/zh-cn/library/cc731089.aspx#BKMK_UI 和
http://www.cnblogs.com/cabin/archive/2010/10/07/1845020.html
如果不想使用Windows自帶的DFS,還有第三方的DFS可供選擇,比如 FastDFS。
