深入存储 | 豆包 MarsCode AI刷题

115 阅读8分钟

大家好,这些天学的内容都没有好好的总结一下,存储系统和数据库系统一般是我们的项目中非常重要的一环,我们项目中的用户信息,或者简单的状态等等都需要用到数据库,当然还有查询数据

存储

  • 存储系统概述

    • 存储系统的特点
    • 存储器层级结果
    • 单机存储栈
    • RAID技术

    这些说实话自己在看文档学习的时候,感觉是从来都没有接触过

  • 数据库系统概览

    • 关系型数据库 (MySQL)
    • 非关系型数据库 (redis)
    • 数据库 与 经典存储的对比
    • 数据库使用方式

主流产品

  • 单机存储产品

    • 单机文件系统
    • 单机 key - value 存储
  • 分布式存储

    • HDFS
    • Ceph
  • 单机数据库产品

    • 关系型数据库 —— PG,MySQL
    • 非关系型数据库 —— ES,MongoDB,Redis
    • Elasticsearch
我的课后思考
  1. 写入存储系统的粒度太大,会不会导致数据原子性问题?例如一次性写100MB,如果系统突然crash,会不会只有一部分数据持久化了,另一部分丢失了?如果要解决原子性问题,一般会设计什么机制?

写入存储系统的粒度太大时,确实可能出现原子性问题。原子性要求一个操作要么全部完成,要么全部不完成。如果一次性写入 100MB 的数据,在写入过程中系统突然崩溃,很有可能只有一部分数据被持久化到存储介质,而另一部分丢失。这是因为存储系统的写入操作通常是由一系列底层的物理操作组成的。

解决原子性问题 - 以下回答来自豆包

  • 日志(Log)机制

    • 预写日志(Write - Ahead Logging,WAL)是一种常用的方法。在进行大规模写入之前,先将要写入的数据的操作记录(如更新操作的内容、数据块的位置等)以日志的形式写入到一个单独的稳定存储区域(如磁盘上的特定日志文件)。
    • 例如,在数据库系统中,事务开始时先将事务的操作记录写入日志,包括插入、更新或删除的数据内容。如果在写入实际数据(100MB 的数据)过程中系统崩溃,系统重启后可以根据日志来恢复数据状态。如果日志记录显示数据写入已经开始但未完成,系统可以根据日志中的信息重新执行未完成的部分或者回滚操作,以保证数据的原子性。
  • 事务机制

    • 采用事务来包裹大规模的写入操作。事务有开始(BEGIN)、提交(COMMIT)和回滚(ROLLBACK)等操作。在一个事务内部,所有的操作被视为一个不可分割的单元。
    • 以关系数据库为例,当执行一个涉及写入大量数据(100MB)的事务时,数据库管理系统会跟踪事务内的所有操作。如果系统在事务执行过程中崩溃,在重新启动后,数据库可以通过检查事务的状态来决定是提交未完成的事务(如果崩溃发生在提交阶段之前,但数据已经完整写入)还是回滚事务(如果数据不完整)。
  • 影子副本(Shadow Copy)机制

    • 这种机制是在写入数据之前,先创建数据的副本(影子副本)。当写入操作完成后,通过原子操作将原数据替换为新写入的数据。
    • 例如,在文件系统中,要更新一个大文件(100MB),可以先将新文件写入到一个新的位置,这个新文件就是影子副本。当新文件写入完成后,通过修改文件系统的指针(一个原子操作)来将原来指向旧文件的指针指向新文件。如果在新文件写入过程中系统崩溃,旧文件仍然完好无损,系统重启后可以重新尝试写入或者放弃写入操作,从而保证了数据的原子性

我觉得这个就是使用AI最好的地方,现在搜索引擎已经没有办法满足人们大多数的需求,而转是这种搜索,能够准确的找到自己所需要的答案

