经典案例
某天,小明同学下载了一个新的APP。因为第一次登陆,所以进入APP后需要注册一个新的账号。小明同学三下五除二地填好了注册资料,按下了「注册」按钮。就这样,数据就从无到有地产生了,并且在数十/数百毫秒内向APP的后端服务器飞奔而去……
小明的个人信息数据开启了一场冒险,在下图中各个不同的介质中疯狂流动:
小明的数据一般会经历以下的持久化过程:
在APP使用的过程中,会不会有以下潜在的问题?
- 数据库怎么保证数据不丢?
- 数据库怎么处理多人同时修改的问题?
- 为什么用数据库,除了数据库还能存到别的存储系统吗?
- 数据库只能处理结构化数据吗?
- 有哪些操作数据库的方式,要用什么编程语言?
存储&数据库
存储系统
什么是存储系统?
一个提供了读写、控制类接口,能够安全有效地把数据持久化的软件,就可以称为存储系统。
存储系统有哪些特点?
- 作为后端软件的底座,性能敏感
- 存储系统软件架构,容易受硬件影响
- 存储系统代码,既“简单”又“复杂”
存储器层次结构如下图,来自Memory hierarchy
数据从应用到存储介质,需要经过以下流程:
- 用户数据需要调用标准库函数,标准库函数拥有其自身的缓冲
- 用户调用刷新函数执行输入输出的系统调用
- 系统调用将用户空间数据拷贝到内核空间缓存
- 调用执行函数将内核数据刷新到硬盘上
在这个过程中,缓存很重要,贯穿整个存储体系,拷贝很昂贵,应该尽量减少。
单机存储系统怎么做到高性能、高性价比、高可靠性?
使用R(edundant) A(rray) of l(nexpensive) D(isks)技术,独立磁盘冗余阵列,通俗的讲就是把多块硬盘组成一个独立的磁盘阵列进行管理。
RAID出现的背景:
- 单块大容量磁盘的价格>多块小容量磁盘
- 单块磁盘的写入性能<多块磁盘的并发写入性能
- 单块磁盘的容错能力有限,不够安全
RAID 0:
将数据条带化,最少需要两块硬盘(每块硬盘的容量一样,实际生产环境中建议使用同品牌同型号同批次同容量的硬盘组成 RAID 0),即将所有组成 RAID 0 的硬盘的可用容量组合在一起,形成计算机上的一个逻辑卷。通俗的讲就是至少使用两块硬盘来存储数据,但是我要存储的数据不是全部存在某一块硬盘上,而是把我要存储的数据分成均等的多部分,然后平均分散存储在组成 RAID 0 的磁盘阵列上。
下图是用四块硬盘组成 RAID 0 的示意图,其中每块硬盘都被分成 ABCD 四个条带,然后我要存数据就先存把数据均分成四部分,如果 A1 能存下其中一份,那就直接将四部分分别存入 A1A4,如果存不下就先存满 A1A4,剩下的按同样的方式存 B1~B4,以此类推。
-
优点:
- 处理大文件很快。
- 提高读写速度,对硬盘的总容量没有损失。
-
缺点:
- 一旦阵列中某块硬盘损坏了,所有数据将不可恢复。
RAID 1:
镜像存储,RAID 1 至少需要两块硬盘组成,两块硬盘互为备份,存储的内容完全相同。建议硬盘容量大小也要一样,如果不一样,那实际可用容量不超过较小的那块硬盘的容量。
-
优点:
- 读取性能翻倍。
- 提供数据冗余,如果其中一块数据丢失,可以通过另一块还原。
-
缺点:
- 磁盘的利用率低,成本高。
RAID 2:
RAID 2 本质上是 RAID 0,只是加入了汉明码来做数据的纠错。以此来优化 RAID 0。汉明码(Hamming Code)是广泛用于内存和磁盘纠错的编码。汉明码不仅可以用来检测转移数据时发生的错误,还可以用来修正错误。要注意的是,汉明码只能发现和修正一位错误,对于两位或者两位以上的错误无法正确和发现。
-
优点:
- 加入了数据纠错机制
-
缺点:
- 成本增高,需要额外的盘做汉明码纠错
RAID 3:
RAID 3 使用字节级别的条带化技术,并采用专用的奇偶校验磁盘。RAID 3 阵列能在一个磁盘出现故障的情况下确保数据不丢失。如果一个物理磁盘出现故障,该磁盘上的数据可以重建到更换磁盘上。如果数据尚未重建到更换驱动器上,而此时又有一个磁盘出现故障,那么阵列中的所有数据都将丢失。本质上和 RAID 0 相同,与 RAID 2 相似,作为 RAID 0 的优化版本。
-
优点:
- 加入了数据纠错机制。
-
缺点:
- 做奇偶校验会消耗系统性能,容易导致系统出现性能瓶颈。
数据库系统
数据库分为关系型数据库和非关系型数据库。
关系型数据库在提供存储的基础功能之外,还具有以下增强功能:
- 结构化数据友好
- 支持事务(ACID)
- 支持复杂查询语句
非关系型数据库也是存储系统,但是一般不要求严格的结构化:
- 半结构化数据友好
- 可能支持事务(ACID)
- 可能支持复杂查询语言
关系型数据库相较于存储系统的优点:
- 帮助我们存储并管理数据
- 支持事务,即ACID
- 支持复杂查询的能力
以SQL为例,数据库支持以下操作:
-
操作数据
- Insert
- Update
- Select
- Delete
- Where
- GroupBy
- OrderBy
- ……
-
操作定义
- Create user
- Create table
- Create database
- Alter table
- ……
主流产品剖析
单机存储
单机存储指单个计算机节点上的存储软件系统,一般不涉及网络交互。单机存储一般有两种方式,本地文件系统和key-value存储。
本地文件系统:
Linux经典哲学:一切皆文件。文件系统的管理单元是文件,文件系统繁多,如Ext2/3/4,sysfs,rootfs等,但都遵循VFS的统一抽象接口。Linux文件系统有两大数据结构,Index Node 和 Directory Entry。
lndex Node记录文件元数据,如id、大小、权限、磁盘位置等,inode是一个文件的唯一标识,会被存储到磁盘上,inode的总数在格式化文件系统时就固定了。
Directory Entry记录文件名、inode指针,层级关系(parent)等,dentry是内存结构,与inode的关系是N:1(hardlink的实现)。
key-value存储:
世间一切皆key-value——key是你身份证,value是你的内涵。
常见使用方式::put(k,v) 或 get(k)
常见数据结构:LSM-Tree,某种程度上牺牲读性能,追求写入性能。
拳头产品:RocksDB
分布式存储
分布式存储在单机存储基础上实现了分布式协议,涉及大量网络交互。分布式存储一般有两类,分布式文件系统和分布式对象存储。
分布式文件系统——HDFS:
HDFS堪称大数据时代的基石,出现背景为专用高级硬件很贵,同时数据存量很大,且要求超高吞吐。
HDFS核心特点:
- 支持海量数据存储
- 高容错性
- 弱POSIX语义
- 使用普通x86服务器,性价比高
分布式存储—Ceph:
Ceph是开源分布式存储系统里的万金油。
Ceph的核心特点:
- 一套系统支持对象接口、块接口、文件接口,但是一切皆对象
- 数据写入采用主备复制模型
- 数据分布模型采用CRUSH(HASH+权重+随机抽签)算法
单机数据库
单机数据库指单个计算机节点上的数据库系统,事务在单机内执行,也可能通过网络交互实现分布式事务。
关系型数据库
商业产品Oracle称王,开源产品MySQL & PostgresQL称霸。
关系型数据库的通用组件:
- Query Engine: 负责解析query,生成查询计划
- Txn Manager: 负责事务并发管理
- Lock Manager: 负责锁相关的策略
- Storage Engine: 负责组织内存/磁盘数据结构
- Replication: 负责主备同步
关键内存数据结构:B-Tree、B+-Tree、LRU List等
关键磁盘数据结构:WriteAheadLog(RedoLog)、Page
非关系型数据库
非关系型数据库中,MongoDB、Redis、Elasticsearch三足鼎立。关系型数据库一般直接使用SQL交互,而非关系型数据库交互方式各不相同。非关系型数据库的数据结构千奇百怪,没有关系约束后,schema相对灵活。不管是否关系型数据库,大家都在尝试支持SQL(子集)和“事务”。
Elasticsearch特点:
- 面向文档存储
- 文档可序列化成JSON,支持嵌套
- 存在index,index是文档的集合
- 存储和构建索引能力依赖Lucene引擎
- 实现了大量搜索数据结构&算法
- 支持RESTFUL API,也支持弱SQL交互
MongoDB特点:
- 面向文档存储
- 文档可序列化成JSON/BSON,支持嵌套
- 存在collection , collection是文档的集合
- 存储和构建索引能力依赖wiredTiger引擎
- 4.0后开始支持事务(多文档、跨分片多文档等)
- 常用client/SDK交互,可通过插件转译支持弱SQL
Redis特点:
- 数据结构丰富(hash表、set、zset、list)
- c语言实现,超高性能
- 主要基于内存,但支持AOF/RDB持久化
- 常用redis-cli/多语言SDK交互
分布式数据库
单机数据库遇到了哪些问题&挑战,需要我们引入分布式架构来解决?
单机数据库容量有限,需要多机扩容;单机数据库不能支持弹性扩缩容;维护单机数据库性价比低。
解决容量问题:
解决弹性问题:
解决性价比问题:
分布式数据库还有更多的事情可以做,例如:
- 单写和多写
- 从磁盘弹性到内存弹性
- 分布式事务优化
新技术演进
软件架构
Kernel Bypass(内核旁路)是绕过Linux内核(TCPIP协议栈)的技术,不使用Linux内核子系统的功能,采用自己实现的相同功能的代码来处理,从用户空间直接访问和控制设备内存,避免数据从设备拷贝到内核,再从内核拷贝到用户空间。Kernel Bypass目前主流实现方案有SPDK、DPDK、SolarFlare。
SPDK是一套存储开发套件,专门为专用设备(NVME)设计。全称是The Storage Performance Development Kit。SPDK提供了一系列的高性能、可扩展、用户态下面的工具和库。
SPDK有以下优势:
- 存储设备的驱动代码运行在用户态,不会运行在内核态,避免了内核的上下文切换节省了大量的处理开销,节省下来的CPU时间片可以用于实际的数据处理,比如重复数据剔除、压缩、加密。
- 轮询模式驱动(Polled Mode Drivers, PMDs),改变了I/O的基本模型。在传统的I/O模型中,应用程序提交读写请求后睡眠,一旦I/O完成,中断就会将其唤醒。PMDs的工作方式不同,应用程序提交读写请求后继续执行其他工作,以一定的时间间隔回头检查I/O是否已经完成。这种方式避免了中断带来的延迟和开销,并使得应用程序提高了I/O的效率。在旋转设备时代(磁带和机械硬盘),中断开销只占整个I/O时间的一个很小的百分比,因此给系统带来了巨大的效率提升。然而,在固态设备的时代,持续引入更低延迟的持久化设备,中断开销成为了整个I/O时间中不能被忽视的部分。这个问题在更低延迟的设备上只会越来越严重。系统已经能够每秒处理数百万个I/O,所以消除数百万个事务的这种开销,能够快速地复制到多个内核中。数据包和数据块被立即分发,等待时间减小到最少,使得延迟更低,一致性延迟更多(抖动更少),吞吐量也得到提高。
- 拥有无锁数据结构,使用Lock-free queue,降低并发时的同步开销。
AI增强存储
AI领域相关技术,Machine Learning在很多领域,如推荐、风控、视觉领域证明了有效性。AI也能在存储领域带来一些存储方式的决策。
例如一般数据库分为行式存储和列式存储,如果需要频繁使用实体的全部数据一般用行式存储,如Mysql;如果需要统计某些数据则适合列式存储,如HBase。行列混合存储数据库会针对数据本身的使用情况,对于某些数据进行行式存储,某些数据进行列式存储。这时候我们可以使用AI决策监察数据,并自动选择适合的存储方式。
新硬件革命
-
RDMA网络
- 传统的网络协议栈,需要基于多层网络协议处理数据包,存在用户态&内核态的切换,足够通用但性能不是最佳
- RDMA是kernel bypass的流派,不经过传统的网络协议栈,可以把用户态虚拟内存映射给网卡 ,减少拷贝开销,减少cpu开销
-
Persistent Memory
- 处于在NVMe SSD和Main Memory间,IO时延介于SSD和Memory之间,约百纳秒量级
- 可以用作易失性内存(memory mode) ,也可以用作持久化介质(app-direct)
-
可编程交换机
- P4 Switch,配有编译器、计算单元、DRAM,可以在交换机层对网络包做计算逻辑。在数据库场景下,可以实现缓存一致性协议等
-
CPU/GPU/DPU
-
CPU:从multi-core走向many-core
-
GPU:强大的算力&越来越大的显存空间
-
DPU:异构计算,减轻CPU的workload
-
课后作业
实现一个(分布式)key-value存储系统
要求:
- 基于本地文件系统实现,支持常用的put(k, v)、get(k, v)、scan_by_prefix(prefix)接口
- 支持存储server独立进程部署,支持跨进程或者网络访问
- IO操作做到低时延
- 支持扩展成分布式架构,多台存储server组成一个分布式key-value存储系统,并保证全局的数据一致性*
参考文档: