分布式系统与网络分区

article/2025/10/11 8:25:45

在OpenStack中,数据库是主要系统“状态”的主要来源。大部分Core Projects都使用传统关系型数据库作为系统数据和状态的存储,另外如Ceilometer使用了MongoDB,还有其他Incubator Projects使用了Redis作为队列或者状态存储。数据库给OpenStack提供了状态组件并把状态的“共享”问题交给了数据库,因此解决OpenStack的扩展问题实际上就是解决使用的数据库本身的扩展问题。比如OpenStack HA Solution最令人头疼的就是传统关系数据库或者其他数据存储的扩展问题,数据库扩展问题的根源是其本身不支持分布式和良好的扩展性,而这个根源又会衍生出分布式系统最大的噩梦–“网络分区”。

下面会分析”网络分区“给数据库扩展带来的问题,同时在OpenStack组件中如何规避和解决。

分布式系统的基本: 数据一致性

现代软件系统由一系列“组件”通过异步、不可靠的网络相互沟通构建。理解一个可信赖的分布式系统需要对网络本身的分析,而“状态”共享就是一个最重要的问题。

举一个例子,当你发表一篇博文后,你可能想知道在你点击“发布”操作之后:
1. 从现在开始会对所有人可见
2. 从现在开始会对你的连接可见,其他人会延迟
3. 你也可能暂时不可见,但是未来会可见
4. 现在可见或者不可见:发生错误
5. …… etc

不同的分布式系统会有对一致性和持久性相互影响的权衡和决定,比如Dynamo类系统通过NRW来指定一致性,如果N=3, W=2,R=1,你将会得到:
1. 可能不会马上看到更新
2. 更新数据会在一个节点失败后存活

如果你像Zookeeper来写入,那会得到一个强一致性保证:写操作会对所有人可见,比如这个写操作在一半以下的节点失败后仍然能够保证。如果你像MySQL写入,取决于你的事物一致性级别,你的写操作一致性会对所有人、你可见或者最终一致性。

网络分区

分布式通常假设网络是异步的,意味着网络可能会导致任意的重复、丢失、延迟或者乱序的节点间消息传递。在实际中,TCP状态机会保证节点间消息传递的不丢失、不重复、时序。但是,在Socket级别上,节点接发消息会阻塞,超时等等。

检测到网络失败是困难,因为我们唯一能跟得到其他节点状态的信息就是通过网络来得到,延迟跟网络失败也无从区分。这里就会产生一个基本的网络分区问题:高延迟可以考虑作为失败。当分区产生后,我们没有渠道去了解到其他节点到底发生了什么事: 它们是否还存活?或者已经crash?是否有收到消息?是否正在尝试回应。当网络最终恢复后,我们需要重新建立连接然后尝试解决在不一致状态时的不一致。

很多系统在解决分区时会进入一个特殊的降级操作模式。CAP理论也告诉我们要么得到一致性要么高可用性,但是很少有数据库系统能够达到CAP理论的极限,多数只是丢失数据。

接下来的内容会介绍一些分布式系统是如何在网络失败后进行相关行为。

实例1:传统数据库与2PC

传统的SQL数据库如MySQL、Postgresql都提供一系列不同的一致性级别,然后通常都只能向一个primary写入,我们可以把这些数据库认为是CP系统(CAP理论),如果分区发生,整个系统会不可用(因为ACID)。

