数据库系统设计概述

数据库系统设计概述

2023年7月27日发(作者:)

数据库系统设计概述世界上只有两种开发⼈员,⼀种使⽤数据库系统的,⼀种开发数据库系统的。数据是系统最重要的信息。⼤部分系统都是对数据的管理。应⽤系统通过数据模型来构建现实世界,通过算法操作对象或数据结构,来改变数据模型的状态。数据被组织在操作系统⽂件中,我们通过数据系统来组织,查询,搜索,处理数据。本⽂将从数据库的发展、数据库的分类、常见数据库架构,数据库常见概念和技术等⽅⾯探讨这个我们接触最多的底层系统,并通过穿插不同数据库的实现原理,来了解数据库的具体实现。本⽂分为五个⼤章节。探古溯源,从数据库的诞⽣,发展,现状和展望来了解数据库存在的意义,以及数据库设计的历史与现实原因。百家争鸣,本节从不同分类⽅式,讲解⼀些不同的数据库系统实现,有助于拓展我们的视野,在技术选型时可以作为参考(底层数据库系统的选型对整个系统的架构实在太重要了)。承上启下,本节是整篇⽂章的中间章节,前两章以兴趣点,纯理论展开,在本节中将对前两章做⼀个总结,有了前两章知识,我们已经可以去选择适合项⽬需求的数据库系统,对那些想更深⼊了解底层存储的同学也可以选择⾃⼰感兴趣的数据库类型和⽅案找到相应的实现,从⽽进⼊下⼀步学习。下⾯两章将讲解更多具体的技术点。知⾏合⼀,这⼀章节将讲解数据库的实现,分析⼀些数据库架构,分布式问题和解决⽅案,透析具体的数据库常见的技术点。针对不同兴趣,⼤家可以按需取之,跳过不感兴趣的,看想关注的点。⼀、探古溯源疑今者察之古,不知来者视之往。——《管⼦》数据库管理系统允许⼈员组织,存储和从计算机检索数据。在计算机的早期,使⽤“打孔卡”⽤于输⼊,输出和数据存储。打孔卡提供了⼀种快速的数据输⼊和检索⽅法。数据库在计算机的最新发展中起了⾮常重要的作⽤。第⼀批计算机程序是在 1950 年代初期开发的,⼏乎完全专注于编码语⾔和算法。当时,计算机基本上是⼤型计算器,数据(名称,电话号码)被认为是处理信息的残余物。当计算机开始商业化后,数据的重要性开始越来越被⼈重视。题外话:穿越时间——笔者去了解⼀个东西,总喜欢追根溯源,从时间的起点,或从逻辑的深处开始探索。⼀个东西的逻辑原点往往是纯粹的简单的,之后随时间发展和⼴延的展开会逐渐复杂起来。所以从头开始了解⼀个东西,往往更容易理解。⽐如我们看⼀个系统的源码,可以从该系统的 1.0.0 版本开始,可以从这个系统最初想要解决的问题开始。计算机数据库始于 1960 年代。此⼗年中,有两种流⾏的数据模型:称为

CODASYL 的⽹络模型和称为 IMS 的层次模型。SABER 系统被证明是商业上成功的⼀种数据库系统,该系统被 IBM ⽤来帮助美国航空管理其预订数据。1970 年,⼤神 EF Codd 发表了⼀篇重要的论⽂:《》,提出了使⽤关系数据库模型的建议,他的想法改变了⼈们对数据库的看法。在他的模型中,数据库的架构或逻辑组织与物理信息存储断开连接,这成为数据库系统的标准原理。之后 UBC 开发了 Ingres 和在 IBM 开发了SystemR。Ingres 使⽤⼀种称为

QUEL 的查询语⾔,引导⽽诞⽣了

Ingres Corp,MS SQL Server,Sybase,PACE 和

Britton-Lee 之类的系统。另⼀⽅⾯,System R 使⽤

SEQUEL 查询语⾔,它有助于

SQL / DS,DB2,Allbase,Oracle 和

Non-Stop SQL 的开发。关系数据库管理系统(RDBMS)已经成为公认的术语。1976 年 P. Chen 提出了⼀个新的数据库模型,称为

Entity-Relationship,即

ER。该模型使设计⼈员可以专注于数据应⽤程序,⽽不是逻辑表结构。1980 年结构化查询语⾔或 SQL 成为标准查询语⾔。RDBM系统是存储和处理结构化数据的有效⽅法。然⽽,随着互联⽹的快速发展,“⾮结构化”数据(视频,照⽚,⾳乐等)变得更加普遍。⾮结构化数据既是⾮关系数据,⼜是⽆模式数据,⽽关系数据库管理系统根本就没有设计⽤于处理此类数据。21 世纪后,NoSql模型进⼊⼈们的视野,NoSql 的出现是对互联⽹以及对更快的速度和对⾮结构化数据的处理需求的⼀种回应。⼀般⽽⾔,由于 NoSQL 数据库的速度和灵活性,它们在某些⽤例中⽐关系数据库更可取的。NoSQL模型是⾮关系型的,并且采⽤“分布式”数据库系统。这个⾮关系系统速度很快,使⽤临时组织数据的⽅法,并且处理⼤量不同类型的数据。⼀般⽽⾔,NoSQL 相对于 RDBMS 系统有如下优势:更⾼的可扩展性分布式计算系统低成本灵活的架构可以处理⾮结构化和半结构化数据没有复杂的关系在数据库的发展历程中,虽然只经历了短短半个世纪,却诞⽣了⼀批优秀的数据库系统,SystemR、Postgresql、Mysql、DB2、Oracle、MongoDB、HBase、Neo4j、Elasticsearch 等等,都在软件的发展中发挥了重要的。⼆、百家争鸣现在春天来了嘛,⼀百种花都让它开放,不要只让⼏种花开放,还有⼏种花不让它开放,这就叫百花齐放。—— ⽑润之迄今为⽌,业界诞⽣的数据系统数不胜数。如果你打开,可以看到⼏百个功能定位不同的数据库系统。查看DB-Engines的分类排名,可以看出DB-Engines将如此众多的系统⼤致分为以下⼏类():Willian Blair 在《Database Software Market:The Long-Awaited Shake-up》⼀⽂中以以下维度为数据库系统做了⼀个细致的分类:关系型/⾮关系型、操作型/分析型。上图中的纵轴分类为

Relational Database(关系型数据库,RDBMS)和

