【设计理念】数据密集型应用特点

数据密集型应用特点

需求

  • 存储数据,以便自己或其他应用程序之后能再次找到——数据库
  • 记住开销昂贵操作的结果,加快读取速度——缓存
  • 允许用户按关键字搜索数据,或以各种方式对数据进行过滤——搜索索引
  • 向其他进程发送消息,进行异步处理——流处理
  • 定期处理累积的大批量数据——批处理

关于数据系统的思考

数据库、消息队列、缓存等工具分属于几个差异显著的类别。虽然数据库和消息队列表面上有一些相似性——它们都会存储一段时间的数据——但它们有迥然不同的访问模式,这意味着迥异的性能特征和实现手段。

越来越多的应用程序有着各种严格而广泛的要求,单个工具不足以满足所有的数据处理和存储需求。取而代之的是,总体工作被拆分成一系列能被单个工具高效完成的任务,并通过应用代码将它们缝合起来。

可靠性

人们对可靠软件的典型期望包括:

  • 应用程序表现出用户所期望的功能。
  • 允许用户犯错,允许用户以出乎意料的方式使用软件。
  • 在预期的负载和数据量下,性能满足要求。
  • 系统能防止未经授权的访问和滥用。

可以把可靠性粗略理解为“即使出现问题,也能继续正确工作”。故障通常定义为系统的一部分状态偏离其标准,而失效则是系统作为一个整体停止向用户提供服务。故障的概率不可能降到零,因此最好设计容错机制以防因故障而导致失效。

我们可以通过故意引发故障来确保容错机制不断运行并接受考验,从而提高故障自然发生时系统能正确处理的信心。

可以恢复的故障种类

硬件故障

硬盘崩溃、内存出错、机房断电、有人拔错网线……

据报道称,硬盘的平均无故障时间约为10到50年。因此从数学期望上讲,在拥有10000个磁盘的存储集群上,平均每天会有1个磁盘出故障。

为了减少系统的故障率,第一反应通常都是增加单个硬件的冗余度,例如:磁盘可以组建RAID,服务器可能有双路电源和热插拔CPU,数据中心可能有电池和柴油发电机作为后备电源,某个组件挂掉时冗余组件可以立刻接管。

软件错误

另一类错误是内部的系统性错误。这类错误难以预料,而且因为是跨节点相关的,所以比起不相关的硬件故障往往可能造成更多的系统失效。例子包括:

  • 接受特定的错误输入,便导致所有应用服务器实例崩溃的BUG。例如2012年6月30日的
    闰秒,由于Linux内核中的一个错误,许多应用同时挂掉了。
  • 失控进程会占用一些共享资源,包括CPU时间、内存、磁盘空间或网络带宽。
  • 系统依赖的服务变慢,没有响应,或者开始返回错误的响应。
  • 级联故障,一个组件中的小故障触发另一个组件中的故障,进而触发更多的故障

导致这类软件故障的BUG通常会潜伏很长时间,直到被异常情况触发为止。这种情况意味着软件对其环境做出了某种假设——虽然这种假设通常来说是正确的,但由于某种原因最后不再成立了。

虽然软件中的系统性故障没有速效药,但我们还是有很多小办法,例如:仔细考虑系统中的假设和交互;彻底的测试;进程隔离;允许进程崩溃并重启;测量、监控并分析生产环境中的系统行为。如果系统能够提供一些保证(例如在一个消息队列中,进入与发出的消息数量相等),那么系统就可以在运行时不断自检,并在出现差异时报警。

可扩展性

可扩展性是用来描述系统应对负载增长能力的术语。

描述负载

在讨论增长问题前,首先要能简要描述系统的当前负载。负载可以用一些称为负载参数的数字来描述。参数的最佳选择取决于系统架构,它可能是每秒向Web服务器发出的请求、数据库中的读写比率、聊天室中同时活跃的用户数量、缓存命中率或其他东西。除此之外,也许平均情况对你很重要,也许你的瓶颈是少数极端场景。

描述性能

一旦系统的负载被描述好,就可以研究当负载增加会发生什么。我们可以从两种角度来看:

  • 增加负载参数并保持系统资源(CPU、内存、网络带宽等)不变时,系统性能将受到什么影响?
  • 增加负载参数并希望保持性能不变时,需要增加多少系统资源?

