深入浅出计算机组成原理:设计?型DMP系统(下)-SSD拯救了所有的DBA(第53讲)

一、上节总结回顾

上一讲里,根据DMP系统的各个应用场景,我们从抽象的原理层面,选择了AeroSpike作为KV数据库,Kafka作为数据管道,Hadoop/Hive来作为数据仓库。

不过呢,肯定有不信邪的工程师会问,为什么MongoDB,甚至是MySQL这样的文档数据库或者传统的关系型数据库不适应呢?为什么不能通过优化SQL、添加缓存这样的调优手段,解决这个问题呢?

今天DMP的下半场,我们就从数据库实现的原理,一起来看一看,这背后的原因。如果你能弄明表今天的这些更深入、更细节的原理,对于什么场景使用什么数据库,就会更加胸有成竹,而不是只有

跑了大量的性能测试才知道。下次做数据库选型的时候,你就可以“以理服人”了。

二、关系型数据库:不得不做的随机读写

我们先来想一想,如果现在让你自己写一个最简单的关系型数据库,你的数据要怎么存放在硬盘上?最简单最直观的想法是,

1、你的数据要怎么存放在硬盘上?

1、用一个CSV文件格式。一个文件就是一个数据表。

2、文件里面的每一行就是这个表里面的一条记录。

3、如果要修改数据库里面的某一条记录,那么我们要先找到这记录,

4、然后直接去修改这一行的数据。读取数据也是一样的。

要找到这样数据,最笨的办法当然是一行一行读,也就是遍历整个CSV文件。不过这样的话,相当于随便读取任何一条数据都要扫描全表

2、太浪费硬盘的吞吐量了。那怎么办呢?

我们可以试试给这个CSV文件加一个索引。比如,给数据的行号加一个索引。如果你学过数据库原理或者算法和数据结构,那你应该知道,通过B+树多半是可以来建立这样一个索引的。

1、索引里面没有一整行的数据,只有一个映射关系,这个映射关系可以让行号直接从硬盘的某个位置去读。

2、所以,索引比起数据小很多。我们可以把索引加载到内存里面。

3、即使不在内存里面,要找数据的时候快速遍历一下整个索引,也不需要读太多的数据。

加了索引之后,我们要读取特定的数据,就不用去扫描整个数据表文件了。直接从特定的硬盘位置,就可以读到想要的行。索引不仅可以索引行号,还可以索引某个字段。
我们可以创建很多个不同的独立的索引。写SQL的时候,where语句后面的查询条件可以用到这些索引。

不过,这样的话,写入数据的时候就会麻烦一些。我们不仅要在数据表里面写入数据,对于所有的索引也都需要进行更新。这个时候,写一条条数据就要触发好几个随机写入的更新。

在这样一个数据模型下,查询操作很灵活。无论是根据哪个字段查询,只要有索引,我们就可以通过一次随机读,很快地读到对应的数据。但是,这个灵活性也带来了一个很大的问题,

3、加索引后查询操作很灵活、但是无论干点什么都有大量的随机读写请求

那就是无论干点什么,都有大量的随机读写请求。而随机读写请求,如果请求最终是要落到硬盘上,特别是HDD硬盘的话,我们就很难做到高并发了。毕竟HDD硬盘只有100左右的QPS。

而这个随时添加索引,可以根据任意字段进行查询,这样表现出的灵活性,又是我们的DMP系统里面不太需要的。DMP的KV数据库主要的应用场景,是根据主键的随机查询,
不需要根据其他字段进行筛选查询。数据管道的需求,则只需要不断追加写入和顺序读取就好了。即使进行数据分析的数据仓库,通常也不是根据字段进行数据筛选,而是全量扫描数据进行分析汇总。

后面的两个场景还好说,大不了我们让程序去扫描全表或者追加写入。但是,在KV数据库这个需求上,刚才这个最简单的关系型数据库的设计,就会面临大量的随机写入和随机读取的挑战。

所以,在实际的大型系统中,大家都会使用专门的分布式KV数据库,来满足这个需求。那么下面,我们就一起来看一看,Facebook开源的Cassandra的数据存储和读写是怎么做的,
这些设计是怎么解决高并发的随机读写问题的。