Nonrelational Database (⾮关系型数据库,NoSQL),横轴的分类为Operational(操作型,即 OLTP)和 Analytical(分析型,即 OLAP)。⾮关系型的分类是⼀个⽐较笼统的划分,主要是针对传统关系型来区分的,与传统关系型系统模型不⼀致的都划分到了⾮关系型中。⾮关系型(NoSQL)可以再进⼀步划分:Key-Value 型、列存储型、⽂档型、图数据库等。⽂档存储:MongoDB、Elasticsearch、Amazon DocumentDB、Azure Cosmos DB 等。Key-Value 存储:Redis Labs、Oracle Berkeley DB、Amazon DynamoDB、Aerospike、LevelDB 等。图数据库:Neo4j 等。时序数据库:InfluxDB、Timescale 等。WideCloumn:DataStax、Cassandra、Apache HBase 和 Bigtable 等。关系模型关系型模型是⼤多数开发⼈员接触最早,接触最多的数据库模型。它基于集合理论,是最经典的数据库模式。关系型数据库采⽤⾏和列的⼆维表来建模数据。它适合于提前知道数据模型,并且数据模型⽐较固定,发⽣变化⽐较⼩,对查询⽐较灵活的场景,你只需要将数据以⾏和列的⽅式存储,在查询的时候以不同的需要组合数据。关系型不适合数据层次较多,记录与记录之间关联较多的场景,这种场景往往造成查询复杂度上升,查询性能下降。关系型数据库主要⽤于⼤多数商业数据处理,其⼤多数是事务处理(如 ERP 系统、银⾏交易、航空公司订票、销售系统、⾦融财务管理系统等)和批处理场景(如客户发票、⼯资单、报告等)。20 世纪 70 年代⾄今,关系型数据库经久不衰,其简洁的数据模型和经典的 SQL 查询语句⽀撑了当前⼤部分互联⽹系统,在线论坛、社交⽹络、电⼦商务等等,各式各样的系统背后,都隐藏着⼀个强⼤的关系数据库。关系型数据库⽤的⽐较多的除了

Oracle、Sql Server 等商业数据库外,就是

Mysql 了,另外本⼈⽐较喜欢和推崇是

Postgresql,被称为世界上功能最强⼤的开源数据库。分析的世界联机分析处理(Online analytical processing),简称OLAP,OLAP 是相对与传统的OLTP(联机事务处理,Online TransactionProcessing)系统⽽⾔的,OLTP 是传统的关系型数据库的主要应⽤,侧重于基本的、⽇常的交互式的事务处理,例如银⾏交易。OLAP 是数据仓库系统的主要应⽤,⽀持复杂的分析操作,侧重分析决策⽀持,并且提供直观易懂的查询结果。OLAP ⼯具让⽤户能够从多个⾓度交互地分析多维数据。OLAP 由三个基本的分析操作组成:上卷(roll-up)、钻取(drill-down)、切⽚(slicing)和切块(dicing)。上卷涉及可以在⼀个或多个维度中累积和计算的数据的聚合。OLAP 利于⼤数据量,数据更新少,经常使⽤⼤量数据做聚合统计的场景。OLTP 适合数据量⼩,频繁操作更新数据的场景。OLAP 主要应⽤于商业智能、风控分析、智能报表等业务场景。分析和事务是两个世界。在分析需求不⼤的时候,很多团队直接使⽤业务事务数据库做分析使⽤,这只能⽀持⼩数据量、分析需求变化不⼤,弱分析的场景。真正的数据分析场景,往往使⽤单独的数据仓库。在不影响业务库的情况下,实时或周期批量地从中提取数据,转换成对分析友好的数据模式,执⾏必要的清理和转换,然后加载到数据仓库中。将数据导⼊仓库的过程称为提取-转换-加载(Extract-Transform-Load,ETL)。OLTP和OLAP没有明确的边界,它们的⼀些典型特性如下所⽰:OLTP⽤户功能数据存取读特征写特征⽇常操作处理OLAP操作⼈员,底层管理⼈员决策⼈员,⾼级管理⼈员分析决策⾯向主题读百万级数据基于⼤量数据汇总批量或数据流100GB~~TB对时间的要求不严格DB 设计⾯向应⽤读写数⼗上百条数据基于键,返回少量数据随机访问,低延迟当前的,新的,细节的,⼆维的,分⽴的历史的,聚集的,多维集成的,统⼀的DB ⼤⼩100MB~~GB时间要求实时性主要应⽤数据仓库OLTP数据库OLAP业界有许多优秀的开源的 OLAP 系统,⽐如:Druid:Metamarkets 公司开发的⼀个⽤于⼤数据实时处理的开源分布式系统。⽬前已经成为 Apache 的开源项⽬。Kylin:Apache Kylin™ 是⼀个开源的、分布式的分析型数据仓库,提供 Hadoop/Spark 之上的 SQL 查询接⼝及多维分析(OLAP)能⼒以⽀持超⼤规模数据,最初由 eBay 开发并贡献⾄开源社区。它能在亚秒内查询巨⼤的表。Presto:Presto 是⼀个对 PB 级数据运⾏交互式分析的开源分布式 SQL 查询引擎。ClickHouse:ClickHouse 是由号称“俄罗斯 Google”的 Yandex 开发的⼀个列存储的 OLAP 系统。列式存储传统 OLTP 数据库通常采⽤⾏式存储。以下图为例,所有的列依次排列构成⼀⾏,以⾏为单位存储,再配合以 B+ 树或 SS-Table 作为索引,就能快速通过主键找到相应的⾏数据。⾏存储适⽤于 OLTP 场景,OLTP 的⼤多数操作都是以实体(Entity)为单位,即对每条记录的增删改查,因此将⼀⾏数据在物理上放在相邻的位置更利于操作,也更利于特定的优化。在 OLAP 场景中,极少单独操作单条记录的情况。OLAP 分析往往针对⼤量的数据集,在⼤量的数据集的基础上对特定的列做分组、过滤、聚合操作。因此在物理上将每列数据放在相邻的位置。这样如果针对某⼀列做分析聚合,只需要找到相应列的⽂件,或数据块的位置,⽐如,要计算上图数据的平均 Age,只需要获取 Age 列的数据集即可。但是,⾯向⾏的存储引擎仍然需要将所有⾏从磁盘加载到内存中、解析它们,并过滤出不符合所需条件的⾏。这可能需要很长的时间。基于列模式的存储,天然就会具备以下⼏个优点:⾃动索引因为基于列存储,所以每⼀列本⾝就相当于索引。所以在做⼀些需要索引的操作时,就不需要额外的数据结构来为此列创建合适的索引。利于数据压缩利于压缩有两个原因。⼀来你会发现⼤部分列数据基数其实是重复的,拿上⾯的数据来说,因为同⼀个 author 会发表多篇博客,所以author 列出现的所有值的基数肯定是⼩于博客数量的,因此在 author 列的存储上其实是不需要存储博客数量这么⼤的数据量的;⼆来相同的列数据类型⼀致,这样利于数据结构填充的优化和压缩,⽽且对于数字列这种数据类型可以采取更多有利的算法去压缩存储。列式存储的概念其实很早就有,只是应时代所需,列式存储在近⼏年才⽕热起来,⼀时涌现了很多优秀的列式存储数据库,甚⾄很多之前的⾏存储系统,也有了列式存储的能⼒。Hbase:⼀个分布式的、⾯向列的开源数据库,该技术来源于 Fay Chang 所撰写的 Google 论⽂《Bigtable:⼀个结构化数据的[分布式存储系统]》。HBase 不同于⼀般的关系数据库,它是⼀个适合于⾮结构化数据存储的数据库。另⼀个不同的是 HBase 基于列的⽽不是基于⾏的模式。Cassandra:它最初由 Facebook 开发,⽤于改善电⼦邮件系统的搜索性能的简单格式数据,集 Google BigTable 的数据模型与Amazon Dynamo 的完全分布式架构于⼀⾝。Facebook 于 2008 将

