[TOC]
描述: 由于FastDFS本身不能对重复上传的文件进行去重, 所以使用FastDFS时如果多次上传同一张照片,默认都会将其上传到storage服务器中,这样造成磁盘空间的浪费,所以我们可以采用 FastDHT 进行重复文件处理,以达到同一份图片只留存一份。
FastDHT是一个高性能的分布式哈希系统,它是基于键值对存储的,它可以存储大量键值对,例如文件名映射,会话数据和用户相关数据。但它依赖于Berkeley DB作为数据存储的媒介,使用libevent做网络IO处理, 同时需要依赖于libfastcommon。
FastDHT 项目地址: https://github.com/happyfish100/fastdht Berkeley DB 下载地址: https://www.Oracle.com/database/technologies/related/berkeleydb-downloads.html
FastDHT是一个高性能的分布式哈希系统,它是基于键值对存储的,而且它需要依赖于Berkeley DB作为数据存储的媒介,使用libevent做网络IO处理。同时需要依赖于libfastcommon。
在 FastDHT 中,key 包含三个字段:namespace、object ID 和 key name。这三个概念类似于数据库系统的概念:命名空间与数据库名称、对象 ID 与表名称以及键名称与字段名称,由于导入了命名空间和对象 ID,系统更加灵活。
命名空间的目的是解决之间可能的数据冲突多个用户,例如不同的应用程序或产品。 对象ID的目的是方便组织和管理 对象相关数据,如用户数据,提高整体性能。FastDHT 流程: 描述: FastDFS的storage server每次上传均计算文件的hash值,然后从FastDHT服务器上进行查找比对,如果没有返回,则写入hash,并将文件保存;如果有返回,则建立一个新的文件链接(软链),不保存文件。
FastDHT 由客户端决定应该选择哪台服务器,为例避免查表根据key(文件)的hash code来选择服务器,算法描述如下:
计算出key(文件)的hash值hash_codegroup_index = hash_code % group_count new_hash_code = hash_code 高16位和低16位互换server_index = new_hash_code % 组内 server_count为啥计算 server_index 和 group_index 时使用了不同的hash code?
因为如果group_count和组内server_count相等,例如都等于2,那么对于一个组来说,任何key值都将选中其中一台固定的服务器server_index == group_index,所以上述高16位和低16位互换就是为了解决此问题。
部署流程:
Step 1.Berkeley DB 与 fastdht 下载编译安装 (此处安装环境还是Ubuntu并已经安装了FastDFS)
# (1) Berkeley DB 需要认证后下载并解压: # https://download.oracle.com/otn/berkeley-db/db-18.1.40.tar.gz # https://download.oracle.com/otn/berkeley-db/db-18.1.32.tar.gz tar -zxf db-18.1.40.tar.gz -C /usr/local/src/ # 防止编译错误,这是db-18.1.40版本的Bug。 mkdir -vp /usr/local/src/db-18.1.40/docs/{bdb-sql,gsg_db_server} # 进入build_unix目录,必须是这个目录 cd /usr/local/src/db-18.1.40/build_unix # 执行 configure 命令(一定要是进入上面的目录后,使用相对路径执行命令): ../dist/configure --prefix=/usr/local/berkeley-db # 编译并安装 make && make install # 查看安装下目录结构 ls /usr/local/berkeley-db # 词语删除db-18.1.40.tar.gz解压后的文件夹 rm -rf /usr/local/src/db-18.1.40 # (2) 拉取 fastdht 项目并进行编译安装 cd /usr/local/src/ git clone https://github.com/happyfish100/fastdht.git cd /usr/local/src/fastdht # 编译安装 (安装前必须解决依赖问题) 一定要确认是否已经安装了libevent、libevent-devel 和libfastcommon依赖安装包。 apt-get install libevent-dev # 解决db.h文件错误问题 vim /usr/local/src/fastdht/make.sh 27 行: CFLAGS='-Wall -D_FILE_OFFSET_BITS=64 -D_GNU_SOURCE -I/usr/local/berkeley-db/include/ -L/usr/local/berkeley-db/lib/' ./make.sh && ./make.sh install # 查看安装了可执行文件以及配置文件 ls /usr/local/bin/fdht* # /usr/local/bin/fdht_batch_test /usr/local/bin/fdht_get /usr/local/bin/fdht_test_set # /usr/local/bin/fdht_compress /usr/local/bin/fdht_set /usr/local/bin/fdht_test_thread # /usr/local/bin/fdhtd /usr/local/bin/fdht_test # /usr/local/bin/fdht_delete /usr/local/bin/fdht_test_get # 安装成功后fastdht被安装在/etc/fdht目录下,生成3个配置文件 ls /etc/fdht/ # fdht_client.conf fdhtd.conf fdht_servers.conf # (3) 拷贝库文件并重新加载库文件 否则将会报错 cp /usr/local/berkeley-db/lib/libdb-18.so /usr/lib/ && cp /usr/local/berkeley-db/lib/libdb-18.so /usr/lib64/ ldconfig # ldd /usr/local/bin/fdhtd
Step 2.fastdht 相关配置文件设置
# (1) 创建fastdht数据日志存放目录 mkdir -vp /home/fdfs/fdht chown -R fdfs:fdfs /home/fdfs/fdht # (2) 修改 /etc/fdht/fdht_client.conf 配置文件 vi /etc/fdht/fdht_client.conf # 保持持久连接 keep_alive=1 base_path=/home/fdfs/fdht ## 本行前有#表示打开,如果想关闭(注释)此选项,则应该为##开头 #include /etc/fdht/fdht_servers.conf # (3) 修改 /etc/fdht/fdht_servers.conf 配置文件 (单节点) group_count = 1 group0 = 10.10.107.225:11411 # group0 = 10.10.107.226:11411 # (4) 修改 /etc/fdht/fdhtd.conf 配置文件 vi /etc/fdht/fdhtd.conf # 启用fdhtd.conf配置 disabled=false # 绑定监听地址 bind_addr=10.10.107.225 port=11411 # FastDHT数据和日志存放目录 base_path=/home/fdfs/fdht # 该目录必须是已经存在的,前面已经创建过了 bash_path= /fastdfs/fastdht # 文件HASH值存放方式BDB for Berkeley DB store_type = BDB # 缓存大小默认64MB(需要根据实际情况进行配置) cache_size = 128MB # 与前面一样,用指定用户和组来执行程序 run_by_group=fdfs run_by_user=fdfs
Step 3.在 FastDFS Storage 配置文件中设置接入FastDHT (重点)
# 配置/etc/fdfs/目录下的storage.conf vi /etc/fdfs/storage.conf # 检查文件副本并使用FastDHT存储文件索引 check_file_duplicate = 1 # 检查文件副本算法方式 ## hash: four 32 bits hash code ## md5: MD5 signature file_signature_method = hash # 用于存储文件索引(键值对)的命名空间 key_namespace = FastDFS # 将keep_alive设置为1以启用与FastDHT服务器的持久连接 keep_alive = 1 # 您可以使用“#include filename”(不包括双引号)指令加载FastDHT服务器列表 (此处非常注意、注意、#与inclue之间没有空格、没有空格以及其它字符) #include /etc/fdht/fdht_servers.conf
Tips : 非常注意启用include时#include之间不能包含空格(巨坑、巨坑)
Step 4.使用systemd管理fdhtd进程和重启fdhtd、storage服务
# 服务清单单元 tee /lib/systemd/system/fdhtd.service <<'EOF' [Unit] Description=FastDHT daemon service After=network-online.target [Service] Type=forking WorkingDirectory=/home/fdfs/fdht PIDFile=/home/fdfs/fdht/data/fdhtd.pid ExecStart=/usr/local/bin/fdhtd /etc/fdht/fdhtd.conf start ExecStop=/usr/local/bin/fdhtd /etc/fdht/fdhtd.conf stop ExecReload=/usr/local/bin/fdhtd /etc/fdht/fdhtd.conf restart # No artificial start/stop timeout TimeoutSec=3 # Disable OOM kill by Linux kernel OOMScoreAdjust=-1000 [Install] WantedBy=multi-user.target EOF systemctl daemon-reload # 防火墙放行设置 ufw allow 11411/tcp # 重新启动服务 /usr/local/bin/fdhtd /etc/fdht/fdhtd.conf stop systemctl restart fdhtd.service && systemctl status fdhtd.service systemctl restart fdfs_storaged.service && systemctl status fdfs_storaged.service # 执行结果: # ● fdhtd.service - FastDHT daemon service # Loaded: loaded (/lib/systemd/system/fdhtd.service; disabled; vendor preset: enabled) # Active: active (running) since Tue 2021-11-02 22:22:17 CST; 6s ago # Process: 940357 ExecStart=/usr/local/bin/fdhtd /etc/fdht/fdhtd.conf start (code=exited, status=0/SUCCESS) # Main PID: 940359 (fdhtd) # Tasks: 12 (limit: 9414) # Memory: 2.5M # CGroup: /system.slice/fdhtd.service # └─940359 /usr/local/bin/fdhtd /etc/fdht/fdhtd.conf start # Nov 02 22:22:17 elk1 systemd[1]: Starting FastDHT daemon service... # Nov 02 22:22:17 elk1 systemd[1]: Started FastDHT daemon service. # fast* 相关进程查看 $ ps aux | grep "/etc/fd" # fdfs 837401 0.0 0.0 211196 6132 ? Sl Oct30 0:38 /usr/bin/fdfs_trackerd /etc/fdfs/tracker.conf start # fdfs 940039 0.0 0.0 534916 4136 ? Sl 22:12 0:00 /usr/bin/fdfs_storaged /etc/fdfs/storage.conf start # fdfs 940359 0.0 0.0 253952 3436 ? Sl 22:22 0:00 /usr/local/bin/fdhtd /etc/fdht/fdhtd.conf start
Step 5.验证FastDHT文件去重功能。
# (1) 我们三次上传同一个文件,首次上传时同一文件分两次先后上传(串行) root@Master:/tmp/test$fdfs_upload_file /etc/fdfs/client.conf bibi.png group1/M00/00/00/Cgpr4mGBS9yABcwKAAFcGln-TU4047.png # 文件首次上传,即生成软链接指向上传文件 root@Master:/tmp/test$fdfs_upload_file /etc/fdfs/client.conf bibi.png group1/M00/00/00/Cgpr4WGBS92ASA_jAAFcGkEHz3I407.png root@Master:/tmp/test$fdfs_upload_file /etc/fdfs/client.conf bibi.png group1/M00/00/00/Cgpr4mGBS92APWWCAAFcGh4OjGI465.png # (2) 可以看到上传的三个文件指向同一个Cgpr4WGBSxaABHlXAAFcGo7c2Jk187.png副本。Nice root@Master:/tmp/test# find /home/fdfs/storage/data/ -name "Cgpr4*.png" -ctime -0.5 -exec ls -lh {} ; -rw-r--r-- 1 fdfs fdfs 88K Nov 2 22:28 /home/fdfs/storage/data/00/00/Cgpr4WGBSxaABHlXAAFcGo7c2Jk187.png lrwxrwxrwx 1 fdfs fdfs 64 Nov 2 22:31 /home/fdfs/storage/data/00/00/Cgpr4WGBS92ASA_jAAFcGkEHz3I407.png -> /home/fdfs/storage/data/00/00/Cgpr4WGBSxaABHlXAAFcGo7c2Jk187.png lrwxrwxrwx 1 fdfs fdfs 64 Nov 2 22:31 /home/fdfs/storage/data/00/00/Cgpr4mGBS9yABcwKAAFcGln-TU4047.png -> /home/fdfs/storage/data/00/00/Cgpr4mGBSxWAV58oAAFcGo7c2Jk916.png lrwxrwxrwx 1 fdfs fdfs 64 Nov 2 22:31 /home/fdfs/storage/data/00/00/Cgpr4mGBS92APWWCAAFcGh4OjGI465.png -> /home/fdfs/storage/data/00/00/Cgpr4mGBSxWAV58oAAFcGo7c2Jk916.png
WeiyiGeek.FastDHT重复处理
至此完毕!
上面是单实例的FastDHT环境搭建,在实际企业环境中我们可以根据需求搭建 FastDHT 集群。
FastDHT 集群由一个或多个组(group)组成,每个组由一台或多台服务器组成,同组服务器上存储的数据是相同的,数据同步只在同组的服务器之间进行。组内各个服务器是对等的,对数据进行存取时,可以根据key的hash值来决定使用哪台服务器。数据同步采用推(Push)的方式,由源服务器主动将数据同步到本组的其他服务器。
Step 1.FastDHT 集群的安装非常的简单,按照上面单实例流程进行安装宁外一台FastDHT服务,然后分别修改两台主机的fdht_servers.conf,重启后即可使用。
# (1) 配置两台机器的fdht_servers.conf文件 vim /etc/fdhtd/fdht_servers.conf group_count = 2 # FastDHT 集群中划分一个组,改组由两台服务器进行存储索引数据(完全相同,它会实时同步)。 group0 = 10.10.107.225:11411 group0 = 10.10.107.226:11411 # group1 = 10.10.107.227:11411 # (2) 重新两台机器的相关服务 /usr/local/bin/fdhtd /etc/fdht/fdhtd.conf stop systemctl restart fdhtd.service && systemctl status fdhtd.service systemctl restart fdfs_storaged.service && systemctl status fdfs_storaged.service
Step 2.验证FastDHT 集群的去重功能是否正常。
# (1) 上传多份hello.logs root@elk2:/tmp# ls hello.logs root@Slave:/tmp# fdfs_upload_file /etc/fdfs/client.conf hello.logs group1/M00/00/00/Cgpr4WGBUTmAKPrOAAAAHW1scFk00.logs group1/M00/00/00/Cgpr4WGBWruAVSl2AAAAHUTG_1091.logs # (2) 同样只有一个源文件,其它都是链接指向 `Cgpr4WGBUTmAH106AAAAHdiEv7475.logs` root@elk2:/tmp# find /home/fdfs/storage/data/ -name "*.logs" -ctime -0.5 -exec ls -lh {} ; lrwxrwxrwx 1 fdfs fdfs 64 Nov 2 22:54 /home/fdfs/storage/data/00/00/Cgpr4WGBUTmAKPrOAAAAHW1scFk00.logs -> /home/fdfs/storage/data/00/00/Cgpr4WGBUTmAH106AAAAHdiEv7475.logs lrwxrwxrwx 1 fdfs fdfs 64 Nov 2 22:54 /home/fdfs/storage/data/00/00/Cgpr4WGBWruAVSl2AAAAHUTG_1091.logs -> /home/fdfs/storage/data/00/00/Cgpr4WGBUTmAH106AAAAHdiEv7475.logs -rw-r--r-- 1 fdfs fdfs 29 Nov 2 22:54 /home/fdfs/storage/data/00/00/Cgpr4WGBUTmAH106AAAAHdiEv7475.logs # (3) 链接拷贝以及文件打开 root@elk2:/tmp# cp /home/fdfs/storage/data/00/00/Cgpr4WGBUTmAKPrOAAAAHW1scFk00.logs . root@elk2:/tmp# ls -alh -rw-r--r-- 1 root root 29 Nov 2 22:55 Cgpr4WGBUTmAKPrOAAAAHW1scFk00.logs # 此时不再是链接文件。 -rw-r--r-- 1 root root 29 Nov 2 22:48 hello.logs root@elk2:/tmp# cat Cgpr4WGBUTmAKPrOAAAAHW1scFk00.logs Hello World,FastDFS! By Test
Tips : FastDFS不会返回原始文件的索引,返回的全部都是软链接,当所有的软链接都被删除的时候,原始文件也会从FastDFS中被删除。
扩展说明: 使用fdht提供的相关工具操作FastDHT服务
# 设置值 fdht_set /etc/fdht/fdht_client.conf database:user01 name='WeiyiGeek',age=18; # success set key count: 2, fail count: 0 # 读取值 fdht_get <config_file> [namespace:][object id] <key list split by comma> fdht_get /etc/fdht/fdht_client.conf database:user01 name,age; # name=WeiyiGeek # age=18 # 删除值 fdht_delete /etc/fdht/fdht_client.conf database:user01 name; # success delete keys: name # success delete key count: 1, fail count: 0
至此安装搭建配置、验证测试完成!
描述: 当其它文档被上传到FastDFS后,Storage服务端将返回的文件索引(FID),其中文件名是根据FastDFS自定义规则重新生成的而不是原始文件名。
例如: 在使用浏览器访问 http://file.weiyigeek.top/group2/M00/00/89/eQ6h3FKJf_PRl8p4AUz4wO8tqaA688.docx, 显示给用户的文件名会是这样的eQ6h3FKJf_PRl8p4AUz4wO8tqaA688.docx 那FastDFS在进行文件下载时如何恢复原始文件名称。
操作流程:
Step 1.应用系统在上传文件到FastDFS成功时将原始文件名以及”文件索引(FID)”都保存下来(例如:保存到数据库)。Step 2.用户点击下载的时用nginx的域名和FID拼出url,然后在url后面增加一个参数,指定原始文件名。 例如:http://file.weiyigeek.top/group2/M00/00/89/eQ6h3FKJf_PRl8p4AUz4wO8tqaA688.docx?attname=filename.docxStep 3.然后在Nginx上进行如下配置此时Nginx就会截获url中的参数attname,并且在Http响应头中进行展示Content-Disposition "attachment;filename=$arg_attname"
location /group1/M00 { if ($arg_attname ~* .(doc|docx|txt|pdf|zip|rar|xls|xlsx|png|jpeg|jpg)$) { add_header Content-Disposition "attachment;filename=$arg_attname"; } ngx_fastdfs_module; }
Tips : 上面脚本主要功能是通过正则匹配文件后缀,然后将下载文件名改为路径参数attname的值,并返回给客户端。
Step 4.现在要将下载后的文件名称由Cgpr4WGCMMOAamL7AAApDWjxgXI44.xlsx改为设备清单.xlsx, 访问如下下载路径格式即可http://file.weiyigeek.top/group1/M00/00/00/Cgpr4WGCMMOAamL7AAApDWjxgXI44.xlsx?attname=设备清单.xlsx# 浏览器返回的响应头 HTTP/1.1 200 OK Server: nginx/1.20.1 Date: Wed, 03 Nov 2021 06:53:42 GMT Content-Type: application/vnd.openxmlformats-officedocument.spreadsheetml.sheet Content-Length: 10509 Last-Modified: Wed, 03 Nov 2021 06:48:35 GMT Connection: keep-alive Accept-Ranges: bytes Content-Disposition: attachment;filename=%E8%AE%BE%E5%A4%87%E6%B8%85%E5%8D%95.xlsx
WeiyiGeek.FastDFS下载文件重命名
描述: 前面使用nginx支持http方式访问文件,但所有人都能直接访问这个文件服务器,所以有些场景我们需要做一下权限控制。
FastDFS 的权限控制是在服务端开启token验证, 客户端根据文件名、当前unix时间戳、秘钥获取token,然后在地址中带上token参数即可通过http方式访问文件。
操作流程:
(1) 服务端开启token验证, 我们修改/etc/fdfs/http.conf配置文件。
vim /etc/fdfs/http.conf # HTTP默认内容类型 http.default_content_type = application/octet-stream # MIME类型映射文件名 http.mime_types_filename = mime.types # 设置为true表示开启token验证 http.anti_steal.check_token=true # 密钥,它需要与客户端配置文件的 fastdfs.http_secret_key 保持一致。 http.anti_steal.secret_key=WeiyiGeek.top # 设置token失效的时间单位为秒(s) http.anti_steal.token_ttl=1800 # 当检查令牌失败时返回文件的内容 http.anti_steal.token_check_fail = /home/yuqing/fastdfs/conf/anti-steal.jpg # 支持HTTP范围的多区域 http.multi_range.enabed = true
(2) 拷贝Token检查失败时显示的图片以及重启Nginx服务。
cp /usr/local/src/fastdfs/conf/anti-steal.jpg /usr/local/nginx/html/anti-steal.jpg systemctl restart nginx
(3) 客户端生成Token需要文件名称、当前时间以及httpSecretKey参数
/** * 获取访问服务器的token,拼接到地址后面 * * @param filepath 文件路径 group1/M00/00/00/wKgzgFnkTPyAIAUGAAEoRmXZPp876.jpeg * @param httpSecretKey 密钥 * @param ts 当前时间戳 * @return 返回token,如: token=078d370098b03e9020b82c829c205e1f&ts=1508141521 */ public static String getToken(String filepath, String httpSecretKey){ // unix seconds int ts = (int) Instant.now().getEpochSecond(); // token String token = "null"; try { token = ProtoCommon.getToken(getFilename(filepath), ts, httpSecretKey); } catch (UnsupportedEncodingException e) { e.printStackTrace(); } catch (NoSuchAlgorithmException e) { e.printStackTrace(); } catch (MyException e) { e.printStackTrace(); } StringBuilder sb = new StringBuilder(); sb.append("token=").append(token); sb.append("&ts=").append(ts); return sb.toString(); //返回的token是token和时间戳的拼接 }(4) 此时访问文件需要带上生成的token以及unix时间戳,例如http://file.weiyigeek.top/group1/M00/00/00/wKgzgFnkaXqAIfXyAAEoRmXZPp878.jpeg?token=078d370098b03e9020b82c829c205e1f&ts=1508141521
注意事项:
Tips: 如果生成的token验证无法通过,请进行如下两项检查: (1) 确认调用token生成函数(ProtoCommon.getToken),传递的文件ID中没有包含group name。传递的文件ID格式形如:M00/00/00/wKgzgFnkTPyAIAUGAAEoRmXZPp876.jpeg (2) 确认服务器时间基本是一致的,注意服务器时间不能相差太多,不要相差到分钟级别。 Tips: 如果系统文件隐私性较高,可以直接通过fastdfs-client提供的API去访问即可,不用再配置Nginx走http访问。配置Nginx的主要目的是为了快速访问服务器的文件(如图片),如果还要加权限验证,则需要客户端生成token,其实已经没有多大意义, 但是防止爬虫还是非常不错的。描述: 当时使用FastDFS存储一个图片的多个分辨率的备份时,希望只记录源图的FID,并能将其它分辨率的图片与源图关联,此时可以使用从文件方法。
主从文件是指文件ID有关联的文件,一个主文件可以对应多个从文件。
主文件ID = 主文件名 + 主文件扩展名 从文件ID = 主文件名 + 从文件后缀名 + 从文件扩展名
以本场景为例:主文件为原始图片,从文件为该图片的一张或多张缩略图。
流程说明:
先上传主文件(即:原文件),得到主文件FID。然后上传从文件(即:缩略图),指定主文件FID和从文件后缀名,上传后得到从文件FID。java伪代码,如下:
private static Logger logger = Logger.getLogger(FastDFSUtils.class); static{ try { ClientGlobal.init("D:/WorkSpace/app-filesystem/conf/fdfs_client.conf"); } catch (Exception e) { throw new RuntimeException(e); } } public static String uploadFile(String filePath) throws Exception{ String fileId = ""; String fileExtName = ""; if (filePath.contains(".")) { fileExtName = filePath.substring(filePath.lastIndexOf(".") + 1); } else { logger.warn("Fail to upload file, because the format of filename is illegal."); return fileId; } //建立连接 /*.......*/ //上传文件 (主文件点) try { fileId = client.upload_file1(filePath, fileExtName, null); } catch (Exception e) { logger.warn("Upload file "" + filePath + ""fails"); }finally{ trackerServer.close(); } return fileId; } public static String uploadSlaveFile(String masterFileId, String prefixName, String slaveFilePath) throws Exception{ String slaveFileId = ""; String slaveFileExtName = ""; if (slaveFilePath.contains(".")) { slaveFileExtName = slaveFilePath.substring(slaveFilePath.lastIndexOf(".") + 1); } else { logger.warn("Fail to upload file, because the format of filename is illegal."); return slaveFileId; } //建立连接 /*.......*/ //上传文件 (从文件点) try { slaveFileId = client.upload_file1(masterFileId, prefixName, slaveFilePath, slaveFileExtName, null); } catch (Exception e) { logger.warn("Upload file "" + slaveFilePath + ""fails"); }finally{ trackerServer.close(); } return slaveFileId; } public static int download(String fileId, String localFile) throws Exception{ int result = 0; //建立连接 TrackerClient tracker = new TrackerClient(); TrackerServer trackerServer = tracker.getConnection(); StorageServer storageServer = null; StorageClient1 client = new StorageClient1(trackerServer, storageServer); //上传文件 try { result = client.download_file1(fileId, localFile); } catch (Exception e) { logger.warn("Download file "" + localFile + ""fails"); }finally{ trackerServer.close(); } return result; } public static void main(String[] args) { try { String masterFileId = uploadFile("D:/Tmp/apk/t01134ede0e696735e7.png"); System.out.println(masterFileId); download(masterFileId, "D:/Tmp/apk/master.png"); String slaveFileId = uploadSlaveFile(masterFileId, "_120x120", "D:/Tmp/apk/PC.png"); System.out.println(slaveFileId); download(slaveFileId, "D:/Tmp/apk/slave.png"); } catch (Exception e) { logger.error("upload file to FastDFS failed.", e); } } }
上面代码运行后打印的文件Id为:
主文件:group1/M00/00/00/wKhbylJx1zkIAAAAAAApPcQL87AAAAAAQCmDxUAAClV522.png 从文件:group1/M00/00/00/wKhbylJx1zkIAAAAAAApPcQL87AAAAAAQCmDxUAAClV522_120x120.png
Tips : FastDFS中的主从文件只是在文件ID上有联系。FastDFS server端没有记录主从文件对应关系,因此删除主文件,FastDFS不会自动删除从文件。删除主文件后,从文件的级联删除,需要由应用端来实现(程序后端)。
参考地址: http://www.ttlsa.com/fastdfs/fastdfs-experience-sharing