三、Cassandra:顺序写和随机读

1、Cassandra的数据模型

作为一个分布式的KV数据库,Cassandra的键一般被称为Row Key。其实就是一个16到36个字节的字符串。每一个Row Key对应的值其实是一个哈希表,里面可以用键值对,再存入很多你需要的数据。

Cassandra本身不像关系型数据库那样,有严格的Schema,在数据库创建的一开始就定义好了有哪些列(Column)。但是,它设计了一个叫作列族(Column Family)的概念,我们需要把经常放在一起使用的
字段,放在同一个列族列族。比如,DMP里面的人口属性信息,我们可以把它当成是一个列族。用户的兴趣信息,可以是另外一个列族。这样,既保持了不需要严格的Schema这样的灵活性,也保留了
可以把常常起使用的数据存放在一起的空间局部性。

往Cassandra的里面读写数据,其实特别简单,就好像是在一个巨大的分布式的哈希表里面写数据。我们指定一个Row Key,然后插入或者更新这个Row Key的数据就好了。

2、Cassandra的写操作

Cassandra解决随机写入数据的解决方案,简单来说,就叫作“不随机写,只顺序写”。对于Cassandra数据库的写操作,通常包含两个动作。第一个是往磁盘上写入一条提交日志(Commit Log)。另一个操作

则是直接在内存的数据结构上去更新数据。后面这个往内存的数据结构里面的数据更新,只有在提交日志写成功之后才会进入。每台机器上,都有一个可靠的硬盘可以让我们去写入提交日志。写入提交日志都是顺序
写(Sequential Write),而不是随机写(Random Write),这使得我们最大化了写入的吞吐量。

如果你不明白这是为什么,可以回到第47讲,看看硬盘的性能评测。无论是HDD硬盘还是SSD硬盘,顺序写入都比随机写入要快得多。

内存的空间比较有限,一旦内存里面的数据量或者条母超过一定的限额,Cassandra就会把内存里面的数据结构dump到硬盘上。这个Dump的操作,也是顺序写而不是随机写,所以性能也不会是一个问题。除了
Dump的数据结构文件,Cassandra还会根据row key来生成一个索引文件,方便后续基于索引来进行快速查询。

随着硬盘上的Dump出来的文件越来越多,Cassandra会在后台进行文件的对比合并。在很多别的KV数据库系统里面,也有类似这种的合并动作,比如AeroSpike或者Google的BigTable。这些操作我们一般称之为
Compaction。合并动作同样是顺序读取多个文件,在内存里面合并完成,再Dump出来一个新的文件。整个操作过程中,在硬盘层面仍然是顺序读写。

3、Cassandra的读操作

当我们要从Cassandra读数据的时候,会从内存里面找数据,再从硬盘读数据,然后把两部分的数据合并成最终结果。这些硬盘上的文件,在内存里面会有对应的Cache,只有在Cache里面找不到,我们才会去请求
硬盘里面的数据。

如果不得不访问硬盘,因为硬盘里面可能Dump了很多个不同时间点的内存数据的快照。所以,找数据的时候,我们也是按照时间从新的往旧的里面找。

这也就带来另外一个问题,我们可能要查询很多个Dump文件,才能找到我们想要的数据。所以,Cassandra在这一点上又做了一个优化。那就是,它会为每一个Dump的文件里面所有Row Key生成一个
BloomFilter,然后把这个BloomFilter放在内存里面。这样,如果想要查询的Row Key在数据文件里面不存在,那么99%以上的情况下,它会被BloomFilter过滤掉,而不需要访问硬盘。

这样,只有当数据在内存里面没有,并且在硬盘的某个特定文件上的时候,才会触发一次对于硬盘的读请求。

四、SSD:DBA们的大救星

Cassandra是Facebook在2008年开源的。那个时候,SSD硬盘还没有那么普及。可以看到,它的读写设计充分考虑了硬件本身的特性。在写入数据进行持久化上,Cassandra没有任何的随机写请求,无论是
Commit Log还是Dump,全部都是顺序写。

