你真的理解CAP理论吗?

      最近在学习消息中间件的时候,接触到了分布式系统,进而接触到CAP理论,上一次接触还是在年初的时候公司的技术分享会上,有人在介绍项目的时候简单介绍了这个CAP理论,但并没有深入研究。这次,该是时候研究一下这个CAP原则到底是个啥了。
       其实,CAP理论在大部分的开发者心里都有一定的位置,在互联网界也有广泛的知名度,稍微经验丰富或者知识广泛的程序员都会把它作为衡量一个系统,尤其是分布式系统的设计准则,也就是我们说的CAP原则。大家都非常清晰的知道:任何的分布式系统,在可用性、一致性和分区容错性方面,是不可兼得的,就像是我们常说的“鱼和熊掌不可兼得”一样,最多值能得其二。所以说,任何一个分布式系统的设计,都是根据各自的实际应用场景和需求,对这三个维度的的不同取舍而已。
 
       说了这么多,大家可能还是比较懵逼。到底什么是CAP原则?下面先知道下它的定义:
 


CAP原则又称CAP定理,指的是在一个分布式系统中, Consistency(一致性)、 Availability(可用性)、Partition tolerance(分区容错性),三者不可得兼。换句话说,就是说在一个系统中对某个数据不存在一个算法同时满足 Consistency, Availability, Partition-tolerance。


 
       定义就是定义,一句话,就把上面的一大段废话说的清晰明了!那可能接下来,又来了个“三脸懵逼”,到底啥是一致性、可用性和分区容错性?同样的,上定义:
 


● 一致性(C):在分布式系统中的所有数据备份,在同一时刻是否同样的值。一致性被称为原子对象,任何的读写都应该看起来是“原子“的,或串行的。(等同于所有节点访问同一份最新的数据副本)
● 可用性(A):在集群中一部分节点故障后,集群整体是否还能响应客户端的读写请求。(对数据更新具备高可用性)
● 分区容错性(P):以实际效果而言,分区相当于对通信的时限要求。系统如果不能在时限内达成数据一致性,就意味着发生了分区的情况,必须就当前操作在C和A之间做出选择。


 
       现在大家应该对这些基本概念有了一个比较清晰的认识。那我们在深入理解CAP原则之前,先了解下CAP原则的前世今生。
 
为什么会产生这个CAP理论?
 
       1985年Lynch证明了异步通信中不存在任何一致性的分布式算法(FLP Impossibility)的同时,人们就开始寻找分布式系统设计的各种因素。一致性算法既然不存在,但若能找到一些设计因素,并进行适当的取舍以最大限度满足实现系统需求成为当时的重要议题。比如,在CAP之前研究者就已经发现低延迟和顺序一致性不可能同时被满足。
       2000年,Eric Brewer教授在PODC的研讨会上提出了一个猜想:一致性、可用性和分区容错性三者无法在分布式系统中被同时满足,并且最多只能满足其中两个!这个猜想首次把一致性、可用性和分区容错三个因素提炼出来作为系统设计的重要特征,断言用此三者可以划分所有的分布式系统,并指明这三个特征之间的不可能性关系。Brewer猜想比单纯的“低延迟和顺序一致性不能被同时满足”的结论更具体,对实际系统的构建也更具有可操作性!Brewer教授当时想象的分布式场景是webservice,一组websevrice后台运行着众多的server,对service的读写会反应到后台的server集群,并对CAP进行了定义,就是上面列出的定义。高可用、数据一致是很多系统设计的目标,但是分区又是不可避免的事情,CAP的出现仿佛是一盏明灯,它揭露了分布式系统的本质,并给出了设计的准则,而这正是1985年以来人们正在寻找的东西!所以CAP在当时的影响力是非常大的!
       2002年,Lynch与其他人证明了Brewer猜想,从而把CAP上升为一个定理。
 