2. 在从应用程序到存储介质的链路上,无论读还是写,数据可能要被拷贝好几次,这几次拷贝能不能去掉?如果我们去掉大部分拷贝操作,会有什么副作用,要怎么缓解副作用?

  1. 数据拷贝的必要性及能否去掉

    • 数据拷贝的原因

      • 缓存机制:在从应用程序到存储介质的链路中,为了提高读写性能,会使用缓存。例如,当应用程序读取数据时,操作系统会先将数据从存储介质读取到内存中的缓存区。如果后续应用程序再次请求相同的数据,就可以直接从缓存中获取,而不必再次访问存储介质。这个过程涉及数据从存储介质到缓存的拷贝。
      • 数据格式转换:存储介质中的数据格式可能与应用程序所期望的数据格式不同。例如,存储在磁盘上的数据可能是经过压缩的,而应用程序需要解压后的数据。在这种情况下,就需要进行数据拷贝来完成格式转换。
      • 数据对齐和缓冲:硬件设备(如磁盘驱动器)通常有自己的读写单位,如磁盘的扇区大小。为了适应这些硬件的要求,数据可能需要进行缓冲和对齐操作,这也会导致数据拷贝。
    • 能否去掉大部分拷贝操作

      • 理论上可以去掉一些拷贝操作,但很难完全去掉。例如,可以通过一些技术手段,如直接内存访问(Direct Memory Access,DMA)技术,让硬件设备(如磁盘控制器)直接将数据传输到应用程序的内存空间,减少中间缓存等环节的数据拷贝。但是,完全去掉所有拷贝操作在实际场景中非常困难,因为不同层次的系统组件(如操作系统、驱动程序、硬件等)都有自己的需求和限制。
  2. 去掉大部分拷贝操作的副作用及缓解方法

    • 副作用

      • 数据一致性问题:如果没有拷贝操作来维护数据的多个副本,当一个组件直接修改数据时,可能会导致其他组件使用的数据不一致。例如,没有缓存中的数据副本,应用程序和存储系统对数据的视图可能会不一致。
      • 性能问题:在某些情况下,去掉拷贝操作可能会导致性能下降。例如,没有数据缓冲,应用程序可能需要频繁地等待存储介质的响应,因为每次读取或写入都需要直接与存储介质进行交互,无法利用缓存来减少延迟。
      • 兼容性问题:许多软件和硬件组件是基于现有的数据拷贝机制设计的。去掉拷贝操作可能会导致这些组件无法正常工作,因为它们可能依赖于数据的副本进行各种操作,如错误检测和恢复。
    • 缓解方法

      • 采用共享内存机制:可以通过共享内存来减少数据拷贝。例如,让应用程序和存储系统的相关组件共享一块内存区域,数据可以直接在这个共享区域中进行读写,而不需要频繁地拷贝。同时,需要使用适当的同步机制(如互斥锁、信号量等)来确保数据的一致性。
      • 优化硬件和软件接口:设计更加智能的硬件和软件接口,使得数据可以在不同组件之间高效地传输,而不需要中间的拷贝环节。例如,使用零拷贝(Zero - Copy)技术,在网络文件传输场景下,让数据直接从磁盘文件系统的缓冲区传输到网络缓冲区,减少内核缓冲区与用户缓冲区之间的数据拷贝。
      • 加强数据一致性协议:为了应对数据一致性问题,可以采用更加严格的数据一致性协议。例如,使用分布式系统中的一致性算法(如 Paxos、Raft 等)来确保多个节点(在存储系统中可以看作是存储节点或者缓存节点)对数据的一致性视图。这些算法通过多轮消息传递和投票机制,保证在数据修改后所有节点能够正确地更新自己的数据副本。

3. 一个关系型数据库大概率是会被并发访问的,如果要保证并发安全,除了在行数据上加悲观锁还有其他方式吗?

乐观锁我个人认为也是可以的,与悲观锁也有一些区别,乐观锁假设大多数事务在执行过程中不会产生冲突。它不是像悲观锁那样在事务开始时就对数据进行加锁,而是在提交事务时检查数据是否被其他事务修改过。通常的做法是在表中添加一个版本号(version)字段或者时间戳(timestamp)字段。

以上是我学完这段课程,给我的一些感悟吧,谢谢大家的观看