设计数据密集型应用读感(一)

数据系统基础

现今很多应用程序都是 数据密集型 (data-intensive 的,而非 计算密集型(compute-intensive) 的。因此 CPU 很少成为这类应用的瓶颈,更大的问题通常来自数据量、数据复杂性、以及数据的变更速度。

这是这本书一开始就阐述的一个道理。应用程序昂贵的是数据的读取和存储之间的balance,但很显然,目前很多的数据存储譬如关系型数据库、非关系型数据库、图数据库、向量数据库等等,他们已经对相应的地方做了很多的很棒的支持,也提供了很不错的优化。

书中还是以数据系统的可靠性、可伸缩性还有可维护性进行分析。

可靠性

书中以一个典型的应用系统举例,简单的可靠性就是:程序能够表现出所期望的功能、允许以出乎意料的方式犯错、在预期情况下满足要求、防止未经授权的访问和滥用。粗略的概括就是即使出现问题也能继续正确工作

后续主要是列举了三个方面:硬件故障软件错误人为错误。这三个方面造成的问题,笔者认为可靠性是最重要的一环,尤其是在大型的系统中,不可靠往往会更容易造成用户流失,财产损失,更严重者信息泄露等等。与笔者息息相关的就是人为错误,大多数的问题都来源于人为错误,往往是对代码没有怀有敬畏之心,当然也有各种赶工问题造成没有太多的时间去考虑周全,只能用自己不太健全的经验去撼动一个健全的系统,这种行为往往是非常可怕的。还有测试流程的不健全也会导致如上问题。系统大多数的时间是在发展阶段,更多的工作就应该是投入到可靠性的维护上面,一个不能用的系统又何谈可伸缩性和可维护性。

可伸缩性

书中给出的可伸缩性的解释是用来描述系统应用负载增长能力的术语。

首先讨论的问题就是系统会以何种方式进行负载增加,同时负载加倍会发生什么(即增长问题),负载是可以用一些负载参数进行描述,每秒请求数,读写比率,活跃用户量,缓存命中,等等。书中用推特的两个业务进行简要的举例:发布推文、主页时间线。

推特的第一个版本优先使用的方法是维护一个全局推文,当用户发送推文时,将推文插入全局推文集合里面,用户在查找自己的主页时间线时,首先查找自己关注的所有人之后查询这些用户发布的推文并按照时间进行排序。但系统是很难跟上主页时间线查询的负载。之后便转向了每个用户维护一个缓存,像是一人一个收件箱,当一个用户发布了推文,则查找他所有的粉丝,之后将推文插入到每个人的主页时间线中,但这种方法会造成大量的额外工作。后来慢慢迭代用两种结合的方式,依据粉丝数的多少,对少量粉丝的人直接使用第二种方法,而对于大量粉丝的作者则使用第一种。

我们上述讨论了对负载的描述,接下来就讨论负载增加会发生什么,系统会收到什么影响,即对性能进行描述。

首先是最长关注的吞吐量响应时间,粗略的解释就是每秒可以处理的记录数量还有客户端发送请求到接收响应之间的时间。但如何进行合理有效的统计是这是一个问题,我们平常是需要将响应时间视作一个可以测量的数值分布,而不是单个数值。

书中用一个图对一段时间内对服务的请求进行描述,展示了一个服务100次请求响应时间的均值和百分位数,通常我们进行对该图的分析都会展示平均响应时间即算是平均值。但书中给出解释是 然而你想知道"典型"响应时间,那么平均值并不是一个非常好的指标 它解释到通常使用百分位点会更好。

比如中位数 ,将这一段请求的响应时间从低到高排序,中位数就在正中间,这就意味着一半请求的返回时间少于这个中位数且另一半比这个要长。典型的场景下用户想要知道需要等待多少时间,显然中位数再合适不过。同时响应时间的高百分位点也同时非常重要,因为这也直接影响用户的服务体验,书中举到例子是亚马逊在描述内部服务的响应时间要求是以99.9百分位点为准,因为这响应最慢的客户往往是数据最多的客户,也就是最有价值的客户,因为他们掏钱了,所以保持这类客户的满意度是非常重要的。当时看见这一段描述,笔者觉得蛮惊奇的一个思考方式。

最后我们来聊一下书中说到的应对负载的方法。

常常讨论的水平伸缩纵向伸缩 都是不错的应对方法,我们需要的就是如何巧妙地将两种方式结合。书中中间说了一些常规的手段笔者就不进行赘述了,但需要注重的一点就是书中说到的大规模的系统架构通常是应用特定的,没有一招鲜吃遍天的通用可伸缩架构(不正式的叫法:万金油(magic scaling sauce) )。应用的问题可能是读取量、写入量、要存储的数据量、数据的复杂度、响应时间要求、访问模式或者所有问题的大杂烩。笔者之前也读过一本书叫人月神话,里面也有一句话是没有永远的银弹,我们应当对于特定的问题进行特定的分析,而不是简单的套用,站在自己以前的经验上面俯视,然而这可能就是我们常常会犯得一种错误。

可维护性

最后说到了可维护性,开发系统的伊始是开心的,但维护的过程是艰辛的,各种遗留的杂症会导致系统的维护成本会越来越大,我们唯有在设计之初尽量的考虑减少维护期间的痛苦,从而避免自己的软件系统成为遗留系统。为此书中提到了三个原则是:可操作性、简单性、可演化性。

让你的系统变的简单起来,让别人容易进行简单的上手操作。

消除系统中多的复杂度用最简单的方式去实现你想要的东西,也可以让别人能够简单的去理解系统,大家要明白的一点就是每个人之间的技术鸿沟是存在的,同时差距和思维方式也是存在的。我们需要用一种特定且大家都能接受的方式来构建一个系统,沟通也是很有必要的,有效的沟通简单的实现这会促成大家能够轻松的应对一套系统。

最后我们说到了可演化性,可演化性并不是站在执行者的角度来进行诉说,这需要有一个人进行全面的统筹,明确系统的发展方向,同时它能预测到未来可能出现的业务,意想不到需求,新老的交替。虽然预见所有但不可能,但把握方向这个是可以做到的,所以系统的构建需要有一个人能够化身领头羊开辟一个符合自然变更规律的道路(笔者建议多读道德经,万物都有迹可寻)。

数据模型与查询语言、存储与检索、编码与演化

这部分应该是总共分为三大类,但我把他们统一揉在一起进行总结,其实这三大类主要还是讲了数据这件事情,从数据的模型到如何存储和检索,再到各种优化最终是编码和传输。

其中数据的模型涉及到了:关系型数据库、NoSQL、文档型数据库,列存储、图数据模型。因为笔者对后续的几种虽然之前接触过但没有怎么使用过,就不做过多的阐述和解释。

接下来就是存储和检索,列举了一些数据结构如:散列索引、SSTable和LSM树、B树。也讲到了如今数据库的两种OLTP(事务处理系统)和OLAP(分析系统),在此基础上说到了列式存储。

最后就是传输的语言格式,JOSN、XML、Thrift和Protocol Buffers、Avro等等,还有我们熟知的RPC和REST。

以上笔者所说的所有大家都可以在平常的学习中了解,我想说的是当书中讲完第一部分即

数据的基础系统后,我理解到,我们在构建一个系统的过程中其实就是不停的在跟数据进行打交道。无论是内存的还是磁盘的,不停的是在做将数据读取、操作、存储的一个过程,如何对这些过程提效是当前乃至未来需要不停思考的事情,我们的系统其实就是一门语言,我们像是翻译官一样,将计算机的东西翻译给人听,翻译的快慢就是我们的一个约束。

结语

本次我单分享了数据系统的基础,其实并没有过多的去讨论数据,还是围绕系统,挑着我认为着重的地方进行了说明,和一些摘录,当前只是讨论了单体系统的数据,后续会分享书中描述的分布式中数据的处理方式,还有他们的绕不开的问题与应对方式和数据系统的未来。

简单分享,如果指正和补充欢迎评论区发表你的见解。

一个刚刚入行的软件工程师

相关推荐
努力的搬砖人.12 分钟前
Kafka相关的面试题
java·后端·kafka
捡田螺的小男孩37 分钟前
CompletableFuture使用的6个坑
java·后端
lmryBC491 小时前
获取golang变量的类型
开发语言·后端·golang
大佬喝可乐1 小时前
精准测试实践
后端·测试
掘金码甲哥1 小时前
老八股谈事务处理,到底在谈什么?
后端
爱因斯不舒坦1 小时前
Trae 实战入门:快速构建一个 SpingBoot 项目
后端
kanlon1 小时前
SQL server分页的四种方法(算很全面了)
后端·sql server
AntBlack1 小时前
DataWorks 体验笔记 :一切的基础都是数据的读和写
大数据·后端·创业
kanlon2 小时前
SQL Server 与 MySQL 的区别
数据库·后端
程序猿本员2 小时前
Linux进程间通信(1)-管道、内存映射
linux·后端