Author: admin

单线程操作中的高并发的实现和分析(如redis) 0

单线程操作中的高并发的实现和分析(如redis)

本周David给大家带来了Redis中高性能的各种实现和分析,相关总结如下: David演讲的slides:单线程操作中的高并发的实现和分析 Epoll实现的介绍:高并发网络编程之epoll详解 一篇不错的Redis性能优化的总结: 怎么样更好的优化Redis性能? 一个不错的介绍Redis的内部数据结构的系列文章:【redis前传】 关于早期Redis分布式实现的方案介绍的一篇文章:面试题:如何保证redis的高并发及高可用? 最新Redis分布式介绍的文章:Redis分布式方案及一致性Hash算法精讲 Redis高并发带来的一些问题:Redis 高并发带来的一些问题 Redis Multi thread的介绍:Improving Redis Performance through Multi-Thread Processing

分布式系统话题讨论简介 0

分布式系统话题讨论简介

我们会在每周的周五PST 6:30PM举行分布式系统话题讨论,每周会有不同的讨论话题。 zoom link:https://us02web.zoom.us/j/81919563184?pwd=NjBBS3JiYTI5eE12MmFZak01blltQT09Password:246110 相关的讨论流程视频如下:

0

分布式系统硬件基础之漫谈存储设备

我们在分析各种分布式系统场景时不可避免地会讨论到数据的读写,很多时候我们会对数据的读写做很多的优化和特殊处理,而这些操作的背后根源都离不开数据存储的硬件,本文就来和大家谈一谈这其中设计的各种硬件和相应的技术。 Cache和读写 我们都知道把数据放到内存中,这样有读请求过来的时候就可以直接从内存中读取到相关数据(hit cache的情况),而不需要去访问具体的物理磁盘,从而减少了disk I/O的操作。同样地,写也可以写到内存中,只是和读不同的是,内存写终究只是一个中间状态,你最终还是要写到磁盘中才行,所以内存到写操作来说只起到一个delay的作用(当然假如你没有persist保存的情况下,可能也不需要写到磁盘,但我们讨论正常的需要persist保存的情况)。 不过当我们再仔细想一下,其实cache对写并不仅仅是一个delay的作用,它其实还有一些别的好处: 多次写,一次flush:我们很容易就可以想到假如我们对一个数据进行了多次更新,然后再进行一次flush到磁盘,那么这些多次的更新操作其实就只要一次磁盘的写就好了。这从另一个角度减少了磁盘的写操作。 I/O Merge:另外一个好处,就是我们可能有多个数值在内存中被修改了,但我们可以把这些数值集合在一起,一次性更新,这样真正的物理写就可以看成是一次磁盘操作了。 理解了这一点之后,我们再来想想我们之前提到的Write-ahead的logging策略。在write-ahead logging中,内存的修改并没有立即flush到disk中(减少了Random IO的操作),而是写到了一个sequential的log文件中(速度比较快),然后再通过一个后台进程来进行优化写(比如合并之类的)。 这里有人会问为什么Random I/O的操作没有Sequential I/O写的速度快,这是因为对物理磁盘来说,磁头移动是需要时间的,Random I/O就意味着每次要写的偏移地址之间有很大的差别,所以这个磁头需要不停地移动,这显然是很费时间的。而Sequential I/O则不尽然,假如偏移地址是连续的,磁头就不需要不停的移动寻找新的写的偏移,这样就减少了磁头偏移的时间(这里还要看各个厂家的fw的设置,就是sequential写之间的间隔对这个也是有影响的,因为假如sequential写之间间隔时间比较长,那么磁头可能会被reset,所以我们一般认为overlap sequential写是最佳的方案)。 SSD 其实我们上文提到的磁盘准确来讲是HDD,事实上在我们现如今的系统中HDD是最后一层存储,在其和Memory之间还存在另外一种存储介质:SSD。它和HDD不同,不再使用磁头和磁盘来进行存储,它是基于固态电子存储芯片阵列制成的硬盘。简单来说,它有以下优点: 和HDD相比来说,它的random读写的速度都要快很多。一般来说,它的读要比写稍微快一点点。稍后我们来解释这个原因。 Sequential的读写也比HDD速度要快。但是因为HDD的Random 读写比Sequential要差很多,所以单纯比较Sequential的读写速度,SSD提升倍数没有Random读写提升得那么明显,但也有很大的提升。 同步操作有很大的提升。因为HDD只有一个磁头(现在有新的HDD可以支持多个磁头,但是每个磁头也只能访问特定的扇区),所以对于同步操作来说就不能做到真正的同步,说白了还是一个单线程的操作。而SSD则没有这样的限制。 对SSD来说,读操作比较简单,你可以不停地读一个小的单元。但是写操作就比较复杂了,在写之前你必须做一个擦除的操作,而且每次擦除只能是一个block,比如512KB。这个擦除操作还是比较慢的,而且最终会把这个block擦坏了(想象一下,你在一张纸上不停用铅笔写,不停要橡皮擦,最终这张纸的命运就是被擦破)。所以我们对HDD一般讨论的是I/O,而对SSD则一般研究的是寿命。 提到block的擦除,我们就不得不聊一聊SSD的GC(Garbage Collection),其实也很好理解,就是为了让一些block预先准备好了,SSD会回收一些block。这个时候就会有一个数据搬移的过程,比如把几个block中的少量数据(就是数据量不到一个block,但是占用了一个block)移到同一个block中,然后这几个block就可以空出一些出来。这种搬移的操作,其实也是一个新的写的循环,我们称之为Write amplification。你也可以想象,这里的GC操作是需要reserve一些空间来进行的,比如有一个空的block,我们就可以很容易把几个block中的数据搬运过去,假如空的block越来越少,那么搬运的代价就越大。 这也是为什么我们发现当SSD要写满的情况下,性能就会急剧下降。比如你写110GB文件到160GB的SSD和写到同样的320GB的SSD得到的速度可能会有差别,究其根源还是因为需要等待擦除操作。一般来说直接写到一个空的block只需要几百微秒,但是擦除则可能需要几毫秒的时间。 RAID RAID全称廉价磁盘冗余阵列(Redundant Arrays of Independent...

Kubernetes架构和常见使用场景 1

Kubernetes架构和常见使用场景

本周讨论话题由Stephen Zhao以及Morgan Wu主讲,相关内容总结如下: Stephen的Slides:K8s Introduction。 官方文档:Kubernetes 官方文档和教程 Anders介绍K8s的视频:K8S应用场景及未来发展 Presented by Databricks Engineering Manager 不错的新手Tutorial视频:Youtube: Kubernetes Tutorial for Beginners [FULL COURSE in 4 Hours] 一个很不错的关于Kubernetes的中文电子书:Kubernetes指南 Kubernetes in three diagrams Kubernetes – A Comprehensive Overview Progress...

0

分布式文件系统中的MapReduce技术介绍

我们在研究分布式文件系统的实现时,不可避免要讨论MapReduce技术。比较常见的使用这一技术的有HDFS (Hadoop Distributed File System),它是Google文件系统GFS的开源实现。当然很多别的分布式文件系统,比如GlusterFS,QFS(Quantcast File System)以及一些存储服务比如Amazon的S3,Azure Blob Storage以及OpenStack Swift都或多或少有这一技术的影子。本文就来基于HDFS详细介绍一下MapReduce的技术。 分布式文件系统 所谓分布式文件系统,我们可以理解为把文件存储在多个节点中,他们之间通过网络相互连接。从而达到在客户端看起来,这些多个节点就像一台机器一样。为了达到这个效果,HDFS会有一个中心的服务器,我们称之为NameNode,它的作用就是用来知道哪台服务器中存储了哪些文件块,就像大脑一样,我们需要访问某一个文件块的时候,就可以先通过它来确定访问哪一天机器。相应的,在每一台机器上,会运行一个守护进程,它暴露了一个网络服务,这样别的节点就可以通过这个服务访问它上面存储的文件。 和数据库比较类似,为了容错,也会有replication的概念,就是把一个机器上的文件保存多个拷贝在不同的机器上。 MapReduce简介 MapReduce其实说白了是一个编程框架,你可以写相应的代码来处理大的数据集。我们来看这样一个例子:你有一个网站,然后有不同的页面,对应不同的URL,每次有人访问一个页面,就会记录一条记录。 每条记录就是URL和访问的信息,那么现在我们需要对这些记录进行分析,大概的步骤如下: 读出记录的文件,把它们分成一条条记录(比如一行表示一条记录) 调用mapper函数,从每条记录中提出一个key和value对。比如这里我们需要分析每个URL有多少人访问,可以以URL为key,value设为空即可。 根据key来进行排序 调用reducer函数来遍历所有的key-value对,并进行聚合,我们的例子中就是把所有相同的URL合并,并计算有多少条(count函数) 假如我们使用MapReduce来实现这些步骤的话,第一步就是输入格式解析,第二步就是map的操作,第四步是reduce的操作,这两部就是你需要实现相关自定义代码的部分。另外第三步的排序不需要额外来做,因为从map出来的输出就是已经排好序的。 那么第二步和第四步的map/reduce是什么意思呢? Mapper:这个函数对每一个输入的记录都需要调用一次,它主要用来提取键值对。它不保存任何状态,就是对每一个记录这个操作都是独立的。 Reducer:处理Mapper出来的输出,对同样key的值进行处理,比如我们上面的提到的计算同样URL的数目等。 分布式执行 MapReduce最大的特点就是可以在不同的机器上并行执行,而且你不需要写什么特殊的逻辑来处理这个并行操作。 我们来看下面这个图所示的例子,它所示的就是Hadoop中的一个MapReduce的job。这里我们把输入进行partition,标志为m1,m2,m3,然后每一个partition都有一个Mapper进行处理。一般来说在决定mapper的运行的时候,会尽量选择靠近相应输入文件的机器,这样一来就可以减少拷贝输入文件的消耗。通常情况下,相应的机器其实并没有运行map的应用程序,所以会把相应的应用程序包拷贝到对应机器,然后在其上运行应用程序,并输出键值对。 在Map处理好了之后,就需要把同样的键值发送给同一个Reduce进行处理(比如图上的r1,r2,r3)等。需要注意的是我们希望进入reduce的数据是按照某种规则排序的,那么这个排序在哪里实现呢?一般来说各个Map会在它本地先进行排序,然后保存一个有序的输出在他们本地,然后通知reduce说我们这边准备好了。Reduce遍历所有的Map,拷贝相关的数据,在这个过程中再进行 一次全局的排序(merge sort),因为每个map都是排好序的,所以在reduce这一端进行排序的消耗其实是相对还蛮小的。我们把这个过程称之为Shuffle,有点confuse,因为洗牌其实是打乱顺序,而这里其实指的是重新排序。最后reduce再根据他自己的逻辑进行处理就可以了。 MapReduce Workflows 其实单个MapReduce能达到的效果是有限的,在现实中会有很多个MapReduce来组成一个链,我们称之为Workflow来处理实际问题。比如我们上面提到的统计每个URL的数目可以用一个MapReduce实现,但假如我们想知道哪些网页是Top 10访问,就需要再加一个MapReduce来实现。...

常见监控系统Metric实现讨论总结 2

常见监控系统Metric实现讨论总结

本周我们完成了关于监控系统metric实现的讨论,相关资料总结如下: 晓东使用的架构图:《我经历过的监控系统演进史》 一篇很好的讨论监控系统实现的文章:《A Tricky System Design Interview Question: Explain Server Monitoring》 David提到的Gorilla实现的论文:《Gorilla: A Fast, Scalable, In-Memory Time Series Database》 使用Pull还是push相关文章:《Pull doesn’t scale – or does it?》 Andy 提到的Uber M3相关文章:《M3: Uber’s Open Source, Large-scale Metrics...

0

深入分析MySQL系列之总体架构介绍

在我们详细深入介绍MySQL的方方面面之前,让我们首先来看一下MySQL的总体架构,从总体上对MySQL有所了解,这样我们在后面的具体介绍部分的时候才能够知道这些部分属于哪个模块,大概有什么样的作用。 MySQL的逻辑架构 首先我们来看一下MySQL的逻辑架构,如下图所示。 我们可以看到大概可以分成三层: Connection/thread handing,这一层其实和MySQL没有什么大的关系,在一般的C/S架构中都会存在,一般用来处理相关的连接,认证,安全等等方面,我们不具体介绍。 Parser/Optimizer。这一层就是MySQL的大脑了,它主要工作就是解析查询语句,分析并进行优化,所有跨storage engines的函数都是在这里实现的,比如Stored Procedures,views等等。 Storage Engines。顾名思义,这一层的主要作用就是存储和查询数据。MySQL支持很多种不同的Storage Engine,我们在后面一一给大家介绍。 并行控制 在了解了MySQL的逻辑架构之后,我们来看一下MySQL对一些常见数据库的问题的处理方法。第一个问题当然就是我们常见的并行控制,简单说就是有读写同时发生的时候会如何处理。我们在之前的文章介绍过常见的处理方法,这里MySQL选用的是读写锁,也就是说读获取锁的时候,可以有多个读同时进行,但是写的锁是排外的,也就是说有写获取锁,那么任何别的读和写都没有办法获取相应的锁。 使用锁有一个重要的问题就是如何确定锁的粒度,说白了,你把锁加在越大的粒度上,并行的性能就会降低,因为拿不到锁的概率就会变大。假如你把锁的粒度搞到比较小,拿不到锁的概率就会变低,这样并行的性能就会变好,但是问题是锁消耗的资源其实是很大的看,粒度越小就意味着需要更多的锁,从而有更多的资源消耗。这就是我们需要考虑的trade off。 MySQL在这个方面提供了一些选择,根据不同的Storage engine可以实现不同的锁机制和锁粒度。不过通常来说有两种锁的机制比较常见: 表锁:顾名思义,即使lock整个表。每次写一个表的时候都去抓这个表锁,也就意味着其它任何读写都需要等待这个锁。 行锁:这个锁的粒度相比表锁来说就细了很多,它是应用到一行上面的。也就是说只有这行的数据被修改的时候,才会影响到需要修改这行数据的读和写。这样一来其实并行读写的性能就会变得比较好。 大多数MySQL使用的不是简单的行锁。他们使用的是行锁和一种称之为多版本同步控制(MVCC)的技术。这个技术我们在之前的《Snapshot的隔离和Repeatable的读》中有详细的介绍。 Transaction Transaction是一个通用的概念,这里我们不详细介绍,大家可以参考《Transactions的基本概念和介绍》这篇文章。 具体到MySQL,它有不同的storage engine支持Transaction,我们这里以最推荐的InnoDB来说明。 默认来说,单独的Insert,Update以及Delete操作是被隐式地转变成 一个Transaction并且立即commit的。也就是我们常说的AUTOCOMMIT。你可以使用SET AUTOCMMIT = 0/1来关掉或者打开这个功能。注意关掉之后,你就会一直在一个transaction里面,直到你commit或者rollback。 另外MySQL还可以自己设置隔离的级别,你可以简单使用下面这个命令来进行设置 如果你想了解具体关于transaction的隔离相关知识,可以参见这些文章: 《Transaction弱隔离之读提交的介绍和实现》 《Snapshot的隔离和Repeatable的读》...

0

老板让你做Mentor,你准备好了吗?

工作几年,曾经青涩的你也脱去了稚嫩,写代码(Bug)的水平与日俱增,渐渐成为了组里面的顶梁柱。有时看着镜子里日益稀少的头发,你也许会告诉自己是时候该考虑转一下Manager了。于是你和你老板多次提起,是否有转管理的机会。皇天不负有心人,在一个风和日丽的早晨,老板把你喊进办公室,让你当一个新人的Mentor,磨炼一下管理的能力。一下子接到任务的你,是否真的掌握了作为一个Mentor该具有的技能了呢?本文就来唠叨唠叨该怎么做一个Mentor以及可能遇到的问题和解决方法。 成为一个Mentor 假如你有机会成为一个Mentor,首先恭喜你,这是一个表现的好机会,一般来说只要你不去打你的Mentee,基本不会因为这件事做得不好而被解雇,所以可以说这是一个只赚不亏的买卖。尽管如此,显然我们还是希望能够很好地做好一个Mentor。 一般来说会有两种Mentor,一个是Intern的Mentor,一个是新人的Mentor。这两者稍有差别,我们一个一个为你慢慢道来。 Intern的Mentor 一般来说,招Intern的目的是希望能够最终招到一些优秀的人才。但是也有一些intern还需要好几年才毕业,因此Mentor的好坏,对最终他是否会接受公司的offer可能影响不是特别大,所以不要有太大的压力。从另外一个角度来说,这也是公司考察intern的过程,但是作为一个mentor来说,哪怕你的intern能力比较差,不能满足公司的要求,你也要让他不讨厌你,因为很多时候他会回去和他的朋友(社交媒体上)分享整个intern的过程,因此即使没有给return offer,我们也希望intern能有一个愉快的实习经历,这一点要谨记于心。 为了达到这个目标,我们首先要做的事情就是为Intern准备好一个项目。一般来说,你可以准备一个复杂度不是很高,然后优先级也比较低的小feature作为开始。比如说你的intern会过来实习10个星期,那么我们觉得准备一个对新人来说需要5个星期的项目是比较合适的。因为Intern过来毕竟还需要On board,搭环境,了解context,也可能会有一些活动,或者他需要请假处理一些学校的事情等等。我们最终的目的是希望Intern能够在他实习结束前完成相应的项目。 项目准备好了之后,你可以和Intern沟通一下,把相关的项目细化到具体的task,然后给出相应的时间节点,注意的是你需要和Intern进行充分的沟通并听取他的反馈。为什么说这个部分是很重要的,因为作为一个Mentor,你其实需要锻炼的技能就是这个过程的沟通,以及根据他的反馈进行调整的能力。而不是说老子天下第一,比你熟悉很多,你只要听我的就好,这样的话intern感觉不好,你也得不到进步。 听的技能对一个未来的Manager来说很重要,因为很多时候你的下属并不能很好地表达出他的意见。就比如说Intern可能会对这个项目的某一个地方不太理解,他可能不会(愿意)直接说出来,你需要学习如何从与他的交流中知道这些,进而和他一起解决这些问题。当你发现intern有不理解的地方的时候,尝试不同的方法来进行解释,比如说你可以在白板上画出来,让他复述他自己的理解等等。相信我,让他一开始就理解这些问题,会让你在后面的日子里轻松很多。 另外一个常见的问题就是Intern会来不停地问你问题,有时候甚至他自己都不思考。不要慌,这正好是另外一个机会来实践Manager的另外一个技能:有效沟通。告诉他在问你一些问题的之前自己需要做一些研究,你可以让他理解某一些地方的代码(比如让他复述他对某一段代码的理解),给他一些文档阅读等。假如这些都不行,那么设一个时间点,比如让他自己独立工作一天到两天,然后再来和你讨论。当然有坏必然也有好,你可能会遇到一个intern,你觉得需要两天完成的工作,他一天不到就完成了,然后过来问你要新的项目,Okay这是一个幸福的烦恼。但显然也是一个很好的事情,所以准备一些额外的项目有时也是很有必要的。 随着时间的推移,我想你应该会渐渐了解你的intern,这个时候做一些定期的sync是很有必要的,这个sync的时间间隔可以根据不同的人来不同安排,可以是每天的,也可以是几天一次或者一周一次,但总得来说,我们认为至少需要一周一次的sync来确保相应的工作是在正常的轨道上。 最终在Intern实习结束之前,会有一个展示。所以在这最后一两周,你可能需要和他一起,帮助他准备好相应的presentation,这最后的展示可以让intern觉得他的工作没有白费,是对整个小组有很大作用的。好的presentation会让Intern在是否接受return offer上有正向的引导作用(当然钱更重要,哈哈)。 Mentoring一个新人 另外一种mentor是针对新人的,它其实和Intern是有所不同的,总得来说新人的Mentor有三个目的:协助新人快速on board,帮助他从学生(一个公司)到另一个公司文化的适应,建立你们之间的联系。 Mentor一个新人很多时候可以让你用一个新的眼光来看一些事情,比如很多东西你已经忘了或者认为理所当然,而事实却并一定正确,我们就曾今觉得一段代码肯定是对的,但是和新人讨论之后发现真的写错了。抓住这个机会来更新一下自己的认知是很重要的。 一般来说一个组都会有一个完善的On boarding文档,在mentor新人的过程其实也是完善这个文档的过程,做好这件事情,会使得后面再有新人on board的时候变得方便快捷很多。 假如你对manager的技能没有兴趣,mentor一个新人还有一个很大的优点就是你可以和他建立很好的私人关系网。说不定哪天他就会在一个你想去的公司或者team,也许有一天你在一个新的team想把他再招过来,这个Mentor的过程就是你们建立相互信任关系网络的一个很好的机会。 总结 本文简单介绍了一下常见的Mentor的遇到的问题和解决方案,看完之后假如心动了,赶快去找你Manager问问是不是有机会当Mentor吧,哈哈。

1

一文带你了解Windows 性能监控系统的使用

我们现实工作中很多时候想知道当前服务器的各项性能指标,比如说CPU的使用率是多少,还有多少内存,各个磁盘的IO是什么样的情况等等。假如我们使用的是windows操作系统,那么它其实已经内置了一个很强的性能监控系统,本文就来介绍一下我们如何使用这个性能监控系统。 Windows Performance counter系统介绍 总得来说Windows performance counter系统是由这几个方面组成的:Consumer,provider,countersets,counters,instances以及counter value组成。 所谓的Consumer其实就是使用performance数据的模块,我们下面介绍的GUI和代码都属于这部分。 Provider是指产生和publish性能数据的部分。它可以把数据publish给不同的countersets。 Counterset就是一个group,它可以包含一个或多个counters,它会返回多个instance。 Counter就是一个性能的定义,它有一个名字和类型。比如磁盘每秒写IO。 Instance是性能数据的entity,可以包含一个或多个counter值。我们可以这样理解,假设我们是看磁盘的信息,磁盘的每秒的写IO就是一个counter,然后每个磁盘就是一个instance,它可以包含每秒写IO的counter,也可以包含每秒读IO的counter。 Counter value就比较直观了,就是counter的值。 一般来说,Consumer会定期从provider的counterset中收集并记录数据。下面是一个简单的性能API架构图 总得来说V1的架构已经要废弃了,大家尽量还是用V2的架构。 Performance Monitor GUI 我们可以在开始菜单打开Performance Monitor界面,如下图所示,我们可以看到在右边其实有一个系统的总体情况的信息,它包括内存使用的情况,网络的传输状况,磁盘的一些简单信息和各个process的整体信息。这是一个实时的显示。 那么我们如何来真正使用这个工具呢?我们可以在左边Data Collector Sets中点击User Defined,然后创建你关心的Countset, 这里我们使用Create Manually来创建我们关心的Data Collector Set 这里选择Performance Counter 然后点击Add加入我们关心的performance Count,我们这里加入一个Process的%Process...

0

Linearizability一致性介绍二

我们在前面《分布式系统中的Linearizability一致性的概念介绍》介绍了Linearizability的基本概念,本文就来详细介绍一下我们如何来实现Linearizability。 我们再来简单回忆一下Linearizability的介绍,他其实就是说所有的replica都像只有一个一样,那么我们是否有个暴力解,就是真的只有一个拷贝,没有replica,这样不就是Linearizable的了?你是对的,哈哈,不过这个显然不是我们想要的答案,毕竟这样一来,如果这个节点出了任何问题,你整个读写就都不能继续了。 那么我们先来看看各种分布式的模型,看看他们能不能Linearizability: 单leader的replication 在单leader的系统中,假如读都是从leader来的话,或者你使用同步更新replica,那是有可能实现Linearizability的,但是注意也只是有可能,毕竟有可能leader出问题,比如leader自己还认为自己是leader,但事实上已经不是了,这种情况就有可能不是linearizability了。 同步算法(Consensus algorithms) 一些同步算法,它能够防止split brain(多个leader)和stale的replica。这种算法的保证下,就是Linearizable的,这也是我们常见的ZooKeeper的实现方式。 多leader的replication 多leader的replication通常来说都是不linearizable的。因为它们通常都是多个写到不同的leader,然后进行async的replica,这个过程甚至有冲突,所以一般来说它天然就是不Linearizable的。 无leader的replication 在无leader的实现中,一般会有r+w>n这样的设定,看起来是一个很强的一致性设置。但通常来说还是很难说它一定是Linearizable的,这主要取决于他具体是如何实现的。我们后面来详细分析。 Linearizability和Quorums 有人认为严格Quorum的读和写就能保证Linearizability,事实上不尽然,我们来看下面这个例子: 在这里,x的初始值是0。然后有一个Writer去把x更新成1了,这里的write是3个,即w=3,n=3。然后同时Reader A去读,这里r=2,所以它读了replica2和replica3,读出来的值是0或者1。在这之后,Reader B也去读,它读了Replica 1和Replica 2,很不幸,这两个replica都还没有更新,所以读出来的值是0,这里就出现了问题,B在A后面读,但是它竟然读到了一个旧的值。而这里的w+r>n的,所以我们不能简单认为Quorum读写就一定会Linearizable。 CAP理论 不管你是怎样的模型,单leader也好,多leader也罢,基本上都要面临下面这些取舍: 假如你的应用要求Linearizability,那么假如有replica不能和别的replica连接因为各种各样的原因,比如网络等等,那么这些replica就不能处理读请求。 假如你的应用不要求Linearizability,那么任何replica都可能会被读或者写,哪怕他们之间有各种各样的连接问题,都可以继续单独进行工作。 这其实就是著名的CAP理论(Consistency,Availability,Partition tolerance),只能满足其中两个。当然这个理论最大的问题就是partition tolerance只指network连接,或者说节点之间能否通信(不涉及节点延时等等)。这里我就不展开说了,相信很多文章都会介绍这个。 Linearizability和网络延迟 虽然Linearizability很有用,但是事实上并没有多少数据库真的实现Linearizability ,主要原因还是它对性能的影响太大了。尤其在网络延迟很大的情况下,linearizable的读写所消耗的性能都很可观。而且没有什么好的算法可以解决这个问题,除非你不需要Linearizability,Okay这其实也是很多数据库最终的选择。 总结 本文把前一篇文章中没有介绍的内容再补充介绍了一下,希望大家能够对Linearizability有充足的了解。