项目中遇到的一些问题总结(六)

Minio是一个使用纠删码技术确保数据安全的分布式对象存储系统,而MySQL的可重复读隔离级别通过MVCC保证事务一致性。Minio通过分块和校验块存储确保数据完整性,即使部分磁盘故障也能恢复。MySQL可重复读隔离级别下,事务只能看到在开始时已经提交的数据,防止脏读和不可重复读,但可能导致幻读和丢失更新问题。
摘要由CSDN通过智能技术生成

Minio

Minio是一个开源的分布式对象存储系统,它使用纠删码技术来保护数据。纠删码技术是一种恢复丢失和损坏数据的数学算法,它将数据分块冗余的分散存储在各个节点的磁盘上,从而提供了一定程度的数据可靠性和冗余性。
在Minio中,所有可用的磁盘组成一个集合,当上传一个文件时,该文件会通过纠删码算法进行分块存储。具体来说,除了将文件本身分成若干个数据块,还会生成若干个校验块。数据块和校验块会分散的存储在这些磁盘上,这样即使某些磁盘出现了故障或损坏,仍然可以通过计算校验块来恢复数据。

例如,如果Minio集合中有8个硬盘,上传一个文件时将其分成4个数据块和4个校验块,然后将它们分别存储在这8个硬盘上。如果其中最多有4个硬盘损坏,Minio仍然可以通过计算校验块来恢复数据,不影响上传和下载操作。但如果有超过4个硬盘损坏,就无法恢复数据了。
因此,Minio使用纠删码技术可以提高数据的可靠性和冗余性,从而保证数据的安全性和可用性。

io.minio:minio:8.4.3

这是MinIO的官方Java客户端,可以用于与MinIO服务器进行交互。该依赖项提供了一组Java API,可以用于创建、读取、更新和删除对象(bucket)、管理桶(bucket)、设置策略、生成预签名URL等操作。使用该依赖项,可以轻松地在Java应用程序中与MinIO进行交互,从而实现文件的上传、下载和管理等功能。

com.squareup.okhttp3:okhttp:4.8.1

这是一个流行的Java HTTP客户端库,用于与HTTP服务器进行交互。在MinIO客户端中,该依赖项用于实现与MinIO服务器的HTTP通信。它提供了一组Java API,可以用于发送HTTP请求和处理HTTP响应。使用该依赖项,可以轻松地在Java应用程序中与MinIO服务器进行通信,从而实现文件的上传、下载和管理等功能。
综上所述,这两个依赖项是Java开发中使用MinIO客户端必备的组件,可以方便地实现与MinIO服务器的交互和数据传输。

Minio如何验证下载的文件完整正确?

Minio使用纠删码技术来保证数据的完整性和可靠性。在下载文件时,Minio客户端会自动计算文件的校验和,并与Minio服务器上存储的校验和进行比较,以验证文件的完整性。如果两个校验和不匹配,则说明文件可能已被篡改或损坏。
在Java中,可以使用Minio Java客户端提供的getObject方法来下载文件,并通过比较文件的MD5校验和来验证文件的完整性。以下是一个示例代码:

import io.minio.MinioClient;
import io.minio.errors.MinioException;
import java.io.IOException;
import java.io.InputStream;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import org.apache.commons.codec.binary.Hex;
public class MinioDownloadExample {
  public static void main(String[] args) throws NoSuchAlgorithmException {
    String endpoint = "http://localhost:9000";
    String accessKey = "YOUR_ACCESS_KEY";
    String secretKey = "YOUR_SECRET_KEY";
    String bucketName = "test-bucket";
    String objectName = "test-object";
    try {
      // Initialize Minio client
      MinioClient minioClient = new MinioClient.Builder()
          .endpoint(endpoint)
          .credentials(accessKey, secretKey)
          .build();
      // Download object and get input stream
      InputStream inputStream = minioClient.getObject(bucketName, objectName);
      // Calculate MD5 hash of downloaded object
      MessageDigest md5Digest = MessageDigest.getInstance("MD5");
      byte[] buffer = new byte[8192];
      int bytesRead;
      while ((bytesRead = inputStream.read(buffer)) != -1) {
        md5Digest.update(buffer, 0, bytesRead);
      }
      byte[] md5Bytes = md5Digest.digest();
      String downloadedMd5 = Hex.encodeHexString(md5Bytes);
      // Get MD5 hash of original object
      String originalMd5 = minioClient.statObject(bucketName, objectName).etag();
      // Compare MD5 hashes to verify file integrity
      if (originalMd5.equals(downloadedMd5)) {
        System.out.println("File downloaded successfully and verified.");
      } else {
        System.out.println("File download failed or file has been modified.");
      }
    } catch (MinioException | IOException e) {
      System.out.println("Error occurred: " + e.getMessage());
      e.printStackTrace();
    }
  }
}

