数据库与存储系统[三] 主流存储产品| 青训营

125 阅读9分钟

存储

单机存储

  • 可以简单理解为单个计算机节点上的存储软件系统,一般不涉及网络交互

本地文件系统

  • 此部分以Linux系统为例

  • Linux有一个著名的哲学:一切皆文件。无论是我们看得到的鼠标,键盘这些外设,还是看不到的文件,进程等等等等,在Linux的系统设计中都被当作文件处理,他们都拥有统一的操作方法,被组织在一个文件系统中。这意味着,我们可以使用相同的命令来处理不同的设备(都是同一个文件,只是文件的内容不同),这极大地增加了它的易用性和扩展性,当我们使用一些安全措施来保护文件时,实际上也保护了设备,病毒等没有相应权限自然无法侵入破坏。

  • 文件自然就是文件系统的最小管理单元

  • 文件系统繁多,一般常见的有ext2/3/4,sysfs,rootfs等,但这些文件系统都遵循VFS的统一抽象接口

  • Linux文件系统无论采用哪一种,一定离不开两大数据结构:Index NodeDirectory Entry

Index Node(INode)

  • 即文件索引节点,用于保存文件的元数据(文件类型,权限,UID,时间戳,大小等)

  • 它存储了除文件名文件数据之外的所有信息

Index Node.png

  • Linux在创建文件系统时,也会创建大量的INode。文件引用的是一个INode号,当用户搜索/访问一个文件时,Linux会通过INode表来找到正确的INode编号,通过这个编号来访问相应的INode目录是目录下的文件名和文件INode号的映射。

  • INode编号在分区级别是唯一的,每个分区都有自己的INode表。如果两个文件的文件名和其它等等都一样,我们能正常打开这两个文件的依据是他们的INode编号不同。如果INode编号用完了,即使分区上还有剩余空间,我们也无法创建新文件

  • 既然之前说过Linux下一切皆文件,那么,我们的字符,设备等等,其实都是有属于它们的INode编号的

  • INode分区级别是唯一的,故当分区不同时,两个文件可以拥有相同的INode编号

  • 我们可以通过一个简单的命令查看文件相应的INode编号

# 仅查看INode
ls -i
# 列出文件的所有信息,第一个是INode
ls -li

INode order.png

  • 硬链接原文件拥有相同的INode编号,如果删除原文件,原来的数据仍可以用硬链接访问。这里的删除原文件,其实只是删除了指向该INode编号的其中一个名称,链接到这个INode的数据仍然可用。只有删除掉与其关联的所有名称,我们才无法访问指定的数据

  • 软链接的创建实际上是建立了一个新的文件,即使它指向一个原有的文件,它也与原文件的INode的编号不同

Directory Entry

  • 目录项,记录了文件名,INode指针,层级关系(parent)等信息
  • 创建硬链接实际上就是创建了一个新的DEntry, INode索引号相同

Key-Value

世间一切都是Key-Value,Key是你的身份证,Value是你的内涵

  • 最典型/常见的例子如Java中的Map
Map<String, int> map = new HashMap<String, int>();
// 存储
map.put("ming",1);
map.put("zi",2);

//取值
int result = map.get("ming");

LSM-Tree

  • 使用Key-Value存储方式的典型数据结构,许多NoSQL都基于LSM-Tree构建

  • 英文全称:Log-Structure Merge-Tree

    • Log-Structure:日志文件追加写入数据

    • Merge-Tree:一般分为两层,内存和磁盘。每次写入时将数据写入到内存中,当积累到一定程度时,使用归并排序的方式将内存的数据合并追加到磁盘队尾

  • 优势:由于物理结构限制,磁盘的随机操作速度很慢,顺序访问却很快。如何将磁盘的这一优势取长补短?最好的办法便是一次性读取或写入固定大小的一块数据,并尽可能地减少随机寻道这个操作的次数(有点像我们的Buffer,不是吗?)。LSM-Tree充分利用了这一特点实现,以日志的形式批次操作数据,牺牲了一部分读的性能来换取绝佳的写性能。前文提过NoSQL在大数据量的情况下表现更佳,作为大多数NoSQL实现的基底,LSM-Tree被设计来提供比传统数据库B+ Tree/ISAM更好的写操作吞吐量,通过消去随机的本地更新来提高性能。

  • 多用于写多读少的场景

RocksDB

  • 使用Key-Value存储方式的著名高性能嵌入式数据库,是Google LevelDB的一个重要分支。基于C++编写

分布式存储

  • 在单机存储的基础上实现了分布式协议,涉及大量的网络交互