那么传统数据库是不是真的是强一致性?它们都是使用2PC([1]策略来提交请求:
1. 客户端commit
2. 服务器端写操作然后回应
3. 客户端收到回应完成提交

1在这三个步骤中,可能发生不一致的情况在于2与3之间,当服务器写操作完成但是回应没有被客户端收到,无论是超时或者网络故障,客户端这时会认为这次操作没有完成,而事实上数据库已经写入。这时就会产生不一致的行为。也就是客户端得到的错误并不能解释到底服务器端有没有写入。

2PC不仅在传统SQL数据库被广泛使用,也有大量用户实现2PC在MongoDB之上来完成多键值事务操作。

那么如何解决这个问题?首先必须接受这个问题,因为网络失败地概率比较低,并且正好在服务器写操作完成与客户端得到回应之间失败。这使得受到影响的操作非常稀有,在大部分业务中,这个失败是可接受到。相对的,如果你必须要强一致性的实施,那么应该在业务中付诸行动,比如所有的事务写操作都是幂等的,是可重入的。这样当遇到网络问题时,retry即可而不管到底写操作有没有完成。最后,一些数据库可以得到事务ID,通过track事务ID你可以在网络故障后重新评估事务是否完成,通过数据库在网络恢复后检查其记录的事物ID然后回滚相应事务。

我们在OpenStack的选择就很有限,目前各个项目中并不是所有写操作都是幂等的,不过幸运的是,OpenStack的数据在罕见的2PC协议特例中损失是能接受的。

实例2: Redis

Redis通常被视为一个共享的heap,因为它容易理解的一致性模型,很多用户把Redis作为消息队列、锁服务或者主要数据库。Redis在一个server上运行实例视为CP系统(CAP理论),因此一致性是它的主要目的。

2

Redis集群通常是主备,primary node负责写入和读取,而slave node只是用来备份。当primary node失败时,slave node有机会被提升为primary node。但是因为primary node和slave node之间是异步传输,因此slave node被提升为primary node后会导致0~N秒的数据丢失。此时Redis的一致性已经被打破,Redis这个模式的集群不是一个CP系统!

Redis有一个官方组件叫Sentinel(参考[Redis Sentinel],它是通过类似Quorum的方式来连接Sentinel instance,然后检测Redis集群的状态,对故障的primary节点试用slave节点替换。Redis官方号称这个是HA solution,通过Redis Sentinel来构建一个CP系统。

3

考虑Redis Sentinel在网络分区时候的情况,这时Redis集群被网络分成两部分,Redis Sentinel在的大区域可能会提升Slave node作为primary node。如果这时候一直client在连接原来的primary node,这时会出现两个primary node(split-brain problem,脑裂问题)!也就是说,Redis Sentinel并没有阻止client连接Old primary node。在此时,已经连接到old primary node的client会写入old primary node,新的client会写入到new primary node。此时,CP系统已经完全瘫痪。虽然Redis集群一直是保持运行的,但是因为依赖于Quorum来提升slave节点,因此它也不会是AP系统。

4

如果使用Redis作为Lock service,那么这个问题会成为致命问题。这会导致分区后同时可以有两个client获取同一个锁并成功,lock service必须是严格的CP系统,像Zookeeper。

如果使用Redis作为queue,那么你需要接受一个item可能会被分发零次、一次或者两次等等,大部分的分布式队列都保证最多只分发一次或者最少分发一次,CP系统会提确切一次的分发然后带来较高的延迟。你需要明确使用Redis作为队列服务的话必须要接受网络分区后队列服务可能导致的不稳定。

如果使用Redis作为database,那么可想而知,利用Redis Sentinel建立的database是不能称为database的。

最后,以目前的Redis来说,使用官方提供的组件它只能成为Cache。构建一个分布式的Redis前往[WheatRedis]

实例3: MongoDB

MongoDB采用类似于Redis的集群方式,primary node作为单点写操作服务然后异步写入replication nodes。但是MongoDB内建了primary选举和复制状态机,这使得primary node失败后,整个MongoDB会进行交流然后选择一个合适的slave node。然后MongoDB支持指定primary node可以确认slave node已经把写操作写入log或者真正写入,也就是通过一定的性能损耗来换取更强的一致性当primary node失败后。

那么MongoDB是否可以认定为是一个严格的CP系统?还是与Redis类似的问题,在网络分区后,当primary node在小的分区里,大的分区里的node会选举产生一个新的primary node,而此时在分区的时候,这两个node是会同时存在的(这个没有问题),然后当分区恢复后,小分区里的old primarynode会把在脑裂期间的操作发送到new primary node,这时候可能会产生冲突!

5

那么如何面对这个问题?接受它,首先这个冲突的概念像2PC一样可以在client端解决,同时MongoDB目前有WriteConnern可以解决这个问题,但会造成巨大的性能影响。

实例4: Dynamo

Dynamo是在传统的primary-slave模式遇到问题时候出现的红宝书,借鉴Dynamo的产品在一段时间内出现的非常多。

之前提到的系统都是面向CP的,起码是面向CP设计的。Amazon设计的Dynamo鲜明地面向AP。在Dynamo,它是天然地分区友好型,每一个node都是平等的,通过NWR来指定不同地一致性级别和可用性。这里不会详细阐述Dynaomo的原理([Dynamo](http://www.read.seas.harvard.edu/~kohler/class/cs239-w08/decandia07dynamo.pdf),每一个试图了解分布式系统的人都应该对Dynamo这篇论文非常熟悉,即使它面临很多问题,但是论文中出现的对Dynamo设计的思考和变迁是宝贵的。

那么当分区发生时,Dynamo发生了什么?首先根据NWR的推荐设定(W+R>N),小区是不能得到新的写操作,新的对象会写在大区。然后在分区恢复后,小区的对象会滞后并与新的对象发生冲突。这里的冲突解决策略非常多,如Cassandra使用的client timestamps,Riak的Vector clock,如果无法解决,冲突可能会硬性覆盖或者推到业务代码。

然后Dynamo本身没有任何方法来判断一个节点是否数据同步,也无法判断,只能通过完全的数据比较,而这个过程是代价昂贵并且不灵活的。因此Dynamo提到说(W+R>N)可以达到强一致性是不可能的,故障节点只会是最终一致性。

因此,解决Dynamo的问题像前面一样,接受它。首先你的数据可以设计成immutable,然后你的数据决定可以在罕见情况下丢弃或者变旧,再或者使用CRDTs来设计你的数据结构。无论如何,Dynamo始终是一个good idea并且它推动了分布式设计的发展。

实例5: BigTable

上面提到的系统都是面向分布式的,要么AP要么CP。那么Bigtable是AC系统,虽然我们介绍的一直是分区问题,但是我们也需要考虑在中心化设计的Bigtable。无论是HBase还是HDFS都是这类设计,它们回避了分区问题并且在单IDC下达到非常好的效果。这里不会详细讨论中心化设计,因为它根本就没有考虑分区问题。

思考: 分布式数据库系统的设计

通过上述的分析可以了解到构建一个分布式数据库集群的困难,无论是同步复制,异步复制,Quorum还是其他的,在网络分区面前,任何挣扎都是无力的,网络错误意味着”I don’t know” not “I failed”。

构建一个“正确的”分布式数据库系统通常在几个方面达成意见:
1. 接受罕见的问题
2. 使用开源的软件,分布式系统会产生极大的“漩涡”在“理论正确的分布式算法”和“实际使用的系统“。一个有Bug的系统但是正确的算法比一个错误的设计更能接受。
3. 利用问题进行正确的设计,如使用[CRDTs](http://pagesperso-systeme.lip6.fr/Marc.Shapiro/papers/RR-6956.pdf)
4. split-brain问题是分区的原罪,如何解决split-brain之后的遗产才是正确的解决方案

小结

如何在OpenStack上做到HA是OpenStack官方和其他发行版公司都在努力的方向,而其中关键就在于数据存储的HA和一致性,在这个方向上,我们通过对”网络分区“这一关键问题的分析并在不同类型的数据库上进行落地思考,可以得到如何在其上规避、解决和接受它。通过在OpenStack的产品上思考这些问题,我们可以在HA Solution上有更强健的基础。

下面一篇会介绍在OpenStack项目的上下文中,各个不同数据库的应用会带来怎样的问题和后果。

 

文章来源 : http://www.ustack.com/blog/distributedsystems_networksdivision/


http://chatgpt.dhexx.cn/article/ILHZ82Z5.shtml

相关文章

分布式架构网络通信

在分布式服务框架中,一个最基础的问题就是远程服务是怎么通讯的,在Java领域中有很多可实现远程通讯的技术,例如:RMI、Hessian、SOAP、ESB和JMS等,它们背后到底是基于什么原理实现的呢 1、基本原理 要实现网络机器间的…

企业分布式网络监控

IT 基础架构已成为提供基本业务服务的基石,无论是内部管理操作还是为客户托管的应用程序服务。监控IT基础设施至关重要,并且已经建立。SMB IT 基础架构需要简单的网络监控工具来监控性能和报告问题。通常,几个 IT 管理员配置网络设备、防火墙…

分布式网络通信框架(一)——集群和分布式

单机聊天服务器 缺点: 受限于硬件资源,服务器所能承受的用户并发量不够大; 任意模块修改,都会导致整个项目代码重新编译、部署; 系统中,有些模块是CPU密集型,有些是IO密集型,造成…

传统分布式网络架构

在同一个自治系统内,当主机A要和A主机B通讯时,需要把发给主机B的数据包先发给网关路由器A,路由器A根据路由表决定数据包下一跳发给路由器B或C,根据IP报文内携带的目的地址11.8.9.12,在路由表中查找最长匹配路由表项&am…

分布式网络基础

在分布式服务化架构设计中,服务与服务之间通信均是基于网络底层协议来实现的,于是我们需要对网络相关基础知识有一个基本的认知,这样在我们服务与服务之间进行通信(跨进程通信)过程能够在我们的脑图形成一个基本的数据传输流程以及其中的细节问题,这样对于我们在进行网络问题的…

服务计算 -- 搭建私有云

服务计算 – 搭建私有云 文章目录 服务计算 -- 搭建私有云下载VirtualBox及所需镜像安装虚拟机配置虚拟机存储位置创建虚拟机内部虚拟网络创建Base虚拟机(Centos为例)链接复制第二台虚拟机 远程桌面访问虚拟机安装图形化界面 下载VirtualBox及所需镜像 …

搭建自己的私有云盘

一、准备工作 centos8,nextcloud,mysql 二、安装docker(官方文档) $ yum install -y yum-utils $ yum-config-manager \ --add-repo \ https://download.docker.com/linux/centos/docker-ce.repo $ yum install -y https://dow…

OwnCloud私有云服务搭建教程

OwnCloud是一款开源的存储云,其作用可以像百度网盘那样存放文件到这个云当中,只要能连上网,手机,平板,电脑都可以从中下载或者上传文件,用起来非常不错,部署的过程也很简单,废话不多…

如何搭建个人私有云盘

前言 文章首发于Noah Sun’s Home 如何搭建个人私有云盘 市场上有很多云盘的产品,比如百度云盘,不过本教程主要目的是要搭建个人私有云盘。查了网上很多资料,个人云盘也有很多,比如nextcloud,owncloud,sea…

服务器上搭建私有云--owncloud

国内云盘太垃圾,各种box又要翻墙,有自己的服务器的朋友不如搭建一个自己的私有云,再也不会有任何限制。私有云的平台有seafile、owncloud等,这里我选择了owncloud。 owncloud的搭建极其简单,官方有提供一键搭建包 ht…

阿里云服务器搭建私人云盘

1、配置安全组端口 新建安全组并开放以下端口 2、利用 Git 来搭建私人云盘 1、利用 Workbench 点击立即登录 进行远程连接 2、安装 docker 容器 docker 是一款开源的容器运行工具,提供了一套便捷的服务打包、分发、部署方式。我们将要部署的服务就是通过 docker …

搭建 ownCloud 私有云教程

Nginx ownCloud PHP MySQL搭建私有云 OwnCloud概述: OwnCloud是一个开源免费专业的私有云存储项目,它可以帮你快速的在个人电脑或者服务器上假设一套专属的私有云文件同步网盘,也可以像百度网盘一样实现文件跨平台同步,共享等…

手把手教你搭建owncloud私有云平台

本来想把标题定为“基于LAMP的owncloud服务器搭建教程”,想了想,如果这么定的话,怕是都没人来看,岂不是自己砸了自己的“招牌”,废话不多说下面开始进入正文。 引言 搭建私有云的初衷不需要再花过重的篇幅去强调&#…

教你如何一招打通「公有云、私有云」,快学起来

数据灾难年年有 一不小心 下一个受害者就是你 当灾难来临时 才会发现备份的重要性 借助群晖NAS 使用 Cloud Sync 就可以将公有云上的数据 自动同步到本地 NAS 上 当然也可以将本地的文件 进行自动上传 使你的数据双倍安全 我们所支持的网盘类型如下: 本次…

私有云服务器搭建教程(保姆级)——台式电脑+ubuntu+docker+nextcloud+mysql+花生壳内网穿透

前言 随着移动互联网的发展,越来越多的人使用云网盘存储他们的文档、照片、视频等文件。不知从什么时候起,我们不知不觉开始为享受云存储的服务付费买单。一次上传,随处访问,越来越成为人们的日常需求。随之而来的是各云网盘每月…

搭建私有云的4大主流方案

随着云计算和移动办公大潮的到来,iPad、智能手机等家庭联网设备不断增多,以及搭载小容量SSD笔记本电脑的流行,能够跨平台分享的个人云服务需求不断增长;而今天的个人云服务也已经极大丰富,从2TB的百度网盘到商务人士中流行的Dropb…

阿里云虚拟私有网络的搭建及MySQL安装方式

一、阿里云虚拟私有网络的搭建 由于安全机制,无法上传,功能服务均已实现 二、通过编译、二进制安装MySQL5.7 2.1 编译安装 yum install cmake gcc gcc-c ncurses-devel bison zlib libxml openssl automake autoconf make libtool bison-devel liba…

本地搭建mysql

首先,本地搭建一个mysql本身没什么实际意思,因为一般项目不会在window上进行开发,但是可以给你提供一个练习mysql的地方,也是很不错的,希望可以帮助到大家,话不多说,开始!&#xff0…

阿里云服务器搭建MySQL环境

目录: 1. 检查是否安装过 2. 下载官方安装包 3. 安装MSQL安装包 4. 启动MySQL服务 5. 检查运行状态 6. 查看初始密码 7. 进入数据库 8. 修改数据库密码 9. 授权远程访问权限 10.设置白名单 1.检查是否安装过 rpm -qa|grep -i mysql 如果安装过,可通过r…

快点搜quickso.cn

【QuickSo】快点搜,搜快点! 助你快速找到资源https://quickso.cn/