1、Cassandra在数据读的请求上做的优化

在数据读的请求上,最新写入的数据都会更新到内存。如果要读取这些数据,会优先从内存读到。这相当于是一个使用了LRU的缓存机制。只有在万般无奈的情况下,才会有对于硬盘的随机读请求。即使在这样的情
况下,Cassandra也在文件之前加了一层BloomFilter,把本来因为Dump文件带来的需要多次读硬盘的问题,简化成多次内存读和一次硬盘读。

这些设计,使得Cassandra即使是在HDD硬盘上,也能有不错的访问性能。因为所有的写入都是顺序写或者写入到内存,所以,写入可以做到高并发。HDD硬盘的吞吐率还是很不错的,每秒可以写入100MB以上的
数据,如果一条数据只有1KB,那么10万的WPS(Writes per seconds)也是能够做到的。这足够支撑我们DMP期望的写入压力了。

而对于数据的读,就有一些挑战了。如果数据读请求有很强的局部性,那我们的内存就能搞定DMP需要的访问量。

2、问题就出在这个局部性上

但是,问题就出在这个局部性上。DMP的数据访问分布,其实是缺少局部性的。你仔细想一想DMP的应用场景就明白了。DMP里面的Row Key都是用户的唯一标识符。普通用户的上网时长怎么会有局部性呢?每个
人上网的时间和访问网页的次数就那么多。上网多的人,一天最多也就24小时。大部分用户一天也要上网2?3小时。我们没办法说,把这些用户的数据放在内存里面,那些用户不放。

那么,我们可不可能有?定的时间局部性呢?如果是Facebook那样的全球社交?络,那可能还有?定的时间局部性。毕竟不同国家的用的时区不一样。我们可以说,在印度人民的一天,把印度人民的数据加载到内
存里面,美国人民的数据就放在硬盘上。到了印度人民的晚上,再把美国人民的数据换到内存里面来。如果你的主要业务是在国内,那这个时间局部性就没有了。大家的上网高峰时段,都是在早上上班路上、中
午休息的时候以及晚上下班之后的时间,没有什么区分度。

面临这个情况,如果你们的CEO或者CTO问你,是不是可以通过优化程序来解决这个问题?如果你没有仔细从数据分布和原理的层面思考这个问题,而直接一下答应下来,那你可能之后要头疼了,因为这个问题很有
可能是搞不定的。

因为缺少了时间局部性,我们内存的缓存能够起到的作用就很小了,大部分请求最终还是要落到HDD硬盘的随机读上。但是,HDD硬盘的随机读的性能太差了,我们在第45讲看过,也就是100QPS左右。而如果全都
放内存,那就太贵了,成本在HDD硬盘100倍以上。

3、2010年SSD硬盘的大规模商用解决了局部性问题

不过,幸运的是,从2010年开始,SSD硬盘的大规模商用帮助我们解决了这个问题。它的价格在HDD硬盘的10倍,但是随机读的访问能力在HDD硬盘的百倍以上。也就是说,用上了SSD硬盘,我们可以用1/10的成
本获得和HDD硬盘同样的QPS。同样的价格的SSD硬盘,容量则是内存的10倍,也能够满足我们的需求,比较低的成本存下整个互联网络信息。

不夸张地说,过去几年的“大数据”“高并发”“千人千面”,有一半的功劳应该归在让SSD容量不断上升、价格不断下降的硬盘产业上。回到我们看到的Cassandra的读写设计,你会发现,Cassandra的写入机制完美匹配了我们在第46和47讲所说的SSD硬盘的优缺点。

在数据写入层面,Cassandra的数据写入都是Commit Log的顺序写入,也就是不断地在硬盘上往后追加内容,而不是去修改现有的文件内容。一旦内存里面的数据超过一定的阈值,Cassandra就会完整地Dump一
个新文件到文件系统上。这同样是一个追加写入。

数据的对等和紧凑化(Compaction),同样是读取现有的多个文件,然后写一个新的文件出来。写入操作只追加不修改的特性,正好天然地符合SSD硬盘只能按块进行擦除写入的操作。在这样的写入模式下,
Cassandra用到的SSD硬盘,不需要频繁地进行后台的Compaction,能够最大化SSD硬盘的使用寿命。这也是为什么,Cassandra在SSD硬盘普及之后,能够获得进一步快速发展。