Cassandra 开源,此后,由于

Cassandra 良好的可扩展性其被许多知名⽹站所采⽤,成为了⼀种流⾏的分布式结构化数据存储⽅案。其中上⼀章节提到的很多 OLAP 数据库⼤多数是⾯向列式存储的。如

Druid、ClickHouse 等。检索不再⾼深曾⼏何时,全⽂检索是⼀个多么⾼深的技术,虽然如 Google 这样的全⽹搜索引擎背后的搜索算法和技术依然不是轻易就可以实现的。但现在⼤⼤⼩⼩的各种 App,⽹站的搜索功能的背后技术基本被⼀个强⼤的开源系统轻松就可以实现了。这个系统就是

Elasticsearch,⼀个基于Lucence 的分布式实时全⽂检索数据库。伦敦的公寓内,Shay Banon 正在忙着寻找⼯作,⽽他的妻⼦正在蓝带 (Le Cordon Bleu) 烹饪学校学习厨艺。在空闲时间,他开始编写搜索引擎来帮助妻⼦管理越来越丰富的菜谱。他的⾸个迭代版本叫做 Compass。第⼆个迭代版本就是 Elasticsearch(基于 Apache Lucene 开发)。他将 Elasticsearch 作为开源产品发布给公众,并创建了 #elasticsearch IRC 通道,剩下来就是静待⽤户出现了。公众反响⼗分强烈。⽤户⾃然⽽然地就喜欢上了这⼀软件。由于使⽤量急速攀升,此软件开始有了⾃⼰的社区,并引起了⼈们的⾼度关注,尤其引发了 Steven Schuurman、Uri Boness 和 Simon Willnauer 的浓厚兴趣。他们四⼈最终共同组建了⼀家搜索公司。⼀个程序员为帮助妻⼦管理菜谱开发的搜索⼯具最终称为⼀个强⼤的全⽂检索数据库。看来,⾯向对象依然是程序员创作的强⼤灵感源泉之⼀。将⾮结构化数据中的⼀部分信息提取出来,重新组织,使其变得有⼀定结构,然后对此有⼀定结构的数据进⾏搜索,从⽽达到搜索相对较快的⽬的。这部分从⾮结构化数据中提取出的然后重新组织的信息,称之索引。将这些索引与⽂档建⽴映射关联,通过索引检索出对应的⽂档数据,这种词汇到⽂档的映射被称之为倒排索引。先建⽴索引,再对索引进⾏搜索的过程就叫全⽂检索。提到全⽂检索,不得不提到的⼀个技术就是 Lucene,Lucene 是 apache 下的⼀个开放源代码的全⽂检索引擎⼯具包。提供了完整的查询引擎和索引引擎,部分⽂本分析引擎。Elastisearch 就是基于 Lucene 的⼀个分布式开源全⽂检索数据库。它提供了⼀个分布式多⽤户能⼒的全⽂搜索引擎,基于 RESTful web 接⼝。Elasticsearch 是⽤ Java 开发的,并作为 Apache 许可条款下的开放源码发布,是当前流⾏的企业级搜索引擎。设计⽤于云计算中,能够达到实时搜索,稳定,可靠,快速,安装使⽤⽅便。许多系统的搜索功能背后,其实就是⼀个强⼤的 Elastisearch 服务,Elasticsearch 也常由于⽇志检索,数据分析场景。K-V 缓存霸主在整个计算机系统中磁盘和⽹络是最慢的部分,⼀个系统中最重要的东西就是数据,⽽⽬前系统中的数据最终都存储在磁盘上。因此当前磁盘缓慢的读写速度和⼈民对系统响应数据和系统⾼并发之间的⽭盾,就是⽬前系统需要解决的主要⽭盾。将透彻了,所有的系统优化都是在缓解这个⽭盾。为提供系统响应数据和并发能⼒,⼀个最常见的⼿段就是缓存。在计算机系统中,CPU,内存,磁盘,⽹络的访问效率差着不同的数量级,为缓解这种数量级带来的访问效率问题,最常见的⼿段就是缓存。CPU 和内存之间有缓存,称之为 CPU ⾼效缓冲;内存和磁盘之间也⾃带缓存。在分布式系统中,数据库访问的压⼒,我们常常使⽤分布式缓存系统来解决。Redis 是⼀个⾼性能的 key-value 数据库。它⽀持存储的 value 类型相对更多,包括 string(字符串)、list(链表)、set(集合)、zset(sorted set --有序集合)和 hash(哈希类型)。Redis ⽀持缓存过期时间,原⼦操作,数据持久化,⽀持集群模式。K-V 缓存:将数据 K-V 化并缓存在 Redis 中,从⽽提⾼数据的访问效率,减⼩数据库的访问压⼒,这种常见的系统优化策略。分布式锁:分布式锁,就是⼀个全局的临界资源,通过对这个临界资源的独占达到⼀种全局锁的功能,任何全局共享资源都可以实现分布式锁的功能,甚⾄ MySql,分布式⽂件系统。基于 Redis 的分布式锁,是常见的⼀种实现。PubSub:发布订阅的管道功能本不应该是⼀个分布式缓存系统的功能,但 Redis 实现了这⼀部分功能,在⼀些简单的发布订阅场景下也可以很好的⼯作。布隆过滤器:通过⼀个 bit 的 0 或 1 来表⽰ key 是否存在,通过 bit 集合来表⽰⼀组数据,这就是简单的布隆过滤器的实现。相对与⽤类似 Hash 的⽅式来存储 key 映射 boolean 值的⽅式,布隆过滤器可以节省⼤量的空间。Redis 就有布隆过滤器的实现。布隆过滤器常⽤来对⼤量数据做 True Or Flase 的判断,⽐如缓存是否存在,⽐如⼤量⽤户是否有权限。HyperLogLog:HyperLogLog 是⽤来快速计算基数的。基数,即不重复元素的个数(类似 SQL 的 count distinct)。⼯具:介绍⼀些好⽤的 Java 技术栈的相关⼯具。,阿⾥开源的⼀个基于注解的缓存框架。,⼀个强⼤的 Redis Java 客户端⼯具。⼩⽽精通常我们使⽤的数据库系统⼤多是 Client-Server 模式的,即数据库服务作为⼀个常驻进程运⾏在 Server 端,应⽤程序通过 TCP/IP 协议访问数据库系统。还有⼀种嵌⼊式的数据库,可以运⾏在本机中,这种数据库嵌⼊到应⽤程序中,随应⽤程序启动,数据存储在本地磁盘中。这种数据库是轻量的,⼀般占⽤内存少,代码精简。:遵守 ACID,实现了⼤多数 SQL 标准,⽀持 SQL 语法。⽀持 JDBC。:⼀个 Java 编写的关系型数据库,它可以被嵌⼊ Java 应⽤程序中使⽤,或者作为⼀个单独的数据库服务器运⾏。Spring Boot 内置的数据库。Berkeley DB:⼀个⾼效的嵌⼊式数据库和键-值数据库编程库。:是 Google 开源的持久化 KV 单机数据库,具有很⾼的随机写,顺序读/写性能,LevelDB 应⽤了 LSM(Log Structured Merge) 策略。另⼀个 Facebook 基于 levelDB 开发的 RocksDB,也是⼀个⾼性能的 key-value 型内嵌式存储引擎。LevelDB 或 RocksDB 常常被当作存储引擎使⽤。⽐如强⼤的时间序列数据库 Influxdb 早期底层存储引擎就是⽤于的 LevelDB;RocksDB 是流式计算框架 Flink 的Checkpoint 的底层存储引擎;著名的分布式 Actor 框架 Akka 也使⽤ RocksDB 作为默认的 checkpint 存储。由于其强⼤的顺序读写能⼒,也常常⽤来做 WAL(write-ahead-log)⽇志存储引擎。这些⼩⽽精的嵌⼊式数据库,除了⽤在⼀些⼩型设备上,如⼿机客户端等。也常常被⽤于很多⾃研数据库系统的存储引擎。这些⾃研的数据库系统,以上⾯那些嵌⼊式数据库作为存储引擎,在上⾯实现⾃⼰特有功能,从⽽实现⼀个特殊的数据库系统,⽐如扩展分布式功能,基于其现实⼀个分布式存储系统;⽐如基于 LevelDB 等实现磁盘队列,和分布式队列;⽐如基于其存储特殊的模型的数据,如时间序列数据库;⽐如基于其实现本地操作⽇志记录和重试提交,实现最终⼀致性的分布式事务解决⽅案。三、承上启下前⼏章我们已经了解了数据库系统的发展,也从不同⾓度了解了数据库系统的不同分类,并且了解到了许多不同功能场景的数据库系统。为我们如何选择数据库系统已经增添了⼀份基础知识。我们应该如何选择⼀个适合的存储⽅案呢?原则1. 选择是基于需求确定的。所以必须明确需求场景,然后按需求场景选择适合的存储⽅案。2. 没有调查就没有发⾔权。⽅案调研就是⼀个调查过程,需要先了解不同数据库的基本特性,才能选择合适的存储⽅案。基本场景和前章数据库系统的分类很相似。其实上⾯数据库系统的分类⼀⽅⾯就是基于不同的使⽤场景才设计的,从⽽有不同实现的数据库系统,从⽽有针对不同场景的特殊优化,从⽽逐渐形成了不同场景的特殊模型。事务性,如 Mysql 这些是最常见的事务性系统使⽤的存储⽅案,满⾜ ACID,使⽤简单。⽀持千万级别数据级别的读写。分析性,适合 BI,数据报表、数据监控等数据服务系统。⽂档型,适合⾼度可变的数据模型,当你事先不知道你的数据看起来究竟像什么样⼦,⽂档型是⼀个不错的选择,⽂档型也适合点查询多余集合查询的场景。图数据库,图数据库是⼀种很特殊的,新兴的数据库类型,它侧重于分析解释数据之间的相互关系⽽不是数据值本⾝,它适合推荐引擎、权限访问控制和地理数据等场景。时序性,时序性数据库在数据分析,时序数据展⽰,监控领域使⽤⽐较多,它适合对⼤量时间型数据查询、过滤、组合、聚合分析等。K-V 型,缓存和固定 View 模式的数据展⽰,K-V 型的需要按查询组合好存储起来,这样查询时按 key 获取即可。读写是否需要写事务顺序读写还是随机读写偏点查询还是⼤量数据集分析查询数据结构变化⼤,还是查询结构变化⼤数据量数据量,需要考虑数据的数量,也需要考虑数据数量的增长速度,这样就需要考虑数据库的量级承载能⼒以及⽔平扩展能⼒。数据⽤途对临时数据和重要的业务数据的存储可以采⽤相对侧重点不⼀致的⽅案。对数据的⼀致性要求的强弱也会影响数据存储系统的选型。对数据事务的要求,对数据保存时间的选择也会不⼀样。可靠性数据的可靠性即保证数据的可⽤的能⼒,可靠性与成本⼀般是权衡的⼀体两⾯,需要对数据可⽤性的要求选⽤不同的存储架构。可扩展性可扩展性表现在数据使⽤的可扩展和系统本⾝的可扩展上。可维护性可运维性:⽅便运营团队来保持系统平稳运⾏。简单性:简化系统复杂性,使新⼯程师能够轻松理解系统。可演化性:后续⼯程师能够轻松地对系统进⾏改进,并根据需求变化将其适配到⾮典型场景,也称为可延伸性、易于修改性或可塑性。学习和了解数据底层存储,除了可以搭建良好的存储架构是提供思路上的帮助,也可以让我们学习到很多平时纯业务开发接触不多的底层技术实现。对底层技术的了解和掌握,⼜可以反过来让我们更加了解我们的整个业务系统,对系统的合理性优化做出重要的选择。也可以帮助我们实现⾃⼰的系统。开源数据库系统的良好的分布式架构,优秀的⽹络通信,性能强劲的内存和磁盘访问优化以及更多经典的数据接⼝和算法都是值得我们学习和借鉴的。四、知⾏合⼀知是⾏的主意,⾏是知的⼯夫;知是⾏之始,⾏是知之成。—— 王阳明这⼀章节将简单讲解⼀些数据库系统的常见技术点。系统架构Master-SlaveMaster-slave 架构可以说是最常⽤的数据存储架构,关系型数据库如:mysql,postgreSql,oracle,Nosql 诸如:MongoDb,消息队列如:Kafka,RabbitMQ 等都使⽤了这种架构。在整个系统中,Master 承担写任务,Slave 通过复制 Master 的数据保证与 Master 数据的⼀致性。Master 和 Slave 都可以承担读任务。Master 架构解决了数据的⾼可⽤问题(Slave 存储了数据副本),也扩展了数据读并发能⼒(多 Slave 同时通过读请求)。在 Master-Slave 架构中,单 Master 如果出现故障,就会导致这个数据库系统不可⽤,这时就可以采⽤ Master-Master 架构,系统中同时存在多个 Master 节点,但是,多个 Mater 节点并不同时提供写服务,同时只会存在⼀个可写的 Master,另⼀个 Master 作为备机存在,只有当其他 Master 不可⽤时才会被选举称为 Master 节点提供写服务,作为备机的 Master 是可以提供读服务的。这种架构的只解决了单 Master 节点的⾼可⽤问题,并没有解决单 Master 负载过⼤的问题,这⾥之所以只有⼀个 Master 提供写服务,是为了保证写数据的⼀致性问题。数据⼀致性我们将同⼀份数据在不同数据节点上的存储称之为副本。只要系统中数据存在多个副本,就会有数据⼀致性问题。如何保证数据多副本的⼀致性,⼀直以来都是分布式系统的最⼤挑战。多节点数据同步,⼀般采⽤复制⽅式,从节点复制主节点的数据,多节点之间相互复制等等,但⽆论采⽤哪种⽅式,都⽆法避免不⼀致的情况。数据⼀致性可以分为最终⼀致性和强⼀致性。强⼀致性模型能够允许你的单服务程序移植到分布式节点集群上并且不会发⽣任何错误。强⼀致性往往通过牺牲系统可⽤性来达到,在写⼊数据时,如⽆法保证多副本⼀致,则失败。最终⼀致性模型中,当停⽌改变数值的⼀段不确定的时间后,所有的复制集将会最终保持⼀致。这表明,在这段时间之前,数据副本在某种情形下是不⼀致的,但数据最终会达到⼀致,最终⼀致性意味着“收敛”,即预期所有的副本最终会收敛到相同的值。在数据收敛过程中,为保证最终数据的⼀致性性,还有许多问题需要解决。如系统间的时序问题,原⼦提交问题,共识问题。CAP 理论定理:⼀个分布式系统不可能同时满⾜ consistency、availability、partition tolerance 这三个基本需求,最多同时满⾜两个。consistency ⼀致性:所有节点同⼀时刻看到相同数据availability 可⽤性:节点失败不阻⽌影响正在运⾏的节点的⼯作partition tolerance 分区容错:即使出现信息丢失或⽹络、节点失败,系统也能继续运⾏(通过复制)这三种性质进⾏俩俩组合,可以得到下⾯三种情况:CA:完全严格的仲裁协议,例如 2PC(两阶段提交协议,第⼀阶段投票,第⼆阶段事物提交)CP:不完全(多数)仲裁协议,例如 Paxos、RaftAP:使⽤冲突解决的协议,例如 Dynamo、GossipCA 和 CP 系统设计遵循的都是强⼀致性理论。不同的是 CA 系统不能容忍节点发⽣故障。CP 系统能够容忍 2f+1 个节点中有 f 个节点发⽣失败。分区上⾯说副本只能保证数据的可⽤性。为提⾼⼤量数据集的读写能⼒,我们可以将数据拆分成不同的分区分开处理,这种技术称之为分⽚。分⽚,即将数据集分割成相互独⽴的⼩数据集,减少因数据集增长⽽带来对单个节点的压⼒。数据分⽚有以下好处:提⾼性能:限制分区中数据量的⼤⼩,降低数据压⼒提⾼可⽤性:数据之间相互独⽴,不同分区之间失败互不影响,允许失败节点的存在分区⾃然也会带来⼀些问题,⾸先需要考虑的就是如何分区的问题。基于关键字区间:将数据按关键字划分为不同区间,将相同区间的数据写⼊同⼀个节点。⽐如⽤户数据 id 分布在[1-1000000]之间,需将数据分布到 10 个节点上,可以将数据划分成⼗个区间:关键字哈希分区: 通过 Hash 算法计算分区号,将数据写⼊相应分区号的分区中。数据分区带来的负载倾斜和热点问题:由于数据的不确定性,数据关键字计算出来的分区存储可能集中在某⼏个区间内,这样就可能导致某些节点数据明显多余其他节点,这种数据集中于某个节点的情况就是数据热点。由于数据热点的出现,整个系统的负载将倾斜到这些节点上,造成分区间的负载不均衡,这就是负载倾斜问题。去中⼼化:DynamoDynamo 是 Amazon 的⼀个分布式存储。Amazon 发表了⼀篇论⽂ 讲解 Dynamo 架构,使得 Dynamo 称为许多数据存储系统借鉴的架构。Dynamo 基于⼀些众所周知的技术实现了可扩展性和⾼可⽤性:数据通过⼀致性哈希算法进⾏分区和复制(partitioned and replicated)通过对象版本化(object versioning)实现⼀致性副本之间的⼀致性由⼀种仲裁的技术(quorum-like technique)和⼀个去中⼼化的副本同步协议(replica synchroni protocol)来保证基于 gossip 协议进⾏分布式故障检测和成员检测(membership)协议管理节点Dynamo 是⼀个完全去中⼼化的系统。向 Dynamo 添加或移除存储节点不需要⼈⼯ partition(调整哈希节点)或 redistribution(在节点之间重新平衡数据分布)Dynamo 采⽤最终⼀致性⽅案。⽣产级别的存储系统的架构是很复杂的。除了最终存储数据的组件之外,系统还要针对以下⽅⾯制定可扩展和健壮的解决⽅案:负载均衡、成员管理(membership)、故障检测、故障恢复、副本同步、过载处理(overload handling)、状态转移、并发和任务调度、请求marshalling、请求路由(routing)、系统监控和告警,以及配置管理。下表总结了 Dynamo 使⽤的这些技术及每项技术的好处。Partition技术:⼀致性哈希好处:增量可扩展性写⾼可⽤技术:读时协调(解决冲突)的向量时钟(vector clocks with reconciliation during reads)好处:version size 和更新频率(update rates)解耦短时故障处理技术:宽松的选举和 hinted handoff(移交给其他节点处理,附带提⽰信息)好处:部分副本不可⽤时,仍然可以提供⾼可⽤性和持久性持久(permanent)故障恢复技术:基于