这两个问题都需要性能数据,所以让我们简单地看一下如何描述系统性能。

延迟和响应时间
  • 响应时间是客户所看到的,除了实际处理请求的时间之外,还包括网络延迟和排队延迟。
  • 延迟是某个请求等待处理的持续时长,在此期间它处于休眠状态,并等待服务。

即使不断重复发送同样的请求,每次得到的响应时间也都会略有不同。现实世界的系统会处理各式各样的请求,响应时间可能会有很大差异。因此我们需要将响应时间视为一个可以测量的数值分布,而不是单个数值。

通常使用百分位点会更好。如果将响应时间列表按最快到最慢排序,那么中位数就在正中间:举个例子,如果你的响应时间中位数是200毫秒,这意味着一半请求的返回时间少于200毫秒,另一半比这个要长。

如果想知道典型场景下用户需要等待多长时间,那么中位数是一个好的度量标准:一半用户请求的响应时间少于响应时间的中位数,另一半服务时间比中位数长。中位数也被称为第50百分位点,有时缩写为p50。注意中位数是关于单个请求的;如果用户同时发出几个请求(在一个会话过程中,或者由于一个页面中包含了多个资源),则至少一个请求比中位数慢的概率远大于50%。

为了弄清异常值有多糟糕,可以看看更高的百分位点,例如第95、99和99.9百分位点(缩写为p95,p99和p999)。它们意味着95%,99%或99.9%的请求响应时间要比该阈值快,例如:如果第95百分位点响应时间是1.5秒,则意味着100个请求中的95个响应时间快于1.5秒,而100个请求中的5个响应时间超过1.5秒。

响应时间的高百分位点(也称为尾部延迟(tail latencies))非常重要,因为它们直接影响用户的服务体验。例如亚马逊在描述内部服务的响应时间要求时以99.9百分位点为准,即使它只影响一千个请求中的一个。这是因为请求响应最慢的客户往往也是数据最多的客户,也可以说是最有价值的客户 —— 因为他们掏钱了。保证网站响应迅速对于保持客户的满意度非常重要。

百分位点通常用于服务级别目标(SLO, service level objectives)和服务级别协议(SLA,service level agreements),即定义服务预期性能和可用性的合同。 SLA可能会声明,如果服务响应时间的中位数小于200毫秒,且99.9百分位点低于1秒,则认为服务工作正常(如果响应时间更长,就认为服务不达标)。这些指标为客户设定了期望值,并允许客户在SLA未达标的情况下要求退款。

排队延迟(queueing delay)通常占了高百分位点处响应时间的很大一部分。由于服务器只能并行处理少量的事务(如受其CPU核数的限制),所以只要有少量缓慢的请求就能阻碍后续请求的处理,这种效应有时被称为头部阻塞(head-of-line blocking)。即使后续请求在服务器上处理的非常迅速,由于需要等待先前请求完成,客户端最终看到的是缓慢的总体响应时间。因为存在这种效应,测量客户端的响应时间非常重要。

为测试系统的可扩展性而人为产生负载时,产生负载的客户端要独立于响应时间不断发送请求。如果客户端在发送下一个请求之前等待先前的请求完成,这种行为会产生人为排队的效果,使得测试时的队列比现实情况更短,使测量结果产生偏差。

应对负载

适应某个级别负载的架构不太可能应付10倍于此的负载。如果你正在开发一个快速增长的服务,那么每次负载发生数量级的增长时,你可能都需要重新考虑架构——或者更频繁。

人们经常讨论纵向扩展(转向更强大的机器)和横向扩展(将负载分布到多台小机器上)之间的对立。跨多台机器分配负载也称为“无共享(shared-nothing)”架构。可以在单台机器上运行的系统通常更简单,但高端机器可能非常贵,所以非常密集的负载通常无法避免地需要横向扩展。现实世界中的优秀架构需要将这两种方法务实地结合,因为使用几台足够强大的机器可能比使用大量的小型虚拟机更简单也更便宜。

