图片文件分布式存储方案设计模式(c#--sqlserver)

1、为了降低web服务器的压力,申请了2台文件服务器,用来存放图片文件。但是两台文件服务器如何让程序自己选择呢?

于是我用了一个算法,思路如下:

从状态表筛选出可用的图片服务器集合记作C,并获取集合的总记录数N,

然后用随机函数产生一个随机数R1与N进行取余运算记作I=R1%N,则c[I]即为要保存图片服务器。

然后我开始设计两个表,一个是图片文件服务器表、一个是图片信息表。1对多的关系。

表1:ImageServerInfo  图片文件服务器表

表2:ImageInfo   图片信息表

 

表脚本入下:

USE [MyImageServer]
GO

/****** Object:  Table [dbo].[ImageServerInfo]    Script Date: 07/04/2020 21:17:15 ******/
SET ANSI_NULLS ON
GO

SET QUOTED_IDENTIFIER ON
GO

CREATE TABLE [dbo].[ImageServerInfo](
    [ServerId] [int] IDENTITY(1,1) NOT NULL,  --服务器id
    [ServerName] [nvarchar](32) NOT NULL,     --图片服务器名称
    [ServerUrl] [nvarchar](100) NOT NULL,     --图片服务器
    [PicRootPath] [nvarchar](100) NOT NULL,   --图片存储的物理路径
    [MaxPicAmount] [int] NOT NULL,            ---图片存储的上限
    [CurPicAmount] [int] NOT NULL,            --图片当前存储的数量
    [FlgUsable] [bit] NOT NULL,               ---图片服务器的状态
 CONSTRAINT [PK_ImageServerInfo] PRIMARY KEY CLUSTERED 
(
    [ServerId] ASC
)WITH (PAD_INDEX  = OFF, STATISTICS_NORECOMPUTE  = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS  = ON, ALLOW_PAGE_LOCKS  = ON) ON [PRIMARY]
) ON [PRIMARY]

GO
----------------
----------------
----------------
----------------

USE [MyImageServer]
GO

/****** Object: Table [dbo].[ImageInfo] Script Date: 07/04/2020 21:16:57 ******/
SET ANSI_NULLS ON
GO

SET QUOTED_IDENTIFIER ON
GO

CREATE TABLE [dbo].[ImageInfo](
[Id] [int] IDENTITY(1,1) NOT NULL,       ---该具体的id
[ImageName] [nvarchar](100) NOT NULL,    ---图片的路径名称
[ImageServerId] [int] NOT NULL,          ---存储到哪台服务器的id
CONSTRAINT [PK_ImageInfo] PRIMARY KEY CLUSTERED
(
[Id] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
) ON [PRIMARY]

GO

ALTER TABLE [dbo].[ImageInfo] WITH CHECK ADD CONSTRAINT [FK_ImageInfo_ImageServerInfo] FOREIGN KEY([ImageServerId])
REFERENCES [dbo].[ImageServerInfo] ([ServerId])
GO

ALTER TABLE [dbo].[ImageInfo] CHECK CONSTRAINT [FK_ImageInfo_ImageServerInfo]
GO

 

 

 表结构建立好之后,开始打开 Microsoft Visual Studio 软件,新建一个 ImageSystem 解决方案,这里用来模拟web服务器。

   1、web层我建立的是MVC进行演示 ImageSystem.WebApp。

   2、然后建立一个实体层ImageSystem.Model 用来引用 Model1.edmx 作为EntityFramework做数据库连接。

   3、建立两个空Web,用来做图片文件服务器。命名为 ImageSystem.ImageServeOne、ImageSystem.ImageServeTwo

   4、项目结构如图:

          

 

 

 web应用服务器的Controllers层的HomeController代码如下:

using ImageSystem.Model;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Net;
using System.Web;
using System.Web.Mvc;

namespace ImageSystem.WebApp.Controllers
{
    public class HomeController : Controller
    {
        MyImageServerEntities db = new MyImageServerEntities();
        // GET: Home
        public ActionResult Index()
        {
            return View();
        }
        public ActionResult FileUpload()
        {
            HttpPostedFileBase file = Request.Files["fileUp"];
            if (file != null)
            {
                string fileName = Path.GetFileName(file.FileName);
                string fileExt = Path.GetExtension(fileName);
                if (fileExt == ".jpg" || fileExt == ".png" || fileExt == ".gif")
                {
                    //从状态表筛选出可用的图片服务器集合记作C,并获取集合的总记录数N,然后用随机函数产生一个随机数R1与N进行取余运算记作I=R1%N,则c[I]即为要保存图片服务器
                 var list=db.ImageServerInfo.Where(a => a.FlgUsable == true).ToList();
                    int count = list.Count();
                    Random random = new Random();
                    int r = random.Next();
                    int i = r % count;
                    ImageServerInfo imageServiceInfo = list[i];//筛选出一个服务器
                    WebClient client = new WebClient();
                    string address = "http://" + imageServiceInfo.ServerUrl + "/FileUp.ashx?serverId=" + imageServiceInfo.ServerId + "&ext=" + fileExt;
                    client.UploadData(address, StreamToByte(file.InputStream));
                    return Content("文件上传成功!");
                }
                else
                {
                    return Content("文件类型错误!!");
                }
            }
            else
            {
                return Content("文件不能为空!!");
            }
        }

        private byte[] StreamToByte(Stream inputStream)
        {
            byte[] buffer = new byte[inputStream.Length];
            inputStream.Read(buffer, 0, buffer.Length);
            inputStream.Seek(0, SeekOrigin.Begin);
            return buffer;
        }
        public ActionResult ShowImage()
        {
            var list = db.ImageServerInfo.Where(a => a.FlgUsable == true).ToList();
            ViewData["list"] = list;
            return View();
              
        }
    }
}

HomeController对应的view视图Index页面如下:

@{
    Layout = null;
}

<!DOCTYPE html>

<html>
<head>
    <meta name="viewport" content="width=device-width" />
    <title>分布式图片上传</title>
</head>
<body>
    <div> 
              <form method="post" action="/Home/FileUpload" enctype="multipart/form-data">
                  <input type="file" name="fileUp"  />
                  <input type="submit"  value="上传图片" />
              </form>
    </div>
</body>
</html>

HomeController对应的view视图ShowImage页面如下:

这个页面是辅助查看上传的图片进行展示

@{
    Layout = null;
}
@using ImageSystem.Model
<!DOCTYPE html>

<html>
<head>
    <meta name="viewport" content="width=device-width" />
    <title>ShowImage</title>
</head>
<body>
    <div>
        @if (ViewData["list"] != null)
        {
            foreach (var ImageServerInfo in (List<ImageServerInfo>)ViewData["list"])
            {
                foreach (var ImageInfo in ImageServerInfo.ImageInfo)
                {
                    <img src="@string.Format("http://{0}{1}",ImageServerInfo.ServerUrl,ImageInfo.ImageName)" alt="" width="200px" height="170px" /> 
@ImageServerInfo.ServerName
@ImageServerInfo.ServerUrl @ImageInfo.ImageName @ImageInfo.ImageServerId <br /> } } } </div> </body> </html>

以上便是模拟的web服务器,下面插入Web图片文件服务器的代码,我只展示一台,另外一台除了ip端口不同,代码都一样的:

在图片文件服务器根目录建立images文件夹,然后新增一个FileUp.ashx一般处理程序,用来接收图片的字节数组,一般处理程序的代码如下:

using ImageSystem.Model;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Web;

namespace ImageSystem.ImageServeTwo
{
    /// <summary>
    /// FileUp 的摘要说明
    /// </summary>
    public class FileUp : IHttpHandler
    {

        public void ProcessRequest(HttpContext context)
        {
            context.Response.ContentType = "text/plain";
            string ext = context.Request["ext"];
            int serverId = int.Parse(context.Request["serverId"]);
            string dir = "/images/" + DateTime.Now.Year + "/" + DateTime.Now.Month + "/" + DateTime.Now.Day + "/";
            Directory.CreateDirectory(Path.GetDirectoryName(context.Request.MapPath(dir)));
            string newfileName = Guid.NewGuid().ToString();
            string fullDir = dir + newfileName + ext;
            using (FileStream stream = File.OpenWrite(context.Request.MapPath(fullDir)))
            {
                //将文件流写到指定的文件下
                context.Request.InputStream.CopyTo(stream);
                MyImageServerEntities db = new MyImageServerEntities();
                ImageInfo imageInfo = new ImageInfo();
                imageInfo.ImageName = fullDir;
                imageInfo.ImageServerId = serverId;
                db.ImageInfo.Add(imageInfo);
                db.SaveChanges();
            }
        }
        public bool IsReusable
        {
            get
            {
                return false;
            }
        }
    }
}

这个处理程序会把接收的图片存储到服务器上,并且把途径插入数据库的表中,这里要引用一下EF实体层的ImageSystem.Model

,此时,就可以启动3个项目了,然后主web服务器上传图片,此时就根据随机算法存储图片。

 后期,如公司继续增加图片文件服务器,你只需要在数据库中加一个ip地址就行了,然后再部署一台文件服务器,主web服务器无需重新发版,就可热使用。

以上便是利用C#和sqlserver数据库做的图片文件分布式存储方案设计模式!

 

posted @ 2020-07-05 15:02  畅聊科技  阅读(777)  评论(2编辑  收藏  举报