Merkle tree 的逆熵(anti-entropy)好处:后台同步版本不⼀致的副本成员管理和故障检测技术:基于

Gossip 的成员管理协议和故障检测好处:保持了架构的对称性,⽆需⼀个中⼼组件(centralized registry)来存储成员和节点状态等信息分布式数据库 Cassandra

就是 Dynamo

的典型实现。有主架构:BigtableBigtable 是 google 开源的数据库系统。Bigtable 是典型的有主架构。Bigtable 主要由三个组件构成:1. ⼀个客户端库,会链接到每个客户端2. ⼀个 master server3. 多个 tablet servermaster 负责:1. 将 tablet 分配给 tablet server2. 检测 tablet server 的过期(expiration)及新加(addition)事件3. 平衡 tablet server 负载4. 垃圾回收(GC)5. 处理 schema 变动,例如 table 和 column family 的创建BigTable 的 Master 只负责元数据的管理,Table Server 负载⾃⾝管理的 Table 的读写功能,客户端只想 Master 同步元数据,数据不经过Master 节点,直接和 Table Server 通信。因此,BigTable 中 Master 节点的负载很低。有主架构中,Master 承担的能⼒也会不⼀致,⽐如在下图架构中,Master 只承担 Coordinate 功能,管理元数据和 Node 节点,Client 获取Mata Data,直接和相应的数据节点通信。在下⾯架构中,Client 不直接和 Data Node 节点通信,⽽是和 Master 通信,Master 更加相关元数据将请求转发给对应的 Data Node:Coordinate-Worker

