无论是构建什么样的应用,大都离不开数据。而在应用的架构设计中,如何设计数据库,使用什么类型的数据库,就是一个架构师必须了解的。所有的数据库的共同点都是以某种方式存储数据,以某种接口来访问存储的数据。我们今天就来看看不同类型的数据库架构和它们的使用场景。
关系型数据库以数据表Table为核心来存储数据。数据是一行一行的表记录Record。表之间通过关联关系相互关联。 关系模型是表(行,列)组成的二维结构。SQL是关系型数据库的统一查询接口。
关系型数据库的架构设计,主要是要解决存储和事务。存储是要解决数据的查询问题。而事务则包含了四个特性,A(原子性)C(一致性)I(隔离性)D(持久性)。
上图是一个关系型数据库的典型架构。索引的存在是为了提高数据查询的性能。
索引通常是B/B+树。在没有索引的情况下,通过ID来查找一条数据记录的时间复杂度是O(n),也就是说随着数据量的增加,查询的速度随线性增加。这个是用户不能接受的。在建立了索引之后,如上图所示,访问记录需要从树的根节点通过两次跳转,达到记录。也就是说访问的速度取决于树的深度。这样的时间复杂度为 O(log n) 。访问速度受数据量的影响非常小。(其实在海量数据的情况下,即使是O(log n)也是个问题)
日志是关系型数据库的另一个核心架构设计概念。因为每一个数据库的操作都会以日志的形式记录。系统可以方便的进行事务的回滚。利用日志。系统可以通过日志回放的方式,构建任何一个时间点的系统状态。
优点:
缺点:
比较流行的关系型数据库有Oracle,MySQL,PostgresSQL等等
为了解决关系型数据库的各种限制和问题,各种NoSQL的数据库出现了。键值数据库就是其中一种。
键-值数据库,或键-值存储,是设计用来存储、检索和管理关联数组的数据存储范式,关联数组是现今更常称为“字典”或散列表的一种数据结构。字典包含对对象或记录的一个收集,依次、记录内有多个不同的“域”或称字段,再次、每个字段都包含数据。这些记录使用唯一标识这个记录的“键”来存储和检索,键还用来在数据库中快速的找到数据。
来自wikipedia的定义
键值数据库大大的简化了关系型数据库的表模型。所有的数据存在一个hash中,只包含key和value。
用户可以通过Key来查找记录。而记录的内容可以是任何东西,他们不需要遵守相同的表结构。这样就类似面向对象的封装和多态。 不同于多数的关系数据库,由于不使用占位符或输入参数来表示可选值,键-值数据库经常比同等的关系数据库使用更少的内存。
键值数据库由于其简单的数据模型,而非常适用于水平扩展。我们之前提到了关系型数据库很难提供高并发的大数据量的读取操作。因为关系的存在,数据表的水平分割是非常困难(虽然可以做到)。而键值数据库就很容易经行水平扩展,从而得到非常好的大规模读写的性能。
优点:
缺点:
流行的键值数据库有Redis,DynamoDB,Memcached等。
键值数据库牺牲了复杂性而打来了性能的显著提升。键值数据库由于其简单和高效性,常常被用作系统的缓存。
这里略微提一下DynamoDB,DynamoDB虽然是以Key-Value为核心构建的数据库,但是它也支持了一些扩展。如下图,DynamoDB有Primary Key和Secondary Key,Primary Key中又包含了Partition Key和Sort Key。用户可以通过设计对应的Key来实现相应的业务查询。
文档数据库是另一种类型的NoSQL数据库,他主要是为了解决关系型数据库的表结构固定,不灵活,不支持非结构化数据的问题而诞生的。
文档型数据库存贮的对象是文档对象,而非表。文档通常用JSON或者BSON来表示,例如如下的文档对象。
[
{
"id": 1,
"content": "test a"
},
{
"id": 2,
"content": "test b"
}
]
相比较关系型数据库,它的主要优点是:
当然没有免费的午餐,文档型数据库也会有缺点:
比较流行的文档数据库有MongoDB,Couchbase, DynamoDB (是的,DynamoDB也是一种文档引擎,它支持文档型的内容多为key value的value)
文档型数据库很适合那些表结构经常改变,数据的逻辑结构没又没那么复杂不需要多表查询操作,数据量又比较大的应用场景。
搜索是大数据场景最常见的需求,就是要找到符合某个搜索条件的数据是否存在,并返回。
基于搜索架构的数据库通常的核心技术是倒排表索引和布隆过滤器。
倒排表索引对于每一个需要搜索的关键词建立一个他所在文档的引用记录。这样就可以快速找到对应的需要搜索的文档。
而布隆过滤器是一种类似Hash的技术,对于每一个文档,生成一个类似bitmap的对象,如果一个关键词在该文档中出现,该关键词的hash对应的bit位就会被置为1。这样当一个新的词如果他的hash中有一位对应的bit位的布隆过滤器的值为0,则可以肯定该关键词没有出现在该文档中。当然,如果所有的hash位都为1,也不能保证该词一定出现在该文档中。利用布隆过滤器,可以快速排除不包含搜索内容的文档,这个也是搜索引擎广泛采用的技术。
搜索型数据库的优点:
缺点:
流行的基于搜索的数据库有Elastic Search,Splunk,Solr。 其中Elastic和Solr都是构建在Apache Lucene上的分布式搜索引擎。
搜索引擎数据库常常被用于系统的运维和监控。我们通常会把一些日志信息导入到基于搜索引擎的数据库中来进行分析和监控。
我这里把列存储数据库和宽列数据库放在一起,它们其实是有些差异的。
传统 OLTP 数据库通常采用行式存储。所有的列依次排列构成一行,以行为单位存储,再配合以 B+ 树或 SS-Table 作为索引,就能快速通过主键找到相应的行数据。行式存储对于 OLTP 场景是很自然的:大多数操作都以实体为单位,即大多为增删改查一整行记录,显然把一行数据存在物理上相邻的位置是个很好的选择。
然而,对于 OLAP 场景,一个典型的查询需要遍历整个表,进行分组、排序、聚合等操作,这样一来按行存储的优势就不复存在了。更糟糕的是,分析型 SQL 常常不会用到所有的列,而仅仅对其中某些感兴趣的列做运算,那一行中那些无关的列也不得不参与扫描。
列式存储就是为这样的需求设计的。同一列的数据被一个接一个紧挨着存放在一起,表的每列构成一个长数组。
显然,列式存储对于 OLTP 不友好,一行数据的写入需要同时修改多个列。但对 OLAP 场景有着很大的优势:
列式存储是为了分析而优化的,它的优点是分析查询的速度快。但不支持事务,一般对写操作不友好。
面向列存储的数据库有:Google Dremel,Apache Parquet
在关系型数据库中,不能将宽列存储与面向列存储相混淆。这是一个内部概念,用于提高RDBMS针对OLAP工作负载的性能,并存储表中的数据,而不是逐条记录,而是逐列存储。
宽列存储(也称为可扩展记录存储)将数据存储在记录中,并且能够容纳大量动态列。由于列名和记录键不是固定的,并且一条记录可以包含数十亿列,因此宽列存储可以看作是二维键值存储。
宽列存储与文档存储共享Shema-free的特性,但是实现却大不相同。
宽列存储的优点:
宽列存储的缺点:
宽列数据库比较流行的有:Cassandra,HBase, Google bigtable
时间序列DBMS是为处理时间序列数据而优化的数据库管理系统:每个条目都与时间戳关联。
例如,时间序列数据可以由所谓的物联网中的传感器,智能电表或RFID生成,或者可以描述高频股票交易系统的股票报价器。
时间序列DBMS旨在有效地收集,存储和查询具有高交易量的各种时间序列。尽管可以使用其他类别的DBMS(从键值存储到关系系统)来管理时间序列数据,但是特定的挑战通常需要专门的系统。例如。像“ SELECT SENSOR1_CPU_FREQUENCY / SENSOR2_HEAT”之类的查询会根据每个时间的重叠区域将两个时间序列合并在一起,并输出单个复合时间序列。
时序数据库的特点有一点类似我们之前的OLAP,它们都是写多读少。要按照指定的维度进行读取和聚合。
流行的时序数据库有: InfluxDB, Prometheus, Kdb+ 等等
图数据库,也称为面向图的数据库,将图结构中的数据表示为节点和边,即节点之间的关系。它们允许轻松处理该形式的数据,并且可以简单地计算图形的特定属性,例如从一个节点到另一节点所需的步骤数。
图数据库通常不会在所有节点上提供索引,在这种情况下,无法基于属性值直接访问节点。
通常,在图计算中,基本的数据结构表达就是:
G=(V, E)V=vertex(节点)E=edge(边)
流行的图数据库有Neo4J,Dgraph,TigerGraph
除了上述提到的数据库类型,还有其它的一些例如对象数据库,事件数据库,内容数据库等,我这里就不列出了,大家可以在用到的时候其查找相应的内容。
希望上述内容能够帮助架构师在选择架构中的数据存储的时候,有所帮助!