使用s3fs-fuse挂载minio文件时无法删除问题排查过程

结论:部分场景无法满足,具体问题详见正文

1. 部署minio

docker run    -p 9000:9100    -p 9090:9190    --name minio    -v /opt/minio/data:/data    -e "MINIO_ROOT_USER=admin"    -e "MINIO_ROOT_PASSWORD=minio123.com"    quay.io/minio/minio server /data --console-address ":9090"

登录minio页面并创建桶

2. 安装s3fs-fuse

直接安装或者下载源码编译安装:https://github.com/s3fs-fuse/s3fs-fuse

启动s3fs服务挂载minio桶到本地,如:

 /usr/bin/s3fs -d data /data -f -o url=http://191.168.3.132:9100,passwd_file=/etc/passwd-s3fs,endpoint
=us-east-1,allow_other,use_cache=/tmp,max_stat_cache_size=1000,stat_cache_expire=900,retries=5,connect_timeout=10,use_pa
th_request_style

其中/etc/passwd-s3fs为用户密码,格式为:

用户名:密码

3. 测试上传下载

使用touch、echo、rm、cp等均可以,查看minio UI可以看见上传的文件,看似一切正常。

4. 发现文件夹无法删除问题

验证过程中发现先解压后删除长时间等待后删除报错,复现步骤:

LAPTOP-TC4A0SCV:/data/test4#tar xzf s3fs-fuse-1.93.tar.gz
LAPTOP-TC4A0SCV:/data/test4# rm -rf s3fs-fuse-1.93/test/
rm: can't remove 's3fs-fuse-1.93/test': I/O error

删除文件夹无法删除掉,但是文件夹下面的文件均已经被删除,就剩下无法删除文件夹本身了,但是通过minio UI管理界面可以删除,同时再删除本地文件夹。

5. 确认是否是s3fs的问题

由于s3fs-fuse工具是C++编写的二进制文件,打算利用Wireshark工具去抓包看看,抓包删除命令请求如下:

可以看出删除bin目录时出现500错误,并且删除了5次(客户端配置重试次数),查看s3fs的日志如下:

2024-01-04T10:24:59.217Z [INF]       curl_util.cpp:url_to_host(334): url is http://191.168.3.132:9100
2024-01-04T10:24:59.220Z [INF]       curl.cpp:RequestPerform(2520): HTTP response code 204
2024-01-04T10:24:59.220Z [INF]       cache.cpp:DelStat(596): delete stat cache entry[path=/test3/spark-3.5.0-bin-hadoop3/yarn/spark-3.5.0-yarn-shuffle.jar]
2024-01-04T10:24:59.220Z [INF]       cache.cpp:DelSymlink(754): delete symbolic link cache entry[path=/test3/spark-3.5.0-bin-hadoop3/yarn/spark-3.5.0-yarn-shuffle.jar]
2024-01-04T10:24:59.220Z [INF]       fdcache.cpp:DeleteCacheFile(139): [path=/test3/spark-3.5.0-bin-hadoop3/yarn/spark-3.5.0-yarn-shuffle.jar]
2024-01-04T10:24:59.228Z [INF] s3fs.cpp:s3fs_rmdir(1358): [path=/test3/spark-3.5.0-bin-hadoop3/yarn]
2024-01-04T10:24:59.229Z [INF]   s3fs.cpp:list_bucket(3434): [path=/test3/spark-3.5.0-bin-hadoop3/yarn]
2024-01-04T10:24:59.229Z [INF]       curl.cpp:ListBucketRequest(3749): [tpath=/test3/spark-3.5.0-bin-hadoop3/yarn]
2024-01-04T10:24:59.229Z [INF]       curl_util.cpp:prepare_url(257): URL is http://191.168.3.132:9100/data?delimiter=/&max-keys=2&prefix=test3/spark-3.5.0-bin-hadoop3/yarn/
2024-01-04T10:24:59.229Z [INF]       curl_util.cpp:prepare_url(290): URL changed is http://191.168.3.132:9100/data/?delimiter=/&max-keys=2&prefix=test3/spark-3.5.0-bin-hadoop3/yarn/
2024-01-04T10:24:59.229Z [INF]       curl.cpp:insertV4Headers(2892): computing signature [GET] [/] [delimiter=/&max-keys=2&prefix=test3/spark-3.5.0-bin-hadoop3/yarn/] []
2024-01-04T10:24:59.229Z [INF]       curl_util.cpp:url_to_host(334): url is http://191.168.3.132:9100
2024-01-04T10:24:59.231Z [INF]       curl.cpp:RequestPerform(2520): HTTP response code 200
2024-01-04T10:24:59.232Z [INF]       curl.cpp:DeleteRequest(2971): [tpath=/test3/spark-3.5.0-bin-hadoop3/yarn/]
2024-01-04T10:24:59.232Z [INF]       curl_util.cpp:prepare_url(257): URL is http://191.168.3.132:9100/data/test3/spark-3.5.0-bin-hadoop3/yarn/
2024-01-04T10:24:59.232Z [INF]       curl_util.cpp:prepare_url(290): URL changed is http://191.168.3.132:9100/data/test3/spark-3.5.0-bin-hadoop3/yarn/
2024-01-04T10:24:59.232Z [INF]       curl.cpp:insertV4Headers(2892): computing signature [DELETE] [/test3/spark-3.5.0-bin-hadoop3/yarn/] [] []
2024-01-04T10:24:59.232Z [INF]       curl_util.cpp:url_to_host(334): url is http://191.168.3.132:9100
<?xml version="1.0" encoding="UTF-8"?>
<Error><Code>InternalError</Code><Message>We encountered an internal error, please try again.: cause(file is corrupted)</Message><Key>test3/spark-3.5.0-bin-hadoop3/yarn/</Key><BucketName>data</BucketName><Resource>/data/test3/spark-3.5.0-bin-hadoop3/yarn/</Resource><Region>us-east-1</Region><RequestId>17A71DFA043AB078</RequestId><HostId>dd9025bab4ad464b049177c95eb6ebf374d3b3fd1af9251148b658df7ac2e3e8</HostId></Error>2024-01-04T10:24:59.235Z [INF]       curl.cpp:RequestPerform(2590): HTTP response code 500 was returned, slowing down
2024-01-04T10:25:01.295Z [INF] curl.cpp:RequestPerform(2719): ### retrying...