架构是很多分布式数据库采⽤的架构,有兴趣的同学可以看看笔者之前讲解的索引数据库系统的索引,就是⽤来提⾼数据检索效率的。数据库系统的数据记录存储在磁盘中,如果没有索引,要从磁盘中检索相应的记录,就需要扫描所有的数据段,这种 O(N) 的访问效率和全磁盘的扫描⾃然不可能在真正的数据库系统中使⽤。为提⾼数据检索能⼒,数据库系统引⼊索引技术,为磁盘上的数据记录做⼀个索引结构,这些索引放在内存中,或按块存储在磁盘上(但只需要少数⼏次磁盘读取就可以读⼊内存中),这样检索⼀个数据先从内存索引中查找到对应的 Key 或磁盘位置,然后从磁盘中读取记录。这⾥索引做了两个事情:将⼤量磁盘检索变成内存检索通过特定的数据结构可以提⾼内存检索的效率,改变 O(N) 这种低效率的检索HASH 索引HASH 即哈希表,类似 Java 的 HashMap 数据结构,Key-Value 格式。假设我们在内存内维护⼀个 HashMap Index,key 为数据的键,Value 是数据在磁盘的存储偏移量。获取数据时,先从内存 Map 获取对应数据的磁盘 offset,然后读取磁盘的数据。写数据时,先将数据追加写⼊磁盘,然后更新内存 HashMap Index。Hash 索引听起来过于简单,但确实是⼀种可⾏的索引⽅法。Hash 索引简单⾼效,查询性能 O(1),更新也⾼效,当时也有明显的缺点,⽐如:需要将整个哈希表放⼊内存,这对于⼤数据量来说内存耗费将不可承受的。只能进⾏精确查询。不能实现范围查询。B-Tree 索引B-trees 索引始见于 1970 年,经受了长久的时间考验,时⾄今⽇,它仍然时⼏乎所有关系数据库中的标准索引实现,许多⾮关系型数据库也经常使⽤。了解B-trees索引先从⼆叉搜索树开始。⼆叉搜索树是⼀种特殊的⼆叉树,它满⾜以下条件:左⼦树⼩于⽗节点右⼦树⼤于⽗节点上图是⼀个搜索⼆叉树,如果我要查找 208 这个 key:先从根节点开始,即 136。⽐较 208 > 136,下⼀步应该从根节点的右⼦树查找398 > 208,继续搜索 398 的左⼦树250 > 208,继续搜索 250 的左⼦树200 < 208,继续搜索 200 的右⼦树。200 的右⼦树并不存在,因此数据中没有 208,查找结束让我们再查找 40:从根节点 136 开始,136 > 40,继续搜索左⼦树80 > 40,继续搜索左⼦树40 = 40,节点存在,从节点中获取数据 id,然后可以更加数据 id 查找对应的数据在索引结构中,树的每个Node包含⼀个 key

