文件存储系统学习笔记

...

Posted by 呆贝斯 on December 15, 2022

简介

go-fastdfs是基于HTTP协议的分布式文件系统,大道至简,运维和扩展更简单,高性能、高可靠、无中心、免维护。

最佳实践

  1. 海量存储不开启文件token认证功能。
  2. 尽量标准上传,上传后业务保存Path,在业务使用时再拼接域名。
  3. 断点续传,上传后要用文件id置换成Path。
  4. 尽量使用物理服务器部署,主要压力或性能在IO。
  5. 避免小文件合并,后期无法删除小文件。
  6. 线上业务尽量使用Nginx+go-fastdfs部署架构(均衡算法使用ip_hash),以满足后面的功能扩展性(nginx+lua)。

集群部署图

海量集群安装

go-fastdfs配置

{
  "绑定端号": "端口",
  "addr": ":8080",
  "是否开启https": "默认不开启,如需启开启,请在conf目录中增加证书文件 server.crt 私钥 文件 server.key",
  "enable_https": false,
  "PeerID": "集群内唯一,请使用0-9的单字符,默认自动生成",
  "peer_id": "0",
  "本主机地址": "本机http地址,默认自动生成(注意端口必须与addr中的端口一致),必须为内网,自动生成不为内网请自行修改,下同",
  "host": "http://10.0.4.7:8080",
  "集群": "集群列表,注意为了高可用,IP必须不能是同一个,同一不会自动备份,且不能为127.0.0.1,且必须为内网IP,默认自动生成",
  "peers": ["http://10.0.4.7:8080"],
  "组号": "用于区别不同的集群(上传或下载)与support_group_manage配合使用,带在下载路径中",
  "group": "group1",
  "是否支持按组(集群)管理,主要用途是Nginx支持多集群": "默认支持,不支持时路径为http://10.1.5.4:8080/action,支持时为http://10.1.5.4:8080/group(配置中的group参数)/action,action为动作名,如status,delete,sync等",
  "support_group_manage": true,
  "是否合并小文件": "默认不合并,合并可以解决inode不够用的情况(当前对于小于1M文件)进行合并",
  "enable_merge_small_file": false,
  "允许后缀名": "允许可以上传的文件后缀名,如jpg,jpeg,png等。留空允许所有。",
  "图片是否缩放": "默认是",
  "enable_image_resize": true,
  "图片最大宽度": "默认值2000",
  "image_max_width": 2000,
  "图片最大高度": "默认值1000",
  "image_max_height": 1000,
  "extensions": [],
  "重试同步失败文件的时间": "单位秒",
  "refresh_interval": 1800,
  "是否自动重命名": "默认不自动重命名,使用原文件名",
  "rename_file": false,
  "是否支持web上传,方便调试": "默认支持web上传",
  "enable_web_upload": true,
  "是否支持非日期路径": "默认支持非日期路径,也即支持自定义路径,需要上传文件时指定path",
  "enable_custom_path": true,
  "下载域名": "用于外网下载文件的域名",
  "download_domain": "",
  "场景列表": "当设定后,用户指的场景必项在列表中,默认不做限制(注意:如果想开启场景认功能,格式如下:'场景名:googleauth_secret' 如 default:N7IET373HB2C5M6D ",
  "scenes": [],
  "默认场景": "默认default",
  "default_scene": "default",
  "是否显示目录": "默认显示,方便调试用,上线时请关闭",
  "show_dir": false,
  "邮件配置": "",
  "mail": {
        "user": "abc@163.com",
        "password": "abc",
        "host": "smtp.163.com:25"
  },
  "告警接收邮件列表": "接收人数组",
  "alarm_receivers": [],
  "告警接收URL": "方法post,参数:subject,message",
  "alarm_url": "",
  "下载是否需带token": "真假",
  "download_use_token": false,
  "下载token过期时间": "单位秒",
  "download_token_expire": 600,
  "是否自动修复": "在超过1亿文件时出现性能问题,取消此选项,请手动按天同步,请查看FAQ",
  "auto_repair": true,
  "文件去重算法md5可能存在冲突,默认md5": "sha1|md5",
  "file_sum_arithmetic": "md5",
  "管理ip列表": "用于管理集的ip白名单,如果放开所有内网则可以用 0.0.0.0 ,注意为了安全,不对外网开放",
  "admin_ips": ["127.0.0.1"],
  "是否启用迁移": "默认不启用",
  "enable_migrate": false,
  "文件是否去重": "默认去重",
  "enable_distinct_file": true,
  "是否开启跨站访问": "默认开启",
  "enable_cross_origin": true,
  "是否开启Google认证,实现安全的上传、下载": "默认不开启",
  "enable_google_auth": false,
  "认证url": "当url不为空时生效,注意:普通上传中使用http参数 auth_token 作为认证参数, 在断点续传中通过HTTP头Upload-Metadata中的auth_token作为认证参数,认证流程参考认证架构图",
  "auth_url": "",
  "下载是否认证": "默认不认证(注意此选项是在auth_url不为空的情况下生效)",
  "enable_download_auth": false,
  "默认是否下载": "默认下载",
  "default_download": true,
  "本机是否只读": "默认可读可写",
  "read_only": false,
  "是否开启断点续传": "默认开启",
  "enable_tus": true,
  "同步单一文件超时时间(单位秒)": "默认为0,程序自动计算,在特殊情况下,自已设定",
  "sync_timeout": 0
}

