精华内容
下载资源
问答
  • 大型互联网分布式系统架构技术要点 解决问题的通用思路是将分而治之(divide-and-conquer),将大问题分为若干个小问题,各个击破。在大型互联网的架构实践中,无一不体现这种思想。 架构目标 低成本:任何公司...

    大型互联网分布式系统架构技术要点

    解决问题的通用思路是将分而治之(divide-and-conquer),将大问题分为若干个小问题,各个击破。在大型互联网的架构实践中,无一不体现这种思想。

    架构目标

    • 低成本:任何公司存在的价值都是为了获取商业利益。在可能的情况下,希望一切都是低成本的。
    • 高性能:网站性能是客观的指标,可以具体体现到响应时间、吞吐量等技术指标。系统的响应延迟,指系统完成某一功能需要使用的时间;系统的吞吐量,指系统在某一时间可以处理的数据总量,通常可以用系统每秒处理的总的数据量来衡量;系统的并发能力,指系统可以同时完成某一功能的能力,通常也用 QPS(query per second)来衡量。
    • 高可用:系统的可用性(availability)指系统在面对各种异常时可以正确提供服务的能力。系统的可用性可 
      以用系统停服务的时间与正常服务的时间的比例来衡量,也可以用某功能的失败次数与成功次数的比例来衡量。
    • 易伸缩:注重线性扩展,是否可以容易通过加入机器来处理不断上升的用户访问压力。系统的伸缩性(scalability)指分布式系统通过扩展集群机器规模提高系统性能(吞吐、延迟、并发)、存储容量、计算能力的特性。
    • 高安全:现在商业环境中,经常出现被网站被拖库,用户账户被盗等现象。网站的安全性不言而喻。

    典型实现

    下面典型的一次web交互请求示意图。

    DNS

    1. 当用户在浏览器中输入网站地址后,浏览器会检查浏览器缓存中是否存在对应域名的解析结果。如果有,则解析过程结束;否则进入下一个步骤
    2. 浏览器查找操作系统缓存中是否存在这个域名的解析结果。这个缓存的内容来源就是操作系统的hosts文件。如果有,则解析过程结束;否则进入下一个步骤
    3. 前两个步骤都是本地查找,没有发生网络交互。在本步骤中,会使用到在网络配置的中DNS地址。这个地址我们通常称之为LDNS(Local DNS)。操作系统会把域名发送给LDNS解析。如果解析成功,则解析过程结束;否则进入下一个步骤
    4. LDNS将请求返回给GTLD(Global Top Level Domain)服务器,GTLD服务器查找此域名对应的Name Server域名的地址。这个Name Server通常就是你的域名提供商的服务器。Name Server根据客户请求,返回该域名对应的IP地址和TTL(Time To Live)值。
    5. 浏览器根据TTL值,把这个域名对应的IP缓存在本地系统中。域名至此解析结束。

    CDN

    CDN(Content Delivery Network,内容分发网络)部署在网络提供商的机房里面。在用户请求网站服务时,可以从距离自己最近的网络提供商获取数据。比如视频网站和内容网站的热点内容。

    如果需要自己搭建CDN系统,有3种主流方案可以选择:

    • squid是缓存服务器科班出生,自己实现了一套内存页/磁盘页的管理系统
    • varnish是觉得squid性能不行,varnish觉得linux内核已经把虚拟内存管理做得很好了,squid的多此一举反而影响了性能。
    • nginx cache是属于不务正业,得益于nginx强大的插件机制。

    LB

    LB(Load Balance,负载均衡)就是将负载(用户的请求)根据某些策略,将负载分摊给多个操作单元执行。该技术可以提供服务器的响应速度以及利用效率,避免出现单点失效。

    这里回顾下前面介绍的两个小节,其实本质上把数据分类(根据数据更新频率,分为动态文件,静态文件),并把数据放在离距离用户最近的地方。另外一点就是,在DNS和CDN具体实现时,也是大量使用了负载均衡技术。

    常见的负载均衡算法由:RR(Round Robin,轮询),WRR(Weighted RR,加权轮询),Random(随机),LC(Least Connection,最少连接),SH(Source Hash,源址哈希)

    在常见的互联网架构中,通常使用软件负载:LVS+HAproxy+WebServer(Nginx)。在部署时,LVS,HAProxy,WebServer都会部署一个集群,用来进行负载均衡。LVS工作在第4层,在网络层利用IP地址进行转发。 HAProxy工作在第7层,根据用户的HTTP请求(比如根据URL,消息头)来进行转发。

    在上述实现中,通常还会使用Keepalived+VIP(虚IP) 技术。Keepalived 提供健康检查,故障转移,提高系统的可用性。通过VIP(配置DNS 绑定域名)的形式对网站进行访问。

    WEB APP

    前端技术:遵循基本的Web前端优化经验,详见Web前端优化最佳实践及工具集锦 
    介绍。另外还可以使用BigPipe,动态页面静态化,无限滚动的翻页技术等技术提供更好的用户体验。另外一部分就是考虑mobile技术了,这块笔者暂时还没涉足,就不谈了。

    后端技术:

    • HTTP协议:HTTP协议大概分为请求头,请求体,响应头,响应体。无论是WebServer还是ApplicationServer,很多花样都是基于请求头的请求路径来玩的。
    • API接口:使用RESTFUL API,暴露接口。它具有如下好处:1.充分利用 HTTP 协议本身语义。2.面向资源,一目了然,具有自解释性。3.无状态,在调用一个接口(访问、操作资源)的时候,可以不用考虑上下文,极大的降低了复杂度。
    • Application Server:在Java中,为了保证程序能够在各个厂商的AS中兼容运行,Sun公司为制定了J2EE规范。从技术发展路径来看, Serverlet,JSP演变都是为了更好地方便程序员们编程。以典型的Tomcat为例,Connector和Container组成一个 Service,多个Service组成一个Server。Connector主要负责接受外部请求,Container负责处理请求。Server提供了生命周期管理,如启动,停止等。
    • Session Framework:在大型互联网架构中,单台机器已经存放不了用户的登录信息。同时为了支持故障转移等特性,需要一套session管理机制,支持海量用户同时在线。通常可以在遵循J2EE的容器内,使用Filter模式和分布式缓存系统来实现。
    • MVC:即Model,View和Controller。Model代表业务逻辑,View表示页面视图,Controller表示根据用户请求,执行相应的业务逻辑,并选择适当的页面视图返回。用过ROR的同学都知道,里面的router配置了什么样的URL和什么样的action相对应。相应的,MVC的本质就是根据不同的URL选择不同的servlet来执行。只不过,结合了Intercepting Filter提供了强大的功能而已。
    • IOC:至于为什么需要IOC,笔者在这篇文章进行了讨论。究其本质实现,无非是反射+单例模式+Hash算法+字节码增强+ThreadLocal。前3者用来实现对象生命周期的管理,后2者用来支持AOP,声明式事务。
    • ORM:这个词实际上放在这里介绍不太合适,但是笔者目前没想把它单独拉出章节来讲。根据笔者的经验,ORM主要完成了类和表的映射,对象和一条表数据记录的映射。其核心实现是通过jdbc获取数据库的meta信息,然后根据映射关系(这里可以通过COC(Conversion Over Configuration,约定优于配置),注解等技术来简化配置)来动态生成sql和返回数据库的执行结果。

    SOA

    网站架构的演进之路,从单一应用架构到垂直应用架构,分布式服务架构以及流动计算架构,越来越体现SOA框架的重要性。这里以优秀的开源实现dubbo为例,简单介绍下。

    dubbo的功能介绍见服务治理过程,对dubbo架构详细介绍的有如何学习dubbo源代码dubbo源代码阅读

    简而言之,就是使用了spring的schema的扩展机制,进而支持自定义dubbo标签;通过类似serviceload机制配置多个可选服务。通过jdk动态代理和Javassist,使服务调用透明化。结合ZooKeeper实现高可用元数据管理。

    MQ

    MQ(Message Queue,消息队列)使服务调用异步化,可以消除并发访问洪峰,提升网站响应速度。 在MQ实现中,笔者写过一篇介绍Kafka的学习笔记,详细介绍见Kafka/Metaq设计思想学习笔记,不再多言。

    CACHE

    Cache就是将数据放到距离计算最近的地方,用来加快处理速度。通常对一定时间内的热点数据进行缓存。 
    在使用缓存时,需要注意缓存预热和缓存穿透问题。

    一般海量数据的缓存系统不会使用Java来实现,是因为Java有额外的对象大小开销以及GC压力。所以一般是用ANSI C来实现。目前用的比较火的是Redis,更多介绍请查看Redis资料汇总

    STORAGE

    在出现NOSQL之前,一统天下的是MySQL分库分表技术。结合类似TDDL等SQL agent技术,也能够执行类似join的操作。后来,就像忽如一夜春风来,出现了很多NOSQL/分布式存储系统产品。

    分布式存储系统是分布式系统中最复杂的一部分,相比较SOA,CACHE等框架,它需要解决的问题更加复杂。常见的问题如下:

    • 数据分布 在多台服务器之间保证数据分布均匀,跨服务器如何读写
    • 一致性 异常情况下如何保证副本一致性
    • 容错 把发生故障当成常态来设计,做到检测是否发生故障并进行故障迁移
    • 负载均衡 新增、移除服务器时如何负载均衡 数据迁移如何不影响已有服务
    • 事务并发控制 如何实现分布式事务,如何实现多版本并发控制
    • 压缩、解压缩 根据数据特点选择恰当算法,如何平衡时间和空间的关系。


    分布式架构

    1.1. web分布式系统的设计原则

    搭建和运营一个可伸缩的web站点或者应用程序意味着什么?在原始层面上这仅仅是用户通过互联网连接到远程资源-使系统变得可伸缩的部分是将资源、或者访问的资源,分布于多个服务器上。

    像生活中大多数事情一样,当构建一个web服务时花时间提前做好计划从长远看来还是很有帮助的;了解一些注意事项和大网站背后的权衡原则可以在创建小型网站时做出更明智的决定。以下是一些影响大规模web系统设计的关键原则:

    • 可用性:对于很多公司来说一个网站的正常运行时间是非常关键的声誉和功能,像一些大型的在线零售系统,即使一分钟的宕 机都有可能导致数千或者数百万美元的损失,因此设计系统的时时可用性和弹性的错误处理机制既是一个基本业务也是一个技术要求。 高可用分布式系统需要仔细考虑关键组件的冗余,分系统失败后能快速修复,并且当问题出现时优雅型降级。
    • 性能:网站的性能正在变成大多数站点考虑的一个重要的方面,网站的速度影响正常使用和用户的满意度,同样影响搜索的排名,这也是影响网站收益和保留用户的一个因素。因此,创建一个快速响应和低延迟的系统是非常关键的。
    • 可靠性:一个系统需要具备可靠性,比如同一个数据的请求始终返回同样的数据响应 。如果数据改变或者被更新,那么同样的数据将返回一个新的数据。用户需要知道一些东西被写入系统或者被存储到系统后,系统会保持不变并且可以在以后恢复到合适的位置。
    • 可伸缩性:当谈到任何大型的分布式系统时,规模大小只是考虑的其中一个方面,同样重要的是增强处理较大规模的负载性能所做的努力,这通常称为系统的可伸缩性。可伸缩性可以代表系统很多不同的参数:额外流量的处理量,添加存储容量的便意性,甚至事务的处理量。
    • 可管理性: 设计一个系统可以方便操作是另一个重要的考虑方面,系统的可管理性等同于操作的可伸缩性:维护和升级。可管理性需要考虑的事情是当问题发生时方便诊断和了解问题,易于升级和修改,以及系统能简单性的操作(即,例行的操作有没有失败和异常?)
    • 成本: 成本是一个重要的因素。很明显这包含硬件和软件成本,但同样重要需要考虑的其他方面是部署和维护系统的成本。开发者构建系统花费的大量时间,运维部署时间,甚至培训时间都需要考虑,成本是总体成本。

    以上每个原则都为设计分布式web架构提供了基础决策。然而,他们也能彼此互斥,例如要实现某个目标就要以另外的作为代价。一个基本的例子:选择通过单纯 增加更多的服务器(可扩展性)来增加地址容量,是以可管理性(你必须操作增加的服务器)和成本(服务器的价格)为代价的。

    当设计任何的web应用程序时,考虑这些关键原则都是很重要的,即使得承认一个设计可能要牺牲它们之中的一个或者多个。

    1.2. 基础

    当设计一个系统架构时,有一些东西是要考虑的:正确的部分是什么,怎样让这些部分很好地融合在一起,以及好的折中方法是什么。通常在系统架构需要之前就为它的可扩展性投资不是一个聪明的商业抉择;然而,在设计上的深谋远虑能在未来节省大量的时间和资源。

    这部分关注点是几乎所有大型web应用程序中心的一些核心因素:服务、冗余、划分和错误处理。每一个因素都包含了选择和妥协,特别是上部分提到的设计原则。为了详细的解析这些,最好是用一个例子来开始。

    实例:图片托管应用

    有时候你可能会在线上传一张图片。对于那些托管并负责分发大量图片的网站来说,要搭建一个既节省成本又高效还能具备较低的延迟性(你能快速的获图片)的网站架构确实是一种挑战。

    我们来假设一个系统,用户可以上传他们的图片到中心服务器,这些图片又能够让一些web链接或者API获取这些图片,就如同现在的Flickr或者 Picasa。为了简化的需要,我们假设应用程序分为两个主要的部分:一个是上传图片到服务器的能力(通常说的写操作),另一个是查询一个图片的能力。然 而,我们当然想上传功能很高效,但是我们更关心的是能够快速分发能力,也就是说当某个人请求一个图片的时候(比如,一个web页面或者其它应用程序请求图 片)能够快速的满足。这种分发能力很像web服务器或者CDN连接服务器(CDN服务器一般用来在多个位置存储内容一边这些内容能够从地理位置或者物理上 更靠近访问它的用户,已达到高效访问的目的)气的作用。

    系统其他重要方面:

    • 对图片存储的数量没有限制,所以存储需要可扩展,在图像数量方面需要考虑。
    • 图片的下载和请求不需要低延迟。
    • 如果用户上传一个图片,图片应该都在那里(图片数据的可靠性)。
    • 系统应该容易管理(可管理性)。
    • 由于图片主机不会有高利润的空间,所以系统需要具有成本效益。

    Figure 1.1是一个简化的功能图。

     

    Figure 1.1: 图片主机应用的简化架构图

    在这个图片主机的例子里,可遇见系统必需快速,它的数据存储要可靠以及这些所有的属性都应该高度的可扩展。建立这个应用程序的一个小版本不是很重要而且很容易部署在单一的服务器上;然而,这不是这节里的感兴趣部分。假设下我们想建一个会增长到和Flickr痛让规模的东西。

     

    服务

    当要考虑设计一个可扩展的系统时,为功能解耦和考虑下系统每部分的服务都定义一个清晰的接口都是很有帮助的。在实际中,在这种方式下的系统设计被成为面向 服务架构(SOA)。对于这类型的系统,每个服务有自己独立的方法上下文,以及使用抽象接口与上下文的外部任何东西进行交互,典型的是别的服务的公共 API。

    把一个系统解构为一些列互补的服务,能够为这些部分从别的部分的操作解耦。这样的抽象帮助在这些服务服、它的基础环境和服务的消费者之间建立清晰的关系。 建立这种清晰的轮廓能帮助隔离问题,但也允许各模块相对其它部分独立扩展。这类面向服务设计系统是非常类似面向对象设计编程的。

    在我们的例子中,上传和检索图像的请求都是由同一个服务器处理的;然而,因为系统需要具有伸缩性,有理由要将这两个功能分解为各由自己的服务进行处理。

    快速转发(Fast-forward)假定服务处于大量使用中;在这种情况下就很容易看到,读取图像所花的时间中有多少是由于受到了写入操作的影响(因为 这两个功能将竞争使用它们共享的资源)。取决于所采用的体系结构,这种影响可能是巨大的。即使上传和下载的速度完全相同(在绝大多数IP网络中都不是这样 的情况,大部分下载速度和上传速度之比都至少设计为3:1),文件读取操作一般都是从高速缓存中进行的,而写操作却不得不进行最终的磁盘操作(而且可能要 写几次才能达成最后的一致状态)。即使所有内容都已在内存中,或者从磁盘(比如SSD磁盘)中进行读取,数据库写入操作几乎往往都要慢于读取操作。 (Pole Position是一个开源的DB基准测试工具,http://polepos.org/,测试结果参见 http://polepos.sourceforge.net/results/PolePositionClientServer.pdf

    这种设计另一个潜在的问题出在web服务器上,像Apache或者lighttpd通常都有一个能够维持的并发连接数上限(默认情况下在500左右,不过 可以更高)和最高流量数,它们会很快被写操作消耗掉。因为读操作可以异步进行,或者采用其它一些像gizp压缩的性能优化或者块传输编码方式,web服务 器可以通过在多个请求服务之间切换来满足比最大连接数更多的请求(一台Apache的最大连接数设置为500,它每秒钟提供近千次读请求服务也是正常 的)。写操作则不同,它需要在上传过程中保持连接,所以大多数家庭网络环境下,上传一个1MB的文件可能需要超过1秒的时间,所以web服务器只能处理 500个这样并发写操作请求。

     

    对于这种瓶颈,一个好的规划案例是将读取和写入图片分离为两个独立的服务,如图Figure 1.2.所示。这让我们可以单独的扩展其中任意一个(因为有可能我们读操作比写操作要频繁很多),同时也有助于我们理清每个节点在做什么。最后,这也避免 了未来的忧虑,这使得故障诊断和查找问题更简单,像慢读问题。

    这种方法的优点是我们能够单独的解决各个模块的问题-我们不用担心写入和检索新图片在同一个上下文环境中。这两种服务仍然使用全球资料库的图片,但是它们 可通过适当的服务接口自由优化它们自己的性能(比如,请求队列,或者缓存热点图片-在这之上的优化)。从维护和成本角度来看,每个服务按需进行独立规模的 规划,这点非常有用,试想如果它们都组合混杂在一起,其中一个无意间影响到了性能,另外的也会受影响。

    当然,上面的例子在你使用两个不同端点时可以很好的工作(事实上,这非常类似于云存储和内容分发网络)。虽然有很多方式来解决这样的瓶颈,但每个都有各自的取舍。

    比如,Flickr通过分配用户访问不同的分片解决这类读/写问题,每一个分片只可以处理一定数量的用户,随着用户的增加更多的分片被添加到集群上(参看“Flickr缩影”的描述http://mysqldba.blogspot.com/2008/04/mysql-uc-2007-presentation-file.html)。 在第一个例子中,可以根据实际用途更简单的规划硬件资源(在整个系统中读和写的比例),然而,Flickr规划是根据用户基数(假定每个用户拥有相同的资 源空间)。在前者中一个故障或者问题会导致整个系统功能的下降(比如,全部不能写入文件了),然而Flickr一个分片的故障只会影响到相关的那部分用 户。在第一个例子中,更容易操作整个数据集-比如,在所有的图像元数据上更新写入服务用来包含新的元数据或者检索-然而在Flickr架构上每一个分片都 需要执行更新或者检索(或者需要创建个索引服务来核对元数据-找出哪一个才是实际结果)。

    冗余(Redundancy)

    为了优雅的处理故障,web架构必须冗余它的服务和数据。例如,单服务器只拥有单文件的话,文件丢失就意味这永远丢失了。丢失数据是个很糟糕的事情,常见的方法是创建多个或者冗余备份。

    同样的原则也适用于服务。如果应用有一个核心功能,确保它同时运行多个备份或者版本可以安全的应对单点故障。

    在系统中创建冗余可以消除单点故障,可以在紧急时刻提供备用功能。例如,如果在一个产品中同时运行服务的两个实例,当其中一个发生故障或者降级(degrade),系统可以转移(failover)到好的那个备份上。故障转移(Failover)可以自动执行或者人工手动干预。

    服务冗余的另一个关键部分是创建无共享(shared-nothing)架构。采用这种架构,每个接点都可以独立的运作,没有中心”大脑”管理状态或者协调活动。这可以大大提高可伸缩性(scalability)因为新的接点可以随时加入而不需要特殊的条件或者知识。而且更重要的是,系统没有单点故障。所以可以更好的应对故障。

    例如,在我们的图片服务应用,所有的图片应该都冗余备份在另外的一个硬件上(理想的情况下,在不同的地理位置,以防数据中心发生大灾难,例如地震,火 灾),而且访问图片的服务(见Figure 1.3.)-包括所有潜在的服务请求-也应该冗余。(负载均衡器是个很好的方法冗余服务,但是下面的方法不仅仅是负载均衡)

     

    Figure 1.3: 使用冗余的图片存储

     

     

    分区

    我们可能遇见单一服务器无法存放的庞大数据集。也可能遇到一个需要过多计算资源的操作,导致性能下降,急需增添容量。这些情况下,你都有两种选择:横向或纵向扩展。

    纵向扩展意味着对单一服务器增添更多资源。对于一个非常庞大的数据集,这可能意味着为单一服务器增加更多(或更大)的硬盘以存放整个数据集。而对于计算操 作,这可能意味着将操作移到一个拥有更快的 CPU 或 更大的内存的服务器中。无论哪种情况,纵向扩展都是为了使单个服务器能够自己处理更多的方法。

    另一方面,对于横向扩展,则是增加更多的节点。例如庞大的数据集,你可以用第二个服务器来存放部分数据;而对于计算操作,你可以切割计算,或是通过额外的 节点加载。想要充分的利用横向扩展的优势,你应该以内在的系统构架设计原则来实现,否则的话,实现的方法将会变成繁琐的修改和切分操作。

    说道横向分区,更常见的技术是将你的服务分区,或分片。分区可以通过对每个功能逻辑集的分割分配而来;可以通过地域划分,也可以通过类似付费 vs. 未付费用户来区分。这种方式的优势是可以通过增添容量来运行服务或实现数据存储。

    以我们的图像服务器为例,将曾经储存在单一的文件服务器的图片重新保存到多个文件服务器中是可以实现的,每个文件服务器都有自己惟一的图片集。(见图表 1.4。)这种构架允许系统将图片保存到某个文件服务器中,在服务器都即将存满时,像增加硬盘一样增加额外的服务器。这种设计需要一种能够将文件名和存放 服务器绑定的命名规则。一个图像的名称可能是映射全部服务器的完整散列方案的形式。或者可选的,每个图像都被分配给一个递增的 ID,当用户请求图像时,图像检索服务只需要保存映射到每个服务器的 ID 范围(类似索引)就可以了。

     

    图 1.4: 使用冗余和分区实现的图片存储服务

    当然,为多个服务器分配数据或功能是充满挑战的。一个关键的问题就是数据局部性;对于分布式系统,计算或操作的数据越相近,系统的性能越佳。因此,一个潜在的问题就是数据的存放遍布多个服务器,当需要一个数据时,它们并不在一起,迫使服务器不得不为从网络中获取数据而付出昂贵的性能代价。

    另一个潜在的问题是不一致性。当多个不同的服务读取和写入同一共享资源时,有可能会遭遇竞争状态——某些数据应当被更新,但读取操作恰 好发生在更新之前——这种情形下,数据就是不一致的。例如图像托管方案中可能出现的竞争状态,一个客户端发送请求,将其某标题为“狗”的图像改名为”小家 伙“。而同时另一个客户端发送读取此图像的请求。第二个客户端中显示的标题是“狗”还是“小家伙”是不能明确的。

    当然,对于分区还有一些障碍存在,但分区允许将问题——数据、负载、使用模式等——切割成可以管理的数据块。这将极大的提高可扩展性和可管理性,但并非没有风险。有很多可以降低风险,处理故障的方法;不过篇幅有限,不再赘述。若有兴趣,可见于此文,获取更多容错和检测的信息。

    1.3. 构建高效和可伸缩的数据访问模块

    在设计分布式系统时一些核心问题已经考虑到,现在让我们来讨论下比较困难的一部分:可伸缩的数据访问。

    对于大多数简单的web应用程序,比如LAMP系统,类似于图 Figure 1.5.

     

    Figure 1.5: 简单web应用程序

    随着它们的成长,主要发生了两方面的变化:应用服务器和数据库的扩展。在一个高度可伸缩的应用程序中,应用服务器通常最小化并且一般是 shared-nothing架构(译注:shared nothing architecture是一 种分布式计算架构,这种架构中不存在集中存储的状态,整个系统中没有资源竞争,这种架构具有非常强的扩张性,在web应用中广泛使用)方式的体现,这使得 系统的应用服务器层水平可伸缩。由于这种设计,数据库服务器可以支持更多的负载和服务;在这一层真正的扩展和性能改变开始发挥作用了。

    剩下的章节主要集中于通过一些更常用的策略和方法提供快速的数据访问来使这些类型服务变得更加迅捷。

     

    Figure 1.6: Oversimplified web application

    大多数系统简化为如图 Figure 1.6所示,这是一个良好的开始。如果你有大量的数据,你想快捷的访问,就像一堆糖果摆放在你办公室抽屉的最上方。虽然过于简化,前面的声明暗示了两个困难的问题:存储的可伸缩性和数据的快速访问。

    为了这一节内容,我们假设你有很大的数据存储空间(TB),并且你想让用户随机访问一小部分数据(查看Figure 1.7)。这类似于在图像应用的例子里在文件服务器定位一个图片文件。

     

    Figure 1.7: Accessing specific data

    这非常具有挑战性,因为它需要把数TB的数据加载到内存中;并且直接转化为磁盘的IO。要知道从磁盘读取比从内存读取慢很多倍-内存的访问速度如同敏捷的 查克·诺里斯(译注:空手道冠军),而磁盘的访问速度就像笨重的卡车一样。这个速度差异在大数据集上会增加更多;在实数顺序读取上内存访问速度至少是磁盘 的6倍,随机读取速度比磁盘快100,000倍(参考“大数据之殇”http://queue.acm.org/detail.cfm?id=1563874)。另外,即使使用唯一的ID,解决获取少量数据存放位置的问题也是个艰巨的任务。这就如同不用眼睛看在你的糖果存放点取出最后一块Jolly Rancher口味的糖果一样。

    谢天谢地,有很多方式你可以让这样的操作更简单些;其中四个比较重要的是缓存,代理,索引和负载均衡。本章的剩余部分将讨论下如何使用每一个概念来使数据访问加快。

    缓存

    缓存利用局部访问原则:最近请求的数据可能会再次被请求。它们几乎被用于计算机的每一层:硬件,操作系统,web浏览器,web应用程序等等。缓存就像短期存储的内存:它有空间的限制,但是通常访问速度比源数据源快并且包含了大多数最近访问的条目。缓存可以在架构的各个层级存在,但是常常在前端比较常见,在这里通常需要在没有下游层级的负担下快速返回数据。

    在我们的API例子中如何使用缓存来快速访问数据?在这种情况下,有两个地方你可以插入缓存。一个操作是在你的请求层节点添加一个缓存,如图 Figure 1.8.

     

    Figure 1.8: Inserting a cache on your request layer node

    直接在一个请求层节点配置一个缓存可以在本地存储相应数据。每次发送一个请求到服务,如果数据存在节点会快速的返回本地缓存的数据。如果数据不在缓存中,请求节点将在磁盘查找数据。请求层节点缓存可以存放在内存和节点本地磁盘中(比网络存储快些)。

     

    Figure 1.9: Multiple caches

    当你扩展这些节点后会发生什么呢?如图Figure 1.9所示,如果请求层扩展为多个节点,每个主机仍然可能有自己的缓存。然而,如果你的负载均衡器随机分配请求到节点,同样的请求将指向不同的节点,从而 增加了缓存的命中缺失率。有两种选择可以解决这个问题:全局缓存和分布式缓存。

     

     

    全局缓存

    全局缓存顾名思义:所有的节点使用同一个缓存空间,这涉及到添加一个服务器,或者某种文件存储系统,速度比访问源存储和通过所有节点访问要快些。每个请求 节点以同样的方式查询本地的一个缓存,这种缓存方案可能有点复杂,因为在客户端和请求数量增加时它很容易被压倒,但是在有些架构里它还是很有用的(尤其是 那些专门的硬件来使全局缓存变得非常快,或者是固定数据集需要被缓存的)。

    在描述图中有两种常见形式的缓存。在图Figure 1.10中,当一个缓存响应没有在缓存中找到时,缓存自身从底层存储中查找出数据。在 Figure 1.11中,当在缓存中招不到数据时,请求节点会向底层去检索数据。

     

    Figure 1.10: Global cache where cache is responsible for retrieval

     

    Figure 1.11: Global cache where request nodes are responsible for retrieval

    大多数使用全局缓存的应用程序趋向于第一类,这类缓存可以管理数据的读取,防止客户端大量的请求同样的数据。然而,一些情况下,第二类实现方式似乎更有意 义。比如,如果一个缓存被用于非常大的文件,一个低命中比的缓存将会导致缓冲区来填满未命中的缓存;在这种情况下,将使缓存中有一个大比例的总数据集。另 一个例子是架构设计中文件在缓存中存储是静态的并且不会被排除。(这可能是因为应用程序要求周围数据的延迟-某些片段的数据可能需要在大数据集中非常快- 在有些地方应用程序逻辑理清排除策略或者热点 比缓存方案好使些)

    分布式缓存

    在分布式缓存(图1.12)中,每个节点都会缓存一部分数据。如果把冰箱看作食杂店的缓存的话,那么分布式缓存就象是把你的食物分别放到多个地方 —— 你的冰箱、柜橱以及便 当盒 ——放到这些便于随时取用的地方就无需一趟趟跑去食杂店了。缓存一般使用一个具有一致性的哈希函数进行分割,如此便可在某请求节点寻找某数据时,能够迅速 知道要到分布式缓存中的哪个地方去找它,以确定改数据是否从缓存中可得。在这种情况下,每个节点都有一个小型缓存,在直接到原数据所作处找数据之前就可以 向别的节点发出寻找数据的请求。由此可得,分布式缓存的一个优势就是,仅仅通过向请求池中添加新的节点便可以拥有更多的缓存空间。

    分布式缓存的一个缺点是修复缺失的节点。一些分布式缓存系统通过在不同节点做多个备份绕过了这个问题;然而,你可以想象这个逻辑迅速变复杂了,尤其是当你 在请求层添加或者删除节点时。即便是一个节点消失和部分缓存数据丢失了,我们还可以在源数据存储地址获取-因此这不一定是灾难性的!

     

    Figure 1.12: Distributed cache

    缓存的伟大之处在于它们使我们的访问速度更快了(当然前提是正确使用),你选择的方法要在更多请求下更快才行。然而,所有这些缓存的代价是必须有额外的存 储空间,通常在放在昂贵的内存中;从来没有嗟来之食。缓存让事情处理起来更快,而且在高负载情况下提供系统功能,否则将会使服务器出现降级。

    有一个很流行的开源缓存项目Memcached (http://memcached.org/)(它可以当做一个本地缓存,也可以用作分布式缓存);当然,还有一些其他操作的支持(包括语言包和框架的一些特有设置)。

    Memcached 被用作很多大型的web站点,尽管他很强大,但也只是简单的内存key-value存储方式,它优化了任意数据存储和快速检索(o(1))。

    Facebook使用了多种不同的缓存来提高他们站点的性能(查看”Facebook caching and performance”)。在语言层面上(使用PHP内置函数调用)他们使用$GLOBALSand APC缓存,这有助于使中间函数调用和结果返回更快(大多数语言都有这样的类库用来提高web页面的性能)。Facebook使用的全局缓存分布在多个服务器上(查看 ”Scaling memcached at Facebook”),这样一个访问缓存的函数调用可以使用很多并行的请求在不同的Memcached 服务器上获取存储的数据。这使得他们在为用户分配数据空间时有了更高的性能和吞吐量,同时有一个中央服务器做更新(这非常重要,因为当你运行上千服务器 时,缓存失效和一致性将是一个大挑战)。

    现在让我们讨论下当数据不在缓存中时该如何处理···

    代理

    简单来说,代理服务器是一种处于客户端和服务器中间的硬件或软件,它从客户端接收请求,并将它们转交给服务器。代理一般用于过滤请求、记录日志或对请求进行转换(增加/删除头部、加密/解密、压缩,等等)。

     

    图1.13: 代理服务器

    当需要协调来自多个服务器的请求时,代理服务器也十分有用,它允许我们从整个系统的角度出发、对请求流量执行优化。压缩转发(collapsed forwarding)是利用代理加快访问的其中一种方法,将多个相同或相似的请求压缩在同一个请求中,然后将单个结果发送给各个客户端。

    假设,有几个节点都希望请求同一份数据,而且它并不在缓存中。在这些请求经过代理时,代理可以通过压缩转发技术将它们合并成为一个请求,这样一来,数据只 需要从磁盘上读取一次即可(见图1.14)。这种技术也有一些缺点,由于每个请求都会有一些时延,有些请求会由于等待与其它请求合并而有所延迟。不管怎么 样,这种技术在高负载环境中是可以帮助提升性能的,特别是在同一份数据被反复访问的情况下。压缩转发有点类似缓存技术,只不过它并不对数据进行存储,而是 充当客户端的代理人,对它们的请求进行某种程度的优化。

    在一个LAN代理服务器中,客户端不需要通过自己的IP连接到Internet,而代理会将请求相同内容的请求合并起来。这里比较容易搞混,因为许多代理同时也充当缓存(这里也确实是一个很适合放缓存的地方),但缓存却不一定能当代理。

     

    图1.14: 通过代理来合并请求

    另一个使用代理的方式不只是合并相同数据的请求,同时也可以用来合并靠近存储源(一般是磁盘)的数据请求。采用这种策略可以让请求最大化使用本地数据,这 样可以减少请求的数据延迟。比如,一群节点请求B部分信息:partB1,partB2等,我们可以设置代理来识别各个请求的空间区域,然后把它们合并为 一个请求并返回一个bigB,大大减少了读取的数据来源(查看图Figure 1.15)。当你随机访问上TB数据时这个请求时间上的差异就非常明显了!代理在高负载情况下,或者限制使用缓存时特别有用,因为它基本上可以批量的把多 个请求合并为一个。

     

    Figure 1.15: Using a proxy to collapse requests for data that is spatially close together

    值得注意的是,代理和缓存可以放到一起使用,但通常最好把缓存放到代理的前面,放到前面的原因和在参加者众多的马拉松比赛中最好让跑得较快的选手在队首起 跑一样。因为缓存从内存中提取数据,速度飞快,它并不介意存在对同一结果的多个请求。但是如果缓存位于代理服务器的另一边,那么在每个请求到达 cache之前都会增加一段额外的时延,这就会影响性能。

    如果你正想在系统中添加代理,那你可以考虑的选项有很多;SquidVarnish都经过了实践检验,广泛用于很多实际的web站点中。这些代理解决方案针对大部分client-server通信提供了大量的优化措施。将二者之中的某一个安装为web服务器层的反向代理(reverse proxy,下面负载均衡器一节中解释)可以大大提高web服务器的性能,减少处理来自客户端的请求所需的工作量。

    索引

    使用索引快速访问数据是个优化数据访问性能公认的策略;可能我们大多数人都是从数据库了解到的索引。索引用增长的存储空间占用和更慢的写(因为你必须写和更新索引)来换取更快的读取。

    你可以把这个概念应用到大数据集中就像应用在传统的关系数据存储。索引要关注的技巧是你必须仔细考虑用户会怎样访问你的数据。如果数据集有很多 TBs,但是每个数据包(payload)很小(可能只有1KB),这时就必须用索引来优化数据访问。在这么大的数据集找到小的数据包是个很有挑战性的工 作因为你不可能在合理的时间內遍历所有数据。甚至,更有可能的是这么大的数据集分布在几个(甚至很多个)物理设备上-这意味着你要用些方法找到期望数据的 正确物理位置。索引是最适合的方法做这种事情。

     

    Figure 1.16: Indexes

    索引可以作为内容的一个表格-表格的每一项指明你的数据存储的位置。例如,如果你正在查找B的第二部分数据-你如何知道去哪里找?如果你有个根据数据类型 (数据A,B,C)排序的索引,索引会告诉你数据B的起点位置。然后你就可以跳转(seek)到那个位置,读取你想要的数据B的第二部分。 (See Figure 1.16.)

    这些索引常常存储在内存中,或者存储在对于客户端请求来说非常快速的本地位置(somewhere very local)。Berkeley DBs (BDBs)和树状数据结构常常按顺序存储数据,非常理想用来存储索引。

    常常索引有很多层,当作数据地图,把你从一个地方指向另外一个地方,一直到你的得到你想要的那块数据。(See Figure 1.17.)

     

    Figure 1.17: Many layers of indexes

    索引也可以用来创建同样数据的多个不同视图(views)。对于大数据集来说,这是个很棒的方法来定义不同的过滤器(filter)和类别(sort),而不用创建多个额外的数据拷贝。

    例如,想象一下,图片存储系统开始实际上存储的是书的每一页的图像,而且服务允许客户查询这些图片中的文字,搜索每个主题的所有书的内容,就像搜索引擎允 许你搜索HTML内容一样。在这种情况下,所有的书的图片占用了很多很多服务器存储,查找其中的一页给用户显示有点难度。首先,用来查询任意词或者词数组 (tuples)的倒排索引(inverse indexes)需要很容易的访问到;然后,导航到那本书的确切页面和位置并获取准确的图片作为返回结果,也有点挑战性。所以,这种境况下,倒排索引应该 映射到每个位置(例如书B),然后B要包含一个索引每个部分所有单词,位置和出现次数的索引。

    可以表示上图Index1的一个倒排索引,可能看起来像下面的样子-每个词或者词数组对应一个包含他们的书。

    Word(s)Book(s)
    being awesomeBook B, Book C, Book D
    alwaysBook C, Book F
    believeBook B

    这个中间索引可能看起来像上面的样子,但是可能只包含词,位置和书B的信息。这种嵌套的索引架构要使每个子索引占用足够小的空间,以防所有的这些信息必须保存在一个大的倒排索引中。

    这是大型系统的关键点,因为即使压缩,这些索引也太大,太昂贵(expensive)而难以存储。在这个系统,如果我们假设我们世界上的很多书-100,000,000 (see Inside Google Books blog post)-每个书只有10页(只是为了下面好计算),每页有250个词,那就是2500亿(250 billion)个词。如果我们假设每个词有5个字符,每个字符占用8位(或者1个字节,即使某些字符要用2个字节),所以每个词占用5个字节,那么每个 词即使只包含一次,这个索引也要占用超过1000GB存储空间。那么,你可以明白创建包含很多其他信息-词组,数据位置和出现次数-的索引,存储空间增长 多快了吧。

    创建这些中间索引和用更小分段表示数据,使的大数据问题可以得到解决。数据可以分散到多个服务器,访问仍然很快。索引是信息检索 (information retrieval)的奠基石,是现代搜索引擎的基础。当然,我们这段只是浅显的介绍,还有其他很多深入研究没有涉及-例如如何使索引更快,更小,包含更 多信息(例如关联(relevancy)),和无缝的更新(在竞争条件下(race conditions),有一些管理性难题;在海量添加或者修改数据的更新中,尤其还涉及到关联(relevancy)和得分(scoring),也有一 些难题)。

    快速简便的查找到数据是很重要的;索引是可以达到这个目的有效简单工具。

    负载均衡器

    最后还要讲讲所有分布式系统中另一个比较关键的部分,负载均衡器。负载均衡器是各种体系结构中一个不可或缺的部分,因为它们担负着将负载在处理服务请求的 一组节点中进行分配的任务。这样就可以让系统中的多个节点透明地服务于同一个功能(参见图1.18)。它的主要目的就是要处理大量并发的连接并将这些连接 分配给某个请求处理节点,从而可使系统具有伸缩性,仅仅通过添加新节点便能处理更多的请求。

     

    图1.18: 负载均衡器

    用于处理这些请求的算法有很多种,包括随机选取节点、循环式选取,甚至可以按照内存或CPU的利用率等等这样特定的条件进行节点选取。负载均衡器可以用软件或硬件设备来实现。近来得到广泛应用的一个开源的软件负载均衡器叫做 HAProxy)。

    在分布式系统中,负载均衡器往往处于系统的最前端,这样所有发来的请求才能进行相应的分发。在一些比较复杂的分布式系统中,将一个请求分发给多个负载均衡器也是常事,如图1.19所示。

     

    图1.19: 多重负载均衡器

    和代理类似,有些负载均衡器还可以基于请求的类型对不同的请求进行不同的处理(技术上讲,这样的叫做反向代理)。

    负载均衡器面临的一个难题是怎么管理同用户的session相关的数据。在电子商务网站中,如果你只有一个客户端,那么很容易就可以把用户放入购物车里的 东西保存起来,等他下次访问访问时购物车里仍能看到那些东西(这很重要,因为当用户回来发现仍然呆在购物车里的产品时很有可能就会买它)。然而,如果在一 个session中将用户分发到了某个节点,但该用户下次访问时却分发到了另外一个节点,这里就有可能产生不一致性,因为新的节点可能就没有保留下用户购 物车里的东西。(要是你把6盒子子农夫山泉放到购物车里了,可下次回来一看购物车空了,难道你不会发火吗?) 解决该问题的一个方法是可以使session具有保持性,让同一用户总是分发到同一个节点之上,但这样一来就很难利用类似failover这样的可靠性措 施了。如果这样的话,用户的购物车里的东西不会丢,但如果用户保持的那个节点失效,就会出现一种特殊的情况,购物车里的东西不会丢这个假设再也不成立了 (虽然但愿不要把这个假设写到程序里)。当然,这个问题还可以用本章中讲到的其它策略和工具来解决,比如服务以及许多并没有讲到的方法(象服务器缓存、 cookie以及URL重写)。

    如果系统中只有不太多的节点,循环式(round robin)DNS系统这样的方案也许更有意义,因为负载均衡器可能比较贵,而且还额外增加了一层没必要的复杂性。当然,在比较大的系统中会有各种各样的 调度以及负载均衡算法,简单点的有随机选取或循环式选取,复杂点的可以考虑上利用率以及处理能力这些因素。所有这些算法都是对浏览和请求进行分发,并能提 供很有用的可靠性工具,比如自动failover或者自动提出失效节点(比如节点失去响应)。然而,这些高级特性会让问题诊断难以进行。例如,当系统载荷 较大时,负载均衡器可能会移除慢速或者超时的节点(由于节点要处理大量请求),但对其它节点而言,这么做实际上是加剧了情况的恶化程度。在这时进行大量的 监测非常重要,因为系统总体流量和吞吐率可能看上去是在下降(因为节点处理的请求变少了),但个别节点却越来越忙得不可开交。

    负载均衡器是一种能让你扩展系统能力的简单易行的方式,和本文中所讲的其它技术一样,它在分布式系统架构中起着基础性的作用。负载均衡器还要提供一个比较 关键的功能,它必需能够探测出节点的运行状况,比如,如果一个节点失去响应或处于过载状态,负载均衡器可以将其总处理请求的节点池中移除出去,还接着使用 系统中冗余的其它不同节点。

    队列

    目前为止我们已经介绍了许多更快读取数据的方法,但另一个使数据层具伸缩性的重要部分是对写的有效管理。当系统简单的时候,只有最小的处理负载和很小的数 据库,写的有多快可以预知;然而,在更复杂的系统,写可能需要几乎无法决定的长久时间。例如,数据可能必须写到不同数据库或索引中的几个地方,或者系统可 能正好处于高负载。这些情况下,写或者任何那一类任务,有可能需要很长的时间,追求性能和可用性需要在系统中创建异步;一个通常的做到那一点的办法是通过 队列。

     

    Figure 1.20: Synchronous request

    设想一个系统,每个客户端都在发起一个远程服务的任务请求。每一个客户端都向服务器发送它们的请求,服务器尽可能快的完成这些任务,并分别返回结果给各个 客户端。在一个小型系统,一个服务器(或逻辑服务)可以给传入的客户端请求提供迅速服务,就像它们来的一样快,这种情形应该工作的很好。然而,当服务器收 到了超过它所能处理数量的请求时,每个客户端在产生一个响应前,将被迫等待其他客户端的请求结束。这是一个同步请求的例子,示意在图1.20。

    这种同步的行为会严重的降低客户端性能;客户端被迫等待,有效的执行零工作,直到它的请求被应答。添加额外的服务器承担系统负载也不会解决这个问题;即使 是有效的负载均衡,为了最大化客户端性能,保证平等的公平的分发工作也是极其困难的。而且,如果服务器处理请求不可及,或者失败了,客户端上行也会失败。 有效解决这个问题在于,需要在客户端请求与实际的提供服务的被执行工作之间建立抽象。

     

    图 1.21:用队列管理请求

    进入队列。一个队列就像它听起来那么简单:一个任务进入,被加入队列然后工人们只要有能力去处理就会拿起下一个任务。(看图1.21)这些任务可能是代表 了简单的写数据库,或者一些复杂的事情,像为一个文档生成一个缩略预览图一类的。当一个客户端提交一个任务请求到一个队列,它们再也不会被迫等待结果;它 们只需要确认请求被正确的接收了。这个确认之后可能在客户端请求的时候,作为一个工作结果的参考。

    队列使客户端能以异步的方式工作,提供了一个客户端请求与其响应的战略抽象。换句话说,在一个同步系统,没有请求与响应的区别,因此它们不能被单独的管 理。在一个异步的系统,客户端请求一个任务,服务端响应一个任务已收到的确认,然后客户端可以周期性的检查任务的状态,一旦它结束就请求结果。当客户端等 待一个异步的请求完成,它可以自由执行其它工作,甚至异步请求其它的服务。后者是队列与消息在分布式系统如何成为杠杆的例子。

    队列也对服务中断和失败提供了防护。例如,创建一个高度强健的队列,这个队列能够重新尝试由于瞬间服务器故障而失败的服务请求,是非常容易的事。相比直接暴露客户端于间歇性服务中断,需要复杂的而且经常矛盾的客户端错误处理程序,用一个队列去加强服务质量的担保更为可取。

    队列对管理任何大规模分布式系统不同部分之间的分布式通信,是一个基础,而且实现它们有许多的方法。有不少开源的队列如 RabbitMQActiveMQBeanstalkD,但是有些也用像 Zookeeper的服务,或者甚至像Redis的数据存储。

    1.4. 结论

    设计有效的系统来进行快速的大数据访问是有趣的,同时有大量的好工具来帮助各种各样的应用程序进行设计。 这文章只覆盖了一些例子,仅仅是一些表面的东西,但将会越来越多–同时在这个领域里一定会继续有更多创新东西。

    以上根据网络内容整理而成!

    展开全文
  • 高并发(High Concurrency)是互联网分布式系统架构设计中必须考虑的因素之一,它通常是指,通过设计保证系统能够同时并行处理很多请求。 高并发相关常用的一些指标有响应时间(Response Time),吞吐量...

    一、什么是高并发

    高并发(High Concurrency)是互联网分布式系统架构设计中必须考虑的因素之一,它通常是指,通过设计保证系统能够同时并行处理很多请求。

    高并发相关常用的一些指标有响应时间(Response Time),吞吐量(Throughput),每秒查询率QPS(Query Per Second),并发用户数等。

    响应时间:系统对请求做出响应的时间。例如系统处理一个HTTP请求需要200ms,这个200ms就是系统的响应时间。

    吞吐量:单位时间内处理的请求数量。

    QPS:每秒响应请求数。在互联网领域,这个指标和吞吐量区分的没有这么明显。

    并发用户数:同时承载正常使用系统功能的用户数量。例如一个即时通讯系统,同时在线量一定程度上代表了系统的并发用户数。

    二、如何提升系统的并发能力

    互联网分布式架构设计,提高系统并发能力的方式,方法论上主要有两种:垂直扩展(Scale Up)与水平扩展(Scale Out)。

    垂直扩展:提升单机处理能力。垂直扩展的方式又有两种:

    (1)增强单机硬件性能,例如:增加CPU核数如32核,升级更好的网卡如万兆,升级更好的硬盘如SSD,扩充硬盘容量如2T,扩充系统内存如128G;

    (2)提升单机架构性能,例如:使用Cache来减少IO次数,使用异步来增加单服务吞吐量,使用无锁数据结构来减少响应时间;

    在互联网业务发展非常迅猛的早期,如果预算不是问题,强烈建议使用“增强单机硬件性能”的方式提升系统并发能力,因为这个阶段,公司的战略往往是发展业务抢时间,而“增强单机硬件性能”往往是最快的方法。

    不管是提升单机硬件性能,还是提升单机架构性能,都有一个致命的不足:单机性能总是有极限的。所以互联网分布式架构设计高并发终极解决方案还是水平扩展。

    水平扩展:只要增加服务器数量,就能线性扩充系统性能。水平扩展对系统架构设计是有要求的,如何在架构各层进行可水平扩展的设计,以及互联网公司架构各层常见的水平扩展实践,是本文重点讨论的内容。

    三、常见的互联网分层架构

    常见互联网分布式架构如上,分为:

    (1)客户端层:典型调用方是浏览器browser或者手机应用APP

    (2)反向代理层:系统入口,反向代理

    (3)站点应用层:实现核心应用逻辑,返回html或者json

    (4)服务层:如果实现了服务化,就有这一层

    (5)数据-缓存层:缓存加速访问存储

    (6)数据-数据库层:数据库固化数据存储

    整个系统各层次的水平扩展,又分别是如何实施的呢?

    四、分层水平扩展架构实践

    反向代理层的水平扩展

    反向代理层的水平扩展,是通过“DNS轮询”实现的:dns-server对于一个域名配置了多个解析ip,每次DNS解析请求来访问dns-server,会轮询返回这些ip。

    当nginx成为瓶颈的时候,只要增加服务器数量,新增nginx服务的部署,增加一个外网ip,就能扩展反向代理层的性能,做到理论上的无限高并发。

    站点层的水平扩展

    站点层的水平扩展,是通过“nginx”实现的。通过修改nginx.conf,可以设置多个web后端。

    当web后端成为瓶颈的时候,只要增加服务器数量,新增web服务的部署,在nginx配置中配置上新的web后端,就能扩展站点层的性能,做到理论上的无限高并发。

    服务层的水平扩展

    服务层的水平扩展,是通过“服务连接池”实现的。

    站点层通过RPC-client调用下游的服务层RPC-server时,RPC-client中的连接池会建立与下游服务多个连接,当服务成为瓶颈的时候,只要增加服务器数量,新增服务部署,在RPC-client处建立新的下游服务连接,就能扩展服务层性能,做到理论上的无限高并发。如果需要优雅的进行服务层自动扩容,这里可能需要配置中心里服务自动发现功能的支持。

    数据层的水平扩展

    在数据量很大的情况下,数据层(缓存,数据库)涉及数据的水平扩展,将原本存储在一台服务器上的数据(缓存,数据库)水平拆分到不同服务器上去,以达到扩充系统性能的目的。

    互联网数据层常见的水平拆分方式有这么几种,以数据库为例:

    按照范围水平拆分

    每一个数据服务,存储一定范围的数据,上图为例:

    user0库,存储uid范围1-1kw

    user1库,存储uid范围1kw-2kw

    这个方案的好处是:

    (1)规则简单,service只需判断一下uid范围就能路由到对应的存储服务;

    (2)数据均衡性较好;

    (3)比较容易扩展,可以随时加一个uid[2kw,3kw]的数据服务;

    不足是:

    (1) 请求的负载不一定均衡,一般来说,新注册的用户会比老用户更活跃,大range的服务请求压力会更大;

    按照哈希水平拆分

    每一个数据库,存储某个key值hash后的部分数据,上图为例:

    user0库,存储偶数uid数据

    user1库,存储奇数uid数据

    这个方案的好处是:

    (1)规则简单,service只需对uid进行hash能路由到对应的存储服务;

    (2)数据均衡性较好;

    (3)请求均匀性较好;

    不足是:

    (1)不容易扩展,扩展一个数据服务,hash方法改变时候,可能需要进行数据迁移;

    这里需要注意的是,通过水平拆分来扩充系统性能,与主从同步读写分离来扩充数据库性能的方式有本质的不同。

    通过水平拆分扩展数据库性能:

    (1)每个服务器上存储的数据量是总量的1/n,所以单机的性能也会有提升;

    (2)n个服务器上的数据没有交集,那个服务器上数据的并集是数据的全集;

    (3)数据水平拆分到了n个服务器上,理论上读性能扩充了n倍,写性能也扩充了n倍(其实远不止n倍,因为单机的数据量变为了原来的1/n);

    通过主从同步读写分离扩展数据库性能:

    (1)每个服务器上存储的数据量是和总量相同;

    (2)n个服务器上的数据都一样,都是全集;

    (3)理论上读性能扩充了n倍,写仍然是单点,写性能不变;

    缓存层的水平拆分和数据库层的水平拆分类似,也是以范围拆分和哈希拆分的方式居多,就不再展开。

    五、总结

    高并发(High Concurrency)是互联网分布式系统架构设计中必须考虑的因素之一,它通常是指,通过设计保证系统能够同时并行处理很多请求。


    提高系统并发能力的方式,方法论上主要有两种:垂直扩展(Scale Up)与水平扩展(Scale Out)。前者垂直扩展可以通过提升单机硬件性能,或者提升单机架构性能,来提高并发性,但单机性能总是有极限的,互联网分布式架构设计高并发终极解决方案还是后者:水平扩展。


    在这里给大家提供一个学习交流的平台,java架构师群:671017482

    具有1-5工作经验的,面对目前流行的技术不知从何下手,需要突破技术瓶颈的可以加群。

    在公司待久了,过得很安逸,但跳槽时面试碰壁。需要在短时间内进修、跳槽拿高薪的可以加群。

    如果没有工作经验,但基础非常扎实,对java工作机制,常用设计思想,常用java开发框架掌握熟练的可以加群。


    互联网分层架构中,各层次水平扩展的实践又有所不同:

    (1)反向代理层可以通过“DNS轮询”的方式来进行水平扩展;

    (2)站点层可以通过nginx来进行水平扩展;

    (3)服务层可以通过服务连接池来进行水平扩展;

    (4)数据库可以按照数据范围,或者数据哈希的方式来进行水平扩展;

    各层实施水平扩展后,能够通过增加服务器数量的方式来提升系统的性能,做到理论上的性能无限。

    展开全文
  • 分布式系统架构

    2019-06-27 18:53:48
    面试官们“爱不释手”的分布式系统架构到底是个什么鬼? 转载地址:http://www.imooc.com/article/288454 一、什么是分布式系统? 在谈分布式系统架构前,我们先来看看,什么是分布式系统? 假设原来我们有一个...

    面试官们“爱不释手”的分布式系统架构到底是个什么鬼?

    转载地址:http://www.imooc.com/article/288454

    一、什么是分布式系统?

    在谈分布式系统架构前,我们先来看看,什么是分布式系统?

    假设原来我们有一个系统,代码量30多万行。现在拆分成20个小系统,每个小系统1万多行代码。

    原本代码之间都是直接基于Spring框架走JVM内存调用,现在拆开来,将20个小系统部署在不同的机器上,然后基于分布式服务框架(比如dubbo)搞一个rpc调用,接口与接口之间通过网络通信来进行请求和响应。

    所以分布式系统很重要的特点就是服务间要跨网络进行调用,我们来看下面的图:

    https://img3.mukewang.com/5d121f610001ec3c04480271.jpg

    此外,分布式系统可以大概可以分成两类。

    1. 底层的分布式系统。

    比如hadoop hdfs(分布式存储系统)、spark(分布式计算系统)、storm(分布式流式计算系统)、elasticsearch(分布式搜索系统)、kafka(分布式发布订阅消息系统)等。

    2. 分布式业务系统

    分布式业务系统,把原来用java开发的一个大块系统,给拆分成多个子系统,多个子系统之间互相调用,形成一个大系统的整体。

    举个例子,假设原来你做了一个OA系统,里面包含了权限模块、员工模块、请假模块、财务模块,一个工程,里面包含了一堆模块,模块与模块之间会互相去调用,1台机器部署。

    现在如果你把他这个系统给拆开,权限系统,员工系统,请假系统,财务系统,4个系统,4个工程,分别在4台机器上部署。

    然后一个请求过来,完成这个请求,员工系统去调用权限系统,调用请假系统,调用财务系统,4个系统分别完成了一部分的事情。

    最后4个系统都干完了以后,才认为是这个请求已经完成了。这就是所谓的分布式业务系统。

    同样,我们来一张图,感受一下上述过程:

    https://img1.mukewang.com/5d121f7300019a8a06760490.jpg

     

    二、为什么要走分布式系统架构?

     

    有的同学可能要问了,我一台服务器跑的好好的,所有系统一个工程全部搞定,多好。为啥一定要去搞什么分布式系统架构,互相调用还要走远程,似乎还增加了不少工作量?

    这里我就以我曾经待过的一个公司的血泪经历为例,来聊聊这个问题。

    很多年前,在没有走分布式架构的时候,我待的这家公司的各个业务线都是垂直的 “烟囱式” 项目。

    随着互联网的快速发展,公司的业务也在不断的发展,注册用户增加、网站应用的功能、规模不断扩大,特别是移动互联网的发展,APP、微信、自助终端机等访问渠道的增加,各种新业务,新需求不断涌入,系统遇到了各种各样的问题。

    首先是项目工程无节制的变得臃肿庞大,系统复杂度增加,大几十万行代码,几十个开发人员,service层,dao层代码大量被copy使用,经常各种代码合并冲突问题要处理,非常耗费时间。

    经常是我改动了我的代码,别人调用了我的接口,导致他的代码也出现问题,需要重新测试,麻烦的要死。

    然后每次发布都是几十万行代码的系统一起发布,大家得一起提心吊胆准备上线,几十万行代码的上线,每次上线都要做很多的检查,很多异常问题的处理,每个人都高度紧张,被搞得几乎崩溃。

    而且如果我现在有个新业务,打算把相关依赖升级一下,比如升级到最新的spring版本,还不行,因为这可能导致别人的代码报错,不敢随意乱改技术。并且一个web工程每次启动都需要好分钟的时间,本地IDE里面调试一次代码都很痛苦。

    其次,随着用户访问流量的增加,系统负载压力变大,变得不堪重负,通过增加实例数,增加硬件扩容能够带来的效果已微乎其微,故障频发,效率低下。系统质量也越来越难以保证,测试周期也变得越来越长,无法满足公司业务发展的需要。

    以上就是以前待过的公司一些 “不堪回首” 的往事,总得来说,问题主要体现在以下几个方面:

    1. 应用代码耦合严重,功能扩展难

    2. 新需求开发交互周期长,测试工作量大

    3. 新加入的开发同事需要很长时间才能熟悉系统

    4. 升级维护也很困难(改动任何一点地方都要升级整个系统)

    5. 系统性能提升艰难,可用性低,不稳定。

    好,既然我们已经深刻体会到了系统耦合的痛苦,那么现在就来看看,系统拆分后带来的好处:

    首先,系统拆分了以后,会感觉整个世界都清爽了。

    几十万行代码的系统,假设拆分成20个服务,平均每个服务就1-3万行代码,每个服务部署到单独的机器上。20个工程,就用20个git仓库代码,20个开发人员,每个人维护自己的那个服务就可以了。

    • 因为是自己独立的代码,跟别人没关系。再也没有代码冲突了,爽!

    • 每次就测试我自己的代码就可以了,爽!

    • 每次就发布我自己的一个小服务就可以了,爽!

    • 技术上想怎么升级就怎么升级,保持接口定义不变,输入输出内容不变就可以了,爽!

    总结起来一句话,分布式系统拆分之后,可以大幅度提升复杂系统大型团队的开发效率。

     

    三、系统如何进行拆分?

     

    一般来说,将系统进行拆分,首先需要对系统整体比较熟悉。可以走多轮拆分的思路,第一次拆分就是将以前的各个大的模块粗粒度的拆分开来。

    比如一个电商系统可以拆分成订单系统、商品系统、店铺系统、会员系统、促销系统、支付系统等等。

    后面可能每个系统又变得越来越复杂了,比如说订单系统又可以进一步拆分出来购物车系统,库存系统,价格系统等。

    总得来说就是基于领域驱动设计的思想以及实战经验总结,同时参考业界一些常规做法,大家讨论着来进行拆分,逐步优化,多轮拆分,小步快跑,最终达到一个比较好的状态。

     

    四、分布式之后带来的技术挑战?

     

    首先就是分布式服务框架的选用,目前国内来讲主流的还是dubbo与spring cloud。

    我们来思考一下,使用服务框架主要用来解决什么问题呢?如果不用dubbo或者spring cloud是否可以做分布式架构呢?

    不用dubbo或者spring cloud等服务框架当然也是可以的,但是这就需要自己处理很多事情了。

    比如,各个子系统走restful接口调用,那么就是http调用,这时比如传送过去一个对象,就要自己搞成一个json,然后一次调用失败后重试怎么做?

    另外,一般来说都是集群部署,目标系统有多个实例,那么自己还要写一个负载均衡算法,如何每次随机从多个目标机器中挑选一个来调用?

    还有,如果目标系统扩容新部署了一个实例,或者服务器故障下线了一个实例,如何动态让调用方感知到呢? 诸如此类的很多问题,如果不用服务框架的话,自己这么瞎搞,会遇到各种各样的问题。

    上述过程,用一张图给大家呈现一下:

    https://img3.mukewang.com/5d121f8e0001639706750281.jpg

    如果选用了某一个分布式服务框架,就需要深入的掌握这个框架的使用与底层原理,比如 dubbo 就需要搞明白以下的一些问题:

    1. dubbo的工作原理?

    2. dubbo支持的序列化协议?

    3. dubbo的负载均衡和高可用策略?动态代理策略?

    4. dubbo的SPI思想?

    5. 如何基于dubbo进行服务治理、服务降级、失败重试以及超时重试?

    6. dubbo服务接口的幂等性如何设计(比如不能重复扣款,不能重复生成订单,不能重复创建卡号)?

    7. dubbo服务接口请求的顺序性如何保证?

    8. 如何自己设计一个类似dubbo的rpc框架?

    使用spring cloud也是一样,比如eureka的工作原理?feign声明式调用的原理?等等各种底层原理要搞懂。

    还有其它一些走分布式架构后常见的要解决的技术问题:

    1. 分布式会话

    2. 分布式锁

    3. 分布式事务

    4. 分布式搜索

    5. 分布式缓存

    6. 分布式消息队列

    7. 统一配置中心

    8. 分布式存储,数据库分库分表

    9. 限流、熔断、降级等。

    以上这些问题,往深了说,每一个点都需要可能 N 篇文章来详细阐述,这里没法逐一展开,后面我们会继续通过一些文章,聊一聊这些分布式架构下的各种技术问题。

    展开全文
  • 互联网公司分布式系统架构演进之路

    千次阅读 多人点赞 2019-11-27 10:36:50
    介绍 ...这就是分布式,而为了应对并发,同时部署好几个用户系统,这就是集群 1 单应用架构 2 应用服务器和数据库服务器分离 单机负载越来越来,所以要将应用服务器和数据库服务器分离 3 应用服务...

    介绍

    分布式和集群的概念经常被搞混,现在一句话让你明白两者的区别。

    分布式:一个业务拆分成多个子业务,部署在不同的服务器上
    集群:同一个业务,部署在多个服务器上

    例如:电商系统可以拆分成商品,订单,用户等子系统。这就是分布式,而为了应对并发,同时部署好几个用户系统,这就是集群

    1 单应用架构

    在这里插入图片描述

    2 应用服务器和数据库服务器分离

    单机负载越来越来,所以要将应用服务器和数据库服务器分离
    在这里插入图片描述

    3 应用服务器做集群

    每个系统的处理能力是有限的,为了提高并发访问量,需要对应用服务器做集群
    在这里插入图片描述
    这时会涉及到两个问题:

    1. 负载均衡
    2. session共享

    负载均衡就是将请求均衡地分配到多个系统上,常见的技术有如下几种

    DNS
    DNS是最简单也是最常见的负载均衡方式,一般用来实现地理级别的均衡。例如,北方的用于访问北京的机房,南方的用户访问广州的机房。一般不会使用DNS来做机器级别的负载均衡,因为太耗费IP资源了。例如,百度搜索可能要10000台以上的机器,不可能将这么多机器全部配置公网IP,然后用DNS来做负载均衡。

    Nginx&LVS&F5
    DNS是用于实现地理级别的负载均衡,而Nginx&LVS&F5用于同一地点内机器级别的负载均衡。其中Nginx是软件的7层负载均衡,LVS是内核的4层负载均衡,F5是硬件做4层负载均衡,性能从低到高位Nginx<LVS<F5

    在这里插入图片描述

    下图形象的展示了一个实际请求过程中,地理级别的负载均衡和机器级别的负载均衡是如何分工和结合的,其中粗线是地理几倍的负载均衡,细线是机器级别的负载均衡,实线代表最终的路由路径

    在这里插入图片描述

    session共享就是用户在A服务器登录,结果查看购物车时,请求发送到了B服务器,因此用户的session存在A服务器上,所以当请求发送到B服务器上时,会认为用户没有登录

    简单说一下session和cookie的交互过程,有想深入了解的看推荐阅读,假设用户在A服务器登录,tomcat会在HttpServletReponse中添加一个cookie,key为JSESSIONID,当用户第二次访问的时候会带上这个cookie,而tomcat会根据这个JSESSIONID找到HttpSession,怎么找到呢?因为tomcat中有这样一个ConcurrentHashMap,key为JSESSIONID value为 Session对象,以后会详细讲这块,要想真正理解清楚,内容也挺多的。

    所以当应用服务器只有一个时,登录一般都是写成如下:

    @RequestMapping(value = "login", method = RequestMethod.POST)
    // ServerResponse是小编封装的一个返回对象
    public ServerResponse<User> login(String username, String passwrod, HttpSession session) {
    	ServerResponse<User> response = userService.login(username, passwrod);
    	// 登录成功,将用户信息放到session中
    	if (response.isSuccess()) {
    		session.setAttribute(Const.CURRENT_USER, response.getData());
    	}
    	return response;
    }
    

    查看购物车时,写成如下

    @RequestMapping(value = "list", method = RequestMethod.GET)
    public ServerResponse<CartVo> list(HttpSession session) {
    	User user = (User)session.getAttribute(Const.CURRENT_USER);
    	if (user == null) {
    	    // session中没有有用户信息,需要登录
    		return ServerResponse.errorCodeMsg(ResponseCode.NEED_LOGIN.getCode(), ResponseCode.NEED_LOGIN.getDesc());
    	}
    	return cartService.list(user.getId());
    }
    

    目前解决session跨域共享问题有如下几种方式

    1. session sticky
      将请求都落到同一个服务器上,如Nginx的ip hash
    2. session replication
      session复制,每台服务器都保存一份相同的session
    3. session 集中存储
      存储在db、 存储在缓存服务器 (redis)
    4. cookie (主流)
      将信息存在加密后的cookie中

    4 数据库高性能操作

    搭建数据库主从集群,实现数据库读写分离,改善数据库负载压力
    在这里插入图片描述

    数据库读写分离的基本实现如下:

    1. 数据库服务器搭建主从集群,一主已从,一主多从都可以
    2. 数据库主机负责读写操作,从机只负责读操作
    3. 数据库主机通过复制将数据同步到从机,每台数据库服务器都存储了所有的业务数据
    4. 业务服务器将写操作分给数据库主机,将读操作分给数据库从机

    实现方式
    读写分离需要将读/写操作区分开来,然后访问不同的数据库服务器;分库分表需要根据不同的数据访问不同的数据库服务器,两者本质上都是一种分配机制,即将不同的SQL语句发送到不同的数据库服务器。

    读写分离,包括后面要提到的分库分表的实现方式有两种:

    1. 程序代码封装
    2. 中间件封装

    程序代码封装指在代码中抽象一个数据访问层来实现读写分离,分库分表
    在这里插入图片描述

    中间件封装指的是独立一套系统出来,实现读写分离和分库分表操作,如我们熟悉的MySQL Router和Mycat等
    在这里插入图片描述

    5 引入搜索引擎来查询

    传统的关系型数据库通过索引来达到快速查询的目的,但是在全文搜索的业务场景下,索引也无能为力,主要体现在如下几点:

    1. 全文搜索的条件可以随意排列组合,如果通过索引来满足,则索引的数量会非常多
    2. 全文搜索的模糊匹配方式,索引无法满足,只能用like查询,而like查询是整表扫描,效率非常低

    在这里插入图片描述

    6 增加缓存

    为了应对流量持续增加,必须增加缓存
    在这里插入图片描述

    常见的方式有如下几种:

    Redis与Memcached

    以我们常见的Mybatis为例,很容易和Redis与Memcached整合起来,缓存已经查询过的SQL,因为Mybatis知道自己不擅长缓存,所以提供了接口让这些缓存工具进行整合

    CDN
    CDN是为了解决用户网络访问时的“最后一公里”效应,本质上是一种“以空间换空间”的加速策略,即建内容缓存在离用户最近的地方,用户访问的是缓存的内容,而不是站点实时的内容。

    7 分库分表

    读写分离分散了数据库读写操作的压力,但没有分散存储压力,当数据量达到千万甚至上亿条的时候,单台服务器的存储能力会成为系统的瓶颈。常见的分散存储的方法有分库和分表两大类
    在这里插入图片描述

    业务分库

    业务分库指的是按照业务模块将数据分散到不同的数据库服务器。例如,一个简单的电商网站,包括商品,订单,用户三个业务模块,我们可以将商品数据,订单数据,用户数据,分开放到3台不同的数据库服务器上,而不是将所有数据都放在一台数据库服务器上

    当然业务分库也会带来新的问题:

    1. join操作问题:业务分库后,原本在同一个数据库中的表分散到不同数据库中,导致无法使用SQL的join查询
    2. 事务问题:原本在同一个数据库中不同的表可以在同一个事务中修改,业务分库后,表分散到不同数据库中,无法通过事务统一修改
    3. 成本问题:业务分库同时也带来了成本的代价,本来1台服务器搞定的事情,现在要3台,如果考虑备份,那就是2台变成6台

    分表

    表单数据拆分有两种方式,垂直分表和水平分表
    在这里插入图片描述

    垂直分表:垂直分表适合将表中某些不常用且占了大量空间的列拆分出去。如上图的nickname和description字段不常用,就可以将这个字段独立到另外一张表中,这样在查询name时,就能带来一定的性能提升

    水平分表:水平分表适合表行数特别大的表,如果单表行数超过5000万就必须进行分表,这个数字可以作为参考,但并不是绝对标准,关键还是要看表的访问性能

    水平分表后,某条数据具体属于哪个切分后的子表,需要增加路由算法进行计算,常见的路由算法有

    范围路由:选取有序的数据列(例如,整型,时间戳等)作为路由条件,不同分段分散到不同的数据库表中。以最常见的用户ID为例,路由算法可以按照1000000的范围大小进行分段,1-999999放到数据库1的表中,1000000-1999999放到数据库2的表中,以此类推

    Hash路由:选取某个列(或者某几个列组合也可以)的值进行Hash运算,然后根据Hash结果分散到不同的数据库表中。同样以用户Id为例,假如我们一开始就规划了10个数据库表,路由算法可以简单地用user_id%10的值来表示数据所属的数据库表编号,ID为985的用户放到编号为5的子表中,ID为10086的用户放到编号为6的子表中。

    配置路由:配置路由就是路由表,用一张独立的表来记录路由信息,同样以用户ID为例,我们新增一张user_router表,这个表包含user_id和table_id两列,根据user_id就可以查询对应的table_id

    8 应用拆分/微服务

    随着业务的发展,业务越来越多,应用的压力越来越大。工程规模也越来越庞大。这个时候就可以考虑将应用拆分,按照领域模型将我们的商品,订单,用户分拆成子系统。
    在这里插入图片描述

    这样拆分以后,可能会有一些相同的代码,比如订单模块有对用户数据的查询,用户模块中肯定也有对用户数据的查询。这些相同的代码和模块一定要抽象出来。这样有利于维护和管理。这时可以将模块变为一个个服务,模块之间互相调用来获取数据,系统就变成一个微服务了。

    在这里插入图片描述

    服务拆分以后,服务之间的通信可以通过RPC技术,比较典型的有:Webservice、Hessian、HTTP、RMI等。如当前的Dubbo和Spring Cloud都是目前比较流行的微服务框架,2者之间还是有很多区别的,以后分享。

    欢迎关注

    在这里插入图片描述

    参考博客

    [1]https://www.cnblogs.com/dump/p/8125539.html
    [2]https://blog.csdn.net/zty1317313805/article/details/80433643
    [3]https://www.zhihu.com/question/20004877
    [4]https://www.cnblogs.com/chenpi/p/5434537.html

    展开全文
  • 这样处理的好处是,不同的服务器分担不同的角色,系统的并发处理能力和系统的数据存储空间得到了很大的改善   3,数据库分布式 用户再次增长的时候,随着数据的访问量增长时,数据库的压力太大导致访问...
  • 主流分布式系统架构分析 主流分布式 --- 系统架构分析 1 主流分布式系统架构分析 目 录 一前言 3 二 SOA 架构解析 3 三微服务 Microservices 架构解析 . 7 四 SOA 和微服务架构的差别 9 五服务网格 Service Mesh ...
  • 二、为什么要走分布式系统架构? 三、系统如何进行拆分? 四、分布式之后带来的技术挑战? 一、什么是分布式系统? 在谈分布式系统架构前,我们先来看看,什么是分布式系统? 假设原来我们有一个系统,...
  • Dubbo分布式系统架构解决方案 Dubbo的概述 什么是SOA SOA是Service-Oriented Architecture的首字母简称它是一种支持面向服务的架构样式从服务基于服务开发和服务的结果来看面向服务是一种思考方式其实SOA架构更多...
  • 范型篇--介绍谷歌、微软、阿里巴巴等知名互联网公司的大规模分布式存储系统架构,涉及分布式文件系统、分布式键值系统、分布式表格系统以及分布式数据库技术等。实践篇--以阿里巴巴的分布式数据库OceanBase为例,...
  • 主流分布式系统架构分析 可编辑 . . . . 目 录 一前言 3 二 SOA 架构解析 3 三微服务 Microservices 架构解析 . 7 四 SOA 和微服务架构的差别 9 五服务网格 Service Mesh 架构解析 . 9 六分布式架构的基本理论 11 ...
  • 分布式系统架构经典资料

    千次阅读 2018-06-28 10:47:30
    前段时间,我写了一系列分布式系统架构方面的文章(拉到文末看目录),有很多读者纷纷留言讨论相关的话题,还有读者留言表示对分布式系统架构这个主题感兴趣,希望我能推荐一些学习资料。 就像我在前面的文章中多次...
  • 高级Java架构师包含:spring boot、Spring cloud、Dubbo、Redis、ActiveMQ、Nginx、Mycat、Spring、MongoDB、ZeroMQ、Git、Nosql、Jvm、Mecached、Netty、Nio、Mina、性能调优、高并发、tomcat负载均衡、大型电商...
  • 本书主要讲解了架构知识,不仅仅是架构知识,更多的是互联网场景下大型网站架构演变过程中核心技术难题的解决方案。
  • 高并发(High Concurrency)是互联网分布式系统架构设计中必须考虑的因素之一,它通常是指,通过设计保证系统能够同时并行处理很多请求。 高并发相关常用的一些指标有响应时间(Response Time),吞吐量(Throughput...
  • Dubbo的分布式系统架构-第三方支付项目的系统架构实战
  • 《大规模分布式系统架构与设计实战》从作者的实战经验出发,深入浅出地讲解了如何建立一个Hadoop那样的分布式系统,实现对多台计算机CPU、内存、硬盘的统一利用,从而获取强大计算能力去解决复杂问题。一般互联网...
  • 本课程主要讲解当前网络环境下互联网应用架构设计,课程针对阿里云平台所提供的分步式系统架构支持来分层说明如何搭建一个高可用的应用架构。 讲师介绍: 石立勇,阿里云生态体系首席架构师,致力于阿里云生态体系...
  • 本书主要讲解了架构知识,不仅仅是架构知识,更多的是互联网场景下大型网站架构演变过程中核心技术难题的解决方案。
  • 本课程主要讲解当前网络环境下互联网应用架构设计,课程针对阿里云平台所提供的分步式系统架构支持来分层说明如何搭建一个高可用的应用架构。 讲师介绍: 石立勇,阿里云生态体系首席架构师,致力于阿里云生态体系...
  • 随着互联网的发展,网站应用的规模不断扩大,常规的垂直应用架构已无法应对,分布式服务架构以及流动计算架构势在必行,亟需一个治理系统确保架构有条不紊的演进。其中阿里的dubbo就是一款分布式服务框架,致力于提供...
  • Java架构开发大型互联网-架构师必须掌握的分布式技术pdf+视频
  • 分布式系统架构思路 一、前言 在计算机领域,当单机性能达到瓶颈时,有两种方式可以解决性能问题,一是堆硬件,进一步提升配置,二是分布式,水平扩展。当然,两者都是一样的烧钱。 今天聊聊我所理解的分布式...
  • Java架构-美团即时物流的分布式系统架构设计

    千次阅读 多人点赞 2018-11-25 17:21:40
    背景 美团外卖已经发展了五年,即时物流探索也经历了 3 年多的时间,业务从...即时物流系统阶段性的逐步实施分布式系统架构升级,最终解决了系统宕机的风险。 围绕成本、效率、体验核心三要素,即时物流体系大量结...
  • 分布式系统架构网络之IDC机房

    万次阅读 2017-09-28 16:46:39
    我们开发的互联网应用被部署到IDC机房里的某个服务器上,从而完成了应用互联网的接入,所以我们接下来学习一些IDC机房的相关知识。IDC机房又被称为互联网数据中心(Internet Data Center)或者数据中心,IDC不仅是...
  • 分布式计算Hadoop分布式系统现在主流开源分布式系统架构都有哪些?关注者950被浏览112,808关注问题写回答​添加评论​分享​邀请回答​14 个回答默认排序​知乎用户68 人赞同了该回答分布式系统是一个非常广泛的...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 137,763
精华内容 55,105
关键字:

互联网分布式系统架构