查看minio的日志如下:

API: DeleteObject(bucket=data, object=test3/spark-3.5.0-bin-hadoop3/yarn/)
Time: 10:26:23 UTC 01/04/2024
DeploymentID: 97c76f90-5749-4676-98d1-14441f0a340c
RequestID: 17A71E0352B75EB7
RemoteHost: 191.168.4.38
Host: 191.168.3.132:9100
UserAgent: s3fs/1.93 (commit hash unknown; OpenSSL)
Error: file is corrupted (cmd.StorageErr)
       5: internal/logger/logger.go:259:logger.LogIf()
       4: cmd/api-errors.go:2362:cmd.toAPIErrorCode()
       3: cmd/api-errors.go:2387:cmd.toAPIError()
       2: cmd/object-handlers.go:2720:cmd.objectAPIHandlers.DeleteObjectHandler()
       1: net/http/server.go:2136:http.HandlerFunc.ServeHTTP()

看样子是删除的文件夹无法被minio删除。抓包删除错误相应如下:

<?xml version="1.0" encoding="UTF-8"?>
<Error>
<Code>InternalError</Code>
<Message>We encountered an internal error, please try again.: cause(file is corrupted)</Message>
<Key>test4/s3fs-fuse-1.93/test/</Key>
<BucketName>data</BucketName>
<Resource>/data/test4/s3fs-fuse-1.93/test/</Resource>
<Region>us-east-1</Region>
<RequestId>17A7550F007E8D1B</RequestId>
<HostId>dd9025bab4ad464b049177c95eb6ebf374d3b3fd1af9251148b658df7ac2e3e8</HostId>
</Error>

我在思考,是否是s3fs客户端在请求的时候出现参数错误或者API调用错误导致,需要确认下,是否可以排除s3fs的问题。

6. 抓包s3fs-fuse的网络请求

抓包分为两部分,一部分是对解压请求进行抓包,另外一部分是对删除请求进行抓包。

解压过程如下:

通过观察解压操作,发现刚开始解压的时候调用了一次PUT请求去创建文件夹,请求如下:

PUT /data/test5/ HTTP/1.1
Host: 191.168.3.132:9100
User-Agent: s3fs/1.93 (commit hash unknown; OpenSSL)
Accept: */*
Authorization: AWS4-HMAC-SHA256 Credential=admin/20240105/us-east-1/s3/aws4_request, SignedHeaders=content-type;host;x-amz-content-sha256;x-amz-date;x-amz-meta-atime;x-amz-meta-ctime;x-amz-meta-gid;x-amz-meta-mode;x-amz-meta-mtime;x-amz-meta-uid, Signature=37c32c17df550e31c074e80aebddc2ef4c44d67ce1df0574c312b53733bc85cb
Content-Type: application/x-directory
x-amz-content-sha256: e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855
x-amz-date: 20240105T083218Z
x-amz-meta-atime: 1704443538.826241406
x-amz-meta-ctime: 1704443538.826241406
x-amz-meta-gid: 0
x-amz-meta-mode: 493
x-amz-meta-mtime: 1704443538.826241406
x-amz-meta-uid: 0
Content-Length: 0

解压完成后再次调用了一次PUT请求创建文件夹,请求如下:

PUT /data/test5/ HTTP/1.1
Host: 191.168.3.132:9100
User-Agent: s3fs/1.93 (commit hash unknown; OpenSSL)
Accept: */*
Authorization: AWS4-HMAC-SHA256 Credential=admin/20240105/us-east-1/s3/aws4_request, SignedHeaders=content-type;host;x-amz-content-sha256;x-amz-copy-source;x-amz-date;x-amz-meta-atime;x-amz-meta-ctime;x-amz-meta-gid;x-amz-meta-mode;x-amz-meta-mtime;x-amz-meta-uid;x-amz-metadata-directive, Signature=1a463b97b0c171419791e6d619930618c80e4c37648937f7defaf129da64899d
Content-Type: application/x-directory
x-amz-content-sha256: e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855
x-amz-copy-source: /data/test5/
x-amz-date: 20240105T065914Z
x-amz-meta-atime: 1704437377.849501720
x-amz-meta-ctime: 1704437954.440296576
x-amz-meta-gid: 0
x-amz-meta-mode: 16877
x-amz-meta-mtime: 1704437377.849501720
x-amz-meta-uid: 0
x-amz-metadata-directive: REPLACE
Content-Length: 0

用过查阅S3 API文档,PUT请求为创建对象,其中第二次PUT请求中传递了x-amz-copy-source和x-amz-metadata-directive,对应是复制对象请求。但是为什么解压过程会触发两次请求呢,百思不得其解。

7. 删除报错问题复现

为了找到原因,硬着头皮去查看s3fs-fuse的源码,通过搜索PUT请求和日志发现是chmod命令触发的,也就是解压过程会先调用创建和授权命令,为了验证,进行如下操作:

LAPTOP-TC4A0SCV:/data/test4# ll
total 278
-rw-r-----    1 root     root        284353 Jan  5 09:39 s3fs-fuse-1.93.tar.gz
LAPTOP-TC4A0SCV:/data/test4# mkdir pp
LAPTOP-TC4A0SCV:/data/test4# ll
total 278
drwxr-xr-x    1 root     root             0 Jan  5 14:20 pp
-rw-r-----    1 root     root        284353 Jan  5 09:39 s3fs-fuse-1.93.tar.gz
LAPTOP-TC4A0SCV:/data/test4# chmod 777 pp
LAPTOP-TC4A0SCV:/data/test4# ll
total 278
drwxrwxrwx    1 root     root             0 Jan  5 14:20 pp
-rw-r-----    1 root     root        284353 Jan  5 09:39 s3fs-fuse-1.93.tar.gz
LAPTOP-TC4A0SCV:/data/test4# ll pp
total 0
LAPTOP-TC4A0SCV:/data/test4# rm -rf pp
rm: can't remove 'pp': I/O error
LAPTOP-TC4A0SCV:/data/test4#

果不其然,复现了该问题,创建文件夹后再进行授权的话,会导致文件夹无法被删除。

8. 问题分析排查未果

通过分析mkdir和chmod发出去的PUT请求,唯一区别是请求头中主要多了x-amz-copy-source、x-amz-metadata-directive等,这个标识着到底是新创建对象还是复制或者更新等,其中x-amz-metadata-directive: REPLACE表示的是更新操作。

如果说s3fs-fuse实现的是标准的s3 api,那么是不是可以这样说,minio在实现s3 api的时候没有完全实现呢?通过查看minio的源码,找到了api-router.go的部分代码如下:


// GetObject
router.Methods(http.MethodGet).Path("/{object:.+}").HandlerFunc(
    collectAPIStats("getobject", maxClients(gz(httpTraceHdrs(api.GetObjectHandler)))))