五、延伸总结

好了,关于DMP和存储器的内容,讲到这里就差不多了。希望今天的这一讲,能够让你从Cassandra的数据库实现的细节层面,彻底理解怎么运用好存储器的性能特性和原理。

传统的关系型数据库,我们把一条条数据存放在一个地方,同时再把索引存放在另外一个地放。这样的存储方式,其实很方便我们进行单次的随机读和随机写,数据的存储也可以很紧凑。但是问题也在于此,大部分的SQL请求,都会带来大量的随机读写的请求。这使得传统的关系型数据库,其实并不适合用在真的高并发的场景下。

我们的DMP需要的访问场景,其实没有复杂的索引需求,但是会有比较高的并发性。我带你一看了Facebook开源的Cassandra这个分布式KV数据库的读写设计。通过在追加写入Commit Log和更新内存,
Cassandra避开了随机写的问题。内存数据的Dump和后台的对比合并,同样也都避开了随机写的问题,使得Cassandra的并发写入性能极高。

在数据读取层面,通过内存缓存和BloomFilter,Cassandra已经尽可能地减少了需要随机读取硬盘里面数据的情况。不过挑战在于,DMP系统的局部性不强,使得我们最终的随机读的请求还是要到硬盘上。幸运
的是,SSD硬盘在数据海量增长的那几年里价格不断下降,使得我们最终通过SSD硬盘解决了这个问题。而SSD硬盘本身的擦除后才能写入的机制,正好非常适合Cassandra的数据读写模式,最终使得Cassandra
在SSD硬盘普及之后得到了更大的发展。

原文地址:https://www.cnblogs.com/luoahong/p/11514616.html

时间: 2024-11-05 13:35:06

深入浅出计算机组成原理:设计?型DMP系统(下)-SSD拯救了所有的DBA(第53讲)的相关文章

深入浅出计算机组成原理

课程目录:第00课.开篇词丨为什么你需要学习计算机组成原理?.rar第01课.冯-诺依曼体系结构:计算机组成的金字塔.rar第02课.给你一张知识地图,计算机组成原理应该这么学.rar第03课.通过你的CPU主频,我们来谈谈“性能”究竟是什么?.rar第04课.穿越功耗墙,我们该从哪些方面提升“性能”?.rar第05课.计算机指令:让我们试试用纸带编程.rar第06课.指令跳转:原来if.rar第07课.函数调用:为什么会发生stackoverflow?.rar第08课.ELF和静态链接:为什么

5. 蛤蟆的计算机组成原理笔记五输入输出系统

5. 蛤蟆的计算机组成原理笔记五输入输出系统 本篇名言:"质朴却比巧妙的言辞更能打动我的心. --莎士比亚" 欢迎转载,转载请标明出:http://blog.csdn.net/notbaron/article/details/48037245 1.  输入输出系统 1.1             I/O 软件 (1) I/O 指令 CPU 指令的一部分 (2) 通道指令 通道自身的指令 1.2             I/O设备与主机信息传送的控制方式 1. 程序查询方式 2. 程序中

深入浅出计算机组成原理:通过你的CPU主频,我们来谈谈“性能”究竟是什么?(第3讲)

一.性能到底指的是什么? 买新电脑的时候,我们会说:"原来的电脑性能跟不上了" 写程序的时候,我们会说:"这个程序西能需要优化一下" 1."性能"到底指的是什么? 在计算机组成原理乃至体系结构中"性能"都是最重要的一个主题.我在前面说过学习和研究计算机组成原理,就是在理解计算机是怎么运作的, 以及为什么要这么运作."为什么"?所要解决的事情,很多时候就是提升"性能" 2.性能有几个指标?

深入浅出计算机组成原理:解读TP-设计和拆解一块ASIC芯片(第33讲)

