坦白说也是机缘巧合,在硕士生阶段进入分布式系统领域学习。无论是大规模存储或计算,其核心也是运用分布式技术利用并行性来解决数据密集型应用的需求。最近开始在啃这本《Designing Data-Intensive Applications》大部头,作者Martin Kleppmann在分布式数据系统领域有着很深的功底,并在这本书中完整的梳理各类纷繁复杂设计背后的技术逻辑,不同架构之间的妥协与超越,很值得开发人员与架构设计者阅读。

很可惜的是国内目前并没有对应的中文版本,这个系列算是一个读书感悟,同时也夹带私货,阐述一些自己的理解与看法,抛砖引玉,希望大家多交流学习。这本书共有12个章节,接下来我会一个章节更新一篇读书笔记。(囧rz,感觉自己又开了一个坑)同时也希望国内的出版社可以尽快引入版权,我也想要参与翻译工作啊(,,• ₃ •,,) !!

1.数据密集应用

作为一个开发者来说,目前绝大多数应用程序都是数据密集型的,而不是计算密集型的。CPU的计算能力不再成为这些应用程序的限制因素,而更加亟待解决的问题是海量的数据、数据结构之间的复杂性,应用的性能。

先看看我们经常打交道的数据系统:

  • 存储数据,以便它们或其他应用程序稍后再找到它(数据库
  • 记住昂贵操作的结果,以加快读取速度。(缓存
  • 允许用户按关键字搜索数据或通过各种方式过滤数据(搜索索引
  • 将消息发送到另一个进程,异步处理(流处理
  • 周期性地压缩大量的累积数据(批处理

而很多时候,我们所谓应用程序的绝大工作就是将这些数据系统进行组合,然后添加我们的运行逻辑,但是如何更加合理的整合这些数据系统,对我们来说仍然是一个值得学习和思考的问题。而数据系统也在慢慢变得越来越相似,不同的数据系统也在各自学习彼此的优点。如Redis这样的缓存系统可以支持数据落地,很多时候的应用场合我们可以替代传统的RDBMS。而Kafka这样的数据队列也可以支持数据落地来存储消息。更加深刻的理解这些数据系统,来更好的权衡架构设计,是一门很精深的课题。

上图是一个典型的由多种数据系统构成的应用程序,随着数据量和数据逻辑的复杂,就成为了一个数据密集型的应用。

2.设计数据密集型应用的三原则

  • 可靠性

    具有容错性(面对硬件或软件故障,甚至是人为错误),系统仍应继续正常工作(在期望的性能水平上执行正确的功能)。
  • 可扩展性

    随着系统的增长(在数据量、流量或复杂度),应该有合理的方法来处理这种增长。
  • 可维护性

    随着时间的推移,许多不同的人将致力改善数据系统(既保持当前的行为,并使系统适应新的环境),他们都应该能够卓有成效地工作。

显然,这三个原则不单单是数据密集型应用应当遵循的原则,在绝大多数软件系统中同样是很重要的问题,接下来我们一一梳理一下。

(1)可靠性

  • 硬件故障

    硬盘崩溃,内存出现故障时,电网停电,有人拔了网线,几乎硬件故障在数据中心总是不间断的出现。

    解决方案

    • 在软件与硬件层面考虑冗余,来确保硬件的故障不会演变为系统的故障。
  • 人为的错误

    人是很不可靠,从驾驶技术的演变就可以看出来,人为的疏失会带来巨大的灾难。而且,人经常犯错。

    解决方案

    • 最小化错误机会的方式设计系统。例如,精心设计的抽象,API和管理界面可以很容易地做“正确的事情”,阻止“错误的事情”。
  • 人们犯最多错误的地方和那些可能导致失败的地方解耦。

  • 全面测试,从单元测试到整个系统集成测试和手动测试。

  • 允许快速和容易地从人为错误中恢复,以尽量减少在失败的情况下的影响。例如,使其快速回滚更改配置,逐步推出新的代码(所以任何意想不到的错误只影响一小部分用户),并提供工具来重新计算数据(如果原来旧的计算是不正确的)。

(2)可扩展性

即使一个系统今天工作可靠,但这并不意味着它将来一定会可靠地工作。一个常见原因是负载增加:也许系统已经从10000个并发用户发展到100000个并发用户,或者从100万个增加到1000万个。

“如果系统以特定的方式增长,我们应对增长的选择是什么?” “我们怎样才能增加计算资源来处理额外的负载?”

  • 描述负载

    首先,我们需要简洁地描述系统当前的负载,负载可以用几个数字来描述,我们称之为负载参数。

    参数的选择取决于系统的体系结构,如:
  • 每秒对Web服务器的请求
  • 数据库中的读写比
  • 聊天室中的活跃用户数量
  • 缓存的命中率

  • 描述性能

    一旦描述了系统上的负载,就可以讨论负载增加时发生的情况。可以从两方面看:

    1.增加负载参数并保持系统资源(CPU、内存、网络带宽等)不变时,系统的性能如何受到影响?

    2.当增加负载时,如果希望保持性能不变,需要增加多少资源?

所以我们需要有描述性能的尺子:

  • 平均响应时间:给定n值的算术平均值,全部加起来,除以n。然而这不是一个很好的指标,因为它不告诉你有多少用户真正体验了延迟。
  • 百分比响应时间:把响应时间列表,从最快到最慢排序,那么中间值是中间点:例如,如果平均响应时间是200毫秒,那意味着一半请求在少于200毫秒时返回,而一半请求花费的时间比那个要长。
  • 高百分比的响应时间:可以看看高百分位数:95th,99th,和99.9th百分位数是常见的(简称P95,P99,和p999),来参考响应时间的阈值。

负载情况与性能情况是很重要的,有时系统的瓶颈是由少数极端情况引起的。作者举了一个Twitter的例子,我觉得很好,这里详细分享一下这个例子:

Twitter的故事

Twitter在2012年11月16日公布的数据。

Twitter的两个主要操作是:

  • 发出Tweet

    用户可以发布一个Tweet给他们的订阅者。(平均4.6k请求/秒,峰值超过1.2万的请求/秒)。
  • 获取Tweet

    用户可以查看他们关注者发布Tweet。(约300K的请求/秒)。

Twitter在扩展性的挑战主要不是由于Tweet的数量,而主要是在每个用户都有很多订阅者,每个用户也有很多关注者。执行这两种操作大致是两种方法:

  • 1、发布一条推特,只需将新的推文插入到全球的推文集合中即可。当用户请求他们关注者的Tweet时,可以查找他们所关注的所有人,并找到每个用户的所有Tweet,并将它们合并(按时间排序)。在关系数据库中,可以编写如下查询,例如:

    java SELECT tweets.*, users.* FROM tweets JOIN users ON tweets.sender_id = users.id JOIN follows ON follows.followee_id = users.id WHERE follows.follower_id = current_user

    如下图所示:

  • 2、为每个用户订阅的Tweet维护一个缓存,就像每个收件人的Twitter邮箱一样。当用户发布一条推文时,请查找所有关注该用户的人,并将新的Tweet推送到他们的缓存中。所以读取Tweet列表是很划算的,因为它的结果提前计算好了。

如上图所示的结构显然更合适Tweet的发布,因为发布的Tweet的写操作几乎比读的操作低两个数量级,所以在这种情况下,最好是在写时做更多的工作,而不是在读时做更多的工作。但是方法2并不适用于有大量关注者的账号,假设某人有3000W粉丝,一次发布Tweet产生的写操作可能是巨大的。所以目前在Twitter的Tweet系统中,Twitter将这两种方法混合。大多数用户的推文在发布时仍然会被扩展到Tweet缓存之中,但只有少数用户拥有大量的关注者(即名人)。用户可以跟踪的任何名人的Tweet,并单独读取并与用户的Tweet缓存中进行合并。这种混合方法能够始终如一地提供良好的性能。

这个例子很精炼的描述了架构设计的妥协与精妙,依据业务特点,最大化的优化了数据系统的性能。很佩服Twitter的工程师在架构设计上的功力。同时也很好奇如微博,微信是不是也是采用类似的架构进行设计。

  • 怎么扩展

    放大(垂直缩放,移动到更强大的机器)和缩放(横向缩放,在多台更小的机器上分配负载)之间的二选一。实际上,好的架构通常涉及到一种实用的混合方法:例如,使用几个功能强大的机器仍然比大量的小型虚拟机更简单、更便宜。无节制的分布式会给系统混入复杂度,这是软件工程中危险的地方,虽然在多台机器上分发无状态服务相当简单,但将有状态数据系统从单个节点转移到分布式安装程序会带来许多额外的复杂性。

    没有这样的东西,一个通用的,一个适合所有的应用的可伸缩的架构。(写的真好

(3)可维护性

这部分教导了一些构建可维护系统的方法。软件的大部分成本不是在最初的开发中,而是在持续的维护中修复bug、保持系统运行、使其适应新业务、添加新特性。

  • 可操作性

    让操作运维团队保持系统运行的顺利。

  • 简单

    让新工程师很容易理解系统,通过尽可能地从系统中删除尽可能多的复杂性。

  • 可进化性

    让工程师很容易在将来对系统进行更改,以适应需求变化时的意料之外的用例。也被称为可扩展性、可修改性、可塑性。

维护别人留下的烂摊子真的是很痛苦的事情,文档,注释真的是重中之重!!!

可靠的、可扩展的、可维护的数据系统 ------《Designing Data-Intensive Applications》读书笔记1的更多相关文章

  1. 《数据密集型应用系统设计》读书笔记-ch1可靠、可扩展与可维护的应用系统

    我们以Twitter为例,使用其2012年11月发布的数据.Twitter的两个典型业务操作是: - 发布tweet消息: 用户可以快速推送新消息到所有的关注者,平均大约4.6k request/se ...

  2. 《编写可维护的javascript》读书笔记(中)——编程实践

    上篇读书笔记系列之:<编写可维护的javascript>读书笔记(上) 上篇说的是编程风格,记录的都是最重要的点,不讲废话,写的比较简洁,而本篇将加入一些实例,因为那样比较容易说明问题. ...

  3. 【读书笔记】读《编写可维护的JavaScript》 - 编程实践(第二部分)

    本书的第二个部分总结了有关编程实践相关的内容,每一个章节都非常不错,捡取了其中5个章节的内容.对大家组织高维护性的代码具有辅导作用. 5个章节如下—— 一.UI层的松耦合 二.避免使用全局变量 三.事 ...

  4. WPF,Silverlight与XAML读书笔记(3) - 标记扩展

    hystar的.Net世界 博客园 首页 新闻 新随笔 联系 管理 订阅 随笔- 103  文章- 0  评论- 107  WPF,Silverlight与XAML读书笔记(3) - 标记扩展   说 ...

  5. [读书笔记]C#学习笔记五: C#3.0自动属性,匿名属性及扩展方法

    前言 这一章算是看这本书最大的收获了, Lambda表达式让人用着屡试不爽, C#3.0可谓颠覆了我们的代码编写风格. 因为Lambda所需篇幅挺大, 所以先总结C#3.0智能编译器给我们带来的诸多好 ...

  6. 深入浅出MySQL 数据库开发、优化与管理维护(第2版) -- 读书笔记 -- 基础篇

      1.切换数据库 use blog; 2.显示当前数据库 所有的表. show tables; +----------------+ | Tables_in_blog | +------------ ...

  7. 编写可维护的Javascript读书笔记

    写在前面:之前硬着头皮参加了java方面的编程规范培训,收货良多,工作半年有余的时候,总算感觉到一丝丝Coding之美,以及造轮子的乐趣,以至于后面开发新功能的时候,在Coding style方面花了 ...

  8. 欧几里德欧几里德原理和扩展的原则,(Euclidean Theory and Extended Euclidean Theory)学习笔记

    题记:这是我第四次审查扩展欧几里德原理,由于不经常使用.当你想使用,可以不记得细节,经常检查信息,所以,简单地梳理这一原则和扩展欧几里德的原则,以博客存档以备查用. 一个.欧几里德原理 欧几里德原理( ...

  9. 《编写可维护的javascript》读书笔记(上)

    最近在读<编写可维护的javascript>这本书,为了加深记忆,简单做个笔记,同时也让没有读过的同学有一个大概的了解. 一.编程风格 程序是写给人读的,所以一个团队的编程风格要保持一致. ...

随机推荐

  1. tar split cat 创建、合并分卷压缩包

    最近用微盘传文件遇到的问题,超过100M不能一次传啊,想想win下有rar和zip创建分卷压缩包很简单,就像linux的tar打包器应该也可以吧,搜了下,要和split配合完成 具体命令如下:对文件: ...

  2. JAVA基础-XML的解析

    一.XML的概述 XML的全名为可扩展标记语言(Extensible Markup Language),XML的作用为:1.传输,2.存取数据,3.软件的配置文件.传输现在都用更轻量的Json,而存储 ...

  3. js文件中使用EL表达式的问题

    var str = '${str}' ; var str = '${obj.属性名}'; 只可以再jsp页面的<script></script>中使用,外部引入的js文件中不能 ...

  4. 本地文件与服务器文件同步shell脚本。

    #!/bin/sh read -t 30 -p "请输入项目名:" name echo -e "\n" echo "项目名为:$name" ...

  5. ajax+php(环境搭建+测试)

    在学习JavaScript,jQuery的ajax部分的时候,一直不明白要如何进行,不知道服务器要怎么弄,什么都不知道,当初在学ajax的时候,除了看一下ajax的内容,实践极少,因为,不知道要怎么做 ...

  6. 采访 Lua 发明人的一篇文章

    采访 Lua 发明人的一篇文章 来源 https://blog.codingnow.com/2010/06/masterminds_of_programming_7_lua.html <Mast ...

  7. css基础语法二(常用文本与背景属性)

    [CSS常用文本属性] 1. 字体.字号类:① font-weight: 字体粗细. bold-加粗.normal-正常.lighter-细体 也可以使用100-900数值,400表示normal,7 ...

  8. 0_Simple__matrixMulCUBLAS

    使用CUDA的线性代数库cuBLAS来计算矩阵乘法.这里主要记录调用规则,关于乘法函数中详细的参数说明和调用规则见另一篇随笔. ▶ 源代码: #include <assert.h> #in ...

  9. :after伪类+content内容生成

    :after伪类+content 清除浮动的影响 浮动元素会让此div的高度塌陷.如下例子: .box{padding:10px; background:gray;} .l{float:left;} ...

  10. ldap数据库--ODSEE--复制协议

    简单介绍一下ODSEE的复制拓扑的建立,复制协议可以通过管理界面进行创建,也可以通过命令行创建.在此之前需要了解一些复制协议的相关概念,这里针对OESEE. 1,复制角色 master(提供者,也可以 ...