在这个示例代码中,我们使用了Minio Java客户端的getObject方法来下载指定的对象,并通过计算MD5校验和来验证文件的完整性。在计算MD5校验和时,我们使用了Java标准库中的MessageDigest类,并将输入流读入缓冲区中以进行计算。最后,我们将下载的文件的MD5校验和与Minio服务器上存储的对象的MD5校验和进行比较,以验证文件的完整性。

MYSQL可重复读

MySQL的事务隔离级别中,可重复读(Repeatable Read)是比较严格的隔离级别之一。在可重复读级别下,一个事务中多次读取同一个数据,将返回同样的结果,而不受其他并发事务对该数据的影响。也就是说,已提交的事务对于其他事务是不可见的,除非它们自己也已经提交。

在MySQL的可重复读隔离级别下,会通过在读取数据时,对数据进行加锁的方式来实现事务的隔离性。这样可以保证事务中的数据操作不被其他事务干扰,同时也可以保证数据的一致性。

在可重复读隔离级别下,其他事务只能读取已经提交的数据,而不能读取当前事务修改了但未提交的数据。因此,在这种隔离级别下,可以避免脏读、不可重复读和幻读等并发问题。

但是,可重复读隔离级别也有一定的缺点。由于事务需要对数据进行加锁,因此可能会对并发性能造成一定的影响。另外,如果一个事务长时间占用了锁资源,可能会阻塞其他事务的执行。因此,在实际应用中,需要根据业务的需要来选择合适的事务隔离级别。

如果是可重复读,第一个事务开启期间,第二个事务修改了某个数据并提交,第一个事务是读取不到修改内容吗

在MySQL的可重复读隔离级别下,如果在第一个事务开启期间,第二个事务修改了某个数据并提交了,那么第一个事务是无法读取到第二个事务对该数据所做的修改的。第一个事务只能读取到在它自己开启期间已经提交的数据。

这是因为MySQL的可重复读隔离级别通过MVCC (多版本并发控制)来实现。在这种机制下,每一个事务都会看到一个与其开启时一样的快照,也就是说,每一个事务都可以读取已经提交的数据,但是无法读取其他事务正在修改但未提交的数据。因此,即使在第一个事务开启期间,第二个事务对某个数据做了修改,但是由于这个修改还没有提交,因此第一个事务仍然无法读取到它。

当然,如果第二个事务回滚了这个修改操作,那么第一个事务在后续的查询操作中就可以看到这个修改被回滚的结果。因此,在可重复读隔离级别下,虽然无法读取其他事务正在修改的数据,但是仍然存在一定程度的幻读问题。

第二个事务的数据已经提交了,为什么第一个还看不到

如果第二个事务的数据已经提交了,而第一个事务仍然无法读取到这个数据,可能是因为第一个事务在读取时使用了MySQL的读取一致性视图(consistent read view)。在MySQL的MVCC机制中,每个事务在执行时都会创建自己的一致性视图,用于保证事务操作的读取一致性。

在可重复读隔离级别下,当一个事务开始执行时,它会创建一个一致性视图,这个视图包含了事务开始时所有已提交事务的快照。而在事务执行期间,其他事务所做的修改不会影响这个一致性视图。如果第二个事务已经提交了数据,在第一个事务的一致性视图中是看不到这个数据的修改的,因此也无法读取到修改后的数据。

需要注意的是,尽管第一个事务无法读取到修改后的数据,但第二个事务的修改是已经生效的,其他事务在读取该数据时,是可以读取到修改后的数据的。只有第一个事务的一致性视图没有包含该修改时,事务读取的数据才是旧的数据。

那这样第一个事务使用旧数据不会有影响吗

如果第一个事务使用旧数据,可能会产生一些问题。假设第一个事务读取了一个旧的数据,而该数据在第二个事务中已经被修改成新的值。如果第一个事务继续执行更新操作,会将旧的值更新到数据库中,从而覆盖了第二个事务所做的修改。

这种问题被称为“丢失更新”(Lost Update),是并发环境中常见的问题之一。为了避免这种问题,可以使用加锁来保证多个事务不会同时更新同一条数据。在MySQL中,可以使用行级锁(如行锁和间隙锁)或表级锁(如表锁)来控制并发访问。

另外,如果在可重复读隔离级别下需要读取最新的数据(即使已经开启了事务),可以使用SELECT … FOR UPDATE或SELECT … LOCK IN SHARE MODE语法来加锁,从而读取最新的数据并阻止其他事务对该数据进行修改。

既然这样,可重复读的意义是什么?