一.引子 过去几年,最知名.最具有实用价值的ASIC就是TPU了.各种解读TPU论文内容的文章网上也很多.不过,这些文章更多地是从机器学习或者AI的角度,来讲解TPU. 上一讲,我为你讲解了FPGA和ASIC,讲解了FPGA如何实现通过“软件”来控制“硬件”,以及我们可以进一步把FPGA设计出来的电路变成一块ASIC芯片. 不过呢,这些似乎距离我们真实的应用场景有点儿远.我们怎么能够设计出来一块有真实应用场景的ASIC呢?如果要去设计一块ASIC,我们应该如何思考和拆解问题呢?今天,我就带着你一

深入浅出计算机组成原理:GPU(下)-为什么深度学习需要使用GPU?(第31讲)

一.引子 上一讲,我带你一起看了三维图形在计算机里的渲染过程.这个渲染过程,分成了顶点处理.图元处理.栅格化.片段处理,以及最后的像素操作.这一连串的过程, 也被称之为图形流水线或者渲染管线. 因为要实时计算渲染的像素特别地多,图形加速卡登上了历史的舞台.通过3dFx的Voodoo或者NVidia的TNT这样的图形加速卡,CPU就不需要再去处理一个个像素点的图元处理.栅格化和片段处理这些操作.而3D游戏也是从这个时代发展起来的. 你可以看这张图,这是“古墓丽影”游戏的多边形建模的变化.这个变化,

深入浅出计算机组成原理:数据完整性(下)-如何还原犯罪现场(第50讲)

一.引子 讲完校验码之后,你现在应该知道,无论是奇偶校验码,还是CRC这样的循环校验码,都只能告诉我们一个事情,就是你的数据出错了.所以,校验码也被称为检错码(Error Detecting Code). 不管是校验码,还是检错码,在硬件出错的时候,只能告诉你“我错了”.但是,下一个问题,“错哪儿了”,它是回答不了的.这就导致,我们的处理?式只有一种,那就是当成“哪儿都错了”.如果是下载一个文件,发现校验码不匹配,我们只能重新去下载:如果是程序计算后放到内存里面的数据,我们只能再重新算一遍. 这

深入浅出计算机组成原理:异常和中断-程序出错了怎么办?(第28讲)

一.引子 过去这么多讲,我们的程序都是自动运行且正常运行的.自动运行的意思是说,我们的程序和指令都是一条条顺序执行,你不需要通过键盘或者网络给这个程序任何输入.正常运行是说,我们的程序都是能够正常执行下去的,没有遇到计算溢出之类的程序错误. 不过,现实的软件世界可没有这么简单.一方面,程序不仅是简单的执行指令,更多的还需要和外部的输入输出打交道.另一方面,程序在执行过程中,还会遇到各种异常情况,比如除以0.溢出,甚至我们自己也可以让程序抛出异常. 那这一讲,我就带你来看看,如果遇到这些情况,计算

深入浅出计算机组成原理:32-FPGA、ASIC和TPU(上)-计算机体系结构的黄金时代(第32讲)

一.引子 过去很长一段时间里,大家在讲到高科技.互联网.信息技术的时候,谈的其实都是“软件”.从1995年微软发布Windows 95开始,高科技似乎就等同于软件业和互联网.著名的风险投资基金Andreessen Horowitz的合伙人Marc Andreessen,在2011年发表了一篇博客,声称“Software is Eating the World”.Marc Andreessen,不仅是投资人,更是Netscape的创始人之一.他当时的搭档就是我们在前两讲提过的SGI创始人Jim C

计算机组成原理基础知识-输入输出系统

四.输入输出系统 --输入输出系统由I/O软件和I/O硬件两部分组成 --I/O设备 输入设备:完成输入程序.数据.命令等功能:键盘.鼠标.触摸屏.其他 输出设备:显示设备.打印设备 其他I/O设备:终端设备.A/D与D/A转换器.汉字处理设备等 --I/O接口 接口可以看做是两个系统或两个部件的交接部分 接口的功能:选址功能.传送命令的的功能.传送数据的功能.反应I/O设备状态的功能 接口类型:按不同方式分类有以下几种: 按数据传送方式分类:有并行接口和串行接口 按功能选择的灵活性分类:有可编