值,⼀个数据指针(或数据 id、磁盘 offset

等)⼆叉搜索树的时间复杂度是

log(N),这是⼀个不错的结果。⼆叉搜索树依旧只能获取特定的值,如果我需要进⾏范围查找,即查找两个数之间的所有数据,就需要去遍历树中的每⼀个节点,去判断节点是否在此范围内,这种情况下,时间复杂度⼜下降到了

O(N)。因此我们需要改进上⾯的数据结构,现代⼤多数数据库都才有⼀种改进的⼆叉搜索树—— B+Tree。B+Tree 在⼆叉搜索树的基础上添加如下特征:仅仅在叶⼦节点存储索引信息(关联表数据的信息)其余节点仅仅⽤于查找到最终的叶⼦节点(叶⼦节点包含了所有的 key)在 B+Tree 中,每个 Key 会存在两个 Node,所有中间节点只⽤于辅助检索最终正确的叶⼦节点(叶⼦节点才包含关联数据的信息)。让我们尝试从上⾯的 B+Tree 中搜索出[40, 100]之间的节点:采⽤和⼆叉搜索树⼀样的⽅式,我们只需要搜索 40 这个节点(或搜索出最接近 40 的节点,当 40 的节点不存在时)然后在叶⼦节点链表中往下追溯,知道超过 100假设树中共有 N 个节点,追溯了 M 个叶⼦节点,那么可以得出,此次搜索的时间复杂度是:log(N) + M。相对于之前的

O(N) 的⼆叉搜索树有以下好处:不需要读取整棵树,这样可以减少读取磁盘的次数(索引数据⼀般按页存储在磁盘上)⼤多数情况下 M (约等于检索范围)会远⼩于整个数据量 N,因此这⾥的

O(M) 时间复杂度⼤多数情况下远⼩于

