《大规模分布式存储系统》这本书是我对于分布式系统的启蒙书籍,观看后整理了脑图,供自己时长记忆.更新中…
数据模型非常重要,它不仅影响了我们的程序该如何编写,更影响了我们如何思考需要解决的问题.
大部分的应用程序都是通过在一层数据模型基础上,构建一套新的数据模型,然后完成功能实现.
总之,系统就是在一层一层的数据模型基础上堆砌出来的.这种分层的思想,使得每一层屏蔽了底层复杂的逻辑.不同的数据模型决定了他们如何被使用,以及适应于哪种应用场景.
关系型数据库源自1970年的理论建议,后来广泛应用于事务处理与批量处理.而NoSQL最初用来指代开源分布式非关系型数据库,后来被重新诠释为Not Only SQL.
目前很多编程语言都是面向对象(object-oriented)的,与关系型数据库的数据模型不一致.被称为”impedance mismatch”.因此(ORM)框架出现了,用以尽量适配两者的不同.
| 数据模型 | 表达方式 |
|---|---|
| 传统关系型数据库 | 1. 多行记录存在额外的从表里,并通过外键链接到主表 2. 将多值数据格式化成json等文本串进行存储 |
| 现代关系型数据库 | 允许结构化,xml或者json数据类型,并提供索引和查询 |
这种一对多关系,使用json格式存储更为方便,因此实际上使用文档型数据库来存储更好.json格式比主从表存储有更好的局部性.主从表需要从多个表中多次查询才能得到完整的一对多关系数据.
当存储一些地方,学校或者公司的时候,存储id值比存储直接的文本更好.因为存储文本后如果需要更改,则需要更改所有存有文本信息的数据.而id我们只需要更改id对应的文本值,而所有存储id的数据行我们不需要更改.
但这样,我们在获取一个完整的数据显示时,就需要一对多或者多对多的join操作.对于关系型数据库join操作很容易,但文档型数据库支持的很弱,如果想要支持join操作,就需要我们在应用层多次查询,然后在应用层实现join操作.
1970年代,广泛使用的数据库是一种简单的层次模型,数据之间通过树形结构来展现,很像json结构.面对一对多关系支持的很好,但对于多对一或者多对多关系,也面临上述问题.
网络模型是层次模型的扩展,在层次模型中,每个记录只允许拥有一个父记录,但在网络模型中,允许拥有多个父记录.这样就解决了多对一或者多对多问题.
然而记录之间的连接并不是通过外键的形式,而是类似于编程语言里的指针关系.因此想要访问一条记录唯一的方式,就是从根记录一直往下查找.这条路径被称为”access path”.而一条记录因为拥有多个父记录,所以可能拥有不止一条”access path”.而查找和更新都需要手写代码实现,而不是系统自动完成,因此查询和更新都极为复杂.
关系型数据库可以看做一群元组的集合.关系型数据库通过外键实现join操作,文档型数据库通过文档引用实现follow-up操作.
| 数据模型 | 优势 | 场景 |
|---|---|---|
| 关系型 | 高效的join操作 更好的支持多对一和多对多操作 |
多对多关系较多的场景 |
| 文档型 | schema比较灵活 局部性,性能好 文档结构贴近应用层数据模型 |
应用中包含文档结构,且会一次性加载 对于某些不存在多对多关系的场景 |
缺少Schema意味着,我们可以写入任意的键值,但同时我们也无法确认具体包含哪些键值.不过实际上我们从另一个观点来看,关系型数据库可以被称为schema-on-write,类似于静态语言,而文档型数据库可以被称为schema-on-read,类似于动态语言.
当我们想要更改数据格式时,对于文档型语言,我们需要在代码层更改读取规则,写入时更改写入的内容.而对于关系型数据库,我们需要alter table更改数据库格式.更改数据库格式通常需要暂停服务,对于MySQL来说,实现上需要拷贝整个库表数据,因此会非常慢.
| 类型 | 场景 |
|---|---|
| schemaless | 1.不同数据类型 2.数据结构由其他系统定义,而不是当前系统. |
| schema | 大量结构一致的数据 |
文档类型将数据存储成一整个字符串,如果应用经常需要查询整个文档,由于局部性,因此文档型数据库性能更好.而关系型数据库需要查询多个表.但是,有时候我们只需要一部分数据时,文档型数据库也会返回给我们整个文档内容,并且当我们需要更改文档的一部分内容时,只有更改后的文档不超过原有大小,才能进行本地更改.因此我们需要尽量保证文档内容小,并且更改保证不超过原有大小,这极大的限制了我们的使用场景.
目前,关系型数据,越来越多的开始支持json,xml或者格式化的数据结构,并提供这些数据类型的索引,使得关系型数据库可以用来存储文档型数据库存储的数据.而文档型数据库开始提供join操作(实际上也是客户端实现).这意味着两者开始逐渐融合,这种融合使得我们的应用程序从中受益.
数据密集型应用特征: CPU能力很少是这类应用的限制因素,反而是数据量,数据的复杂度以及数据的变化速度.
数据密集型应用通常是由多种通用功能模块组合而成,这些功能包括:
1.数据库
2.缓存
3.索引
4.流处理
5.批处理
而不同的数据库系统提供不同的功能特征,因此当我们建设数据密集型应用时,我们需要根据需求和环境来选择不同的数据库系统,组合它们来达到我们的目标.
我们统称这些功能模块是数据系统.
可靠性,简单来说就是系统能够正确地运行,即使遇到了故障(fault).如果一个系统能够预期到故障并准备好了应对措施,那么我们称该系统具有容错性(fault-tolerant),或者弹性(resilient).当然容错也是要有限度的,这里的容错是指一些特定类型的故障.
故障和失败(failure)是有区别的,故障往往是指系统的一部分的运行偏离了预期,而失败则表示系统无法提供服务了.设计良好的容错机制可以防止由于故障导致的服务失败.有时候,我们设计了容错机制,我们可以故意杀死系统某个进程,来人工引入故障,从而来检验我们的容错机制是否发挥了作用.Netflix公司开源的Chaos Monkey就是这样一款工具.
硬件错误包罗万象,包括硬盘故障,内存条毁坏,断电,网络设置错误等等.
冗余:RAID配置防止硬盘故障,服务器双电源防止断电,热切换CPU防止cpu错误,机房的备用电源.冗余并不能让阻止硬件的故障,但能够让我们的服务持续地工作着. 因此针对相当重要需要高可用的应用,我们会使用多机器冗余.
但是随着机器使用数量的增加,硬件故障越来越多,因此现在有种趋势就是倾向于软件容错,而不是进行硬件容错.
由于bug导致的一系列服务故障.
bug故障很难避免,因此需要开发者付出更多的注意来尽量减少bug的出现.
人为的操作失误,是导致停服的主要原因,而硬件故障只占了10-25%.可以从以下几个方面来加强系统:
可扩展性是用来描述服务应对负载增长的能力.
负载参数用来描述系统的负载情况.包括每秒的请求数,数据库的读写比例,同时在线人数,缓存的命中率等.
可以从两个方面来看待性能:
性能指标通常有: |性能指标|应用| |-|-| |吞吐量(throughput)|在批处理系统中,例如Hadoop里,每秒系统能处理的记录数,或者在固定数量的数据上,运行一个任务所消耗的时间| |响应时间(response time)|在线系统,通常我们关注客户端发送请求,到接受请求的时间间隔| |时延(Latency)|时延包括网络时延,以及处理请求的排队时延| |数据分布(distribution)|我们观察一次响应时间没有意义,通过观察多次的分布比较有意义| |平均数(average)|一般是指算数平均数| |百分位数(percentiles)|中位数(median)是指中间的观测指标值,长尾延迟(tail latencies)也很重要.| |pn|n从0到100,意味着一次请求,有n%的概率符合某种要求| |SLOs(service level objectives) and SLAs(service level agreements|约定了服务期望的性能与能力|
首先,需要明确,单一的架构的设计是不现实的.尤其是当你的服务数量级一直在不停增长时,你的架构必须不停的变化.可扩展性往往包好纵向扩展(使用更强大的机器)和横向扩展(增加更多的机器),一个好的架构设计一定是混合使用两者进行设计的.
将系统设计成弹性可扩展的(即能够根据负载自动扩容)固然是很好的,但很显然人工配置扩容更加容易也更少出错.
对于无状态的服务,横向扩容很明显有很大的收益.但是对于像数据库这样的服务,横向扩容会导致额外的复杂度,因此除非迫不得已,尽量进行纵向扩容.当然,随着分布式系统设计的越来越好,分布式数据系统将会成为一种趋势.
众所众知,一个系统最大的消耗不是开发阶段,而是修bug,运维系统,排查错误,升级系统,增加新的功能等等.
为了设计出具有可维护性的系统,我们需要遵守三个原则:
良好的操作,通常能够突破设计不良的软件带来的限制.但是一个设计良好的软件,未必能在不良好的操作环境下正常运行.
良好的操作包括:
对于数据系统而言,以下是特定的良好操作行为:
通过抽象(abstraction)来将复杂逻辑从系统移除,从而简化系统的设计.
通过敏捷开发,来适应软件的快速变化.
有用的应用被设计出来需要满足各种需求,包括功能需求(存储,检索,查询,处理数据)和非功能需求(安全性,可靠性,可扩展性,可维护性等等).
可靠性意味着,即使发生了故障系统也能正确运行.故障包括硬件故障,软件故障和人为故障.通过容错性机制来规避一些类型的故障.
可扩展性意味着,即使系统负载增加,我们仍有策略能够保证我们的性能.
可维护性内涵比较多,我们通过抽象化和良好的运维机制来达到需求.
最近在看«这,就是街舞»,看完之后有种强烈的代入感.大神就是大神,气场和技术真的就是远远高出其他人,让人眼前一亮.给人的感觉就是他们从来不用考虑是否能晋级,只需要自信的展示就好了.
而所谓的高手们,则只能凭借着现场的表现,或者各种各样的方式,一轮一轮的battle来博取导师们的那条毛巾.不是他们不强,只是他们没那么强.强到人不假思索就是你的那种程度.
记忆最深刻的,就是韩庚队伍(所有人都是最后决定,而不是表现完就表态)里的小白,表现完以后我就忍不住对老婆说:他不用待定了,肯定韩庚直接就给毛巾了,这个人太牛了,其他人跟他不是一个level的.果然,韩庚赞不绝口直接给了毛巾.
之后,我就陷入了深深的思考.当我去答辩或者面试的时候,我又是什么level呢?因为没有那么强,所以需要准备各种硬实力以外的东西,去幻想着成为加分项.可看完了这个节目,我觉得这实在是种小孩子的手段.站在局外的人和考官们,只需要一眼就看的真真切切,明明白白了,之后你所有略带可笑的表现,好尴尬啊.你没那么强,所以只有当机会大于强者人数时,你才能残喘着跟和你差不多的人再去争个头破血流.为什么不一开始就把所有的努力,都放到硬实力上呢?