可重复读隔离级别的基本含义是:一个事务在执行期间看到的数据总是跟它在事务开始时看到的数据相同,即保持读取的一致性。这意味着,在某个事务中读取的数据,在该事务执行期间不会被其他事务所修改。这种隔离级别可以保证事务的读一致性,避免了出现“脏读”(dirty read)、“不可重复读”(non-repeatable read)和“幻读”(phantom read)等问题。

对于一些对数据一致性要求较高的应用,比如账务系统、库存管理等业务,可重复读隔离级别具有非常重要的意义。因为采用该隔离级别的应用,可以保证在事务中读取的数据总是一致的,不会受到其他并发事务的影响,从而大大降低了数据异常的可能性。

当然,可重复读隔离级别并不能完全消除并发访问带来的问题,如上述的丢失更新、死锁等情况仍有可能发生,需要开发人员在编写应用程序时加以避免或处理。

可重复读的实现原理

MySQL数据库中,可重复读隔离级别的实现主要依赖于以下两种机制:

  1. 数据快照

在事务启动时,MySQL会为该事务创建一个独立的存储空间,称之为“事务视图”(Transaction Snapshot)。该存储空间包含了当前系统中所有数值偏移量小于等于该事务启动时间的数据行版本。在该事务执行过程中,除了被该事务修改的数据以外,它对数据的读取都是从事务视图中读取的,而不直接读取数据库中的数据。因此,该事务在执行期间能够看到的数据总是跟它在事务开始时看到的数据相同。

  1. 行级锁和多版本并发控制

为了保证事务执行期间的数据一致性,MySQL在可重复读隔离级别下使用了多版本并发控制(Multiversion Concurrency Control,MVCC)机制。该机制允许多个事务在不同的版本上并发读取和修改同一个数据行。

具体来讲,MySQL为每个被修改的数据行创建一个事务版本号,每个事务的修改都会产生一个新的版本,被修改的数据行也会被标记为“已经修改”。而其他事务在读取该数据行时,只能读取该数据行的未被修改的版本,因为修改后的版本对它们都是不可见的。对于已经被修改的数据行,在其他事务中读取该数据行时,会根据该事务的隔离级别和创建时间决定如何处理。例如,如果是可重复读隔离级别,将从视图中读取相应的版本号。

除了数据快照和MVCC机制,MySQL还使用了行级锁来避免多个事务同时修改同一个数据行而导致的数据不一致问题。行级锁分为共享锁和排他锁两种,共享锁用于读操作,排他锁用于写操作。在可重复读隔离级别下,MySQL会自动给所有的SELECT语句加上共享锁,以保证事务期间读取的数据不会受到其他事务的修改影响。而在写操作时,则需要使用到排他锁,来保证只有该事务能够修改对应的数据行。这就保证了在可重复读隔离级别下的数据一致性。

详细介绍第二种机制

第二种机制是MySQL在可重复读隔离级别下使用的多版本并发控制(Multiversion Concurrency Control,MVCC)机制。该机制允许多个事务在不同的版本上并发读取和修改同一个数据行,以保证事务的隔离性,并发性和一致性。

MVCC实现的核心思想是:对于每个事务,不直接读取数据库中的数据,而是创建一个“事务版本”,在事务版本集(Transaction Version Set)中记录该事务读取的所有数据行的版本号。在读取数据时,会将该数据行的版本号和该事务的版本号作比较,以判断是否可以进行读取。在修改数据时,会为该数据行创建一个新的版本号,并将新的版本号和事务版本集中的版本号做比较,以判断是否可以进行修改。

具体来说,MVCC机制通常涉及到以下几个概念:

  1. 版本号:每个数据行都会有一个版本号,用来标识该数据行的修改情况。MySQL中的版本号实际上就是每个事务提交的时间戳,也称之为系统版本号(System Version Number,SVN)。

  2. 事务版本集:每个事务都有一个事务版本集,它存储了该事务所读取的所有数据行的版本号。

  3. 可见性规则:指定了在什么情况下,一个事务能够看到一个数据行的版本。在可重复读隔离级别下,只有一个事务启动时已经存在的版本才是可见的,即该事务启动时已经提交的事务版本。而其他事务所做的修改,则对该事务是不可见的。

  4. 回滚段:MySQL通过回滚段(Undo Log Segment)来实现对MVCC机制的支持。每个回滚段都有一个唯一ID,用来标识一组回滚段。

通过以上机制的支持,MySQL在可重复读隔离级别下可以实现对并发事务的控制,保证了每个事务只能读取到在启动时已经存在的数据版本号,并在修改时为其分配新的版本号。这种方式可以避免"不可重复读"和"脏读"等问题的出现,从而保证了数据的一致性和隔离性。

  • 2
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

路上阡陌

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值