一直在思考分布式系统设计的问题,业务对象原封不动的状况下部署在客户端和服务器端,能够根据配置文件选择是链接服务器仍是链接本地的数据库,这个问题让我绞尽脑汁,我老是设想的客户端与服务器端通讯的方式是最低端的Socket。花了两个晚上研究CSLA.NET框架关于数据门户这块代码,才发现问题的关键所在:客户端与服务器端通讯不能采用最低端的Socket,而要用高端的WebService、.NET Remoting或者是本身定义一种协议等,只要它们支持客户端直接根据服务器端的服务URL、类名、方法名和方法参数四个信息就能够调用服务器对应的类和方法就行。php
说明:本文中所表达的思想与CSLA.NET有很大区别,不要看了本文就觉得是CSLA.NET的设计思想,也不要觉得本文错误的解释了CSLA.NET,这不是一篇介绍CSLA.NET的文章,但纯思想上它们是相同的。css
日常咱们都说三层架构,我认为它是一个广义的模型,更多层的设计能够合并相邻几层的方式最终回归到三层这个宽泛的概念上来,个人意思是:这些都只是概念,忘记这些概念去实际分析设计会离这些概念更近一些。html
接下来我要把三层变的更简单点,两层,数据访问层合并到业务层,统称为业务层,由于咱们面对的问题不是分层的问题,而是分布式系统中各层应该怎么部署的问题。在CSLA.NET书中也说到业务层和数据访问层放到同一台机器上能够提升性能和容错性。所以他们俩的合并不影响分布式系统的部署。前端
不过要解释的是数据库系统(CSLA.NET中说的数据存储和管理层)并无考虑到三层中来,也就是它不包含在数据访问层中,若是把它算进来,那么它是在数据访问层之下单独存在的。node
综上,在分布式系统部署角度考虑的分层实际是三层:界面层、业务层(包含数据访问层的业务层)、数据存储层。mysql
下面举例说明可能的部署情景,带阴影的框框表示一台机器,虚线框表示根据使用场合无关紧要,虚横线表示今后处划开单独出服务器。在B/S应用中,Web浏览器为客户端,其余所有为服务器。在C/S应用中,处在最上层的界面层+业务层为客户端,其余为服务器。nginx
非分布式系统的部署git
单机版github
两三台机器web
分布式系统的部署
分布式的Web系统
分布式的C/S系统
有几点要说明:
1. 客户端上的验证等业务逻辑是不可信的,所以任何一种部署都须要服务器端包含业务层;
2. 为了开发、维护和部署中的高度可伸缩性,图中的各业务层所包含的代码都是如出一辙的;
3. 由于第2点,因此我遇到了业务层的同一个操做是与其余机器上的业务层通讯仍是访问数据库这个难题。
这个问题是关键问题,也就是上面几点说明中的第3个问题,为了解决这个问题咱们引入数据门户的概念。
下面以WebService为例说明:界面层访问本机的业务对象的增删改查中的“查”方法时,跳过数据库的查询操做,访问另外一台机器中的同一个业务对象类的“查”方法。
以上是向另外一台机器发送请求,该请求并不直接调用另外一台机器上的业务对象类的“查”方法,而是将要调用的业务对象和方法参数信息转为一个“二进制包”,做为参数去调用另外一台机器上通用的“查”方法,另外一台机器上的“查”方法再解开这个包,而后去调用解开的包中所表示的业务对象类型,下面的静态图是另外一台机器接受到请求后的工做。
又有些说明:
1. 关于原理都已在图中作了描述,不另写大段文字解释了;
2. 上面两个图中,除了“实际业务对象类”之外的部分所有属于架构或者框架部分;
3. 若是用OO的思想去审查上面的两个图,你必定会为这糟糕的设计而抱怨,这里只是为了尽量简单的表述分布式系统的工做原理,你能够采用策略模式使数据门户不改变的状况下适应各类请求响应场合,采用工厂模式实现不一样的请求响应场合的切换。
为了解决数据库服务器的负担,咱们可能但愿把数据分布存储在多个服务器上,我设想的数据库分布方案是,各服务器上的数据库在结构上如出一辙,而表里的数据存储到不一样服务器上,这样数据访问层在查数据的时候分别向全部数据库服务器发送一样的sql命令,而后数据访问层获得数据后整合,这样减轻每台服务器的工做量。亦或者根据表里的某个表明性的字段(如:省份)分布数据到不一样服务器。
简单说,分布式是以缩短单个任务的执行时间来提高效率的,而集群则是经过提升单位时间内执行的任务数来提高效率。
集群主要分为:高可用集群(High Availability Cluster),负载均衡集群(Load Balance Cluster,nginx便可实现),科学计算集群(High Performance Computing Cluster)。
分布式是指将不一样的业务分布在不一样的地方;而集群指的是将几台服务器集中在一块儿,实现同一业务。分布式中的每个节点,均可以作集群。 而集群并不必定就是分布式的。
以前在网上看到一篇关于大型网站演化的博客。http://www.cnblogs.com/leefreeman/p/3993449.html
每一个大型网站都会有不一样的架构模式,而架构内容也就是在处理均衡负载,缓存,数据库,文件系统等,只是在不一样的环境下,不一样的条件下,架构的模型不同,目的旨在提升网站的性能。
最初的架构只有应用程序,数据库,文件服务。
到后来,分布式服务、集群架设。
在上一篇,《Nginx反向代理实现均衡负载》讨论过过的nginx现实均衡负载方案,这里选择另外一种HAProxy+Keepalived双机高可用均衡负载方案。
HAProxy是免费、极速且可靠的用于为TCP和基于HTTP应用程序提供高可用、负载均衡和代理服务的解决方案,尤为适用于高负载且须要持久链接或7层处理机制的web站点。
不管是Haproxy仍是Keepalived甚至是上游服务器均提升生产力并加强可用性,也就是以下架构中Haproxy,Keepalived,Httpd服务器任意宕机一台服务仍是能够正常运行的。
HAProxy的优势:
一、HAProxy是支持虚拟主机的,能够工做在四、7层(支持多网段);
二、可以补充Nginx的一些缺点好比Session的保持,Cookie的引导等工做;
三、支持url检测后端的服务器;
四、自己仅仅就只是一款负载均衡软件;单纯从效率上来说HAProxy更会比Nginx有更出色的负载均衡速度,在并发处理上也是优于Nginx的;
五、HAProxy能够对Mysql读进行负载均衡,对后端的MySQL节点进行检测和负载均衡;
缓存分为服务器缓存和应用程序缓存。
关于应用程序内缓存,已经在Jue后台框架里面作了模块处理了。
关于服务器缓存,主要缓存服务器文件,减小服务器和php交互,减小均衡负载服务器和应用程序服务器交互。
缓存里面有一种典型的memcached,如今用的多的是redis轻量级缓存方案。
关于memcached与redis,看这篇 《Memcached vs Redis?》
Redis主要将数据存储在各类格式:列表,数组,集合和排序集,一次能接受多个命令,阻塞读写,等待直到另外一个进程将数据写入高速缓存。
一篇关于Reids缓存方案。《高可用、开源的Redis缓存集群方案》
(第一期不作,后期需求时候考虑)
Sphinx是俄罗斯人开发的,号称是很吊啦,千万级数据检索,每秒10MB/s,搭过环境。
Sphinx和MySQL是基于数据库的全文引擎,建立索引是B+树和hash key-value的方式。
原理相似于用底层C检索MySQL,而后弄出一个sphinx.conf配置文件,索引与搜索均以这个文件为依据进行,要进行全文检索,首先就要配置好sphinx.conf,告诉sphinx哪些字段须要进行索引,哪些字段须要在where,orderby,groupby中用到。
NoSQL在这里的使用价值是处理一些杂事,好比用户我的网站的一些css值,height,width,color等等的小而繁多的数据,采用NoSQL旨在提高数据库速度,减小对MySQL的SELECT请求。
关于NoSQL的方案不少了,选一个简单的MongDB好了。
(作分布式MySQL还没尝试过,初期也不清楚mysql所须要的压力,因此第一期不打算作分布式MySQL)
综合起来,大体就是以下模型,初探分布式架构,不少模块将就形势作调整,时时更新中,待续。。。
系统的目标很明确,针对千万级以上PV的网站,设计一套用于后台的高并发的分布式处理系统。这套系统包含业务逻辑的处理、各类计算、存储、日志、备份等方面内容,可用于类微博,SNS,广告推送,邮件等有大量线上并发请求的场景。
如何抗大流量高并发?(不要告诉我把服务器买的再好一点)提及来很简单,就是“分”,如何“分”,简单的说就是把不一样的业务分拆到不一样的服务器上去跑(垂直拆分),相同的业务压力分拆到不一样的服务器去跑(水平拆分),并时刻不要忘记备份、扩展、意外处理等讨厌的问题。提及来都比较简单,但设计和实现起来,就会比较困难。之前个人文章,都是“从整到零”的方式来设计一个系统,此次我们就反着顺序来。
那咱们首先来看,咱们的数据应该如何存储和取用。根据咱们以前肯定的“分”的方法,先肯定如下2点:
(1)咱们的分布式系统,按不一样的业务,存储不一样的数据;(2)一样的业务,同一个数据应存储多份,其中有的存储提供读写,而有的存储只提供读。
好,先解释下这2点。对于(1)应该容易理解,好比说,我这套系统用于微博(就假想咱们作一个山寨的推特吧,给他个命名就叫“山推” 好了,如下都叫山推,Stwi),那么,“我关注的人”这一个业务的数据,确定和“我发了的推文”这个业务的数据是分开存储的,那么咱们如今把,每个业务所负责的数据的存储,称为一个group。即以group的方式,来负责各个业务的数据的存储。接下来讲(2),如今咱们已经知道,数据按业务拆到group里面去存取,那么一个group里面又应该有哪些角色呢?天然的,应该有一台主要的机器,做为group的核心,咱们称它为Group Master,是的,它就是这个group的主要表明。这个group的数据,在Group Master上应该都能找到,进行读写。另外,咱们还须要一些辅助角色,咱们称它们为Group Slaves,这些slave机器作啥工做呢?它们负责去Group Master处拿数据,并尽可能保持和它同步,并提供读服务。请注意个人用词,“尽可能”,稍后将会解释。如今咱们已经有了一个group的基本轮廓:
一个group提供对外的接口(废话不然怎么存取数据),group的底层能够是实际的File System,甚至是HDFS。Group Master和Group Slave能够共享同一个File System(用于不能丢数据的强一致性系统),也能够分别指向不一样的File System(用于弱一致性,容许停写服务和系统宕机时丢数据的系统),但总之应认为这个"File System"是无状态,有状态的是Group Master和各个Group Slave。
下面来讲一个group如何工做,同步等核心问题。首先,一个group的Group Master和Group Slave
间应保持强一致性仍是弱一致性(最终一致性)应取决于具体的业务需求,以咱们的“山推”来讲,Group Master和Group Slave并不要求保持强一致性,而弱一致性(最终一致性)即能知足要求,为何?由于对于“山推”来说,一个Group Master写了一个数据,而另外一个Group Slave被读到一个“过时”(由于Group Master已经写,但此Group Slave还未更新此数据)的数据一般并不会带来大问题,好比,我在“山推”上发了一个推文,“关注个人人”并无即时同步地看到个人最新推文,并无太大影响,只要“稍后”它们能看到最新的数据便可,这就是所谓的最终一致性。但当Group Master挂掉时,写服务将中断一小段时间由其它Group Slave来顶替,稍后还要再讲这个问题。假如咱们要作的系统不是山推,而是淘宝购物车,支付宝一类的,那么弱一致性(最终一致性)则很难知足要求,同时写服务挂掉也是不能忍受的,对于这样的系统,应保证“强一致性”,保证不能丢失任何数据。
接下来仍是以咱们的“山推“为例,看看一个group如何完成数据同步。假设,如今我有一个请求要写一个数据,因为只有Group Master能写,那么Group Master将接受这个写请求,并加入写的队列,而后Group Master将通知全部Group Slave来更新这个数据,以后这个数据才真正被写入File System。那么如今就有一个问题,是否应等全部Group Slave都更新了这个数据,才算写成功了呢?这里涉及一些NWR的概念,咱们做一个取舍,即至少有一个Group Slave同步成功,才能返回写请求的成功。这是为何呢?由于假如这时候Group Master忽然挂掉了,那么咱们至少能够找到一台Group Slave保持和Group Master彻底同步的数据并顶替它继续工做,剩下的、其它的Group Slave将“异步”地更新这个新数据,很显然,假如如今有多个读请求过来并到达不一样的Group Slave节点,它们极可能读到不同的数据,但最终这些数据会一致,如前所述。咱们作的这种取舍,叫“半同步”模式。那以前所说的强一致性系统应如何工做呢?很显然,必须得等全部Group Slave都同步完成才能返回写成功,这样Group Master挂了,没事,其它Group Slave顶上就行,不会丢失数据,可是付出的代价就是,等待同步的时间。假如咱们的group是跨机房、跨地区分布的,那么等待全部Group Slave同步完成将是很大的性能挑战。因此综合考虑,除了对某些特别的系统,采用“最终一致性”和“半同步”工做的系统,是符合高并发线上应用需求的。并且,还有一个很是重要的缘由,就是一般线上的请求都是读>>写,这也正是“最终一致性”符合的应用场景。
好,继续。刚才咱们曾提到,若是Group Master宕机挂掉,至少能够找到一个和它保持同不的Group Slave来顶替它继续工做,其它的Group Slave则“尽可能”保持和Group Master同步,如前文所述。那么这是如何作到的呢?这里涉及到“分布式选举”的概念,如Paxos协议,经过分布式选举,总能找到一个最接近Group Master的Group Slave,来顶替它,从而保证系统的可持续工做。固然,在此过程当中,对于最终一致性系统,仍然会有一小段时间的写服务中断。如今继续假设,咱们的“山推”已经有了一些规模,而负责“山推”推文的这个group也有了五台机器,并跨机房,跨地区分布,按照上述设计,不管哪一个机房断电或机器故障,都不会影响这个group的正常工做,只是会有一些小的影响而已。
那么对于这个group,还剩2个问题,一是如何知道Group Master挂掉了呢?二是在图中咱们已经看到Group Slave是可扩展的,那么新加入的Group Slave应如何去“偷”数据从而逐渐和其它节点同步呢?对于问题一,咱们的方案是这样的,另外提供一个相似“心跳”的服务(由谁提供呢,后面咱们将讲到的Global Master将派上用场),group内全部节点不管是Group Master仍是Group Slave都不停地向这个“心跳”服务去申请一个证书,或认为是一把锁,而且这个锁是有时间的,会过时。“心跳”服务按期检查Group Master的锁和其有效性,一旦过时,若是Group Master工做正常,它将锁延期并继续工做,不然说明Group Master挂掉,由其它Group Slave竞争获得此锁(分布式选举),从而变成新的Group Master。对于问题二,则很简单,新加入的Group Slave不断地“偷”老数据,而新数据总因为Group Master通知其更新,最终与其它全部结点同步。(固然,“偷”数据所用的时间并不乐观,一般在小时级别)
上篇(连接)咱们完成了在此分布式系统中,一个group的设计。那么接下来,咱们设计系统的其余部分。如前文所述,咱们的业务及其数据以group为单位,显然在此系统中将存在many many的groups(别告诉我你的网站总共有一个业务,像咱们的“山推”,那业务是一堆一堆地),那么由谁来管理这些groups呢?由Web过来的请求,又将如何到达指定的group,并由该group处理它的请求呢?这就是咱们要讨论的问题。
咱们引入了一个新的角色——Global Master,顾名思义,它是管理全局的一个节点,它主要完成以下工做:(1)管理系统全局配置,发送全局控制信息;(2)监控各个group的工做状态,提供心跳服务,若发现宕机,通知该group发起分布式选举产生新的Group Master;(3)处理Client端首次到达的请求,找出负责处理该请求的group并将此group的信息(location)返回,则来自同一个前端请求源的该类业务请求自第二次起不须要再向Global Master查询group信息(缓存机制);(4)保持和Global Slave的强一致性同步,保持自身健康状态并向全局的“心跳”服务验证自身的状态。
如今咱们结合图来逐条解释上述工做,显然,这个系统的完整轮廓已经初现。
首先要明确,无论咱们的系统如何“分布式”,总之会有至少一个最主要的节点,术语可称为primary node,如图所示,咱们的系统中,这个节点叫Global Master,也许读过GFS + Bigtable论文的同窗知道,在GFS + Bigtable里,这样的节点叫Config Master,虽然名称不同,但所作的事情却差很少。这个主要的Global Master可认为是系统状态健康的标志之一,只要它在正常工做,那么基本能够保证整个系统的状态是基本正常的(什么?group或其余结点会不正常不工做?前面已经说过,group内会经过“分布式选举”来保证本身组内的正常工做状态,不要告诉我group内全部机器都挂掉了,那个几率我想要忽略它),假如Global Master不正常了,挂掉了,怎么办?显然,图中的Global Slave就派上用场了,在咱们设计的这个“山推”系统中,至少有一个Global Slave,和Global Master保持“强一致性”的彻底同步,固然,若是有不止一个Global Slave,它们也都和Global Master保持强一致性彻底同步,这样有个好处,假如Global Master挂掉,不用停写服务,不用进行分布式选举,更不会读服务,随便找一个Global Slave顶替Global Master工做便可。这就是强一致性最大的好处。那么有的同窗就会问,为何咱们以前的group,不能这么搞,非要搞什么最终一致性,搞什么分布式选举(Paxos协议属于既难理解又难实现的坑爹一族)呢?我告诉你,仍是压力,压力。咱们的系统是面向日均千万级PV以上的网站(“山推”嘛,推特是亿级PV,咱们千万级也不过度吧),但系统的压力主要在哪呢?细心的同窗就会发现,系统的压力并不在Global Master,更不会在Global Slave,由于他们根本不提供数据的读写服务!是的,系统的压力正是在各个group,因此group的设计才是最关键的。同时,细心的同窗也发现了,因为Global Master存放的是各个group的信息和状态,而不是用户存取的数据,因此它更新较少,也不能认为读>>写,这是不成立的,因此,Global Slave和Global Master保持强一致性彻底同步,正是最好的选择。因此咱们的系统,一台Global Master和一台Global Slave,暂时能够知足需求了。
好,咱们继续。如今已经了解Global Master的大概用途,那么,一个来自Client端的请求,如何到达真正的业务group去呢?在这里,Global Master将提供“首次查询”服务,即,新请求首次请求指定的group时,经过Global Master得到相应的group的信息,之后,Client将使用该信息直接尝试访问对应的group并提交请求,若是group信息已过时或是不正确,group将拒绝处理该请求并让Client从新向Global Master请求新的group信息。显然,咱们的系统要求Client端缓存group的信息,避免屡次重复地向Global Master查询group信息。这里其实又挖了许多烂坑等着咱们去跳,首先,这样的工做模式知足基本的Ddos攻击条件,这得经过其余安全性措施来解决,避免group老是收到不正确的Client请求而拒绝为其服务;其次,当出现大量“首次”访问时,Global Master尽管只提供查询group信息的读服务,仍有可能不堪重负而挂掉,因此,这里仍有很大的优化空间,比较容易想到的就是采用DNS负载均衡,由于Global Master和其Global Slave保持彻底同步,因此DNS负载均衡能够有效地解决“首次”查询时Global Master的压力问题;再者,这个工做模式要求Client端缓存由Global Master查询获得的group的信息,万一Client不缓存怎么办?呵呵,不用担忧,Client端的API也是由咱们设计的,以后才面向Web前端。
以后要说的,就是图中的“Global Heartbeat”,这又是个什么东西呢?可认为这是一个管理Global Master和Global Slave的节点,Global Master和各个Global Slave都不停向Global Heartbeat竞争成为Global Master,若是Global Master正常工做,按期更新其状态并延期其得到的锁,不然由Global Slave替换之,原理和group内的“心跳”同样,但不一样的是,此处Global Master和Global Slave是强一致性的彻底同步,不须要分布式选举。有同窗可能又要问了,假如Global Heartbeat挂掉了呢?我只能告诉你,这
个很不常见,由于它没有任何压力,并且挂掉了必须人工干预才能修复。在GFS + Bigtable里,这个Global Heartbeat叫作Lock Service。
如今接着设计咱们的“山推”系统。有了前面两篇的铺垫,咱们的系统如今已经有了五脏六腑,剩下的工做就是要让其羽翼丰满。那么,是时候,放出咱们的“山推”系统全貌了:
前面啰嗦了半天,也许很多同窗看的不明不白,好了,如今开始看图说话环节:
(1)整个系统由N台机器组合而成,其中Global Master一台,Global Slave一台到多台,二者之间保持强一致性并彻底同步,可由Global Slave随时顶替Global Master工做,它们被Global Heartbeat(一台)来管理,保证有一个Global Master正常工做;Global Heartbeat因为无压力,一般认为其不能挂掉,若是它挂掉了,则必须人工干预才能恢复正常;
(2)整个系统由多个groups合成,每个group负责相应业务的数据的存取,它们是数据节点,是真正抗压力的地方,每个group由一个Group Master和一个到多个Group Slave构成,Group Master做为该group的主节点,提供读和写,而Group Slave则只提供读服务且保证这些Group Slave节点中,至少有一个和Group Master保持彻底同步,剩余的Group Slave和Group Master可以达到最终一致,它们之间以“半同步”模式工做保证最终一致性;
(3)每个group的健康状态由Global Master来管理,Global Master向group发送管理信息,并保证有一个Group Master正常工做,若Group Master宕机,在该group内经过分布式选举产生新的Group Master顶替原来宕机的机器继续工做,但仍然有一小段时间须要中断写服务来切换新的Group Master;
(4)每个group的底层是实际的存储系统,File system,它们是无状态的,即,由分布式选举产生的Group Master能够在原来的File system上继续工做;
(5)Client的上端可认为是Web请求,Client在“首次”进行数据读写时,向Global Master查询相应的group信息,并将其缓存,后续将直接与相应的group进行通讯;为避免大量“首次”查询冲垮Global Master,在Client与Global Master之间增长DNS负载均衡,可由Global Slave分担部分查询工做;
(6)当Client已经拥有足够的group信息时,它将直接与group通讯进行工做,从而真正的压力和流量由各个group分担,并处理完成须要的工做。
好了,如今咱们的“山推”系统设计完成了,可是要将它编码实现,还有很远的路要走,细枝末节的问题也会暴露更多。若是该系统用于线上计算,若有大量的Map-Reduce运行于group中,系统将会更复杂,由于此时不光考虑的数据的存储同步问题,操做也须要同步。如今来检验下咱们设计的“山推”系统,主要分布式指标:
一致性:如前文所述,Global机器强一致性,Group机器最终一致性;
可用性:Global机器保证了HA(高可用性),Group机器则不保证,但知足了分区容错性;
备份Replication:Global机器采用彻底同步,Group机器则是半同步模式,均可以进行横向扩展;
故障恢复:如前文所述,Global机器彻底同步,故障可不受中断由slave恢复工做,但Group机器采用分布式选举和最终一致性,故障时有较短期的写服务须要中断并切换到slave机器,但读服务可不中断。
还有其余一些指标,这里就再也不多说了。还有一些细节,须要提一下,好比以前的评论中有同窗提到,group中master挂时,由slave去顶替,但这样一来该group内其余全部slave须要分担以前成这新master的这个slave的压力,有可能继续挂掉而形成雪崩。针对此种状况,可采用以下作法:即在一个group内,至少还存在一个真正作“备份”用途的slave,平时不抗压力,只同步数据,这样当出现上述状况时,可由该备份slave来顶替成为新master的那个slave,从而避免雪崩效应。不过这样一来,就有新的问题,因为备份slave平时不抗压力,加入抗压力后必然产生必定的数据迁移,数据迁移也是一个较麻烦的问题。常采用的分摊压力作法如一致性Hash算法(环状Hash),可将新结点加入对整个group的影响降到较小的程度。
另外,还有一个较为棘手的问题,就是系统的日志处理,主要是系统宕机后如何恢复以前的操做日志。比较常见的方法是对日志做快照(Snapshot)和回放点(checkpoint),并采用Copy-on-write方式按期将日志做snapshot存储,当发现宕机后,找出对应的回放点并恢复以后的snapshot,但此时仍可能有新的写操做到达,并产生不一致,这里主要依靠Copy-on-write来同步。
最后再说说图中的Client部分。显然这个模块就是面向Web的接口,后面链接咱们的“山推”系统,它能够包含诸多业务逻辑,最重要的,是要缓存group的信息。在Client和Web之间,还能够有诸如Nginx之类的反向代理服务器存在,作进一步性能提高,这已经超出了本文的范畴,但咱们必须明白的是,一个高并发高性能的网站,对性能的要求是从起点开始的,何为起点,即用户的浏览器。
如今,让咱们来看看GFS的设计:
很明显,这么牛的系统我是设计不出来的,咱们的“山推”,就是在学习GFS + Bigtable的主要思想。说到这,也必须提一句,可能我文章中,名词摆的有点多了,如NWR,分布式选举,Paxos包括Copy-on-write等,有兴趣的同窗可自行google了解。由于说实在的,这些概念我也无法讲透彻,只是只知其一;不知其二。另外,你们可参考一些分布式项目的设计,如Cassandra,包括淘宝的Oceanbase等,以加深理解。
在计算机领域,当单机性能达到瓶颈时,有两种方式能够解决性能问题,一是堆硬件,进一步提高配置,二是分布式,水平扩展。固然,二者都是同样的烧钱。
今天聊聊我所理解的分布式系统的架构思路。
平时接触到的分布式系统有不少种,好比分布式文件系统,分布式数据库,分布式WebService,分布式计算等等,面向的情景不一样,但分布式的思路是不是同样的呢?
假设咱们有一台服务器,它能够承担1百万/秒的请求,这个请求能够的是经过http访问网页,经过tcp下载文件,jdbc执行sql,RPC调用接口…,如今咱们有一条数据的请求是2百万/秒,很显然服务器hold不住了,会各类拒绝访问,甚至崩溃,宕机,怎么办呢。一台机器解决不了的问题,那就两台。因此咱们加一台机器,每台承担1百万。若是请求继续增长呢,两台解决不了的问题,那就三台呗。这种方式咱们称之为水平扩展。如何实现请求的平均分配即是负载均衡了。
另外一个栗子,咱们如今有两个数据请求,数据1 90万,数据2 80万,上面那台机器也hold不住,咱们加一台机器来负载均衡一下,每台机器处理45万数据1和40万数据2,可是平分太麻烦,不如一台处理数据1,一台处理数据2,一样能解决问题,这种方式咱们称之为垂直拆分。
水平扩展和垂直拆分是分布式架构的两种思路,但并非一个二选一的问题,更多的是兼并合用。下面介绍一个实际的场景。这也是许多互联网的公司架构思路。
我此时所在的公司的计算机系统很庞大,天然是一个整的分布式系统,为了方便组织管理,公司将整个技术部按业务和平台拆分为部门,订单的,会员的,商家的等等,每一个部门有本身的web服务器集群,数据库服务器集群,经过同一个网站访问的连接可能来自于不一样的服务器和数据库,对网站及底层对数据库的访问被分配到了不一样的服务器集群,这个即是典型的按业务作的垂直拆分,每一个部门的服务器在hold不住时,会有弹性的扩展,这即是水平扩展。
在数据库层,有些表很是大,数据量在亿级,若是只是纯粹的水平的扩展并不必定最好,若是对表进行拆分,好比能够按用户id进行水平拆表,经过对id取模的方式,将用户划分到多张表中,同时这些表也能够处在不一样的服务器。按业务的垂直拆库和按用户水平拆表是分布式数据库中通用的解决方案。
前面咱们谈到了分布式来解决性能问题,但其附带的问题是怎么分布,即如何负载均衡。这里要解决的问题是当客户端请求时,应该让它请求分布式系统中哪一台服务器,一般的作法是经过一台中间服务器来给客服端分配目标服务器。
这里一样拿两个不一样的分布式系统作说明,下图左边是分布式文件系统FastDFS,右边是一个用于分布式的RPC中间件。
其中tracker即是负载均衡服务器,storage是存储文件和处理上传下载请求的服务器。
zookeeper是分布式系统中一个负载均衡框架,google的chubby的一个开源实现,是是Hadoop和Hbase的重要组件。
一样的在http中,常据说的nginx也是一个负载均衡服务器,它面向的是分布式web服务器。至于具体的负载均衡算法轮询,hash等这里就不深刻了。
分布式系统中,解决了负载均衡的问题后,另一个问题就是数据的一致性了,这个就须要经过同步来保障。根据不一样的场景和需求,同步的方式也是有选择的。
在分布式文件系统中,好比商品页面的图片,若是进行了修改,同步要求并不高,就算有数秒甚至数分钟的延迟都是能够接受的,由于通常不会产生损失性的影响,所以能够简单的经过文件修改的时间戳,隔必定时间扫描同步一次,能够牺牲一致性来提升效率。
但银行中的分布式数据库就不同了,一丁点不一样步就是没法接受的,甚至能够经过加锁等牺牲性能的方式来保障彻底的一致。
在一致性算法中paxos算法是公认的最好的算法,chubby、zookeeper中paxos是它保证一致性的核心。这个算法比较难懂,我目前也没弄懂,这里就不深刻了。
接触过这么多分布式系统后发现,它们的设计思路是如此的类似,这或许就是万法归一吧。
做者:弓长张
连接:https://www.zhihu.com/question/19699884/answer/32253702
来源:知乎
著做权归做者全部,转载请联系做者得到受权。
Q1.为甚么会有分布式框架的出现? A:计算量和数据量的爆炸,好比要你统计10个1MB文本文件里的相异单词数目,很简单,一个一个读出来计算就能够实现,10个文本文件最多10MB,能够彻底读到单机(普通我的计算机)的内存里。或者让你对一组数据进行很简单的几回四则运算,这些计算和任务在普通机器上都可以很流畅运行。可是,换一种状况,若是要你读取100000个文件的相异单词数目,那么单单总文件大小就有100GB,普通机器在这个任务上就遇到两个瓶颈,第一个是从外存储器到内存的,一个是从内存到CPU的,这样的任务在通常机器上没法再可接受的时间内完成。另外一个状况,你要对一组数据(数据量不是很大)进行数千亿(极大量)的迭代复杂运算,单单靠一个普通机器的CPU和内存也不能在可接受的时间内完成。因此人们为了解决这些状况,才推出了分布式这个东西。 Q2分布式框架如何解决以上问题的? A:我说简单点,就是经过纵向和横向的并行实现的。若是1000台机器(节点)同时处理这个任务,每台机器只会去处理10个文件了,这个道理是很简单易懂的,这就是横向上的并行。而纵向上的并行主要是靠神马创建缓冲池,分解任务之类实现的,道理很简单,为了达到最大效率,就要让CPU何内存在任什么时候候都最大发挥,通常的方法可能会出现一些时候IO空闲,运算负载和一些时候运算空闲,IO负载的问题,纵向的优化就是要让IO和运算任什么时候候都不空闲。 Q3分布式框架的基本核心问题。 A:1.对于实际任务来讲,横向的并行每每不是把数据文件分红若干份运算那么简单。 2.分布式要解决的问题每每是能够线性分割的。 3.如今分布式解决的主要问题其实仍是对于大数据量的解决