O(N)。任何事情都是双⾯的。B+Tree 索引带来的检索优势,必然会有其他⽅⾯的损失。这主要体现在删除数据时。因为叶⼦节点类似于链表结构,删除⼀个节点需要从 header 开始遍历,时间复杂度是 O(N)。B+Tree 索引具有⽐较好的检索性能,为了减少磁盘访问次数,⼤多数索引系统的 B+tree 都只有 3- 4 层,因此 B+Tree 索引能够承载的节点数是有限的。B+Tree 在更新节点是需要⾃排序和⾃平衡,这需要额外的性能消耗,B+Tree 的插⼊和删除时间复杂度是

O(log(N))。这就是为什么在使⽤数据库时不建议索引字段都添加索引,⽽是充分考虑具体情况,在需要的字段上添加索引,否则索引太多会影响表的insertupdatedelete操作性能。LSMB+Tree 是基于页的索引引擎,B+Tree 的数据存储本⾝是⽆序的,其建⽴索引的思想是在内存中维护⼀个 key 与数据磁盘位置的对应关系,并保证这个内存数据结构有序。有⼀种基于⽂件的存储引擎,它将数据划分成⽂件段,并保证数据在磁盘⽂件段中有序,因此,这种存储引擎并不需要在内存中维护所有数据的顺序表,只需要在内存中维护⼀个稀疏的索引结构,每次从内存索引中搜索到的数据并不是具体到每条数据,⽽是⼀个⽂件段(或⽂件块),然后将这些有序的数据读⼊内存,再按序获取具体的数据。(如何保证写⼊数据有序?)LSM(Log-Structured Merge-Tree),就是这样⼀种索引结构。LSM 的架构如所⽰:SSTable: LSM 的磁盘⽂件,称作SSTable(Sorted String Table)。望⽂得意,LSM 存储在磁盘中的⽂件,数据也是按 Key 排序存储的,这样就可以解决上⾯讲到的数据量⼤了之后⽆法将数据全部索引到内存中的问题。如果磁盘⽂件也是有序的,那么内存索引可以采取”稀疏索引“(Sparse Index),可以每⼀段记录⼀个索引,将数据逻辑上分成多个block,稀疏索引只需要记录每个block的偏移量,每条数据通过遍历block实现。这样索引量将⼤⼤减⼩。Memtable: LSM 的内存结构叫做Memtable。Memtable是⼀个有序结构,同样可以采⽤树结构,可以⽤跳表。LSM 写数据时,只需要写⼊内存中的Memtable,当Memtable到达⼀定量之后,会异步刷⼊磁盘,就是上⾯的SSTable。Immutable Memtable: 在数据从内存Memtable刷⼊SSTable时,为避免读写锁导致的性能问题,LSM 会在内存中 copy ⼀份immutableMemtable表,顾名思义,这个数据结构不可改变,新写⼊的数据只会写⼊新的Memtable,immutable Memtable供刷盘线程读取,查询数据的请求也可以访问这个数据结构,这样如果数据在内存中,就不需要访问磁盘,可以提供数据查询的效率。WAL: write ahead log,预写⽇志,关于 WAL,可以参考我之前的⽂章。在 LSM 中,在数据刷⼊磁盘前,为防⽌异常导致数据丢失,LSM 会先将数据写⼊ WAL,然后写⼊ SSTable,系统重启时,LSM 会从 WAL 中回溯 SSTable,当写完⼀个 SSTable 时,LSM 会清理掉过期的 WAL ⽇志,防⽌ WAL 过量。LSM 如何写⼊数据:1. 写⼊

WAL2. 写⼊

Memtable3.

Memtable 达到阈值时,复制

Imutable Memtable4. 异步刷⼊磁盘LSM 如何删除数据: 为保证顺序写磁盘,LSM 不会去直接删除数据,⽽是通过写⼀条 delete 标识来表⽰数据被删除,数据只有在被Compact 时才会被真正删除。LSM 如何读取数据: LSM 读取数据将从memtable、imutable、sstable依次读取,直到读取到数据或读完所有层次的数据结构返回⽆数据。所以当数据不存在时,需要依次读取各层⽂件。LSM 可以通过引⼊布隆过滤器来先判断⼀个数据是否存在,避免⽆效的扫⽂件。密集索引(dense index)