跨多台机器部署无状态服务非常简单,但将带状态的数据系统从单节点变为分布式配置则可能引入许多额外复杂度。出于这个原因,常识告诉我们应该将数据库放在单个节点上(纵向扩展),直到扩展成本或可用性需求迫使其改为分布式。

可维护性

在设计之初就尽量考虑尽可能减少维护期间的痛苦,从而避免自己的软件系统变成遗留系统。为此,我们将特别关注软件系统的三个设计原则:

  • 可操作性(Operability)便于运维团队保持系统平稳运行。
  • 简单性(Simplicity)从系统中消除尽可能多的复杂度,使新工程师也能轻松理解系统。(注意这和用户接口的简单性不一样。)
  • 可演化性(evolability)使工程师在未来能轻松地对系统进行更改,当需求变化时为新应用场景做适配。也称为可扩展性,可修改性或可塑性。

可操作性

良好的可操作性意味着更轻松的日常工作,进而运维团队能专注于高价值的事情。数据系统可以通过各种方式使日常任务更轻松:

  • 通过良好的监控,提供对系统内部状态和运行时行为的可见性(visibility)
  • 为自动化提供良好支持,将系统与标准化工具相集成
  • 避免依赖单台机器(在整个系统继续不间断运行的情况下允许机器停机维护)
  • 提供良好的文档和易于理解的操作模型(“如果做X,会发生Y”)
  • 提供良好的默认行为,但需要时也允许管理员自由覆盖默认值
  • 有条件时进行自我修复,但需要时也允许管理员手动控制系统状态
  • 行为可预测,最大限度减少意外

简单性

复杂度(complexity)有各种可能的症状,例如:状态空间激增、模块间紧密耦合、纠结的依赖关系、不一致的命名和术语、解决性能问题的Hack、需要绕开的特例等等。

用于消除额外复杂度的最好工具之一是抽象(abstraction)。一个好的抽象可以将大量实现细节隐藏在一个干净,简单易懂的外观下面。一个好的抽象也可以广泛用于各类不同应用。比起重复造很多轮子,重用抽象不仅更有效率,而且有助于开发高质量的软件。抽象组件的质量改进将使所有使用它的应用受益。

可演化性

系统的需求永远不变,基本是不可能的。更可能的情况是,它们处于常态的变化中,例如:你了解了新的事实、出现意想不到的应用场景、业务优先级发生变化、用户要求新功能、新平台取代旧平台、法律或监管要求发生变化、系统增长迫使架构变化等。

原文地址:https://www.cnblogs.com/Ryan16231112/p/12239675.html

时间: 2024-10-31 08:46:12

【设计理念】数据密集型应用特点的相关文章

数据密集型 和 cpu密集型 event loop

Node.js在官网上是这样定义的:“一个搭建在Chrome JavaScript运行时上的平台,用于构建高速.可伸缩的网络程序.Node.js采用的事件驱动.非阻塞I/O模型使它既轻量又高效,是构建运行在分布式设备上的数据密集型实时程序的完美选择.”Web站点早已不仅限于内容的呈现,很多交互性和协作型环境也逐渐被搬到了网站上,而且这种需求还在不断地增长.这就是所谓的数据密集型实时(data-intensive real-time)应用程序,比如在线协作的白板,多人在线游戏等,这种web应用程序

数据密集型系统架构设计

按照使用的资源类型划分,我们可以把系统分为三大类型:IO密集型.计算密集型,数据密集型.系统的类型反映了系统的主要瓶颈.现实情况中,大部分系统在由小变大的过程中,最先出现瓶颈的是IO.IO问题体现在两个方面:高并发,存储介质的读写(例如数据库,磁盘等).随着业务逻辑的复杂化,接下来出现瓶颈的是计算,也就是常说的CPU idle不足.出现计算瓶颈的时候,一般会使用水平扩展(加机器)和垂直扩张(服务拆分)两个方法.随着数据量(用户数量,客户数量)的增长,再接下来出现瓶颈的是内存. 如今,内存的合理使

数据密集型应用及其可靠、可扩展与可维护的定义