// CopyObject
router.Methods(http.MethodPut).Path("/{object:.+}").HeadersRegexp(xhttp.AmzCopySource, ".*?(\\/|%2F).*?").HandlerFunc(
    collectAPIStats("copyobject", maxClients(gz(httpTraceAll(api.CopyObjectHandler)))))
// PutObjectRetention
router.Methods(http.MethodPut).Path("/{object:.+}").HandlerFunc(
    collectAPIStats("putobjectretention", maxClients(gz(httpTraceAll(api.PutObjectRetentionHandler))))).Queries("retention", "")
// PutObjectLegalHold
router.Methods(http.MethodPut).Path("/{object:.+}").HandlerFunc(
    collectAPIStats("putobjectlegalhold", maxClients(gz(httpTraceAll(api.PutObjectLegalHoldHandler))))).Queries("legal-hold", "") // PutObject with auto-extract support for zip
router.Methods(http.MethodPut).Path("/{object:.+}").HeadersRegexp(xhttp.AmzSnowballExtract, "true").HandlerFunc(
    collectAPIStats("putobject", maxClients(gz(httpTraceHdrs(api.PutObjectExtractHandler))))) // PutObject
router.Methods(http.MethodPut).Path("/{object:.+}").HandlerFunc(
    collectAPIStats("putobject", maxClients(gz(httpTraceHdrs(api.PutObjectHandler))))) // DeleteObject
router.Methods(http.MethodDelete).Path("/{object:.+}").HandlerFunc(
    collectAPIStats("deleteobject", maxClients(gz(httpTraceAll(api.DeleteObjectHandler)))))

其中CopyObject对应的PUT方法和匹配请求头中包含xhttp.AmzCopySource的请求,PutObject对应的是PUT方法请求。查看api.CopyObjectHandler源码,看了一会啥也不看出来,就是不懂,遂放弃。

9. 最后的挣扎

通过自己无法解决时,是否可以求助对象项目的支持呢,随即分别向minio和s3fs-fuse提出了issue,希望可以有解决思路。issue分别如下:

通过等待后,minio给出了回复,先是让找s3fs-fuse项目,然后说是不推荐传统的挂载使用方式,建议社区远离它。回复如下:

We really discourage using filesystem on top of object storage. We wish community embraces and moves away from legacy.

然s3fs-fuse提问没有回复,但是从我的判断来看,出现问题的是minio的问题,可能是实现s3 api接口的时候出现了某种问题,奈何看不懂minio的源码。对于minio和s3 api的关系,minio官方描述如下:

MinIO is a High Performance Object Storage released under GNU Affero General Public License v3.0. It is API compatible with Amazon S3 cloud storage service. Use MinIO to build high performance infrastructure for machine learning, analytics and application data workloads.

既然minio兼容s3 api,那么出现问题的话就是minio对s3 api兼容性实现存在问题。限于本人能力,此问题分析到这里。

总的来说,这种方案满足一般的文件管理,比如上传、下载、删除、读取等等,要达到和普通磁盘一样的操作等,还是无法满足。


  • 博客:https://www.cnblogs.com/flowerbirds
  • Gituhub:https://github.com/FlowerBirds

