当前存在为各种专门场景设计的数据库系统,在实践中可以依据具体应用的规模、复杂性和功能需求来选择合适的数据库。这与早期信息化解决方案中“用一套Oracle数据库解决所有问题”形成鲜明的对比。数据库有增、查、改、删四大操作,简称CRUD(Create、Read、Update、Delete)操作。不同的数据库技术设计的本质都是对这四种操作的性能进行优化和平衡。
1.关系型数据库与NoSQL
关系型数据库一直是信息技术发展的主流。随着大数据的出现,由于关系型数据库在应对大数据时遇到挑战,因而在面向某些特定场景时,全新的NoSQL数据库技术开始兴起。NoSQL数据库能够提供丰富的数据模型支持,可实现大吞吐量“读”或“写”的高效率,以及良好的扩展性。NoSQL数据库技术普遍选择牺牲支持复杂的SQL及ACID事务来换取弹性扩展能力,通常不保证强一致性,但支持最终一致性。与此同时,关系型数据库也在不断演进,通过支持列式存储模式、MPP分布式架构,在保持一定关系数据处理能力的基础上,也能够实现良好的分析性能支持。在关系型数据库技术与NoSQL数据库技术之间,不同路线的技术不是完全的替代关系,而是互补关系,综合运用可以更好地应对不同场景的需求。
(1)关系型数据库理论及优势
关系型数据库(Relational Database)是建立在严谨的关系数据模型基础上的,支持强事务,通过统一结构化语言(SQL)操作。关系型数据库主要面向事务(Transaction)设计,要求保证事务过程(Transaction Processing)的正确执行与数据的正确性,即使执行过程中遇到出错、断点、系统崩溃等异常也是如此。关系型数据库严格遵循ACID原则。
原子性(Atomicity):保证一个事务被看作一个单元,事务中的所有操作,要么全部完成,数据库更新到新的状态,要么全部不完成,数据库状态保持不变。
一致性(Consistency):保证一个事务执行前后的数据库状态都是有效的。有效状态(Valid State)是指事务完成后数据库的数据符合所有预定义的规则:约束(Constraint)、级联(Cascades of Rollback)、触发器(Trigger)及其任意组合。一致性可以阻止数据库被非法的事务所破坏,例如参照完整性(Referential Integrity)保证了主键-外键关系。一致性并不保证从应用层看事务是正确的。
隔离性(Isolation),又称独立性:保证事务并发执行与串行执行所获得的数据库状态相同。为了提高数据库的处理效率,事务通常需要并行执行,例如多个事务同时读取和写入一个表。为了保持隔离性,需要对事务进行并发控制,不同级别的控制方法提供不同的效率与事务间影响的平衡。
持久性(Durability):保证一旦事务被提交,即使存在系统故障,事务也一定是生
效的。
为实现以上原则,数据库需要实现同步锁、多版本并发控制(MVCC)、日志(Log)等功能,例如在提交事务前,先把事务写入WAL(Write Ahead Log)。关系型数据库无论是在理论,还是在技术、商业产品、产业生态方面都十分成熟,易于理解、方便使用、维护简单,除了支持事务,也支持一定量级的分析应用。
(2)关系型数据库在应对大数据时遇到的挑战
关系型数据库技术难以应对数据量大、增长速度快、高响应时效、内容丰富等大数据场景的数据处理要求,举例如下。
低延迟高并发:大数据时代要求支持海量数据的高效存储和访问,但关系型数据库受事务、架构约束,随着数据量的增长,其读写性能会迅速下降,难以实现高并发、实时动态大数据量的获取和更新。
扩展性:大数据时代用户量可能出现爆发式增长,需要数据系统具有快速扩展的能力,而关系型数据库难以方便、灵活、短周期、低成本地满足这一需求。
模型自由:对于半结构化(如JSON)、非结构化数据(如文档、影像),关系型数据库只能将其存储为一个二进制数据块,无法支持对数据内容的检索、分析等处理。
大规模的数据读取:在进行数据统计分析时常常需要批量读取数据,随着数据量的增长,传统关系数据库在需要批量扫描对数据进行读取时效率不足。
常见的解决方案有两种:纵向扩展(Scale Up)与横向扩展(Scale Out)。对于关系型数据库,纵向扩展是提升单服务器的性能,这是IOE(IBM、Oracle、EMC)类厂商给大型银行等机构提供的常见一体机解决方案,上限瓶颈明显,且成本高昂;横向扩展是通过读写分离、分库分表等方法在数据库设计与应用层实现的,这会使得应用层实现、维护都变得十分复杂和僵化,无法应对需求的快速变化。随着数据量的不断增长,我们需要不断调整方案,效率十分低下,且容易出错。
(3)NoSQL数据库的特点
NoSQL主要指非关系型、分布式、不提供ACID的数据库设计模式,支持快速大规模的水平扩展。对NoSQL最普遍的解释是“非关系型的”。NoSQL是一组相互非常不同的数据库系统的泛称,并且难以用一个分类去划分。NoSQL数据库的数据模型主要包括键-值模型(Key-Value)、列族模型(Wide Column)、文档模型(Document)、图模型(Graph)。另外,DB-ENGINES网站将搜索引擎(Search Engine)系统也视为NoSQL数据库,但严格来讲,搜索引擎并不是普遍意义上的数据库。DB-ENGINES网站还认为NoSQL包含RDF存储库、Native XML DBMS、内容存储库。
通过放松标准关系数据模型、ACID原则要求支持,NoSQL数据库具有如下优点:
更高的性能;
易于在不同节点上分布数据(如分片),从而实现扩展性(scalability)和容错能力(fault tolerance);
通过使用无模式(schema-free)的数据模型来提高灵活性;
管理简化。
2.键-值模型数据库
当前键-值数据库使用极其广泛,适用于高性能缓存场景,例如会话、用户配置、购物车等场景的数据存储,单条超低延迟读/写,高并发要求,内容简单且相互独立,但不适用于事务处理、多键关联数据、统计分析。Amazon的工程师对他们自己的数据库查询和使用情况进行了分析,发现70%的工作负载都是单键值操作,而且键值操作很少使用Oracle数据库提供的关系功能,另外20%的工作负载访问也仅限于一个表,只有10%的工作负载需要跨多个键访问数据而使用到关系型数据库的功能。
(1)键-值模型简介
从使用方式来看,键-值模型数据库是最简单的NoSQL数据库。客户端可以根据键对其所对应的值进行CRUD操作。键值数据库支持的键值类型十分丰富。
键-值模型极大地简化了传统的关系数据模型,相当于只有两个字段的表。键-值模型的实现类似于Map结构,在键和值间建立映射关系。键-值模型数据库面向高效访问场景,使用非常广泛,典型的如Memcached、Redis、DynamoDB。
(2)Redis
Redis是开源的、键-值模型NoSQL数据库,适合在高速响应场景下作为数据缓存使用,同时提供持久化数据的能力。Redis集群使用主从架构实现高可用。
Redis不是简单的键值存储数据库,而是一个数据结构服务器。这里的值不局限于简单的字符串,还包括几种复杂的数据结构。Redis的每条记录都有一个键和一个值。键是二进制安全的,这意味着可以使用任何二进制序列作为键,如可以是一个字符串,也可以是一个JPEG图片文件的内容,最大支持512MB,但太长的键会影响存储效率和查询效率。值支持五种数据结构类型:String、List、Hash、Set、Zset。不同数据结构类型的说明如下。
- List是按照插入顺序排列的字符串列表。
- Hash是字段和值都是String类型的映射表。
- Set是成员为String类型的不重复无序集合。
- Zset(或Sorted set)与Set的区别是每个元素关联一个分值,元素按分值从小到大排序。
为了支持多种值类型、优化存储、内存回收、共享对象等功能,Redis的值存储使用一个内部定义的RedisObject结构体。该结构体包括五个字段:值的数据结构类型(type)、内部编码格式(encoding)、最后一次访问时间(lru)、被引用次数(refcount)、值或值的指针(*ptr)。该结构体在64位系统中占16个字节。Redis支持多种数据结构类型,在不同的使用场景,Redis会选择合适的内部编码,以节省内存或优化性能,最多可以省90%的内存(平均为50%),并且这对于用户和API来说是透明的。内部编码涉及如下内容。
String有三种内部编码:int(8字节)、embstr(≤44字节)、raw(>44字节)。
当List的元素较少时,使用ziplist(压缩列表)存储;当元素增多,超过配置的阈值时,List会自动转换为linkedlist(双向链表)存储。ziplist是Redis为了节约内存而专门开发的一种连续的数据结构。
同样,Hash和Zset在数据量小时也使用ziplist存储,当超过配置的阈值后会分别转存为hashtable(哈希表)和skiplist(跳跃链表)。
当Set的元素较少时,使用intset(整数集合)存储,当超过配置的阈值后则转存为hashtable(哈希表)。
3.列族模型数据库
列族模型数据库能够支持大量的动态列,与文档模型数据库具有相似的无模式特性,但实现方式完全不同。列族可以看作二维的键-值存储。注意,列族模型与列式存储不是一个概念。列族模型数据库支持低延迟单条数据读写、高并发、灵活的表结构调整,但不适合做需要大规模批量读取的统计数据分析。
(1)列族模型简介
在列族模型数据库中预先定义的是列族而不是列。一个列族下可以有很多个列,且每个列族下列的个数可以不一样。一个列族下的数据存储在一起。列族在建表的时候定义,一般是不可变的,但在后续的使用中还可以添加列。列族不需要像关系型数据库的列那样预定义数据类型,只要数据可以转为字节数组即可。比较常见的开源列族模型数据库有Hbase、Cassandra/ScyllaDB。
(2)HBase
HBase的设计思想来源于2006年Google发布的Bitable论文。HBase是一个开源、分布式、可扩展、面向列族的NoSQL数据库,主要解决超大规模数据集的实时、随机访问等问题,其底层文件存储基于HDFS。
HBase采用主从架构,主要由HBase Master(也称HMaster)和HRegionServer构成,同时使用ZooKeeper协同管理。HBase将表横向切分来实现分布式存储,将一个表分为多份(HRegion),同一个表的不同HRegion分布在不同的RegionServer上。HMaster负责表的创建、删除等DDL(数据库定义语言)操作,同时在新表上线、集群启动、负载均衡时,负责将各个表的HRegion分配至RegionServer上。ZooKeeper维护集群中所有节点的状态,比如节点出现了故障等。
HBase中的表由行和列族构成,列族对应的逻辑概念是存储。HBase是先写内存,再将内存中的数据刷写至HDFS,因此存储分为内存中的MemStore和HDFS上的StoreFile。HBase架构示意图如图1所示。
▲图1 HBase架构
4.文档模型数据库
文档模型数据库是无模式的,适合处理半结构化数据,如日志、网页、内容等,无须将文档解析为独立字段的表,但支持按文档内的字段进行查询分析等操作,不适合复杂事务场景。
(1)文档模型简介
文档模型数据库用于储存、检索和管理面向文档的信息。与关系型数据库按字段处理不同,在文档模型数据库中,文档是信息处理的基本单位。文档格式其实是半结构化数据,一般是键值对的一个有序集,支持嵌套结构,例如XML、JSON、BSON等。文档模型没有预定义的模式,文档的键和值不要求固定类型和大小。常见的文档模型数据库有CouchDB、MongoDB等。
(2)MongoDB
MongoDB不需要像关系型数据库那样预定义表结构,而是通过BSON将数据和结构保存在一起。参考关系型数据库的库、表、行、列(字段)等层次,MongoDB的逻辑结构分层依次是库、集合、文档、字段,但这些库、集合的作用与关系型数据库中的库、表完全不同,主要是为了便于用户分类组织管理数据。
字段:每个字段包含字段名和字段值两部分。字段名是字符串类型,区分大小写,字段名不能重复。字段值可以是string、int、long、double、boolean、子文档、数组等。
文档:MongoDB中数据的基本存储单元。文档使用BSON结构表示,文档中的字段是有序的,不同序则是不同文档。每个文档都有一个默认的_id键,相当于关系型数据库中的主键,默认是ObjectId类型。若用户不显式定义文档的_id值,MongoDB会自动生成。
集合:集合由若干条文档记录构成,集合是无模式的,即集合中的文档可以拥有不同的结构。在集合上可以对文档中的字段创建索引。
数据库:一个数据库中可以包含多个集合。
5.图模型数据库
图模型数据库适合处理知识图谱、推荐、反欺诈、物流、社交关系等场景。近年来,图模型数据库是各种数据库类型中发展最快的。当前人气最高的图模型数据库仍然是2007年发布的开源图数据库—Neo4j,但Neo4j不支持横向扩展,在处理数据规模上受限于单机,集群模式仅用于高可用和提高查询性能。支持水平扩展的图模型数据库有从Titan发展来的JanusGraph,其底层依赖Hbase、ScyllaDB等作为外部存储。分布式原生图模型数据库有2019年开源的Nebula和2017年发布的TigerGraph(未开源)。
(1)图模型简介
图模型数据库使用图结构进行语义查询,主要是使用节点、边、属性来描述和存储数据。图模型可以高效地存储实体“关系”数据,这个“关系”与关系型数据库的含义不同。最常见的关系数据的例子是人与人之间的关系、知识图谱。
以图形式表达实体之间的关系非常便于关系的检索,无论是正向的还是反向的。如果使用关系型数据库处理“关系”数据,需要使用外键将数据关联起来,在检索时需要执行表间的JOIN操作,计算成本很高,且不便于反向关系查找。
图结构就是顶点、边以及属性的集合。
顶点:图中的节点,每个顶点会有一个唯一的ID,顶点可以拥有一个或者多个属性描述。
边:边用来连接各个顶点,表达节点之间的关系,边可以是无方向的,也可以是单向或者双向的,边也可以拥有属性和ID。
图通常使用邻接矩阵或邻接表等存储模式。邻接指的是顶点之间的关系,如果两个顶点之间有边,则这两个点互为邻接点。邻接矩阵与邻接表分别使用数组与链表作为基础存储数据结构,所以数组与链表的优缺点就是邻接矩阵与邻接表的优缺点。
邻接矩阵使用二维数组来存储图关系,矩阵的行和列都代表顶点,相同行号和列号对应同一个顶点。如果两个顶点之间存在关系,则在数组的相应位置存储相应的数字。对于无向图,则数组可以仅仅是0、1值,0代表无关系,1代表有关系。使用数组存放数据,可以实现数据的快速定位和更新,但如果对于顶点量大但边稀疏的图,例如路网图,会存在很大的存储浪费,因此邻接矩阵适合顶点少、关系稠密的关系图。
邻接表使用链表存储图关系,顶点信息存储在一个一维数组中,数组的每个元素是一个结构体,对应一个顶点,并且每个元素中存储一个指向该元素邻接点链表的指针。
(2)Neo4j
Neo4j是一个有商业支持的开源图模型数据库,它是基于图原生底层存储设计,而不是嫁接在关系型数据库之上设计的。Neo4j具有以下特点:ACID事务处理模式、高可用性、可扩展到数十亿节点和关系、通过遍历可实现高速查询、强大的图形搜索能力。Neo4J通过Cypher语言来操作数据库。Cypher是当前图模型数据库领域主流的图查询语言之一。
Neo4j不支持数据规模的水平扩展,但支持高可用集群模式Neo4j HA。Neo4j由独立的主数据库(Master)和从数据库(Slave)组成,Master主要负责数据的写入,Slave从Master同步数据更改,Slave是Master的精确副本,以提高查询负载支持。如果Master失效,集群将选举出新的Leader作为新的Master。
6.搜索引擎系统
搜索引擎系统不是面向数据库场景设计的,但在某些场景可以替代数据库,作为存储系统,例如文档数据处理、数据分析。搜索引擎系统相对于提取数据系统具有如下特点:
- 全文检索;
- 词干提取;
- 复杂的搜索表达式;
- 搜索结果的排名和分组;
- 分布式搜索以实现高可扩展性。
搜索引擎系统需要的存储空间比其他数据库系统大很多,另外,为了提高搜索的性能,在插入和更新时需要消耗比较多的计算和存储资源去建立索引。流行的开源搜索引擎系统有Elasticsearch、Solr,这两个都是在全文检索引擎工具包Lucene基础上实现的。
Elasticsearch是一个分布式的开源全文搜索和分析引擎,适用于所有类型的数据,包括文本、数字、地理空间、结构化和非结构化数据。Elasticsearch会存储文档并构建倒排索引,支持近实时的、快速的全文本搜索,可以找到包含词汇的全部文档。它通常与Logstash和Kibana配合使用,Logstash进行日志采集,Kibana做可视化展现,合称为ELK,在日志处理领域应用非常广泛。
7.关系模型MPP数据库
在需要大规模数据读取的数据分析场景,传统的单机数据库已无法满足需求,所以一些数据库厂商推出了MPP数据库一体机,但价格昂贵。这时运行在普通硬件集群上的开源MPP数据库软件出现了,最典型的就是Greenplum。
(1)Greenplum介绍
Greenplum数据库系统是基于PostgreSQL开源技术开发的,实际上是由一组PostgreSQL数据库节点组合而成,可以作为一个单一数据库管理系统使用。PostgreSQL是功能最为完善、健壮的开源关系型数据库,因此Greenplum也是所有开源MPP数据库系统中功能支持最为完善的。数据库用户与Greenplum数据库进行交互,就像与常规PostgreSQL DBMS进行交互一样。Greenplum数据库的特点如下所示。
- 并行数据加载;
- 实现新的查询规划器;
- 可以使用追加优化(append-optimized)存储;
- 支持行存储,也支持列存储,可以针对每个表来指定。
(2)Greenplum数据库架构
Greenplum的设计初衷是管理大规模分析数据仓库和BI系统。Greenplum数据库通过在多个服务器之间分布数据和工作负载来存储与处理大量数据,其体系架构实际上是由多台PostgreSQL数据库服务器组成的矩阵。
Greenplum中的服务器节点按功能可分为两种:Master实例和Segment实例。Greenplum架构示意图如图2所示。
▲图2 Greenplum架构
Master是Greenplum数据库系统的入口点,客户端通过Master上的数据库实例连接并提交SQL语句。Master上存储全局系统目录,但不包含任何用户数据。Segment上存储和处理实际数据,它是独立的PostgreSQL数据库,每个数据库都存储一部分数据并执行大部分查询处理。Master协调所有Segment数据库实例的工作。当用户在Master节点上执行SQL查询时,Master会将SQL以及SQL Plan分发到所有Segment节点,待Segment处理好后,再由Segment将数据发回Master节点。
Segment运行在被称作Segment主机的服务器上。一台Segment主机通常运行2~8个Greenplum的Segment,具体取决于CPU核数、RAM、存储、网络接口和工作负载。通常Segment实例所在主机应采用相同的配置,集群的互联网推荐采用万兆网络。
本文摘编于《数据应用工程:方法论与实践》,经出版方授权发布。(书号:9787111704096)转载请保留文章出处。