当前位置: 首页 > 科技观察

图解分布式系统——程序员的进阶之路

时间:2023-03-13 22:42:17 科技观察

65小哥工作两年了,一直在做简单重复的编程工作,成了一个只懂CRUD的兼职少年。65哥:总是听大佬们讲分布式发行。什么是分布式系统?分布式系统是分布在不同网络计算机上的硬件或软件系统,彼此之间仅通过消息传递进行通信和协调。系统。在分布式系统中,一组独立的计算机将用户呈现为一个统一的整体,就好像它是一个系统一样。系统具有多种通用的物理和逻辑资源,可以动态分配任务,分散的物理和逻辑资源通过计算机网络实现信息交换。好吧,让我们从最熟悉的事物开始了解分布式系统是如何产生和发展的,并通过实践总结出一般的理论。这些理论成为指导我们如何设计更完善的分布式系统的基础。从本文中,您将了解到以下知识:Web应用的扩展中为什么会出现分布式应用?65弟兄:这个我不知道。我以前都是直接把web应用写进Tomcat里,启动Tomcat就访问了,这绝对不是分布式应用。好吧,就从大家最熟悉的web后台应用说起吧。以前我们系统访问量小,业务不复杂。一台服务器和一个应用程序可以处理所有业务请求。后来我们公司发展了,来的人也多了。现在,业务也扩大了。虽然老大还是没有给我们加薪,但是老是抱怨我们的系统不稳定,处理不了大并发。如果我们的服务器可以添加无限的配置,那么所有的性能问题都不是问题。为了提高系统的处理能力,我们首先想到的扩容方式就是升级系统配置。8核CPU升级为32核、64核,内存由64G升级为128G、256G,带宽为10G、100G,堪称纵向扩展。然而,最终,由于以下原因,这种扩张将无法持续。单机系统的处理能力最终会达到瓶颈,升级单机系统的边际成本会越来越大。没有什么能阻止我们编程和工作。俗话说,系统撑不住就加服务器,一台不行就加两台。当纵向扩展达到技术瓶颈或者投入产出比超出预期时,可以考虑增加服务器数量来提升并发能力,这就是横向扩展。SystemSplit65哥:哦,这是分布式系统?就这么简单吗?呵呵,没那么简单。在横向扩展上,我们增加了服务器的数量,但是如何让这些服务器整体对外提供稳定有效的服务是关键。既然有了多台服务器,就要考虑如何将系统部署到不同的节点上。65哥:这不容易啊。我把我的SpringBoot项目部署到多台服务器上,只是在前面加了nginx。现在我们的系统都是这样的,稳定高效。给你画个结构图(悄悄话,这个我上学的时候就知道了)世上没有安静的时光,而是有人替你背负着。上面你想的很简单,其实有两个原因:系统的分离不彻底,还有很重要的一点,还是共享一个数据库。在这个成熟的系统中,有太多成熟的中间件为我们服务,比如上面提到的nginx系统的拆分方式也有两种,垂直拆分和水平拆分。请注意,这并没有处理与上面提到的垂直扩展和水平扩展相同的问题。(65哥:哈哈,我知道了,世间万物无非就是纵横二字)。系统的垂直拆分就是部署多套同一个系统。所有的节点都没有区别,它们的作用和功能是相同的。它们各自共享一部分功能请求,使整个系统的处理能力有所提高。从处理Web请求的角度来看,垂直拆分的每个节点处理一个完整的请求,每个节点承担一部分请求量;从数据存储的角度来看,每个数据节点存储相同的业务数据,每个节点存储一部分数据。系统的横向拆分就是把系统拆分成不同的模块或者角色,不同的模块处理不同的事情。从Web请求的角度来看,需要多个相互依赖的系统协同完成一个请求,各个节点的处理需求不一致;从数据存储的角度来看,每个数据节点存储的都是和自己业务模块相关的数据,它们的数据都是不一样的。上面垂直拆分后,每个节点形成一个集群,当每个节点水平拆分时,就是分布式的。这就是集群和分布式的区别。集群除了可以提高上面提到的并发处理能力外,还可以保证系统的高可用。当部分节点出现故障时,整个系统仍然可以提供完整的服务。分布式也是如此。除了提高并发性,解耦系统,让系统边界更清晰,系统功能更内聚也是一大好处。因此,在实际系统中,我们往往会同时使用这两种方式,而我们经常提到的分布式系统,其实也包含了集群的概念。分布式目标的归纳和演绎是人类理性的基石。学习和思考就是不断总结过去的经验,得到普遍规律,然后将得到的规律推演到其他事物上,指导更好的实践过程。上面我们解释了分布式系统的由来,现在我们回顾总结一下这个过程。我们引入分布式系统必须基于现实的需求和目标。65哥:分布式的目标是什么?Distributed旨在满足以下目标:Transparency:透明性,即用户不关心系统背后的分布式,无论系统是分布式还是单机,都应该对用户透明,并且只有用户需要关心系统可用的能力。这里的透明包括以下几个方面:访问透明:固定统一的访问接口和方法,不因分布式系统内部的变化而改变系统的访问方式。位置透明:外部访问者无需知道分布式系统的具体地址,系统节点的变化不会影响其功能。并发透明性:多个进程可以同时使用共享资源而不会相互干扰。复制透明性:使用资源的多个实例可以提高可靠性和性能,而无需用户和程序员了解副本。故障透明性:分布式系统中部分节点的故障不影响系统的整体功能。移动透明:资源和客户可以在系统内移动而不受影响。性能透明:随着负载的变化,可以重新配置系统以提高性能。伸缩透明:系统和应用可以在不改变系统结构和应用算法的情况下进行扩展。开放性:开放性、通用协议和用法。Scalability:可扩展性,随着资源数量的增加和用户访问量的增加,系统仍能保持其有效性,系统称为可扩展的。分布式系统在系统规模和系统管理方面都应该是可扩展的。Performance:性能,相比单体应用,分布式系统应该使用更突出的性能。可靠性:可靠性,与单体系统相比,分布式系统应该具有更好的安全性、一致性和隐藏错误的能力。分布式挑战分布式挑战来自不确定性。想一想,分布式系统相比单体应用有什么优势呢?65哥:服务节点比较多,服务之间有网络通信。是的,看来65哥已经很会系统思考和分析了。分布式系统的所有挑战都来自于这两者的不确定性。1.节点故障:节点越多,故障概率越高。分布式系统需要保证在发生故障时系统仍然可用。这就要求系统能够感知所有节点的服务状态,并在某个节点出现故障时,将负责该节点的计算和存储任务转移给其他节点。2、不可靠的网络:节点通过网络进行通信,我们都知道网络是不可靠的。可能出现的网络问题包括:网络分段、延迟、丢包、乱序。与单机进程调用相比,网络通信最头疼的就是超时和双向流量的不确定性。当发生超时时,网络通信发起方无法判断当前请求是否处理成功。在不可靠的网络和节点中,分布式系统仍然需要保证其可用性、稳定性和效率,这是一个系统最基本的需求。因此,分布式系统的设计和架构充满了挑战。分而治之的分布式系统就是充分利用更多的资源进行并行计算和存储,以提高系统性能。这就是分而治之的原则。65弟兄:哦,我明白了,我明白了。MapReduce的map、Elasticsearch的sharding、Kafka的partition都是基于分布式分而治之的原则吗?是的,65师兄不仅可以归纳,还可以举一反三。是的,不管是map,sharding,partition,甚至requestrouting负载均衡,都是将计算或者数据进行拆分,然后分布到不同的节点上进行计算和存储,从而提高系统的并发性。不同集群类型的分片也是分片,不同的领域通常会有不同的说法,甚至是不同实现的系统。Sharding通常是一种将不同数据分布到数据存储系统中不同节点的方式,中文通常翻译为数据分片。例如在MongoDB中,当MongoDB存储海量数据时,一台机器可能不足以存储数据,也可能不足以提供可接受的读写吞吐量。这时,我们可以通过将数据拆分到多台机器上,使数据库系统能够存储和处理更多的数据。比如在Elasticsearch中,每个索引都有一个或多个分片,索引数据分布到每个分片上,相当于一桶水用了N杯。Sharding有助于水平扩展,N个分片会尽可能均匀地分布在不同的节点上(rebalance)。partition分区的概念在Kafka中经常看到。在Kafka中,topic是一个逻辑概念。从分布式队列的角度来看,topic是一个用户的队列。在Kafka的具体实现中,主题分布在不同的节点上,分区由分区组成。每个分区根据分区算法分为多个分区。在Kafka中,同一个partition不能被同一个group下的多个consumer消费,所以一个topic有多少partition是有一定意义的。指示该主题具有多少并发处理能力。在Amazing分布式数据库DynamoDB中,一张表在底层实现上也是被划分成不同分区的。负载平衡负载平衡是高可用网络基础设施的关键组成部分,通常用于将工作负载分配给多台服务器,以提高网站、应用程序、数据库或其他服务的性能和可靠性。例如nginx的负载均衡,通过不同的负载均衡分配策略,将http请求分配到web应用的不同节点,从而提高应用的并发处理能力。例如,dubbo的客户端加载能力可以将dubbo请求路由到特定的生产者节点。负载均衡是一个完整的RPC应该具备的能力。在SpringCloud体系中,Robbin组件可以通过SpringCloud各个微服务之间通信的负载均衡分配问题,将请求分发到集群中的不同节点。分区策略无论是分区、分片,还是分区路由,其实都有一些通用的分区算法。很多同学可能在不同的领域见过下面的概念。比如上面看到的反向代理服务器nginx中,比如分布式消息队列kafka中,比如RPC框架Dubbo,这个有时候会让很多同学感到困惑。其实不管你在哪个领域,只要掌握了它的核心功能就可以理解它。他们在考虑如何划分,如何将处理请求(也就是计算)平均分配到不同的机器上,以及数据如何分配到不同的节点上。从一般的角度来看,有两种策略,一种是可重现的,一种是不可重现的。可重现。该策略根据一定的算法分配计算和数据。同样的条件下,无论在哪个时间点,结果都是一样的。因此,对于相同条件下的请求和数据,它是可重现的。在不同的时间相同的请求和数据总是在同一个节点上。这种策略一般用于有数据状态的情况。它无法复制。该策略使用完全随机的方法。即使在相同的条件下,不同时间点得到的结果也不一致,所以也是不可逆的。如果只是为了恢复,如果已经通过元数据记录了数据,然后需要恢复的时候,可以通过元数据准确知道数据的位置。65哥:有这么神奇吗?我想看看不同的系统有什么策略。Dubbo的负载均衡Dubbo是阿里开源的分布式服务框架。它实现了各种负载均衡策略。RandomLoadBalance是随机的,可以通过权重设置随机概率。一个section的碰撞概率高,但是调用量越大,分布越均匀,使用概率后权重也越均匀,有利于动态调整provider权重。RoundRobinLoadBalance轮询,按照约定后的权重设置轮询比例。有一个慢provider积累请求的问题,比如:第二台机器很慢,但是没有挂掉,当请求转到第二台机器的时候卡在那里。久而久之,所有的请求都卡在了第二台机器上。LeastActiveLoadBalance是最少的活跃调用数,相同的活跃数是随机的,活跃数是指调用前后的计数差值。让慢的提供者接收更少的请求,因为对于慢的提供者来说,调用前后的计数差异会更大。ConsistentHashLoadBalance一致的Hash,具有相同参数的请求总是发送给同一个提供者。当某个provider宕机时,原本发送给该provider的请求会基于虚拟节点扩散到其他provider,不会引起剧烈变化。Kafka的分区分配策略Kafka提供了多分区分配算法(PartitionAssignor)的实现:RangeAssignorRangeAssignor策略的原理是将消费者总数和分区总数相除得到一个span,然后将分区均匀分配根据span来确保Partition尽可能均匀地分布在所有消费者中。对于每一个Topic,RangeAssignor策略会按照名称的字典序对消费者组中所有订阅该Topic的消费者进行排序,然后为每个消费者划分一个固定的分区范围。或者将被分配一个额外的分区。RoundRobinAssignorRoundRobinAssignor的分配策略是对所有的Topic分区和所有订阅在消费者组中的消费者进行排序,并尽可能均匀地分配(RangeAssignor对单个Topic的分区进行排序分配)。StickyAssignor从字面上看,Sticky就是“粘性”,可以理解为赋值结果是“粘性的”——每次赋值变化相对于上一次赋值变化最小(上一次的结果是粘性的),其主要目的是实现以下两个目标:尽量平衡分区的分布,尽量使每次重新分配的结果与上次的分配结果保持一致。65哥:哇,看来优秀的系统都是连着的。Replica是为了解决分布式集群的高可用问题。在集群系统中,每个服务器节点都是不可靠的,每个系统都有宕机的风险。如何在系统中少数节点故障时保证整个系统的可用性是分布式系统面临的挑战之一。副本是解决此类问题的方法。副本还可以提高并发处理能力。比如数据可以在不同的节点上分别读写,也可以并行读取。这里其实有很多说法,比如Master-Salve、Leader-Follower、Primary-Shard、Leader-Replica等等。Mysql的主从架构目前主流的关系型数据库大多都提供了主从热备份功能。通过配置两个(或多个)数据库的主从关系,可以将一台数据库服务器的数据更新同步到另一台。在一台服务器上。这样既可以实现数据库的读写分离,从而改善数据库的负载压力,又可以提高数据的高可用性。多个数据备份可降低数据丢失的风险。Elasticsearch的replica机制在ES中有primaryshards和replicashards的概念。副本分片的主要目的是为了故障转移。如果持有主分片的节点发生故障,将提升一个副本分片作为主分片的角色,对外提供查询服务。CAP理论在理论计算机科学中,CAP定理,又称布鲁尔定理,指出对于一个分布式计算系统,不可能同时满足分布式系统的一致性和可用性。以及分区容错(即CAP中的“C”、“A”、“P”):65师兄:什么是一致性、可用性、分区容错?一致性(Consistency)一致性是指所有客户端在同一时间看到的是相同的数据,无论它们连接到哪个节点。为此,无论何时向一个节点写入数据,都必须立即将数据转发或复制到系统中的所有其他节点,然后才能认为写入“成功”。可用性(Availability)任何客户端请求都可以获得响应数据,并且不会出现响应错误。换句话说,可用性是从分布式系统的角度对访问这个系统的客户的另一种承诺:我一定会给你返回数据,不会给你返回错误,但我不保证数据是最新的日期。重点是没有错。分区容错分区是分布式系统中的通信中断,是两个节点之间丢失或暂时延迟的连接。分区容错性意味着尽管系统中的节点之间存在通信故障,但集群必须继续运行。结合这三个性质,可以得到以下三种情况:CA:完全严格的仲裁协议,如2PC(两阶段提交协议,第一阶段投票,第二阶段交易提交)CP:不完全(多数)仲裁协议,例如Paxos,RaftAP:使用冲突解决的协议,例如Dynamo,GossipCA,CP系统都是为了遵循强一致性理论而设计的。区别在于CA系统不能容忍节点故障。CP系统可以容忍2f+1个节点中的f个节点发生故障。BasetheoryCAP理论表明,对于一个分布式系统来说,它不能同时满足Consistency(强一致性)、Availability(可用性)和Partitiontolerance(分区容错)三个条件,同时只能满足其中两个条件最多。个人。在分布式环境中,我们会发现必须选择P(partitiontolerance)因子,因为网络本身不能100%可靠,可能会出现故障,所以分区是必然现象。也就是说,分区容错是分布式系统最基本的需求之一。CAP定理限制我们不能同时满足三者,但我们可以尽量满足C、A、P。这就是BASE定理。BASE理论是BasicallyAvailable(基本可用)、SoftState(软状态)和EventuallyConsistent(最终一致性)三个短语的首字母缩写。即使无法实现强一致性(Strongconsistency),各个应用也可以根据自身的业务特点采用合适的方法使系统实现最终一致性(Eventualconsistency)。基本可用(BasicallyAvailable)基本可用是指当分布式系统发生故障时,允许失去部分可用性,即保证核心可用。在电商推广过程中,为了应对访问量激增,部分用户可能会被引导至降级页面,服务层可能只提供降级服务,这是部分可用性丧失的表现。软态(SoftState)什么是软态?相对于原子性,要求多个节点的数据副本一致,是一种“硬态”。软状态是指:允许系统中的数据以一种中间状态存在,并认为这种状态不影响系统的整体可用性,即允许系统在多个不同的数据副本中存在数据延迟节点。最终一致性(EventualConsistency)最终一致性是指系统中的所有数据副本在经过一定时间后最终能够达到一致状态。弱一致性是强一致性的对立面,最终一致性是弱一致性的特例。BASE理论面向大规模高可用和可扩展的分布式系统。与传统的ACID特性相反,也不同于ACID的强一致性模型,BASE提出通过牺牲强一致性来获得可用性,允许数据在一段时间内不一致,但最终达到一致状态。分布式是系统扩展的必然方向。分布式系统遇到的问题很常见。随着一大批优秀的项目在分布式的道路上披荆斩棘,前人总结了大量丰富的理论。而不同领域的分布式系统层出不穷。我们不仅要学好这些好的理论知识,还要多看看不同分布式系统的实现,总结它们的共性,找到它们在不同领域的独特亮点。重要的是,我们要把所学运用到日常项目的实践中,还要在实践中多总结规律理论。感谢各位读者阅读本文。码哥会持续为广大读者输出优质文章。下一期我们将继续深入探讨分布式一致性存在的问题及解决方案,敬请期待。