这么一帆风顺吗?直至今日,对CAP理论的质疑声不断
 
       就在这些理论被踢出来,大家觉得终于对分布式系统设计有了指导原则的时候,有些工程师和研究者就对CAP提出了各种质疑,纷纷有用反例证明着CAP在各种场合不适用性,同时挑战着Lynch的证明结果!你是否看了CAP的概念定义后还是感觉很模糊?如果是,你并不孤独,有很多人都是如此!CAP没有考虑不同的基础架构、不同的应用场景、不同的网络基础和用户需求,而C、A、P在这些不同场景中的含义可能完全不同,这种无视差异化的定义导致了非常大的概念模糊,同时也变成CAP被质疑的源头!

       其中,这些质疑主要集中在以下几个方面:
 

  • 概念模糊混乱,废话一堆,不能作为定理

  • 不适用于数据库事务架构

  • 应该构建不可变模型避免CAP的复杂性

  • 分区容错概念有误导

 
       其实,搞了半天,我也不是很清晰这些高大上的推论和证明,也不是我们该操心的,因为CAP理论的提出者和证明者也在后续对这些质疑进行了相应的“回击”!
 
回击和解释
 
       面对大量的质疑,Brewer和Lynch终于坐不住了,因此两人纷纷出来澄清。Brewer于2012年重申”3个中的2个“这个表述是不准确的,在某些分区极少发生的情况下,三者能顺畅地在一起配合,而且CAP不仅仅是发生在整个系统中,可能是发生在某个子系统或系统的某个阶段。
       Lynch也在10年后的2012年重写了论文,缩小CAP适用的定义,消除质疑的场景,展示了CAP在非单一一致性结果下的广阔的研究结果!并顺便暗示CAP定理依旧正确!
 
       多么精彩的“撕逼”过程!但是对我们来说,真正有意义的还是CAP理论本身。
 
我们该如何看待CAP理论本身?
 
       首先肯定的是,CAP并不适合作为一个适应任何场景的定理,它的正确性更加适合基于原子读写的NoSQL场景。质疑虽然很多,但很多质疑者只是偷欢概念,并没有解决各个因素之间的取舍问题。而无论如何C、A、P这个三个概念始终存在任何分布式系统,只是不同的模型会对其有不同的呈现,可能某些场景对三者之间的关系敏感,而另一些不敏感。就像Lynch所说,现在分布式系统有很多特性,比如扩展性、优雅降级等,随着时间的发展,或许这些也会被纳入研究范畴,而作为开发者,这都是我们需要考虑的问题,而不仅是CAP三者!
 
对CAP三者的选择
 
       当处理CAP的问题时,你会有几个选择。最明显的是:


 
1.(CA)放弃Partition Tolerance:
如果你想避免partition问题发生,你就必须要阻止其发生。一种做法是将所有的东西(与事务相关的)都放到一台机器上。或者放在像rack这类的atomically-failling单元上。无法100%地保证,因为还是有可能部分失败,但你不太可能碰到由partition问题带来的负面效果。当然,这个选择会严重影响scale限制。

2.(CP)放弃Availability:
相对于放弃partition tolerance来说,其反面就是放弃availability。一旦遇到partition 事件,受影响的服务需要等待数据一致,因此在等待期间就无法对外提供服务。在多个节点上控制这一点会相当复杂,而且恢复的节点需要处理逻辑,以便平滑地返回服务状态。

3.(AP)放弃Consistency:
或者如同Werner Vogels所提倡的,接受事情会变得“最终一致(Eventually Consistent)”(2008年12月更新)。Vogels的文章值得一读。他比我在这里讨论了更多的操作方面的细节。许多的不一致性并不比你想的需要更多的工作(意味着持续的consistency或许并不是我们所需要的)。在购书的例子中,如果一本库存的书,接到了2个订单,第二个就会成为备份订单。只要告知客户这种情况(请记住这是一种罕见的情况),也许每个人都会高兴的。
 


 
总结
 
       在Consistency, Availability和Partition-tolerance中,你只能保证2点,这是确实的,并且已经被这个星球上最成功的网站证实了。如果对网站是有效的,我看不出在企业环境中,在日常的工作中,不考虑同样的折衷设计的理由。当然,CAP理论也只是对我们的分布式系统设计起到一个指导性的作用,我们在设计系统时,要考虑的方面也绝非只有这三个方面,正如上文所提到的,扩展性、降级等也是我们需要考虑的内容,所有,只有结合实际的业务需求和使用场景,才能设计出更加合适的系统。

参考资料:
1、http://blog.csdn.net/chen77716/article/details/30635543
2、http://blog.sina.com.cn/s/blog_493a8455010161hi.html