一.什么算是“数据密集型应用” 对于一个应用系统,如果“数据”是其成败决定性因素,包括数据的规模.数据的复杂度或者数据产生与变化的速率等,我们就可以称为“数据密集型应用系统”:与之对应的是计算密集型,CPU主频往往是后者最大的制约瓶颈. 例如:使用了以下组件的应用系统:关系型数据库.NoSql.消息队列.缓存.搜索引擎.批处理与流处理框架 二.可靠.可扩展与可维护的应用系统 1.可靠性 意味着即使发生故障,系统也可以正常工作.故障包括: 1)硬件故障.如硬盘崩溃.内存故障.电网停电.硬盘的平均无

CPU-bound(计算密集型) 和I/O bound(I/O密集型)/数据密集型

https://blog.csdn.net/q_l_s/article/details/51538039 I/O密集型 (CPU-bound)I/O bound 指的是系统的CPU效能相对硬盘/内存的效能要好很多,此时,系统运作,大部分的状况是 CPU 在等 I/O (硬盘/内存) 的读/写,此时 CPU Loading 不高.CPU bound 指的是系统的 硬盘/内存 效能 相对 CPU 的效能 要好很多,此时,系统运作,大部分的状况是 CPU Loading 100%,CPU 要读/写 I

大数据工具集详

查询引擎 一.Phoenix 贡献者::Salesforce 简介:这是一个Java中间层,可以让开发者在Apache HBase上执行SQL查询.Phoenix完全使用Java编写,代码位于GitHub上,并且提供了一个客户端可嵌入的JDBC驱动. Phoenix查询引擎会将SQL查询转换为一个或多个HBase scan,并编排执行以生成标准的JDBC结果集.直接使用HBase API.协同处理器与自定义过滤器,对于简单查询来说,其性能量级是毫秒,对于百万级别的行数来说,其性能量级是秒. Ph

知识总结之几种数据存储的区别及用法

在H5到来之前,数据存储的方式大多使用cookie,但由于其体积太小以及请求时地址栏显示数据等缺点,便有了H5中的localStorage,可以存储较大数据,且不会自动发送到后台.这里主要介绍总结集中web前端数据存储的几种方法及区别.   1.cookie 存储数据较小,大小4K之内: 请求时地址栏带数据,存储在客户端(电脑浏览器中): 不易存储内容过多,会严重占用服务器端带宽,影响性能: 对于IE浏览器有UserData,大小是64k,只有IE浏览器支持. 2.本地存储localStorag

Node.js异步处理CPU密集型任务

Node.js擅长数据密集型实时(data-intensive real-time)交互的应用场景.然而数据密集型实时应用程序并不是只有I/O密集型任务,当碰到CPU密集型任务时,比如要对数据加解密(node.bcrypt.js),数据压缩和解压(node-tar),或者要根据用户的身份对图片做些个性化处理,在这些场景下,主线程致力于做复杂的CPU计算,IO请求队列中的任务就被阻塞. Node.js主线程的event loop在处理所有的任务/事件时,都是沿着事件队列顺序执行的,所以在其中任何一

第 15 章 生成数据

数据可视化指的是通过可视化表示来探索数据,它与数据挖掘紧密相关,而数据挖掘指的是使用代码来探索数据集的规律和关联.数据集可以是一行代码就能表示的小型数字列表,也可以是数亿G字节的数据. 漂亮地呈现数据关乎的并非仅仅是漂亮的图片.以引人注目的简洁方式呈现数据,让观看者能够明白其含义,发现数据集中原本未意识到的规律和意义. 所幸即便没有超级计算机,也能够可视化复杂的数据.鉴于Python的高效性,使用它在笔记本电脑上就能快速地探索由数百万个数据点组成的数据集.数据点并非必须是数字,利用本书前半部分介

大数据之二:Hadoop与Spark辨析

转载自知乎:https://www.zhihu.com/question/26568496 1) MapReduce:是一种离线计算框架,将一个算法抽象成Map和Reduce两个阶段进行 处理,非常适合数据密集型计算. 2) Spark:MapReduce计算框架不适合迭代计算和交互式计算,MapReduce是一种磁盘 计算框架,而Spark则是一种内存计算框架,它将数据尽可能放到内存中以提高迭代 应用和交互式应用的计算效率. 3) Storm:MapReduce也不适合进行流式计算.实时分析,