分佈式文件存儲庫MinIO可還行?

在傳統的單體應用架構中,一個應用程序對應一臺服務器,提供單進程服務。

但是隨着業務的升級,技術的更新迭代,分佈式、集羣架構、微服務等現已儼然成爲主流。

幾乎所有的項目都會與文件掛鉤,例如OA系統的報表文件,電商系統的商品圖片等等...

我們來看一下傳統的(單體應用)文件存儲與讀取方式

 一臺主機對於N個客戶端,如果是小項目還好,稍微大點的項目,服務器分分鐘崩潰

進而演進爲分佈式架構

 將每一個大的模塊進行拆分,以前單進程支撐的系統現在多進程協同。將文件操作也進行剝離,部署到不同的服務器進行維護,各司其職,減輕不同模塊服務器的壓力.

話又說回來了,怎樣實現呢?

這裏的話我主要說一下分佈式文件的存儲服務MinIO。當然還有其他的一些中間件及工具,大家隨意即可。

首先介紹一下MinIO,MinIO是一款高性能的對象資源存儲庫,而且自身很輕量。

GitHub上start數已經有20多K了

https://github.com/minio

 而且MinIO支持多種語言,也提供了豐富的API.

OK!現在要動手了。

用它肯定要先安裝它,我本次操作在Linux下。

首先在Docker中拉取一個鏡像並運行

docker pull minio/minio
docker run -p 9000:9000 minio/minio server /data

它會分配給你密鑰,用作登錄。這個密鑰在後續項目中也會用到。

 在瀏覽器中輸入ip:port如果正常顯示,就證明你安裝成功了。如下:

 我們可以點擊加號,創建一個桶(文件夾)

 注意文件夾的名稱不能大寫

 我們可以上傳一張圖片

 找到它的鏈接就可以在瀏覽器中訪問了

 

 接下來在代碼中進行CRUD了😅

 先在項目中引入Minio包

PM> Install-Package Minio

我的是webapi的項目,你可隨意

 上傳文件:

        /// <summary>
        /// 上傳文件
        /// </summary>
        /// <param name="file"></param>
        /// <returns></returns>
        [HttpPost]
        public async Task<IActionResult> Upload(IFormFile file)
        {
            try
            {
                var minio = new MinioClient(_configuration["Minio:endpoint"], _configuration["Minio:accessKey"], _configuration["Minio:secretKey"]);
                var data = await FileUpload.Run(minio, file);
                return new JsonResult(new
                {
                    success = true,
                    fileUrl = data.fileUrl,
                    message = data.message
                });
            }
            catch (Exception ex)
            {
                return new JsonResult(new
                {
                    success = false,
                    fileUrl = default(string),
                    message = ex.Message
                });
            }
        }
        public async static Task<FileData> Run(MinioClient minio, IFormFile formFile)
        {
            var bucketName = "picfile";
            var location = "us-east-1";
            var objectName = $"pic/{DateTime.Now.ToString("yyyy-MM-dd")}/" + Guid.NewGuid().ToString().Replace("-", string.Empty);
            var contentType = "image/jpeg";
            try
            {
                //判斷桶(文件夾)是否存在
                bool found = await minio.BucketExistsAsync(bucketName);
                if (!found)
                {
                    //新增桶(文件夾)
                    await minio.MakeBucketAsync(bucketName, location);
                }
                //文件大小
                var len = formFile.Length;
                //打開請求流以讀取上載的文件
                var stream = formFile.OpenReadStream();
                //上傳文件到桶(文件夾).
                await minio.PutObjectAsync(bucketName, objectName, stream, len, contentType, null, null);
                //返回url
                var url = await minio.PresignedGetObjectAsync(bucketName, objectName, 3600 * 24 * 7);
                //var data = await minio.StatObjectAsync("picfile", objectName);
                //... 對數據庫進行操作,例如存入文件名與桶(文件夾)的名稱
                return new FileData { success = true, fileUrl = url, message = "上傳成功" };
            }
            catch (MinioException ex)
            {
                return new FileData { success = false, fileUrl = default(string), message = ex.Message };
            }
        }

密鑰和ip這些配置項我們可以寫在appsettings.json中

 在控制器中已注入的形式使用

 下載文件:

        /// <summary>
        /// 下載文件
        /// </summary>
        /// <param name="bucketName">桶(文件夾)名稱</param>
        /// <param name="objextName">文件名稱</param>
        /// <returns></returns>
        [HttpGet]
        public async Task<IActionResult> DownLoadFile(string bucketName, string objextName)
        {
            try
            {
                if (string.IsNullOrEmpty(bucketName) && string.IsNullOrEmpty(objextName)) return new JsonResult(new { message = "桶(文件夾)名稱和文件名稱不能爲空!" });
                //實例化minio客戶端
                var minio = new MinioClient(_configuration["Minio:endpoint"], _configuration["Minio:accessKey"], _configuration["Minio:secretKey"]);
                //獲得圖片的鏈接
                var url = await minio.PresignedGetObjectAsync("picfile", objextName, 3600 * 24 * 7);
                //實例化WebClient 對象
                var webClient = new WebClient();
                //根據圖片鏈接轉成byte字節數組
                var dataByte = webClient.DownloadData(url);
                return File(dataByte, "image/jpeg");
            }
            catch (Exception ex)
            {
                return new JsonResult(new
                {
                    message = ex.Message,
                    success = false
                });
            }
        }

移除文件:

        /// <summary>
        /// 移除文件
        /// </summary>
        /// <param name="bucketName"></param>
        /// <param name="objextName"></param>
        /// <returns></returns>
        [HttpDelete]
        public async Task<IActionResult> DeleteFile(string bucketName, string objextName)
        {
            try
            {
                if (string.IsNullOrEmpty(bucketName) && string.IsNullOrEmpty(objextName)) return new JsonResult(new { message = "桶(文件夾)名稱和文件名稱不能爲空!" });
                //實例化minio客戶端
                var minio = new MinioClient(_configuration["Minio:endpoint"], _configuration["Minio:accessKey"], _configuration["Minio:secretKey"]);
                //移除文件
                await minio.RemoveObjectAsync(bucketName, objextName);
                return new JsonResult(new
                {
                    message = "移除資源文件成功",
                    success = true
                });
            }
            catch (Exception ex)
            {
                return new JsonResult(new
                {
                    message = ex.Message,
                    success = false
                });
            }
        }

這裏的話只列舉以上幾個較常用的api,MinIO其實還提供了很多api,大家可以慢慢研究。

 到此MinIO就介紹完了,大家可以根據自己需要在進行擴展。

中文官網:http://docs.minio.org.cn

Smiling Face with Smiling Eyes on Microsoft Windows 10 May 2019 Update

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章