相关文章:

  • 分布式一致性算法:Raft 算法

  • 分布式系列文章——Paxos算法原理与推导

  • 分布式基础通信协议:paxos,totem和gossip

原文地址:https://ask.zkbhj.com/?/article/61


.NET社区新闻,深度好文,微信中搜索dotNET跨平台或扫描二维码关注

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/326315.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

264. 丑数 II---LeetCode---JAVA(动态规划)

class Solution { public int nthUglyNumber(int n) {int[] nums new int[n];//初始化数组int index2 0;int index3 0;int index5 0;int tmp 1;nums[0] 1;//初始化第一个值&#xff0c;当n等于1的时候直接是1int cnt 1;while (cnt < n) {tmp Math.min(nums[index2] …

老司机实战Windows Server Docker:4 单节点Windows Docker服务器简单运维(下)

上篇中&#xff0c;我们主要介绍了使用docker-compose对Windows Docker单服务器进行远程管理&#xff0c;编译和部署镜像&#xff0c;并且设置容器的自动启动。但是&#xff0c;还有一些重要的问题没有解决&#xff0c;这些问题不解决&#xff0c;就完全谈不上运维&#xff1a;…

2018蓝桥杯省赛---java---C---4( 第几个幸运数)

题目描述 思路分析 直接暴力 代码实现 package TEST;public class Main {public static void main(String[] args) {long n 59084709587505L, cnt 0;for (long a 1; a < n; a * 3)for (long b 1; b < n; b * 5)for (long c 1; c < n; c * 7)if (a * b * c <…

MySQL year()函数

转载自 MySQL year()函数 MySQL YEAR函数简介 YEAR()函数接受date参数&#xff0c;并返回日期的年份。请参阅YEAR()函数的语法&#xff1a; YEAR(date);YEAR()函数返回一个指定日期的年份值&#xff0c;范围为1000到9999&#xff0c;如果日期为零&#xff0c;YEAR()函数返回…

MySQL协议.NET Core实现(一)

一个有技术追求的研发团对&#xff0c;无论使用什么框架、什么工具、什么语言&#xff0c;团队里应该有人有能力把控所使用框架、工具、语言的每一个核心功能的实现细节。团队里的每个成员应该根据自身所长挑选其中一块做深入研究&#xff0c;并把研究成果分享给团队&#xff0…

2018蓝桥杯省赛---java---C---7(缩位求和)

题目描述 问题描述在电子计算机普及以前&#xff0c;人们经常用一个粗略的方法来验算四则运算是否正确。 比如&#xff1a;248 * 15 3720 把乘数和被乘数分别逐位求和&#xff0c;如果是多位数再逐位求和&#xff0c;直到是1位数&#xff0c;得 2 4 8 14 > 1 4 5; 1 …

龙芯linux内核,龙芯的linux kernel,内核开发与编译

在很久很久以前&#xff0c;linux被视为geek极客的玩具。自行升级Linux内核&#xff0c;对普通用户来说&#xff0c;简直是天方夜谭。曾经的曾经&#xff0c;升级内核需要很多纷繁复杂的步骤&#xff0c;也需要花费很多的时间。但是&#xff0c;现在不一样了。内核的安装可以方…

2018蓝桥杯省赛---java---C---8(等腰三角形)

题目描述 问题描述本题目要求你在控制台输出一个由数字组成的等腰三角形。 具体的步骤是&#xff1a;先用1,2,3&#xff0c;…的自然数拼一个足够长的串 用这个串填充三角形的三条边。从上方顶点开始&#xff0c;逆时针填充。 比如&#xff0c;当三角形高度是8时&#xff1a;1…

Git,Git Flow,GitLab使用指南

高效利用一次蹲坑时间&#xff0c;看看如何使用Git Flow进行高效开发&#xff0c;什么才是Git提交的正确姿势&#xff0c;怎样使用GitLab进行Code Review&#xff1a; 使用Git Flow高效开发&#xff1b;Git提交正确姿势&#xff0c;Commit message编写指南&#xff1b;使用Git…

arm linux gcc 编译,Linux arm-linux-gcc交叉编译环境配置

Linux下的arm-linux-gcc交叉编译环境安装安装arm-linux-gcc(1) 打开终端&#xff0c;使用sudo命令进入从超级管理员&#xff1a;sudo su输入超级管理员密码。(2) 使用cd命令进入桌面&#xff1a;cd Desktop(3)复制arm-linux-gcc-4.4.3.tar.gz安装包到Ubuntu桌面下面(4)打开终端…

2019蓝桥杯省赛---java---C---1(求和)

题目描述 代码实现 package TEST;public class Main {public static void main(String[] args) {int cnt 0;for (int i 1; i < 2019; i)if (check(i)) cnt i;System.out.print(cnt);}static boolean check(int n) {String an"";if (a.contains("2")…

使用EntityFrameworkCore实现Repository, UnitOfWork,支持MySQL分库分表

昨天&#xff08;星期五&#xff09;下班&#xff0c;19&#xff1a;00左右回到家&#xff0c;洗个澡&#xff0c;然后20&#xff1a;30左右开始写代码&#xff0c;写完代码之后&#xff0c;上床看了《生活大爆炸10季》17、18两集&#xff0c;发现没有更新到19集&#xff0c;瞄…

2019蓝桥杯省赛---java---C---2(矩阵切割)

题目描述 代码实现 package TEST;import java.util.Scanner;public class Main {public static void main(String[] args) {Scanner sc new Scanner(System.in);int max sc.nextInt();int min sc.nextInt();int sum 0, temp;while (max ! 0 && min ! 0) {if (max …

期待微软平台即服务技术Service Fabric 开源

微软的Azure Service Fabric的官方博客在3.24日发布了一篇博客 Service Fabric .NET SDK goes open source &#xff0c;介绍了社区呼声最高的Service Fabric开源的情况以及当前的情况&#xff0c;这次开源了Service Fabric的.NET SDK部分&#xff0c;主要是两个&#xff1a; …

2019蓝桥杯省赛---java---C---4(质数)

题目描述 代码实现 package TEST; public class Main {public static void main(String[] args) {int cnt 0;for (int i 2; ; i )if(check(i)){cnt ;if(cnt 2019){System.out.println(i);break;}}}public static boolean check(int n){//判断一个数是否为质数for (int i 2…

eclipse下载与安装步骤详解,包含解决错误(最全最详细)

以前一直用的是myeclipse,今天有幸接触eclipse,那我们就先来安装的配置一下&#xff0c;下载地址&#xff1a;点击下载密码&#xff1a;h0kg&#xff0c;下载完成以后就可以安装了&#xff0c;首先我们来先安装jdk1.7, 打开jdk的安装包 双击即可&#xff0c; 直接点击下一步&…

CoreCLR文档翻译 - GC的设计

此文档来源于CoreCLR的BOTR(The Book of the Runtime), 点击打开原文一切著作权归微软公司所有 GC的设计 作者: Maoni Stephens (maoni0) - 2015 提示: 推荐看 The Garbage Collection Handbook 这本书学习更多关于GC的知识 (在文章底部的链接中) 组件结构 在GC中有两个主…

CoreCLR源码探索(四) GC内存收集器的内部实现 分析篇

在这篇中我将讲述GC Collector内部的实现, 这是CoreCLR中除了JIT以外最复杂部分&#xff0c;下面一些概念目前尚未有公开的文档和书籍讲到。 为了分析这部分我花了一个多月的时间&#xff0c;期间也多次向CoreCLR的开发组提问过&#xff0c;我有信心以下内容都是比较准确的&am…

vue开源项目

转载自 vue开源项目 一、前台UI组件库 1.Element 优点&#xff1a;中文文档&#xff0c;ui种类比较全&#xff0c;ui设计简洁清晰 缺点&#xff1a;不够有特点 2.iView 优点&#xff1a;和element的UI很相似&#xff0c;有一些多的补充&#xff0c;可以相互替换 缺点&am…

linux跑循环脚本占内存,Linux下实现脚本监测特定进程占用内存情况

Linux系统下&#xff0c;我们可以利用以下命令来获取特定进程的运行情况&#xff1a;cat /proc/$PID/status其中PID是具体的进程号&#xff0c;这个命令打印出/proc/特定进程/status文件的内容&#xff0c;信息比较多&#xff0c;包含了物理内存/虚拟内存的使用状况&#xff0c…