Nginx配置

worker_processes  auto;
events {
    worker_connections  1024;
}
http {
    include       mime.types;
    default_type  application/html;
    log_format  main  '$remote_addr - $remote_user [$time_local] "$request" '
                    '$status $body_bytes_sent "$http_referer" '
                    '"$http_user_agent" "$http_x_forwarded_for"';
    access_log  /var/log/nginx/access.log  main;
    error_log  /var/log/nginx/error.log  error;
    sendfile        on;
    keepalive_timeout  65;
    rewrite_log on;
    client_max_body_size 0;
    proxy_redirect ~/(\w+)/big/upload/(.*) /$1/big/upload/$2;  #继点续传一定要设置(注意)
    #以下是一下横向扩展的配置,当前统一大集群容量不够时,只要增加一个小集群,也就是增加一个
    #upstream ,一个小群集内按业务需求设定副本数,也就是机器数。
    upstream gofastdfs-group1 {
        server 10.1.51.70:8082;
        #server 10.1.14.37:8082;
        ip_hash;     #notice:very important(注意)
    }
    upstream gofastdfs-group2 {
        server 10.1.51.70:8083;
        #server 10.1.14.36:8083;
        ip_hash;     #notice:very important(注意)
    }

    server {
        listen       8001;
        server_name  localhost;

        if ( $request_uri ~ /godfs/group ) {
            # 注意group会随组的前缀改变而改变
            rewrite ^/godfs/(.*)$ /$1 last;
        }
        
        location ~ /group(\d) { 
            #统一在url前增加godfs,以便统一出入口。
            proxy_set_header Host $host;
            proxy_set_header X-Real-IP $remote_addr;
            proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; 
            proxy_pass http://gofastdfs-group$1;
        }
        
        location ~ /godfs/upload { 
            #这是一个横向扩展配置,前期可能只有一个集群group1,当group1满后,只需将上传指向group2,
            #也就是将rewrite , proxy_pass 中的group1改为group2即可。
            proxy_set_header Host $host;
            proxy_set_header X-Real-IP $remote_addr;
            proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; 
            rewrite ^/godfs/upload /group1/upload break;
            proxy_pass http://gofastdfs-group1;
        }
        
        location ~ /godfs/big/upload { 
            #以上上类似。
            proxy_set_header Host $host;
            proxy_set_header X-Real-IP $remote_addr;
            proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; 
            rewrite ^/godfs/upload /group1/big/upload break;
            proxy_pass http://gofastdfs-group1;
        }
    }
}

认证

Google认证码认证

用户自定义认证

示例:

  1. 安装依赖包
     pip install flask requests
    
  2. 启动认证服务
     from flask import  Flask,request
     app = Flask(__name__)
     @app.route('/',methods=["GET", "POST"])
     def index():
         auth_token = request.form.get("auth_token") # check auth_token here
         print(auth_token)
         if auth_token=='abc':
             return 'ok' #success
         else:
             return 'fail'
     if __name__ == '__main__':
     app.run(host='0.0.0.0',debug=True)
    

    python app.py

  3. 配置认证url “auth_url”: “http://127.0.0.1:5000”

  4. 上传示例
     import requests
     url = 'http://10.1.5.9:8080/group1/upload'
     files = {'file': open('report.xls', 'rb')}
     options={'output':'json','path':'','scene':'','auth_token':'abc'} #参阅浏览器上传的选项
     r = requests.post(url,data=options, files=files)
     print(r.text)