一、KV数据库
KV,Key-Value,让人想定Mongo数据库,和JSON数据交换格式。数据存储,存储的数据主要分两种:结构数据(关系表),非结构数据(大文件,杂数据(模式和内容揉合(HTML))
以下是KV数据库的详细讲解:
- 数据模型:KV数据库采用简单的键值数据模型,其中每个记录由一个唯一的键和对应的值组成。这种简单而直接的数据模型使得KV数据库非常适合于需要快速存取和查询数据的场景。
- 存储结构:KV数据库可以采用多种不同的存储结构,例如哈希表、B+树等。不同的存储结构具有不同的特点和适用场景,选择合适的存储结构可以提高数据读写效率和性能。
- 数据操作:KV数据库提供了基本的CRUD操作(创建Create、读取Read、更新Update、删除Delete),可以通过键来进行数据插入、查询、更新和删除操作。同时,一些高级功能如批量操作、事务支持等也可能会被提供。
- 分布式架构:为了满足大规模数据处理和高可用性需求,一些KV数据库支持分布式架构。通过将数据分片存储在多台机器上,并使用分布式算法来管理和复制数据,可以实现横向扩展和数据冗余,提高系统的性能和可靠性。
- 数据一致性:在分布式环境中,保持数据一致性是一个重要的挑战。KV数据库通常会提供一些机制来确保数据在不同节点之间的一致性,例如使用副本复制、分布式事务等。
- 应用场景:由于其简单高效的特点,KV数据库被广泛应用于各种场景,包括缓存系统、会话管理、用户配置存储、元数据存储等。它们通常需要快速读写访问,并且对数据模型没有严格要求。
二、分布式存储系统
分布式存储系统是一种将数据存储在多个节点上的系统,它通过将数据划分为多个部分并在不同节点上进行存储和管理,以提供高性能、可扩展性和容错性。
1、数据划分:为了实现数据的分布式存储,需要将数据划分成多个部分,并决定每个部分应该存储在哪个节点上。常见的划分方式包括哈希划分、范围划分和副本复制等。这样可以使得每个节点只负责一部分数据,从而实现横向扩展。
2、数据复制:为了保证数据的可靠性和容错性,在分布式存储系统中通常会采用数据复制机制。即将同一份数据副本存储在不同的节点上,当某个节点发生故障时可以使用其他副本来恢复数据。常见的复制策略有主从复制、多主复制等。
3、一致性协议:在一个分布式环境下,保持数据一致性是一个重要问题。为了确保所有节点之间的数据一致,需要采用合适的一致性协议,如Paxos、Raft等。这些协议定义了节点之间如何达成一致并处理冲突的规则。
4、数据访问:分布式存储系统提供了对数据的读取和写入操作。对于读取操作,可以根据数据划分策略选择合适的节点来进行查询。对于写入操作,需要考虑如何将新的数据正确地存储在相应的节点上,并保证多个副本之间的一致性。
5、可扩展性:分布式存储系统具有良好的可扩展性,可以通过增加节点来扩展存储容量和处理能力。当数据量增加时,可以动态地添加新节点来均衡负载并提高性能。
6、容错性:分布式存储系统通过复制机制和冗余设计实现容错能力。即使某个节点发生故障,其他正常运行的节点仍然可以提供服务,并且通过自动恢复机制可以将故障节点重新加入系统。
7、一致性与性能权衡:在设计分布式存储系统时需要权衡一致性和性能之间的关系。强一致性要求可能会带来更高的延迟和更大的开销,而松散一致性可能会导致数据不一致。因此,需要根据实际需求选择适当的一致性级别。
机存储引擎
存储系统提供的基本功能包括:增删改查(CRUD==增加(Create)、读取查询(Retrieve)、更新(Update)和删除(Delete))。不同的存储方案根据业务不同侧重点不同,导致存储系统的性能和功能具有一定的差异。
目前主要的单机存储引擎有:
1、哈希存储:hash的CRUD是最快的。但缺点是不支持顺序扫描。bitcask是一个基于hash表结构的存储系统。他将写操作(包括删除标识)追加到文件尾。并定期合并新老文件&记录。
2、B树:既支持随机读取又支持范围查找的系统。查找时间复杂度为logd(n)(d为每个节点的出度)。Mysql的InnoDB的引擎和OS的文件系统使用的就是B+树。(为什么选择使用B树的变种B+树,读者有兴趣可以去探究下。提示:磁盘读取)
3、LSM树(Log Structured Merge Tree):由B+数改进而来。其思想为:将增量写操作保存在内存中,超过阈值时刷入磁盘,从而减少随机写磁盘操作。读操作则需要合并磁盘数据和内存中的写操作。通过Memtable/SSTable实现,实现细节在此不做深入探究。比较适合写操作较多的业务场景。BigTable/HBase/Cassandra中的列簇的数据存储方式采用的即是LSM树。
三、RocksDB
RocksDB相对传统的关系数据库的一大改进是采用LSM树存储引擎。LSM树是非常有创意的一种数据结构,它和传统的B+树不太一样.
RocksDB的主要设计目标是保证存取快速存储器和高负载服务器更高效,保证充分利用Flash或RAM子系统提供的高速率读写,支持高效的查找和范围scan,支持高负载的随机读、高负载的更新操作或两者的结合。其架构应该支持高并发读写和容量大增时系统的一致性。
RocksDB是一个嵌入式键值存储器,其中键和值是任意的字节流。RocksDB中的所有数据是按序存放的。常见操作包括Get(key), Put(key), Delete(key) and Scan(key)。RocksDB有三个基本结构:RocksDB memtable,sstfile和logfile。memtable是一个内存数据结构——新数据会插入到memtable和日志文件(可选)。日志文件是 顺序写入的,位于磁盘。当memtable写满后,数据会被刷新到磁盘上的sstfile文件,同时相应的日志文件可以安全地删除。sstfile中的数据经过排序的,目的 是为了加快键查找。
3.1假设和目标
性能:RocksDB的主要设计目标是保证存取快速存储器和高负载服务器更高效,保证充分利用Flash或RAM子系统提供的高速率读写,支持高效的查找和范围scan,支持高负载的随机读、高负载的更新操作或两者的结合。其架构应该支持高并发读写和容量大增时系统的一致性。
向后兼容性:这个软件的新版本应该是向后兼容的,因此,当升级到新版本时现有的应用程序不需要改变。
3.2高级体系结构
RocksDB是一个嵌入式键值存储器,其中键和值是任意的字节流。RocksDB中的所有数据是按序存放的。常见操作包括Get(key), Put(key), Delete(key) and Scan(key)。
RocksDB有三个基本结构:RocksDB memtable,sstfile和logfile。memtable是一个内存数据结构——新数据会插入到memtable和日志文件(可选)。日志文件是顺序写入的,位于磁盘。当memtable写满后,数据会被刷新到磁盘上的sstfile文件,同时相应的日志文件可以安全地删除。sstfile中的数据经过排序的,目的是为了加快键查找。
3.3特性
Gets,迭代器和快照
键和值被视为纯字节流,没有大小的限制。Get接口允许应用程序从数据库中获取一个键值。MultiGet接口允许应用程序从数据库中检索多个键值。MultiGet接口返回的key-value对都是相互匹配的。所有数据库中的数据都按顺序存放。应用程序可以指定一个key比较方法来定义key的排序顺序。迭代器允许应用程序对数据库进行RangeScan。
迭代器可以先定位一个指定的键,然后应用程序就可以从这个定位点开始一个一个扫描key。迭代器还可以用来对key做反向迭代。创建迭代器是会创建当前数据库的一个快照视图,因此,通过迭代器返回的所有键都来自同一个数据库视图。
Snapshot允许应用程序创建一个快照视图。Get和迭代器可以从一个指定的快照读取数据。在某种意义上,Snapshot和迭代器都提供了某个时间点上数据库的快照视图,但两者的实现是不同的。短暂的扫描最好通过迭代器而耗时较长的扫描最好通过快照。迭代器记录了数据库当前视图对应文件,直到迭代器被释放才删除这些。而快照并不能阻止文件删除;相反,compaction流程知道当前的快照并且不会删除任何现有快照中的key。数据库重启后,快照将丢失。重载RocksDB(通过服务器重启)会释放所有先前的快照。前缀迭代器
大多数LSM引擎无法支持一个高效RangeScan,因为它需要查找每一个数据文件。但大多数应用程序不会对key进行随机扫描,而更多的是扫描给定前缀的key。RocksDB利用了这种优势。应用程序可以通过prefix_extractor指定一个key的前缀。RocksDB用此来保存每个key前缀的bloom,指定了前缀(通过ReadOptions) 的迭代器将使用bloom二进制位来避免查找不包含指定key前缀的文件。更新
Put操作向数据库插入单个key-value。如果键已经存在,旧值将被覆盖。Writer操作允许将多个keys-values原子地插入到数据库中。数据库保证同一个Writer操作中的所有keys-values要么全部插入,要么都不插入。如果其中任何一个键已经存在于数据库中,旧值将被覆盖。
持久性
Put操作数据会存储在内存中的缓冲区称为memtable,也会选择性地插入到事务日志。每一个Put操作都有一组标志(通过WriteOptions设置),这些标志指定Put操作数据是否应该插入到事务日志。WriteOptions也可以指定在put操作提交前一个同步调用是否写入事务日志。在内部,RocksDB使用batch-commit机制批量写入事务日志,这样它可以使用一个同步调用提交多个事务。
容错
RocksDB使用校验和检测数据是否正确。每个块(通常是4k到128k大小)都有自己的校验和。一块数据一旦写入将不会修改。RocksDB通过硬件支持动态获取校验和的计算结果,以避免需要是自己计算校验和。多线程Compaction
Compactions可以删除同一key的多个副本,副本是应用程序覆盖现有key是产生的,可以删除key。通过配置可以让Compaction以多线程方式运行。
LSM的写数据的整体吞吐量直接取决于Compaction的速度,特别是当数据存储在SSD或RAM这种存储器中。RocksDB可以处理多个线程并发的Comopaction请求。多线程Compaction场景下写数据的速率比单线程场景下的速率快10倍。
整个数据库存储在一组sstfiles。memtable写满时,它的内容会被写入Level-0层的一个文件中,在此过程中,重复和被覆盖的key会被删除。
一些文件被定期压缩合并形成更大的文件——这就是所谓的compaction。RocksDB支持两种不同形式的compaction。普遍的做法是将所有文件按时间顺序保存在L0。compaction选择几个彼此相邻的文件并将它们合并成一个新文件L0。所有文件可以有重叠的key。
分层形式的compaction将数据存储在数据库中的多个层中。最新的数据存储在L0和最旧的数据存储在Lmax。L0层中的文件可以有重叠的key,但其他层中文件的key不能重叠。一次compaction过程就是选择Ln层的一个文件及它在Ln+1层的所有重叠文件进行压缩合并形成Ln+1层的新文件。相比层形式的compaction方法,普遍的compaction方法写数据性能较低,但空间利用率较高。
MANIFEST文件记录了数据库的状态。compaction在添加新文件和从数据库删除现有的文件后,会将这些操作记录到MANIFEST文件。事务日志是被批量提交到MANIFEST文件中的,目的是为了减少对MANIFEST文件的重复同步访问。Compaction过滤器
一些应用程序可能需要在Compaction过程中处理某些key。例如,一个支持TTL的数据库可能删除过期的key,这可以通过定义一个Compaction过滤器完成。
如果应用程序想要不断删除旧数据,可以使用Compaction过滤掉丢弃过期的记录。RocksDB Compaction过滤器可以允许应用程序去修改对应key的value或作为Compaction过程的一部分直接丢弃key。只读的模式
数据库可以在只读的模式下打开。只读模式下应用程序不能修改任何数据。这可以保证更高的读取性能,因为避免了代码执行路径的切换和锁的使用。
数据库调试日志
RocksDB的详细日志被写入到名为LOG*的文件中。这些日志用于调试和分析运行中的系统。可以按配置的指定周期记录日志。
数据压缩
RocksDB支持snappy,zlib,bzip2 lz4和lz4_hc压缩算法。对不同层的数据可以配置不同的压缩算法。一般来说,90%的数据保存在Lmax层一个典型的安装可能是L0-L2层不配置压缩算法,中间层用snappy压缩算法,而Lmax层采用zlib压缩。事务日志
RocksDB将事务日志保存在logfile文件中以防止系统崩溃。系统启动时会重新处理日志文件。logfile和_sstfile_s可以存放在不同目录下,比如下面的场景,当你希望将所有数据文件存储在非持久但快速的存储设备中,同时把事务日志保存在存取速度慢但持久的存储设备中。
四、KV储存项目实列
基于键值(Key-Value)存储的项目通常是构建高性能、可扩展的分布式存储系统。这种类型的存储系统将数据以键值对的形式进行存储和检索,具有快速的读写操作和良好的水平扩展性。
4.1kv存储的架构设计
在设计一个基础架构-KV存储项目时,可以考虑以下几个方面:
- 存储引擎选择:选择适合的底层存储引擎,如LevelDB、RocksDB、Redis等,根据需求权衡各自的优势和特点。
- 数据分片和分布式部署:将数据按照一定规则划分为多个分片,并将其分布到不同节点上,实现数据的负载均衡和水平扩展。
- 数据复制和容错性:采用主从或者多副本机制,保证数据的冗余备份,在节点故障时能够快速恢复服务。
- 一致性协议选择:选择适合的一致性协议,如Paxos、Raft等,确保数据在集群中的一致性和可靠性。
- 缓存策略:结合缓存技术如LRU(Least Recently Used)、LFU(Least Frequently Used)等策略提高读写效率。
- 高可用性和负载均衡:使用负载均衡器、故障转移机制等,实现高可用性和请求的均衡分发。
- 安全性和权限控制:考虑数据的安全性,设计相应的权限控制机制,保护数据免受未授权访问。
4.2网络同步与事务序列化
网络同步和事务序列化是在分布式系统中常见的两个概念。
网络同步: 网络同步是指在分布式系统中,各个节点之间通过网络进行通信时,保证数据的一致性和可靠性。当一个节点发起操作请求时,其他相关节点需要及时响应并保持数据的一致状态。
常见的网络同步方法包括:
- 时钟同步:各个节点使用统一的时间标准来确保事件发生的顺序一致。
- 消息传递:通过消息传递机制,在不同节点之间发送消息,并等待确认或者响应来实现数据同步。
- 分布式锁:使用分布式锁来保证在某个时间段内只有一个节点可以访问共享资源。
事务序列化:事务序列化是指在分布式数据库系统中,对多个事务进行调度和执行的方式。由于并发事务可能会导致数据不一致问题,因此需要采取合适的调度策略来保证事务的隔离性、原子性、一致性和持久性。
常见的事务序列化方法包括:
- 串行化:将多个并发事务按照先后顺序依次执行,确保每个事务都完全独立地执行。
- 2PL(Two-Phase Locking):采用锁机制来保证事务的隔离性,分为加锁和释放锁两个阶段。
- MVCC(Multi-Version Concurrency Control):通过版本控制机制来实现并发事务的执行,每个事务读取到的数据都是一个确定的版本。
总之,网络同步主要关注节点之间数据的一致性和可靠性,而事务序列化则关注在分布式数据库系统中多个事务的调度和执行方式。它们都是为了保证分布式系统的正确运行和数据一致性。
4.3KV存储的性能测试
KV存储(键值存储)的性能测试通常涉及以下指标:
- 吞吐量(Throughput):衡量系统在单位时间内能够处理的请求数量。可以通过并发访问系统,同时发送多个读写请求,并统计系统的响应速度来评估吞吐量。
- 延迟(Latency):衡量系统响应请求所需的时间。可以通过发送单个请求,并记录从发送到接收到响应所经过的时间来评估延迟。
- 可扩展性(Scalability):衡量系统在面对不断增加的负载时,是否能够保持稳定的性能水平。可以逐渐增加负载并监测系统的吞吐量和延迟来评估可扩展性。
- 内存占用(Memory Footprint):衡量系统在存储大规模数据时所消耗的内存空间。可以监测系统在加载和处理数据时所占用的内存大小。
- 磁盘使用率(Disk Usage):衡量系统在持久化数据时占用磁盘空间的情况。可以检查磁盘上数据文件和日志文件的大小来评估磁盘使用率。
这些指标可以通过自动化测试工具或编写自定义测试脚本进行性能测试。具体测试方法和工具选择取决于所使用的KV存储系统。常用的KV存储系统包括Redis、RocksDB、LevelDB等。
秋招面试简历项目的,给给大家推荐六个C++项目实战案列:
大家需要简历装饰的,可以自行购买,立刻加入学习。