图床项目总结

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 : 只需要配置datalogs路径!

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 xxdownload 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]) : 创建一个无名管道,其中fd[0] 表示读端 ,fd[1] 表示写端;
    • 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. 注册登录

相关推荐
Dream of maid3 小时前
Python12(网络编程)
开发语言·网络·php
minji...4 小时前
Linux 线程同步与互斥(三) 生产者消费者模型,基于阻塞队列的生产者消费者模型的代码实现
linux·运维·服务器·开发语言·网络·c++·算法
运维行者_5 小时前
OpManager MSP NetFlow Analyzer集成解决方案,应对多客户端网络流量监控挑战
大数据·运维·服务器·网络·数据库·自动化·运维开发
dashizhi20156 小时前
共享文件禁止拖动本地磁盘、共享文件禁止另存为、禁止打印共享文件、禁止复制共享文件的方法
运维·服务器·网络·安全·电脑
网教盟人才服务平台6 小时前
AI 全面重塑网络攻防生态,智能安全进入深度对抗时代
网络·人工智能·安全
头铁的伦9 小时前
QNX 网络模型
linux·网络·车载系统
小贾要学习9 小时前
【Linux】TCP网络通信编程
linux·服务器·网络·c++·网络协议·tcp/ip
vortex59 小时前
构建可审计、可分层、可扩展的SSH身份管理体系
网络·ssh·php
Hello_Embed10 小时前
嵌入式上位机开发入门(十九):Socket 状态检测与断线重连
网络·单片机·网络协议·tcp/ip·嵌入式
cheems952710 小时前
[SpringMVC]Cookie 和Session 从无状态协议到状态保存实务
网络·http