兴起原因

  • 成本,成本,还是TMD成本:互联网业务的发展十分迅速,使得存储系统无法依靠传统的纵向扩展的方式:先买小型机,不够用时再买中型机,甚至大型机超大型机。每次设备的迭代都要涉及迁移升级和备份等诸多问题,更何况不断升级的设备所消耗的资金更是大量的。现代的互联网后端都是分布式系统,要求支持横向扩展,即通过增加普通PC服务器来提高系统的整体处理能力

  • 软件需求:普通PC服务器性价比高,但故障率也高,需要在软件层面实现自动容错,保证数据的一致性。

  • 线性扩展:随着服务器的加入,需要在软件层面实现自动负载均衡,使得系统的处理能力可以线性扩展。

HDFS(Hadoop Distribution File System)

  • 堪称大数据时代的基石

  • 核心特点:

    • 支持海量数据存储

    • 高容错性

    • POSIX语义

    • 使用普通x86服务器,性价比高

HDFS.png

  • 如果客户端想要读取数据,首先从NameNode获取该文件的位置(指向哪个DataNode),再到具体的DataNode中拿到

  • 各部分角色:

    • NameNode:管理整个文件系统的元数据,以及每一个路径(文件)所对应的数据块信息

    • DataNode:管理用户的文件数据块,每一个数据块都可以在多个DataNode上存储多个副本

    • Secondary NameNode:监控HDFS状态的辅助后台程序,每隔一段时间获取HDFS状态快照,辅助NameNode管理元数据信息

Ceph

  • 开源分布式存储系统里的万金油

  • 核心特点:

  • 一套系统支持对象接口,块接口,文件接口,一切皆对象

  • 数据写入采用主备复制模型

  • 数据分布模型采用CRUSH算法

ceph.png

  • 相比于HDFS,Ceph的扩展性更强,且无单点。当对云计算的大数据进行处理时,特别是离线批量处理,计算性能逊于HDFS

数据库

单机数据库

  • 单个计算机上的节点系统。数据库中的事务可以在单机内执行,也可以通过网络交互实现分布式事务。

关系型数据库

  • 关系型数据库的通用组件

    • Query Engine:负责解析Query,生成查询计划

    • Txn Manager:负责事务的并发管理

    • Lock Manager:负责锁相关的策略

    • Storage Engine:负责组织内存/磁盘数据结构

    • Replication:负责主备同步

  • 商业产品中,Oracle的数据库独占鳌头

  • 常见的开源产品:MySQL,PostgreSQL等

非关系型数据库

  • MongoDB,Redis,Elasticsearch三足鼎立

  • 不同的非关系型数据库交互方式各不相同,数据结构千奇百怪,因为没有关系约束,scheme相对灵活

  • 都在尝试支持SQL(子集)事务

Elasticsearch

elastic.jpeg

  • 面向文档存储

  • 文档可序列化为JSON,支持嵌套

  • 存在index,index就是文档的集合

  • 存储和构建索引的能力依赖Lucene引擎

  • 实现了大量的搜索数据结构和算法

  • 支持RESTFUL API,支持弱SQL交互

MongoDB

mongoDB.jpg

  • 面向文档存储

  • 文档可序列化为JSON,支持嵌套

  • 存在collectioncollection就是文档的集合

  • 存储和构建索引的能力依赖wiredTiger引擎

  • 4.0之后开始支持事务(多文档,跨分片多文档等)

  • 常用client/SDK交互,可通过插件转译支持弱SQL

Redis

redis.jpeg

  • 数据结构丰富(hash表,set,zset,list)

  • 纯C实现,超高性能

  • 主要基于内存,支持AOF/RDB持久化

  • 常用redis-cli多语言SDK交互

分布式数据库

  • 解决问题

    • 容量问题:单点存储的容量有限,受硬件限制。分布式数据库将存储节点的数据库池化,可以动态地伸缩容量。

    • 弹性问题:单点存储的升级/降级需要大幅度的迁移数据,且缩容时各个磁盘的冗余问题无法解决。将节点池化后,软件层可以自由调度存储空间,用户并不需要关心底层的内存细节,容量由分布式系统决定。

    • 性价比问题:对单点存储的机型进行扩容后,CPU资源浪费会及其严重(更大的磁盘需要更好的CPU)。存储池中的CPU无需升级,当CPU资源不够时,可以从Server层直接升级/增加CPU,存储空间不够时,可以扩展存储池容量,无需当扩容时必须一对一配备更好的CPU

  • 新的问题

    • 如何优化写入性能,使得多个用户可以共同操作数据?

    • 在实现磁盘容量弹性的基础上,如何实现内存的弹性?

    • 如何在分布式的基础上,提高对事务的处理能力?