使用s3fs-fuse挂载minio文件时无法删除问题排查过程的更多相关文章

  1. 【Linux命令】在Linux服务器上与windows通过SCP命令互传文件时出现的问题排查过程

    1,在linux 执行 scp 1.txt adminitrator@10.10.10.10:/d:/后,报连接超时 原因:windows不支持ssh,可以安装支持SSH服务的工具,如:winsshd ...

  2. 解决git push时发现有超过100M的文件时,删除文件后,发现还是提交不上去的问题

    我这里故意放了一个超过100M的文件 后续,git add ,git commit 然后,git push 此时会发现出现了错误.如果,我们再这里直接在文件系统中删除这个大的文件,然后再次提交,会发现 ...

  3. JAVA 创建文件和文件夹,删除文件和文件夹的实用工具

    package com.file; import java.io.File; import java.io.IOException; //创建新文件和目录 public class CCRDFile ...

  4. centos使用fuse挂载NTFS

    FUSE:用户空间文件系统(Filesystem in Userspace),是Linux 中用于挂载某些网络空间,如SSH,到本地文件系统的模块.如果装的是双系统,centOS并不支持ntfs分区, ...

  5. 使用s3fs-fuse 挂载minio s3 对象存储

    minio 是一个aws s3 兼容的对象存储系统,我们可以通过s3fs 进行数据桶的挂载,这样可以做好多方便的事情 环境准备 使用docker-compose 运行 minio docker-com ...

  6. Linux创建和挂载XFS文件系统测试实践

    XFS文件系统简介 维基百科关于XFS的简介如下: XFS is a high-performance 64-bit 年,由Silicon Graphics为他们的IRIX操作系统而开发,是IRIX ...

  7. 如何在 Linux 中挂载 ISO 文件

    在 Windows 中,我们常常使用 Daemon Tools 和 Virtual CloneDrive 等虚拟光驱软件挂载光盘镜像,下面我们一起来学习在 Linux 中如何挂载 ISO 文件. 在 ...

  8. Qt SD卡 文件系统挂载、文件预览

    /********************************************************************************** * Qt SD卡 文件系统挂载. ...

  9. Linux中磁盘还有空间,但创建文件时提示空间不足

    首先需要知道创建文件时,需要满足两个条件:1.磁盘上还有空间:2.inode号还有剩余. 这两个条件可以分别使用"df -h"以及"df -i"查看使用情况 [ ...

  10. Linux下,拷贝文件时,排除某些文件

     一下是自己用到到几次实践,觉得很赞:   1.拷贝文件时,排除某些不需要的文件:   1)使用xargs来做: ls /tmp/test/ |grep -v .gz |xargs -i cp -r ...

随机推荐

  1. SE54视图簇

    一.创建关联表 头表 行表 设置行表的外键  创建两张表的表维护生成器,此处不再展开 二.SE54视图簇 激活上述 三.创建事务代码维护 四.效果展示 定期更文,欢迎关注 TRANSLATE with ...

  2. modint 板子

    自动对 int 取模 // modint template<int MOD> struct Fp { ll val; constexpr Fp(ll v = 0) noexcept : v ...

  3. 极速生成缩略图,Serverless 支撑赛事转播锁定冬奥亮点

    作者 | 西流.筱姜 ​ "北京冬奥会在开赛的第四天便成为了历史上收视最高的一届冬奥会,其转播内容总生产量将达 6000 小时,超过平昌冬奥会的 5400 小时.关注北京冬奥会的人群比往届都 ...

  4. vue用qrcodejs2生成二维码,解决多个二维码追加的问题

    vue使用qrcodejs2生成二维码 1.安装qrcodejs2 npm install qrcodejs2 2.代码 //导入组件 import QRCode from 'qrcodejs2' / ...

  5. oppo和海康嵌入式软件工程师面经总结

    目录 海康 一面(3.23,35min) 自我介绍 项目介绍 你做的这个项目遇到了那些问题,如何解决的? 移植uboot,只做了移植吗? 用的那个文件系统? 移植过程中,网卡驱动做了那些工作? 写过那 ...

  6. C#爬虫知识介绍

    爬虫 爬虫(Web Crawler)是指使用程序自动获取互联网上的信息和数据的一种技术手段.它通常从一个起始网址出发,按照一定的规则递归地遍历网页,并将有用的信息提取出来,然后存储到本地或者数据库中, ...

  7. ASP.NET Core 5.0 MVC 页面标记帮助程序的使用

    什么是标记帮助程序 标记帮助程序使服务器端代码可以在 Razor 文件中参与创建和呈现 HTML 元素.标记帮助程序使用 C# 创建,基于元素名称.属性名称或父标记以 HTML 元素为目标. 创建标记 ...

  8. chage详解:liunx账户密码过期时处理

    公司安装elasticSearcher7.10.2版本时提示账户密码过期,可以做以下的处理方式: 一.查看账户的使用情况 chage -l baikang [root@localhost ~]# ch ...

  9. Git | git branch 分支操作

    假设我们已经有了稳定的代码,现在我想整一些花活.比较安全的一个方式是,在新的分支上整活. 新建 vga 分支:git branch vga,然后切换到 vga 分支:git switch vga,或者 ...

  10. Redis 缓存与数据库数据不一致问题

    Redis缓存与数据库数据不一致问题是指在使用Redis作为缓存系统时,由于缓存和数据库之间的操作没有同步或处理不当,导致缓存中的数据与数据库中的数据不同步,产生数据不一致的情况. 现象: 数据库更新 ...