稀疏索引(spare index):密集索引为每条数据对应⼀个索引记录,稀疏索引⼀般只索引数据块或⽂件,是跳跃式的。因此稀疏索引⽐密集索引更节省空间。压缩数据压缩对数据库系统中 I/O 性能的影响相当明显,它可以减少磁盘空间使⽤、降低带宽使⽤和提⾼吞吐量。数据库系统中的数据存储、索引存储、数据转换、数据备份和⽹络通信都会⽤到相应的压缩技术。当将数据库压缩引⼊实时数据库时。压缩算法必须提供⾼压缩⽐才能实现⾼数据存储,压缩算法必须⾜够快,才能在实时数据库中实现实时记录和查询功能。压缩过程⼀般由两个独⽴的部分组成,建模和编码。建模定义输⼊流中不同符号的特征。模型存储有关符号在数据中出现的频率的信息,即符号概率。编码是压缩过程的第⼆部分,它根据模型提供的概率为不同符号创建⼀组代码,从⽽产⽣数据的压缩版本。将更频繁地出现的符号与较短的代码词和较长的稀有符号互换。数据的均匀性会影响⼤多数压缩算法的压缩⽐,但对压缩速度没有任何影响。因此,为了达到更好的压缩性能,压缩算法是专门为数据的每个部分设计的,因此不同的压缩算法对不同类型的,不同量级和不同组合的数据的压缩效果是不⼀致的。也因此⼤多数⽀持数据压缩的数据库系统都会提供多种不同的压缩算法让⽤户根据⾃⾝数据情况⾃由选择。压缩算法可以分为以下两⼤类:有损压缩:有损压缩会重构原始数据。所以读取的压缩后的数据是不完整的。这种压缩⽅式通常⽤在⾳频、视频等流⽂件的压缩中。⽆损压缩:⽆损压缩不影响压缩数据的原始值。通常使⽤在⽂本,数字等数据的压缩中。压缩应该考虑什么问题:⼤⼩:压缩后的⽂件⼤⼩,即压缩⽐。当使⽤压缩时,本就是为了降低数据⼤⼩,所以压缩算法的压缩⽐是⾸要考虑的问题。速度:压缩速度会影响数据的读写效率,这对实时系统来说尤为重要,速度和⼤⼩是 trade-off 的两⾯,必须充分考虑具体的使⽤场景。资源: 压缩节省了磁盘和宽带,但是会增加 CPU 和压缩时的内存使⽤。所以压缩时的资源耗损情况也需要考虑。下⾯列举⼀些常见的压缩算法或⽅法(Gzip、Bzip2、LZMA、XZ、LZ4、LZO),并做相应的对⽐:测试条件:Intel Core i5 CPU 750 at 2.67GHz8GB of DDR3 memorytmpfs as ram diskLinux kernel 3.3.2, gentoo amd64CFLAGS: -pipe -O2 -g -floop-block -floop-interchange -fgraphitebzip2-1.0.6-r3, xz-utils-5.0.3, gzip-1.4⽂件压缩对⽐结果(原数据: 445M):压缩⽐对⽐:压缩耗时对⽐:各⼤数据库系统多多少少都会⽤到压缩技术来降低数据存储空间,来提⾼系统性能,以下列举⼀些数据库系统使⽤到的压缩技术:Google 在 BigTable 和 MapReduce 中使⽤ Snappy 压缩数据和⽹络传输。SQL Server 使⽤ XPRESS 算法压缩备份数据。Oracle 使⽤⾃实现的 Oracle Advanced Compression 算法压缩数据。MySQL 使⽤ LZ77 算法压缩 InnoDB 的表。Kafka 同时⽀持 gzip 和 snappy 和 lz4 算法,并对默认的 lz4 做了特定的优化。Druid 使⽤ lz4 压缩数据。数值压缩:delta-of-delta数值压缩经常⽤于压缩列式存储的数字列。前⾯我们讲到过,列式存储将每列的数据存储在相邻的位置。这样的存储结构利于压缩数据,下⾯我们讲⼀下在许多列式存储中使⽤的 Delta 数值压缩技术。如图所⽰,假设有 6 个原始数值(73、300、302、332、343、372)。在未压缩之前,每个数值占⽤ 4 个字节,6 * 4 = 24 共占⽤ 24 个字节。Delta 压缩算法不存储原始的数值,⽽是先确定⼀个数字(⼀般取第⼀个数值),后⾯的数值是相对于第⼀个数值的差值,如图第⼆⾏所⽰得到的数据集为(73、227、3、30、11、29)。因为最⼤的差值是 227,因此只需要⼀个 byte 就可以表⽰,因此之前需要使⽤ 4 个字节存储的每个数值,现在只需要使⽤ 1 个字节。为了保存对应的差值相关元描述信息,需要额外的 1 字节保存这些信息,上图还将数据分块存储,因此最终需要的字节数是 7 个。这样相对于原始的 24 字节节约了将近 3 倍的空间。其实上图就是 Elasticsearch 底层使⽤ Lucence 的原理。delta-of-delta 适⽤于数值类型数据的压缩,且对数据量⼤并且数据集中的数据压缩才有效果。如果数据集⽐较⼩,且⽐较稀疏,数据的最⼤差值已经和数据值可以表⽰的最⼤值相差不⼤,那么压缩的意思便存在。读写数据存储系统就是⼀个与磁盘和⽹络打交道的系统,所以数据存储系统在这⽅⾯的优化可谓精益求精,⽐如异步IO、缓冲批量读写、append写数据、按磁盘页读写数据,预读数据和磁盘内存映射技术等等。异步与异步 IO 对应的是同步 IO,即每进⾏⼀次 IO 操作,需要等待此次操作结束才能继续接下来的操作,这样在⼤量并发请求情况下,IO 的效率将会⼤⼤降低,磁盘 IO 和⽹络 IO 在并发量⼤的情况下采⽤异步 IO 可以明显提供效率。Mysql 的 InnoDB 也采⽤ AIO 提⾼效率,InnoDB1.1.x 之前,AIO 的实现通过 InnoDB 存储引擎中的代码来模拟实现,从 InnoDB1.1.x 开始,提供了内核级别的 AIO ⽀持,称为 Native AIO。在 InnoDB 存储引擎中,read ahead ⽅式的读取都是通过 AIO 完成,脏页的刷新,即磁盘的写⼊操作则全部由 AIO 完成。在 Kafka 中,Broker 的数据磁盘落地,都是采⽤的 Java NIO 的⽅式处理的,这是 Java 的异步 IO 的实现,Java NIO 可以提供数据写⼊的并发性能。缓冲缓冲技术是为了协调吞吐速度相差很⼤的设备之间数据传送⽽采⽤的技术。在数据到达与离去速度不匹配的地⽅,就应该使⽤缓冲技术。缓冲技术好⽐是⼀个⽔库,如果上游来的⽔太多,下游来不及排⾛,⽔库就起到“缓冲”作⽤,先让⽔在⽔库中停⼀些时候,等下游能继续排⽔,再把⽔送往下游。将缓冲和批量发送结合,可以提⾼数据在在⽹络和磁盘中的写⼊速率。在数据写⼊⽹络或磁盘时,先设置⼀个缓冲池,当数据达到⼀定的数量或缓冲时间超时时,在将数据批量发送出去,可以减少请求并发,也可以减少请求额外数据带来的带宽和磁盘消耗。在 Mysql 中,Innodb 在多个地⽅使⽤缓冲来提升写⼊性能。⽐如插⼊缓冲,将多个插⼊请求合并到⼀个操作中,这样可以将之前的⼀些⾮顺序写⼊变成相对的顺序写⼊,以提⾼写⼊效率。另⼀⽅⾯也可以按磁盘物理页写⼊数据,这样充分利⽤了磁盘的写⼊特性。在 Elastisearch 和 Kafka 的客户端中,都采⽤了缓冲批量写⼊的功能来减少写⼊并发情况。磁盘在磁盘的读写优化上,经常可以看到以下技术:按磁盘页读写数据:磁盘读写的单位是页。为了减少读写数据时磁盘访问频率,数据库系统通常都按页读写数据。预读数据:⼀些数据库系统认为⽤户访问了⼀部分数据,那么在它相邻的放的数据下次被访问的可能性也很⼤,所以会预先读取多个页的数据。磁盘内存映射(MMP):即盘扇区映射到进程的虚拟内存空间的过程。MMP 读写数据时跨过了页缓存,减少了数据的拷贝次数;实现了⽤户空间和内核空间的⾼效交互⽅式;可以缓解系统内存不⾜的压⼒。本⽂对各种技术浅尝辄⽌,其实每⼀个技术点都可以深⼊讲解,感兴趣的同学请持续关注我们后期的⽂章。参考:希望读者 「点赞」「分享」「在看」三连就是最⼤的⿎励。后台回复 “加群” 进⼊专属技术群⼀起成长

发布者:admin,转转请注明出处:http://www.yc00.com/news/1690433674a349204.html

相关推荐

发表回复

评论列表(0条)

  • 暂无评论

联系我们

400-800-8888

在线咨询: QQ交谈

邮件:admin@example.com

工作时间:周一至周五,9:30-18:30,节假日休息

关注微信