@Hederahelix
2015-11-07T13:19:39.000000Z
字数 6850
阅读 3212
大数据
数据挖掘
算法
一般我们会选择一个开源的Server作为容器,直接使用JSP/Servlet等技术或者使用开源框架来构建我们的应用。选择一个数据库来存储数据,通过JDBC进行数据库连接和操作。这样就完成了一个最基础的环境。
对于实际的大型网站来说,情况远比我们看到的这个例子要复杂。大型网站中,其实最核心的功能就是计算和存储。上图中,DB就是用来存储数据的,而Application Server完成了业务逻辑,是用来计算的。一个网站从小到大的演进可以说都是围绕着这两个方面进行。
加假设我们的交易网站支持用户、商品、交易这三个模块,那么,基于java技术用单机构建这个交易网站的话,大概是下图的样子。
在这里有两个地方需要注意, 即各个功能模块之间是通过JVM内部的方法调用来进行交互的,而应用逻辑和数据库之间是通过JDBC来进行访问的。后续将围绕这两个部分会有不同的变化。
随着访问量不断增大,我们这个服务器的负载持续升高,必须要采取一些办法来应对了。越来越多的用户访问导致性能越来越差,越来越多的数据导致存储空间不足。这时就需要讲应用和数据分离。应用和数据分离后整个网站使用三台服务器:应用服务器、文件服务器、和数据库服务器。这三台服务器对硬件资源要求各不相同,应用服务器需要处理大量的业务逻辑,因此需要更强大的CPU;数据库和文件服务器需要存储大量数据,需要更快的磁盘和内存。
调整以后我们需要对代码变化很小,由于应用还是在一台机器上,所以还是通过JVM内部的方法调用来进行交互的。当与数据库连接时,只需要修改JDBC配置吧数据库地址从本机改到另外一台机器上而已。
应用服务器压力变大时,可以针对性地进行优化,这里介绍的是把应用从单机改为集群的优化方式。
在上图中,应用服务器从一台变为了两台。这两台服务器之间没有直接的交互,它们都是依赖数据库对外提供服务的。但是,我们有下面两个问题需要解决:
第一个问题可以通过引入负载均衡设备解决,这就不多讲。第二个问题有以下几种常见解决方法。
通过将应用服务器集群化很好的缓解了服务器端的压力,由于服务器之间没有交互,所以还是JVM内部的方法调用来进行交互的。
随着业务发展,我们的数据量和访问量都在增长。对于大型网站来说,有不少业务是读多写少的,这个状况也直接反映到数据库上。那么对于这样的情况,我们可以考虑使用读写分离的方式。目前大部分的主流都提供主从备份功能,通过设置丽娜国泰数据库主从关系,可以将一台数据库服务器的数据更新同步到另一台服务器上。从而改善数据库负责压力。
我们在前面的结构上增加了一个读库,这个库不承担写的工作,只提供读服务。
这个结构的变化带来两个问题:
网站访问特点和现实世界的财富分配一样遵循二八定律:80%的业务访问集中在20%的数据上。既然大部分的业务访问集中在一小部分数据上,那么如果把这一小部分数据缓存在内存中,是不是就可以减少数据库的访问压力,提高整个网站的数据访问速度,改善数据库写入性能了呢?
通过读写分离以及某些场景用分布式存储系统替换关系型数据库的方式,能够降低主库的压力,解决数据存储方面的问题。不过随着业务的发展,我们的主库也会遇到瓶颈。我们的网站演进到现在,交易、商品、用户的数据还都在一个数据库中。尽管采取了增加缓存、读写分离的方式,这个数据库的压力还是在继续增加,因此我们需要去解决这个问题,我们有数据垂直拆分和水平拆分两种选择。
垂直拆分的意思是把数据库中不同的业务数据拆分到不同的数据库中。结合现在的例子,就是把交易、商品、用户的数据分开。
这样的变化需要让应用配置多个数据源,这就增加了所需的配置。不同业务的数据从原来的一个数据库中拆分到了多个数据库中,那么就需要考虑如何处理原来单机中跨业务的事务。一种办法是使用分布式事务,其性能要明显低于之前的单机事务;而另一种方法就是使用冗余建表。
与数据库垂直拆分对应的还有数据水平拆分。数据水平拆分就是把同一个表的数据拆分到两个数据库中。产生数据水平拆分的原因是某个业务的数据表的数据量或者更新量达到了单个数据库的瓶颈,这时就可以把这个表拆分到两个或者多个数据库中。数据库水平拆分与读写分离的区别是,读写分离解决的是读压力大的问题,对于数据量大或者更新量的情况并不起作用。数据库水平拆分与数据库垂直拆分的区别是,垂直拆分是把不同的表拆分到不同的数据库中,而水平拆分是把同一个表拆分到不同数据库中。
我们来分析下水平拆分后给业务应用带来的。首先,访问用户信息的应用系统需要解决SQL路由的问题,因为现在用户信息分在了两个数据库中,需要在进行数据库操作时了解需要操作的数据在哪里。此外,主键的处理也会变得不同。原来依赖单个数据库的一些机制需要变化,例如MYSQL表上的自增字段,现在不能简单地继续使用了。并且在不同数据库中也不能直接使用一些数据库的限制来保证主键的不重复了。
前面所讲的读写分离、分布式存储、数据垂直拆分和数据水平拆分都是在解决数据方面的问题。下面我们来看看应用方面的变化。
之前解决了应用服务器从单机到多机的扩展,应用就可以在一定范围内水平扩展了。随着业务的发展,应用的功能会越来越多,应用也会越来越大。我们需要考虑如何不让应用持续变大,这就需要把应用拆开,从一个应用变为两个甚至多个应用。我们来看两种方式。
第一种方式,根据业务的特性把应用拆开。在我们的例子中,主要的业务功能分为三大部分:交易、商品和用户。我们可以把原来的一个应用拆分以交易和商品为主的两个应用,对于交易和商品都会有涉及用户的地方,我们让这两个系统自己完成涉及用户的工作,而类似用户注册、登陆等基础的用户工作,可以暂时交给两系统之一来完成。
我们根据业务的不同功能拆分了几个业务应用,而且这些业务应用之间不存在直接的调用,它们都依赖底层的数据库、缓存、文件系统、搜索等。这样的应用拆分确实能够解决当下的一些问题,不过也有一些缺点。
随着业务拆分越来越小,存储系统越来越大,应用系统的整体复杂度呈指数级增加,部署维护越来越困难。由于所有应用都要和所有数据库系统连接,在数万台服务器规模的网站中,这些连接的数目是服务器规模的平方,导致存数据库连接资源不足,拒绝服务。
既然每一个应用系统都需要执行许多相同的业务操作,比如用户管理、商品管理等,那么可以将这些共用的业务提取出来,独立部署。由这些可复用的业务连接数据库,提供共用的业务服务,而应用系统只需要管理用户界面,通过分布式服务调用共用业务服务完成具体业务操作。
上图与之前的结构相比有几个很重要的变化。首先,业务功能之间访问不仅是单机内部的方法调用了,还引入了远程的服务调用。其次,共享的代码不再是散落在不同的应用中了,这些实现被放在了各个服务中心。第三,数据库的连接也发生了一些变化,我们把与数据库的交互工作放到了服务中心,让前端的Web应用更加注重与浏览器的交互工作,而不必过多关注业务逻辑的事情。连接数据库的任务交给相应业务服务中心了,这样就可以降低数据库的连接数。而服务中心不仅把一些可以共用的之前散落在各个业务的代码集中了起来,并且能够使这些代码得到更好的维护。第四,通过服务化,无论是前端Web应用还是服务中心,都可以是由固定小团队来维护系统,这样能够更好地保持稳定性,并能更好地控制系统本身的发展。
关于什么是模式,这个来自建筑学的词汇是这样定义的:“每一个模式描述了一个在我们周围不断重复发生的问题及该问题解决方案的核心。这样,你就能一次又一次地使用该方案而不必做重复工作”。模式的关键在于模式的可重复性,问题与场景的可重复性带来解决方案的可重复使用。网站架构也有一些共同的模式,这些模式已经被许多大型网站一再验证,通过这些模式的学习,我们可以掌握大型网站的一般思路和解决方案,以指导我们的架构设计。
分层是企业应用系统中最常见的一种架构模式,将系统在横向维度上切分为几个部分,每个部分负责一部分相对比较单一的职责,然后通过上层对下层的依赖和调用组成一个完整的系统。
分层结构在计算机世界中无处不在,网络的七层通信协议是一种典型案例。在大型网站架构中也采用分层结构,将网站软件系统分为应用层、服务层、数据层。
通过分层,可以更好地讲一个庞大的软件系统切分为不同的部分,便于分工合作开发和维护;各层之间具有一定的独立性,只要维持调用接口不变,各层可以根据具体问题独立演化发展而不需要其它层做出相应调整。
如果说分层是将软件在横向方面进行切分,那么分割就是在纵向方面对软件进行切分。网站越大,功能越复杂,服务和数据处理的种类也越多,将这些不同的功能和服务分割开来,包装成高内聚低耦合的模块单元,一方面有助于软件的开发和维护;另一方面便于不同模块部署。
对于大型网站,分层和分割的一个主要目的就是为了切分后的模块便于分布式部署,即将不同模块部署在不同的服务器上,通过远程调用协同工作。分布式意味着可以使用更多的计算机完成同样的功能,计算机越多,CPU、内存、存储资源也就越多,能够处理的并发访问和数据量也就越大,进而能够为更多的用户提供服务。但分布式在解决网站高并发问题同时也带来了其它问题。首先,分布式意味着服务调用必须通过网络,这可能对性能造成比较严重的影响;其次,服务器越多,服务宕机的概率也就越大;另外,数据在分布式环境中保持一致性也非常困难,分布式事务也难以保证,这对网络业务正确性和业务流程有可能造成很大影响。
缓存就是改善软件性能的第一手段,大型网站架构设计在很多方面都使用了缓存设计,例如CDN、反向代理、本地缓存、分布式缓存。使用缓存有两个前提条件,一是数据访问热点不均衡,某些数据会被更频繁的访问,这些数据应该放在缓存中;二是数据在某个时间段有效,不会很快过期,否在缓存的数据会因为已经失效而产生脏读,影响结果的正确性。网站应用中,缓存除了可以加快数据访问速度,还可以减轻后端应用和数据存储的负载压力,这一点对网站数据库架构至关重要。
计算机软件发展的一个重要目标和驱动力就是降低软件耦合性。事物之间直接关系越少就越少被彼此影响,越可以独立发展。大型网站架构中,系统解耦的手段除了前面提到的分层、分布式等,还有一个重要手段是异步,业务之间的消息传递不是同步调用,而是将一个业务操作分为多个阶段,每个阶段之间通过共享数据的方式异步执行。在单一服务器内部就可通过多线程共享内部队列的方式实现异步,处在业务操作前面的线程将输出写入到队列,后面的线程从队列中读取数据进行处理。在分布式系统中,多个服务器集群通过分布式消息队列实现异步。使用异步队列还有如下特性。
提高系统可用性:消费者服务器发生故障,数据会在消息队列中存储堆积,生产者服务器可以继续处理业务请求,系统整体表现无故障。消费者服务恢复正常后,继续处理消息队列中的数据。
加快网站效应速度:处在业务处理前端的生产者服务器在处理完业务请求后,将数据写入消息队列,不需要等待消费者服务器处理就可以返回,响应延迟减少。
消除并发访问高峰:用户访问网站是随机的,存在高峰和低谷,即使按照网站一般访问高峰进行规划和部署,也依然会出现突发事件,比如促销、热点事件都会造成网站并发访问突然增大,这可能会造成整个网站负载过重,响应延迟,严重时甚至会造成服务宕机情况。使用消息队列将突然增加的访问请求数据放入消息队列中,等待消费者服务器依次处理,就不会对整个网站负载造成太大压力。具有削峰的特性。
网站需要7*24小时连续运行,但是服务器随时都可能出现故障,特别是服务器规模较大时,出现某台服务器宕机是必然事件。要想保住在服务器宕机的情况下网站依然可以继续服务,不丢失数据,就需要一定程度的服务器冗余运行,数据冗余备份,这样当某台服务器宕机时,可以将其上的服务和数据转移到其他机器上。
一般来说,除了当前的系统功能需求以外,软甲架构还需要关注性能、可用性、伸缩性、扩展性和安全性这5个框架要素,架构设计过程需要平衡这5个要素之间的关系以实现需求和架构目标,也可以通过考察这些架构要素来衡量一个软件架构设计的优劣,判断其是否满足期望。
性能
衡量网站性能有一系列指标,重要的有响应时间、TPS、系统性能计数器等,通过测试这些指标以确定系统设计是否达到目标。这些指标也是网站监控的重要参数,通过监控这些指标可以分析系统瓶颈,预测网站容量,并对异常指标进行报警,保障系统可用性。
可用性
对于大型网站而言,特别是知名网站,网站宕掉、服务不可用是一个重大的事故。因为网站使用的服务器硬件通常是普通的商用服务器,这些服务器的设计目标本身并不保证高可用,也就是说,很有可能会出现服务器硬件故障,也就是俗称的服务器宕机。大型网站通常都会有上万台服务器,每天都必定会有一些服务器宕机,因此网站高可用架构设计的前提是必然会出现服务器宕机,而高可用设计的目标就是当服务器宕机的时候,服务或者应用依然可用。网站高可用性的主要手段就是冗余。应用部署在多台服务器上同时提供服务,数据存储在多台应用服务器通过负载均衡设备组成一个集群共同对外提供服务,任何一台服务器宕机,只需把请求切换到其他服务器就可实现的高可用,但是一个前提条件是应用服务器上不能保存请求的会话信息。否则服务器宕机,会话丢失,即使将用户请求转发到其他服务器也无法完成业务处理。对于存储服务器,由于其上存储着数据,需要对数据进行实时备份,当服务器宕机时需要将数据访问转移到可用的服务器上,并进行数据恢复以保证继续有服务器宕机的时候数据依然可用。
伸缩性
大型网站需要面对大量用户的高并发访问和存储海量数据,不可能只用一台服务器就处理全部用户请求,存储全部数据。网站通过集群的方式将多台服务器组成一个整体共同提供服务。所谓的伸缩性是指通过不断向集群中加入服务器的手段来缓解不断上升的用户并发访问压力和不断增长的数据存储需求。衡量架构伸缩性的主要标志就是是否容易向集群添加新的服务器。加入新的服务器后是否可以提供和原来的服务器无差别的服务。集群中可容纳的总的服务器数量是否有限制。对于应用服务器集群,只要服务器上不保存数据,所有服务器都是对等的,通过使用合适的负载均衡设备就可以向集群中不断加入服务器。而对于缓存服务器集群,加入新的服务器可能导致缓存路由失效,进而导致集群中大部分缓存数据都无法访问。
扩展性
不同于其他架构要素主要关注非功能性需求,网站的扩展性架构直接关注网站的功能需求。网站快速发展,功能不断扩张,如何设计网站的架构使其能够快速响应需求变化,是网站可扩展架构主要的目的。衡量网站架构扩展性好坏的主要标准就是在网站增加新的业务产品时,是否可以实现对现有产品透明无影响,不需要任何改动或者很少的改动既有业务功能就可以上线新产品。不同产品之间很少耦合,一个产品改动对其他产品无影响,其他产品和功能不需要受其牵连进行改动。网站可扩展性的主要手段是事件驱动架构和分布式服务。事件架构驱动在网站主要通过消息队列实现,将用户请求和其他业务事件构造成消息发布到消息队列,消息的处理分离开来,可以透明地增加新的消息生产者任务或者新的消费者任务。分布式服务则是将业务和可复用服务分离开来,通过分布式服务框架调用。新增产品可以通过调用可复用的服务实现自身的业务逻辑,而对现有产品没有任何影响。