图床项目总结

1. fastdfs 、nginx 文件管理模块

1. 1 fastdfs 三大组件

1.1.1 tracker server

相当于一个调度器 ,其内部不存储文件,只存储storage 服务器相关的一些元信息(存在于内存中) ,通过连接storage后由storage汇报的信息 生成的,根据这些信息 组成一个 group --> storage 的关联信息。

当需要上传文件的时候,

  1. 分配goup : 客户端先访问tracker ,tracker根据负载均衡的策略(比如:某个剩余空间大的storage服务器),分配一个group;
  2. 分配storage :然后再到group中选择一个storage 并给出path;
  3. 客户端访问storage: 客户端将向storage发送写文件请求,storage将会为文件分配一个数据存储目录

配置tracker : 只需要配置data和logs路径!

1.1.2 storage server

真正存储文件的服务器,其中经过tracker的分配,会有一个逻辑上的组:group ,每个group中含有多个storage ,互为备份 ,当上传文件的时候选择其中一个上传,其余storage后续通过binlog日志进行同步 。一般内部会有 256*256个子目录 去存储文件。比如 00/00/ 00/01等。
当文件上传的时候:

  1. 记录Fileid :storage会为文件生成一个Fileid,由:storage server ip、文件创建时间、文件大小、文件crc32和一个随机数拼接而成,然后将这个二进制串进行base64编码,转换为可打印的字符串。
  2. 存储到两级目录: 每个存储目录下有两级256*256的子目录,storage会按文件fileid进行两次hash(猜测),路由到其中一个子目录,然后将文件以fileid为文件名存储到该子目录下
  3. 生成文件名: 当文件存储到某个子目录后,即认为该文件存储成功,接下来会为该文件生成一个文件名,文件名由:group、存储目录、两级子目录、fileid、文件后缀名(由客户端指定,主要用于区分文件类型)拼接而成。

    配置storage: ① 需要设置好data的存储位置;② 需要设置好M00的映射地址(真正的物理地址)

1.1.3 client

提供的一个客户端,相当于需要往fastdfs中输入一些指令 upload xx xx 、download xx xx

1.1.4 fastdfs-nginx-module 下载文件

该模块是fastdfs中长期使用的稳定模块,而且配置文件的路径和storage一致,这个模块的作用

  1. 如果没有此模块:
    • 后端从数据库取出文件ID: 如 group1/M00/00/00/xxx.txt
    • 后端连接Tracker : 调用指令获取文件所在的地址
    • 后端发送读取请求,获取文件流: 调用指令读取文件
    • 后端返回文件流给前端
  2. 如果有此模块:
    • 后端只返回一个 HTTP URL 给前端: http://10.0.0.1:80/group1/M00/00/00/xxx.txt
    • 前端直接使用URL下载: 前端直接使用这个 URL 下载(<a 标签或 window.open),流量直接从 Nginx 流向客户端,不经过业务后端

1. 2 nginx 模块

nginx-upload-module用于上传文件
如果没有该模块,则上传文件的二进制内容 全都要放在请求体中 ,数据解析困难 。
引入该模块之后,便可以在nginx层面解析multipart/form-data ,将文件保存到临时目录 ,然后生成包含文件信息的变量 (如$upload_tmp_path等),再将请求转发到后端 (如/api/upload),后端从变量或环境变量中获取文件路径来处理。

2. 文件上传

2.0 文件秒传

其实就是根据MD5,查看file_info中是否已经存在相同MD5的文件,如果已经存在则再去查user_file_list中有没有,如果没有则添加一条记录,并且把file_info的引用计数 +1。
如果秒传失败,则触发2.1

2.1 上传

经过nginx-upload-file 模块的recv的数据是和前端调用axios后发送的有所不同!

  1. content解析: 其中content 以一个WebKitFormBoundaryjWE3qXXORSg2hZiB分割,进行filename、filetype、md5等信息的解析;
  2. 文件名拼接: 在经过nginx模块上传后,文件统一去掉了后缀名,这里找到type和filename进行拼接即可;
  3. fastdfs命令上传: 用到了进程间通信 ,需要执行fdfs_upload_file(指令) /etc/fdfs/client.conf(配置文件路径) 123.txt(文件) ,此步骤完成后可以获取到 group1/M00/00/00/xxx.txt
    • pipe(int fd[2]) : 创建一个无名管道,其中fd0 表示读端 ,fd1 表示写端;
    • pid_t pid = fork() : 创建子进程,子进程会完全复制父进程的地址空间,但是区分pid;
    • 子进程: pid = 0 则说明是子进程
      • 关闭读端,保留写端;
      • 将标准输出重定向到写管道;
    • 父进程: pid = 1 则说明是父进程
      • 关闭写端,保留读端;
      • 设置读取数据的端 read(fd[0], fileid, TEMP_BUF_MAX_LEN) ,读取数据到fileid中
    • wait(NULL)/close(fd[0]) : 等待子进程结束,并关闭挥手
  4. 完整路径:
    • 依旧使用父子进程方式,执行命令fdfs_file_info ,获取ip
    • 拼接 http:// + ip + group1/M00/00/00/xxx.txt
  5. 数据库持久化: 将上传文件信息插入表做持久化,file_info 插入一条,user_file_list 插入一条;

父子间进程通信的原理: 可以使用popen() 是在fork()、pipe()之上的封装

在fork()创建子进程后,共享父进程的数据 (也就是说父子进程皆可以访问管道的读写端,持有其fd ),如果是在此之前创建了pipe() ,那么父子进程都会有pipe读端和写端的引用 ,如果写端引用不为0 ,则无法在读端读取数据,因此需要关闭子进程的读和父进程的写!

2. 注册登录

相关推荐
hhhjhl6 小时前
Protobuf.js 跨端三方库仓颉适配全流程
javascript·网络·udp
ITxiaobing20238 小时前
中国公司海外广告投放的 IP 地址库选型:从“查归属”到“验真实”的工程视角
网络·网络协议·tcp/ip
KKKlucifer8 小时前
运营商非结构化文档安全管控体系建设实践
大数据·网络·安全
网络小江10 小时前
组网第35课:静态路由——下一跳、出接口、默认路由、浮动静态与黑洞路由
服务器·网络·默认路由·黑洞路由·浮动静态路由
acrel710 小时前
医院用电隐患治理与节能降耗及智慧能源平台应用
网络·数据库
Escalating_xu11 小时前
【Linux 网络编程】应用层协议 HTTP(下):Header、连接管理与 C++ HTTP 服务器
linux·服务器·网络
明天也要努力学习13 小时前
TCP 协议的相关特性
网络·网络协议·tcp/ip
qq_4017004113 小时前
100 个 IoT 小项目,给 ESP32 入门补上实操
前端·网络·stm32
2401_8734794013 小时前
源IP告警太多用什么工具分层?ASN与风险评分操作指南
网络·网络协议·tcp/ip