storj.io/minio@v0.0.0-20230509071714-0cbc90f649b1/docs/zh_CN/shared-backend/DESIGN.md (about)

     1  介绍 [![Slack](https://slack.min.io/slack?type=svg)](https://slack.min.io)
     2  ------------
     3  
     4  该特性可以让多个Minio实例使用一个共享的NAS存储,而且不需要做什么特殊的设置。文件默认已经做了同步以及加锁。
     5  
     6  目的
     7  ----------
     8  
     9  由于Minio的设计理念是为单租户场景服务,所以用户希望采用在一个存储后端上运行多个Minio实例,这个存储后端可能是一个已有的NAS。Minio支持这种共享存储后端的特性,而且不需要用户做额外的设置。
    10  
    11  
    12  限制
    13  ------------
    14  
    15  * 如果正在执行GetObject(),则PutObject()会阻塞并等待。
    16  * 如果正在执行PutObject()或者GetObject(),则CompleteMultipartUpload()会阻塞并等待。
    17  * 无法
    18  * A CompleteMultipartUpload() is blocked and waits if another PutObject() or GetObject() is in progress.
    19  * 无法运行FS模式作为remote disk RPC。
    20  
    21  ## 如何运行?
    22  
    23  运行共享存储后端的Minio和直接运行在一块独立磁盘的Minio没有啥区别,不需要做额外设置来开启这个特性。访问NAS上的文件默认就会加锁和同步。以下示例将对您选择的每个操作系统上的操作进行阐述:
    24  
    25  ### Ubuntu 16.04 LTS
    26  
    27  示例1: 运行Minio实例在持载在`/path/to/nfs-volume`路径下的共享后端存储。
    28  
    29  On linux server1
    30  ```shell
    31  minio server /path/to/nfs-volume
    32  ```
    33  
    34  On linux server2
    35  ```shell
    36  minio server /path/to/nfs-volume
    37  ```
    38  
    39  ### Windows 2012 Server
    40  
    41  示例1: 运行Minio实例在持载在`\\remote-server\cifs`路径下的共享后端存储。
    42  
    43  On windows server1
    44  ```cmd
    45  minio.exe server \\remote-server\cifs\data
    46  ```
    47  
    48  On windows server2
    49  ```cmd
    50  minio.exe server \\remote-server\cifs\data
    51  ```
    52  
    53  或者共享存储挂载在`D:\`盘.
    54  
    55  On windows server1
    56  ```cmd
    57  minio.exe server D:\data
    58  ```
    59  
    60  On windows server2
    61  ```cmd
    62  minio.exe server D:\data
    63  ```
    64  
    65  架构
    66  ------------------
    67  
    68  ## POSIX/Win32 Locks
    69  
    70  ### Lock process
    71  
    72  在同一个Minio实例中,lock由现有的内存命名空间锁(** sync.RWMutex **等)处理。 为了在许多Minio实例之间同步锁,我们利用Unix上的POSIX`fcntl()`锁定和Windows`LockFileEx()`Win32 API)。 如果相邻Minio实例在同一路径上有任何读锁,则写锁请求会被阻塞。 如果有正在进行的写锁,读锁也是如此。
    73  
    74  ### Unlock process
    75  
    76  
    77  关闭文件描述符(fd)就会将之前获得的锁释放。关闭fd将告诉内核放弃当前进程在路径上保留的所有锁。当相同进程在同一路径上有多个读操作时,这会变得更加棘手,这意味着关闭一个fd也会为所有并发读释放锁。 为了正确地处理这种情况,实现了简单的fd引用计数,多个读操作之间共享相同的fd。 当读操作开始关闭fd时,我们开始减少引用计数,一旦引用计数达到零,我们可以确保没有更多的活跃读操作。 所以我们继续关闭底层文件描述符,这将放弃在路径上保留的读锁。
    78  
    79  这个不适用于写操作,因为对于每个对象总是有一个写和多个读。
    80  
    81  ## 处理并发。
    82  
    83  这里的一个例子显示了如何使用GetObject()处理争用。
    84  
    85  GetObject()持有`fs.json`的一个读锁。
    86  
    87  ```go
    88  	fsMetaPath := pathJoin(fs.fsPath, minioMetaBucket, bucketMetaPrefix, bucket, object, fsMetaJSONFile)
    89  	rlk, err := fs.rwPool.Open(fsMetaPath)
    90  	if err != nil {
    91  		return toObjectErr(err, bucket, object)
    92  	}
    93  	defer rlk.Close()
    94  
    95  ... you can perform other operations here ...
    96  
    97  	_, err = io.Copy(writer, reader)
    98  
    99  ... after successful copy operation unlocks the read lock ...
   100  ```
   101  
   102  对同一个对象的并发PutObject操作
   103  在同一个对象上请求一个并发的PutObject, PutObject()尝试获取一个`fs.json`上的写锁。
   104  
   105  ```go
   106  	fsMetaPath := pathJoin(fs.fsPath, minioMetaBucket, bucketMetaPrefix, bucket, object, fsMetaJSONFile)
   107  	wlk, err := fs.rwPool.Create(fsMetaPath)
   108  	if err != nil {
   109  		return ObjectInfo{}, toObjectErr(err, bucket, object)
   110  	}
   111  	// This close will allow for locks to be synchronized on `fs.json`.
   112  	defer wlk.Close()
   113  ```
   114  
   115  现在从上面的代码片段可以看到,直到GetObject()返回。 以下部分代码将被阻塞。
   116  
   117  ```go
   118  	wlk, err := fs.rwPool.Create(fsMetaPath)
   119  ```
   120  
   121  这咱限制是必须的,以避免给客户端返回损坏的数据。反之亦然,PutObject(),GetObject()也会等待PutObject()完成之后再执行。
   122  
   123  ### 警告 (并发)
   124  
   125  假设有3个Minio服务共享一个存储后端
   126  
   127  minio1
   128  
   129  - DeleteObject(object1) --> 在object1删除操作时持有`fs.json`的锁。
   130  
   131  minio2
   132  
   133  - PutObject(object1) --> 等DeleteObject完毕后进行锁定。
   134  
   135  minio3
   136  
   137  - PutObject(object1) --> (concurrent request during PutObject minio2 checking if `fs.json` exists)
   138  
   139  一旦获取到锁之后,minio2验证文件是否真的存在,以避免获得已被删除的fd的锁。但是这种情况与minio3存在竞争,因为minio3也在尝试写同一个文件。这就存在一种可能,`fs.json`已经被创建了,所以minio2获得的锁就无效,这样就可能会导致数据不一致。
   140  
   141  这是一种已知的问题,而且没办法通过POSIX fcntl锁来解决。这种情况是共享存储后端的限制,请你知晓。