zoukankan      html  css  js  c++  java
  • SeaweedFS在.net core下的实践方案

    一直对分布式的文件储存系统很感兴趣,最开始关注淘宝的TFS(Taobao File System),好像搁浅了,官方地址无法访问,github上面,各种编译问题,无意间发现了SeaweedFS

    链接seaweedfs

    测试了一番,写个应用的文章和.net core实践的短文分享一下

    SeaweedFS如何使用

    SeaweedFS的Releases下面下载成品,1.20(主要原因是懒,不想去编译)

    运行命令

    weed master

    再挂载两个分布的服务

    weed volume -dir="D:/FileService/Volume/1" -max=1000  -mserver="localhost:9333" -port=8080
    weed volume -dir="D:/FileService/Volume/2" -max=1000  -mserver="localhost:9333" -port=8081

    我们在访问一下

    http://localhost:9333/dir/assign

    返回可能是这样的内容

    {"fid":"1,1642d6a0d7","url":"127.0.0.1:8081","publicUrl":"127.0.0.1:8081","count":1}

    我们解释一下

    fid是我们需要的上传的参数

    publicUrl是我们实际上需要上传的地址

    我们这次上传的目标地址是

    http://publicUrl/fid
    http://127.0.0.1:8081/
    1,1642d6a0d7

    上传的参数file是对应的文件,上传类型是form-data,就是标准的html表单提交方式

    返回你的类型可能是

    {
        "name": "150106109346115258.jpg",
        "size": 206354,
        "eTag": "9e663632"
    }

    这个etag,经常做web缓存的人,肯定不陌生,http缓存的策略

    访问地址则为

    http://127.0.0.1:8081/1,1642d6a0d7
    http://127.0.0.1:8081/1/1642d6a0d7
    http://127.0.0.1:8081/1/1642d6a0d7/150106109346115258.jpg

    SeaweedFS支持多数据中心,这个在官方github有提到,SeaweedFS自带健康检查,内部走的GRPC做健康检查,所以请保持分布的服务端口,外界可访问,无论是docker还是虚拟机、VPS,最终上传还是走的那个端口

    .Net Core下的实践

    我们先把两个返回的实体对象做一下

        public class SeaweedFSDirAssignModel
        {
            public string Fid { get; set; }
            public string Url { get; set; }
            public string PublicUrl { get; set; }
            public int Count { get; set; }
        }
        public class SeaweedFSUploadResponse
        {
            public string Name { get; set; }
            public int Size { get; set; }
            public string ETag { get; set; }
        }

    我们再根据这两个实体,设计一个上传服务

        public interface IFileService
        {
            Task<SeaweedFSDirAssignModel> GetUploadFileUrlAsync();
    
            Task<SeaweedFSUploadResponse> UploadFileAsync(string url,byte[] context);
        }

    再设计一个注入的参数

        public class SeaweedFSServiceConfiguration
        {
            public string BaseUrl { get; set; } = "localhost:9333";
            public string DirAssign { get; set; } = "/dir/assign";
        }

    DirAssign这个是默认的参数,如果要用数据中心的话,这个就可以自定义修改了

        public class SeaweedFSService : IFileService
        {
            private SeaweedFSServiceConfiguration Configuration { get; }
    
            public SeaweedFSService(IOptions<SeaweedFSServiceConfiguration> options)
            {
                Configuration = options.Value;
            }
    
            public async Task<SeaweedFSDirAssignModel> GetUploadFileUrlAsync()
            {
                using (var client = HttpClientFactory.Create())
                {
                    var url = $"http://{Configuration.BaseUrl}{Configuration.DirAssign}";
                    var response = await client.GetAsync(url);
                    var body = await response.Content.ReadAsStringAsync();
                    var json = JsonConvert.DeserializeObject<SeaweedFSDirAssignModel>(body);
    
                    return json;
                }
            }
    
            public async Task<SeaweedFSUploadResponse> UploadFileAsync(string url, byte[] context)
            {
                using (var client = HttpClientFactory.Create())
                {
                    using (var multipartContext = new MultipartFormDataContent())
                    {
                        multipartContext.Add(
                            new ByteArrayContent(
                                context
                            ),
                            "file"
                        );
    
                        var fileUrl = $"{url}";
                        var response = await client.PostAsync(fileUrl, multipartContext);
                        var body = await response.Content.ReadAsStringAsync();
                        var json = JsonConvert.DeserializeObject<SeaweedFSUploadResponse>(body);
    
                        return json;
                    }
                }
            }
        }

    在Startup.cs的注入一下

            public void ConfigureServices(IServiceCollection services)
            {
                services.AddMvc().SetCompatibilityVersion(CompatibilityVersion.Version_2_1);
    
                #region 注入服务
                services.Configure<SeaweedFSServiceConfiguration>(options=> new SeaweedFSServiceConfiguration());
                services.AddScoped<IFileService, SeaweedFSService>();
                #endregion
            }

    测试文件上传

    先写一个扩展方法,我们希望看见的返回地址是

    http://127.0.0.1:8081/1,1642d6a0d7
    http://127.0.0.1:8081/1/1642d6a0d7

    这个地址的后者

    实现如下

        internal static class SeaweedFSDirAssignModelExtension
        {
            public static string ToFileName(this SeaweedFSDirAssignModel response)
            {
                var splits = response.Fid.Split(",".ToCharArray(), StringSplitOptions.RemoveEmptyEntries);
    
                if (splits.Length != 2)
                    throw new ArgumentException($"String Split Fail, value:{response.Fid}");
    
                return $"{splits[0]}/{splits[1]}";
            }
        }

    写一个控制器测试上传

    构建一下返回参数和入参

        public class UploadFileResponseModel
        {
            public string FileName { get; set; }
        }
        public class UploadFileRequestModel
        {
            public IFormFile File { get; set; }
        }

    控制器代码如下

        [Route("api/[controller]")]
        [ApiController]
        public class FileController : ControllerBase
        {
            private IFileService FileService { get; }
    
            public FileController(IFileService fileService)
            {
                FileService = fileService;
            }
    
            [HttpPost("Upload")]
            public async Task<UploadFileResponseModel> Upload([FromForm]UploadFileRequestModel param)
            {
                #region IO读取
                var stream = param.File.OpenReadStream();
                var bytes = new byte[param.File.Length];
                await stream.ReadAsync(bytes, 0, bytes.Length);
                #endregion
    
                var fileInfo = await FileService.GetUploadFileUrlAsync();
                var url = $"http://{fileInfo.PublicUrl}/{fileInfo.Fid}";
                var uploadResponse = await FileService.UploadFileAsync(url, bytes);
    
                return new UploadFileResponseModel()
                {
                    FileName = $"{fileInfo.ToFileName()}"
                };
            }
        }

    我们用postman测试一下

    ok,上传成功,我们访问

    http://localhost:9333/4,1ca657cf3f
    http://localhost:9333/4/1ca657cf3f
    http://127.0.0.1:8080/4,1ca657cf3f
    http://127.0.0.1:8080/4/1ca657cf3f

    前面两个地址会转跳到后面两个地址

    后记

    我这代码测试,会出现,不返回name字段的情况

    {
        "name": "150106109346115258.jpg",
        "size": 206354,
        "eTag": "9e663632"
    }

    这种json格式是直接上传的返回

    但是我们这个上传服务会变成

    {
        "size": 206354,
        "eTag": "9e663632"
    }

    我见了鬼了,谁有发现原因,请告诉我一下,拜托了

  • 相关阅读:
    python lambda函数的用法
    python 中is 和 ==的区别
    Mongo 聚合函数 $group方法的使用
    mongo聚合
    当mongo数据库报错关于 Failed global initialization:
    python 中字符串的拼接
    python eval()用法报错 SyntaxError: unexpected EOF while parsing
    高性能MySQL(六):选择合适的存储引擎
    高性能MySQL(五):存储引擎
    高性能MySQL(四):多版本并发控制
  • 原文地址:https://www.cnblogs.com/NCoreCoder/p/10254503.html
Copyright © 2011-2022 走看看