Spring中的aware接口详情
682
2022-09-21
内存数据库解析与主流产品对比(一)(内存数据库和传统数据库的区别)
作者:实验室小陈/大数据开放实验室8月26日,星环邀请来自华东师范大学软件工程学院的博士生导师宫学庆教授带来《数据库前沿技术系列讲座》,分享数据库业内前沿发展和研究热点。现将宫学庆教授的培训第一讲内容:内存数据库的技术发展分享给大家。
— 基于磁盘的数据库管理系统 —
传统的数据库管理系统(DBMS)通常是采用基于磁盘的设计,原因在于早期数据库管理系统设计时受到了硬件资源如单CPU、单核、可用内存小等条件的限制,把整个数据库放到内存里是不现实的,只能放在磁盘上。由于磁盘是一个非常慢的存储设备(相对于CPU的速度),因此学术界和工业界发展出的数据库管理系统在架构上都必须适应当时的硬件条件,沿用至今的Oracle和MySQL等数据库管理系统仍然采用的是这种架构设计。
伴随着技术的发展,内存已经越来越便宜,容量也越来越大。单台计算机的内存可以配置到几百GB甚至TB级别。对于一个数据库应用来说,这样的内存配置已经足够将所有的业务数据加载到内存中进行使用。虽然大数据处理的数据量可能是PB级别的,但那些数据一般是非结构化的数据。通常来讲,结构化数据的规模并不会特别大,例如一个银行10年到20年的交易数据加在一起可能只有几十TB。这样规模的结构化数据如果放在基于磁盘的DBMS中,在面对大规模SQL查询和交易处理时,受限于磁盘的I/O性能,很多时候数据库系统会成为整个应用系统的性能瓶颈。
如果我们为数据库服务器配置足够大的内存,是否可以仍然采用原来的架构,通过把所有的结构化数据加载到内存缓冲区中,就可以解决数据库系统的性能问题呢?这种方式虽然能够在一定程度上提高数据库系统的性能,但在日志机制和更新数据落盘等方面仍然受限于磁盘的读写速度,远没有发挥出大内存系统的优势。内存数据库管理系统和传统基于磁盘的数据库管理系统在架构设计和内存使用方式上还是有着明显的区别。
— 缓冲区管理方式 —
总结来看,基于磁盘的DBMS和内存数据库在实现技术上一个重要区别是:在访问数据时,基于磁盘的DBMS需要通过地址映射将数据在磁盘上的地址转换成在内存中地址,而内存数据库在设计上则是直接使用数据在内存中的地址。
— 事务ACID属性保证 —
在数据库管理系统中,需要保证并发访问场景下事务的ACID属性,即事务的原子性、一致性、隔离性和持久性。事务的ACID属性主要靠数据库管理系统中的两个机制实现,一个是并发控制,另一个是Logging/Recovery机制。
并发控制
传统基于磁盘的DBMS大部分是采用基于锁(Lock)的悲观并发控制,即事务在访问数据时先加锁,用完后再进行解锁,其他事务在访问数据时如果存在冲突则需要等待拥有锁的事务释放锁。传统DBMS一般会在内存中维护一个单独数据结构——Lock Table来存放所有的锁,由Lock Manager模块进行统一管理,这样在内存中锁和缓冲区中的数据是分开存放和管理的。事务在访问数据时先向Lock Manager申请数据所对应的锁,然后再访问数据;执行结束后通过Lock Manager把锁释放,Lock Manager能够保证所有事务申请和释放锁都是遵循严格的两阶段封锁协议(strict 2 phase locking protocol)。同时,并发控制机制所带来的开销与用户的实际业务处理没有直接关系,是用于保证事务一致性和隔离性的额外开销。
内存数据库在访问数据时也需要加锁,但和基于磁盘的DBMS不同,锁和数据在内存中是存放在一起的,通常是将锁信息保存在数据记录Header中。为什么基于磁盘的DBMS要单独将锁信息放在Lock Table中,而内存数据库就可以把锁信息和数据存放在一起呢?因为在基于磁盘的DBMS中,数据块是有可能被系统从内存缓冲区中替换到磁盘上,如果锁信息和数据放在一起,一旦数据块被替换出去,Lock Manager和所有事务都无法获得关于数据的锁信息。所以说对于传统基于磁盘的DBMS来讲,锁要单独维护在内存中,且需要始终保持在内存中,不能被替换出去。而对于内存数据库来说,不存在这样的场景。
实际上,数据库管理系统中有两种锁机制,分别被称为Lock和Latch,目的都是为了保护数据的一致性不被并发访问所破坏。Lock机制是对数据库逻辑内容的保护,一般来说拥有持续时间长,通常是事务执行的整个过程;并且Lock机制要支持事务的回滚以撤销事务对数据修改。而Latch机制是为了保证内存中特定的数据结构不会因为并发访问而导致错误,比如在多线程编程时有一个共享队列发生插入、删除等操作时,需要Latch保证操作过程中的队列不受其他线程的干扰。Latch的保持时长与操作有关,本次操作做完就结束,同时也不需要支持对数据修改的回滚。
在传统DBMS的Logging和Recovery中,最重要的概念是WAL(Write-Ahead Log)——预写式日志。WAL是指系统中所有更新操作都有对应的日志,而在日志没有落盘前,对数据的修改不允许落盘。系统中每条日志都有一个LSN号(Log Sequence Number),所有的LSN号单调递增,日志落盘的过程是向磁盘的连续写(顺序写)。但如果系统严格按照一条日志对应一条操作,日志落盘后马上将操作对数据的更新结果落盘,那么系统性能会受到很大影响。所以,大多数的DBMS会采用Steal + No Force的缓冲区管理策略。Steal是指DBMS可以将未提交事务的更新刷到磁盘,不必等事务提交时再把更新刷到磁盘,提高了系统刷盘的灵活性和性能;如果在事务未提交时发生crash,由于更新可能已经写到磁盘,这时就需要通过对日志的undo操作进行回滚。No Force是指在事务已经提交后,对数据的更新可以依然存放在内存缓冲区中不写入磁盘,在合并其他事务的更新后再一次性写入磁盘,为系统提供优化空间。但No Force可能带来的风险是:如果事务已经成功提交但更新没有写到磁盘,此时出现crash,则仍然在内存中的数据更新就会丢失,需要根据已经写到磁盘的日志(事务成功提交的前提是其所有日志都必须已经落盘)进行redo操作。
有了WAL和Steal + No Force机制后,就可以给基于磁盘的DBMS提供最大的灵活性,来优化磁盘I/O。但对于内存数据库而言,所有的数据放在内存里,是否还需要这个机制呢?可以明确的一点是,内存数据库还是需要Logging的,但和基于磁盘的DBMS有所区别,在日志中只记载redo操作所需的信息,不记载undo所需的信息。大家可以想一下这是为什么?另一方面,内存数据库在Logging过程中不记录关于索引的更新,只记录对于基础表的更新,那Logging过程中所需写盘的内容就少了很多。而在内存数据库出现故障需要恢复时,首先从磁盘上保存的检查点(Check Point)数据和日志中恢复基础表,然后在内存中重新构造索引。
— 面向磁盘的DBMS性能开销 —
可以看到,基于磁盘的数据库管理系统做了很多额外的管理工作,这些工作虽然不处理业务逻辑,但在保证业务逻辑正确性上不可或缺。对于内存数据库而言,面临的问题是应该做哪些优化来得到最优的性能。和基于磁盘的系统相比,内存数据库主存储是内存,但依然需要磁盘来做Check Point和Logging,故障时要靠磁盘上的检查点数据和日志来恢复整个内存数据库。
— 内存数据库技术历史发展 —
内存数据库的发展大致可以分成三个阶段:1984年到1994年的10年;1994年到2005年的10年;2005年以后到现在。第一个阶段出现了内存相关的处理技术;第二阶段出现了一些内存数据库系统;第三个阶段就是我们现在面临的场景。
1984年 - 1994年
在1984年到1994年间,学术界针对内存数据管理提出了很多假设,比如内存缓冲区可以放进全部数据,可以采用组提交和快速提交优化技术等。同时也提出了面向内存的数据访问方法,不再像基于磁盘的DBMS一样采用Page ID + Offset方式进行访问,而是在所有数据结构中都直接采用内存地址。还有面向内存的T-tree索引结构以及对系统按功能分成多个处理引擎,有的专门做事务处理,有的专门做恢复,相当于有两个核,一个专门负责事务处理,另一个负责日志处理。此外还有和Partition相关的主存数据库,把数据库分成很多个Partition,每个Partition对应一个核(或节点),进程间没有竞争。可以看到,这个期间的数据库技术发展已经在考虑如果数据全部放在内存,可以采用哪些技术。但受限于当时的硬件条件,这些技术并没有得到大规模应用。
注:本文部分材料来自于:
VLDB 2016会议上的现代主存数据库系统教程(Modern Main-Memory Database Systems Tutorial) CMU(卡耐基梅隆大学)Andy Pavlo教授的高级数据库系统(Advanced Database Systems)课程
版权声明:本文内容由网络用户投稿,版权归原作者所有,本站不拥有其著作权,亦不承担相应法律责任。如果您发现本站中有涉嫌抄袭或描述失实的内容,请联系我们jiasou666@gmail.com 处理,核实后本网站将在24小时内删除侵权内容。
发表评论
暂时没有评论,来抢沙发吧~