大型互联网系统设计综述

前言

1994年,中国科学院设立了中国第一个web服务器,推出了中国第一个网站。刚刚过去的2015年双十一,阿里巴巴当日线上交易额超过700亿,支付宝交易峰值为8.95万笔/秒。中国的互联网,正在以难以想象的速度释放着它的能量。css

大众对互联网爆炸式的需求,不断推进着互联网技术向着更高的层次发展,从最初的静态新闻展现,到大型的电子商务平台,网站技术突飞猛进。也许在四五年前,咱们谈到网站制做,想到的仍是Html、IIS、论坛系统,可是如今推出一个网站,已经不是简简单单开发一套供人浏览的Html那么容易,而是要克服高并发、高可用、大容量、体验友好、可扩展等诸多设计和技术上的难题。html

本文从技术角度简要分析设计大型互联网系统的一些考虑因素,没有高深之语,只是工做读书之余的总结。前端

1、互联网技术的学习历程

事物的发展老是按部就班,不可能一蹴而就。java

2003年的淘宝网最初是基于经典的开源黄金搭档LAMP(Linux+Apache+Mysql+PHP)创建的。当时的淘宝,比如学武之人刚刚练就一套太祖长拳,只是可以作到行走江湖不吃亏。后来随着业务的不断扩大,系统通过不断从新设计和优化,可以支撑的访问量也从百万级别逐渐上升的千万级别。此时的淘宝网,就已经脱胎换骨,不但吸收了众家之长融会贯通,并且可以自创武功,足以笑傲江湖了。linux

一、仍是从最简单的场景提及。搭建一个网站其实很简单,写几个Html文件,运行一个web服务器软件,就能够经过浏览器访问之,这样网站就算建成了,可以为用户提供浏览html网页的服务。git

二、静态的Html网页其实没什么看头,没有新鲜的资讯吸引用户的网站是不会有什么访问量的,因而动态网页技术应运而生。管理员能够随时发布和管理资讯,用户可以看到更多的动态的内容,这种网站能够称做是CMS系统,例如帝国CMS、Joomla、PHPCMS等。程序员

大部分同窗通过学校的课程或者自学,都可以掌握制做动态网站的技术,从而掌握从前端Html到后端数据库的相关技巧。达到这一阶段,就具有了行走江湖的资本,能够凭此手艺挣口饭讨生活了。可是此时若没能访得明师指点、增加见识,继而打通任督二脉,则会沉沦于庸常的增删改查之中,没法一窥网站技术之堂奥。github

三、所谓的名师指点,就是在大项目中遇到困难,由于困难是最好的老师。web

这里所说的困难多种多样:例如指访问量太大,网站撑不住了;业务需求爆炸,代码没法维护;前台交互繁琐,页面难看等等。每个困难要完全解决都不简单,一代一代的网站构架师,正式从不断地尝试解决这些困难的过程当中,成长起来的。算法

此时,最早想到的办法——借鉴成功的开源框架的经验。好比经典的SSH框架(Spirng+Struts+Hibernate),采用了通用的MVC分层模式,可以将业务逻辑、前端展现、持久化数据库隔离,并分别提供比较专业的解决方案;好比BootStrap,解决了前端显示的风格统一;好比Angularjs,让程序员从噩梦般的前端开发中脱离出来。在这个阶段,咱们参考了各式各样的框架设计,所谓观千剑然后识器,心中造成些许的丘壑,但尚不能融会贯通。

四、网站的业务更加复杂、访问量更大。要求咱们的视线从单纯的增删改查上跳出来,从总体上全面地重构系统。咱们要从前端想到后端,从高可用性考虑到安全性,从用户角度思考后再转过身来从开发者角度考虑。这样咱们被迫站到了新的高度,这是一个前所未见的绝地,没有现成的方案能够搬过来使用,在经历无数次反复思考和尝试以后,才会完成一个软件工程师到构架师的艰难转变。 

记得之前据说过一个理论,计算机领域的任何问题均可以经过增长一个虚拟层来解决。大型网站通用的分层策略是将网站分为应用层、服务层、数据层,下面首先分别讨论一下这三个层次所涉及到的技术要点。

2、应用层技术要点

应用层,即利用服务层提供的标准服务,对用户提供个性化的业务服务。

前端构架是这一层须要考虑的东西,前端框架须要考虑自适应用户的浏览器版本、屏幕尺寸,避免给用户带来糟糕的体验。

为了提升性能,前端设计须要考虑:

一、合理设置http meta中的缓存指令,利用浏览器缓存提升访问速度

二、为提升并发访问链接的数目,可将资源至于不一样的域名之下

三、减小页面cookies传输,提升传输效率

四、在服务器压缩图片和文件,在浏览器端进行解压,减小传输的数据量

五、合并css、JavaScript、合并图片,减小请求的次数

六、CSS放在页面最上面,JavaScript放到页面最下面。浏览器会在下载彻底部css以后才对页面进行渲染,为了让用户尽快看到页面,css文件要放在上面;相反,JavaScript加载以后会当即执行,这样会影响页面的显示速度,因此JavaScript要放到页面下面。

七、自适应的页面设计,知足不一样屏幕尺寸的要求

Angularjs是采用JavaScript编写的客户端MVC框架,由Google团队于2012年正式推出,Angularjs致力于帮助开发者编写现代化的单页应用,尤为适用于编写大量CRUD操做的、具备Ajax风格的富客户端应用。

Angularjs直接面向html操做,不鼓励进行DOM级别的操做。最具备吸引力的特性包括双向数据绑定、模块依赖注入、自定义指令等等。

Bootstrap是Twitter推出的一个用于前端开发的开源工具包。它由Twitter的设计师Mark Otto和Jacob Thornton合做开发,是一个CSS/HTML框架。附加大量的JavaScript插件,适合对CSS设计不熟悉的开发团队快速打造自适应的、简洁的前端页面。

3、服务层技术要点

服务层,是在业务梳理的基础上,将功能独立的业务单独提取出来,对外提供统一的无状态的服务,好比用户管理、产品管理、库存管理、订单管理等等。

一、应用层是如何知道有哪些服务可使用呢,这就须要一个高效率的服务注册、管理、发布机制,即分布式服务访问框架,例如阿里开源的Dubbo(http://dubbo.io/Home-zh.htm)以及谷歌的Grpc。

分布式服务访问框架通常能够分解为服务提供者(Provider)、服务消费者(Consumer)、注册中心(Registry)三个部分。

Provider:以接口的方式将服务注册到Registry,提供的信息包括服务的名称、版本、依赖、描述、所在机器地址等。

Registry:接收服务注册请求,对这些服务进行管理和维护,Dubbo采用开源Zookeeper做为本身的Registry。注册中心负责将服务注册信息的更新通知实时的Push给服务消费者(主要是经过Zookeeper的Watcher机制来实现的)。

Consumer:在启动的时候从服务注册中心获取须要的服务注册信息;将注册信息缓存到本地;监听服务注册信息的变动,如接收到服务注册中心的服务变动通知,则在本地缓存中更新服务的注册信息;

)来转发请求; 对服务提供方的存活进行检测,若是出现服务不可用的服务提供方,将从本地缓存中剔除;构造请求调用,从本地缓存列表中,采用负载均衡算法,选出合适的服务提供者进行服务调用。


图1 分布式服务框架结构

服务路由:若是多个Provider同时提供了相同的服务,就存在一个路由的问题,能够采用的机制有轮询、随机、根据时间的负载均衡机制等。可以实现软件层次的负载均衡,同时也知足了失效转移的要求(即一个服务失效,将请求转移到另一个可用的服务上去)。

底层通讯:基于RPC模式,封装Netty提供高效的异步IO通讯的能力。

链路维护:Provider、Registry、Consumer之间采用心跳检测机制维护链路的可用性,发现链路不可用、或者服务不可用时,能够及时予以告警,实现高可用性。

通讯格式:可选择使用xml、json等等。

ZooKeeper简介:http://www.cnblogs.com/mingziday/p/5182550.html

4、数据层技术要点

数据层有时候又称为持久层,即将数据持久化到数据库的过程。随着数据存储量的增大,数据查询会愈来愈慢,单一数据库服务不能知足大容量的要求,因而对数据层进行改形成为必然的抉择。

一、改造数据库结构,设置合理的索引;将大数据字段进行拆分。

二、数据库的读写分离,由一个读写库拆分为一个写库+若干读库的结构,读写库之间经过定时复制机制实现同步。

三、分库,分为垂直分库和水平分库。垂直分库是将不一样的业务数据放到不一样的数据库中,水平分库是指依据某种拆分原则,把一个表分为相同结构的若干个表,分到不一样的数据库中。进行分库以后,要考虑数据库之间的联合查询该怎么处理,例如阿里构架师行颠研发的数据库路由框架DBRoute,统一处理了数据的合并排序分页,让程序员像使用一个数据库同样使用多个数据库。

四、支持异构数据库的统一处理,例如Mysql、Oracle,可以对外展现透明的访问接口,即对上层屏蔽了不一样数据库的差别。

五、数据量持续加大,考虑采用分布式数据库中间件,例如阿里的Cobar。不但支持分库、屏蔽数据库异构,并且提供动态伸缩的能力,提供SQL的汇聚、分析、和优化能力。

目前比较成熟的分布式数据库开源系统主要有Amoeba(http://sourceforge.net/projects/amoeba/)

以及阿里开源的Cobar https://github.com/alibaba/cobar)

六、采用集群数据库缓存,使得大部分热点数据都从缓存获取,提升数据访问效率。例如memcached就是一款比较流行的数据库缓存系统,将在下面一节介绍。

5、缓存技术在互联网构架中的应用

缓存就是讲数据放在距离用户最近的位置以缩短处理流程、加快传输速度。

下面是一个常见的网站访问流程框架:

 

图2 缓存在web访问流程中的位置

一、浏览器缓存

http meta中的Cache-Control、Expire等设置,可以控制用户浏览器缓存。

二、CDN

CDN,Content Delivery Network,即内容分发网络,部署在距离终端用户最近的网络服务商的机房里面(即所谓网络访问第一跳),服务器端的大量静态资源放置于CDN中,是一种比较特殊并且实用的缓存技术。

三、RedWare硬件负载均衡器

基于IP+Port级别的负载均衡器,有效对网络流量进行分流

链路层负载均衡:不一样于RedWare的Ip级别的负载均衡。顾名思义,链路层负载均衡是在TCP协议的链路层进行操做。当数据请求到达后,其IP地址并不被修改,修改的是mac地址,将数据包路由给响应的服务器,服务器处理完成后,能够直接返回数据给客户,没必要通过负载均衡器。Linux平台上最好的链路负载均衡器为LVS(Linux Virtual Server,章文嵩博士发起的最先的开源项目之一)

四、Nginx

反向代理服务器,能够做为应用级别的负载均衡器使用,根据Url的不一样将访问转发到不一样的内部服务器

来自互联网的访问请求必须通过反向代理服务器,至关于在web服务器和网络攻击之间创建了一个屏障,起到安全防御的做用;反向代理服务器也能够配置缓存功能加速web请求;反向代理也能够实现负载均衡配置,进而改善网站高并发下的性能。

另一款著名的反向代理服务器是Squid,官网http://www.squid-cache.org

五、Varnish

静态资源(img/css/html)缓存服务器,Nginx根据路由策略,会将静态资源路由到Varnish,命中后直接返回缓存的资源

六、分布式缓存服务器

Memcached,最经常使用的分布式内存对象缓存系统。其缓存服务器和应用服务器分开部署,应用服务器经过Hash路由算法选择缓存服务器获取数据,缓存服务器之间不相互通讯,如图3所示。

和应用服务器集群不一样(各个服务器运行相同的应用),分布式缓存集群服务器中,不一样的服务器存储的是不一样的数据。

图3 Memcached集群和应用服务器的交互

图4 memcached的访问模型

memcached:一套分布式的高速缓存系统,由LiveJournal的Brad Fitzpatrick采用C语言开发,但目前被许多网站使用以提高网站的访问速度,尤为对于一些大型的、须要频繁访问数据库的网站访问速度提高效果十分显著。 memcached的通讯模块基于 Libevent ,是一个支持事件触发的网络通讯程序库。采用 key-vaule键值对 的方式存数数据,时间复杂度O(1),效率很是高;内存分配借鉴了Linux内存管理的 Slab机制 (寻找大于Size的最小内存块存储该数据);采用 LRU算法 淘汰最近最久未被访问的数据;只支持内存方式存储。

memcached访问过程如图4所示,应用程序输入须要写缓存的数据<BEIJING,DATA>,API将BEIJING输入路由算法模块,路由算法根据key和memcached集群服务器列表计算获得一台服务器编号NODE1,进而获得该机器的IP地址和端口10.0.0.0:91000。API调用通讯模块和NODE1的服务器通讯,将数据<BEIJING,DATA>写入分布式缓存中,读取数据的过程与之相似。
memcached采用固定内存分配,即将空间分配成固定的大小,存储数据的时候根据Size的大小,寻找一个大于Size的最小chunk将数据写入,避免频繁分配性能问题以及内存分片问题,但时也会引入内存浪费的问题。
当考虑加入一个新的缓存服务器的时候,由于路由算法没有改变,会致使大量的缓存不命中,所以没法支持动态伸缩,解决方法是采用一致性Hash算法

个人问题是,写入缓存的数据如何与数据库的数据保持同步?
这里介绍一下其它几种分布式缓存系统:
Tair: 淘宝开源缓存系统,支持内存/文件级别缓存,采用C++实现。
Redis :C语言实现,支持Set/Map/List等多种数据结构
Ehcache: 健全的,通过验证的,全特性的,使用普遍的分布式缓存实现,采用Java实现,支持内存/文件级别的缓存
Oracle coherence:这是一个基于Oracle的收费的缓存系统

缓存预热:缓存中存放的是热点数据,这些数据是经过大量用户的访问经过LRU算法筛选出来的。若是一开始就可以预料到哪些数据是热点数据,首先经过必定的手段将他们加载到缓存中,将大大提升缓存的利用率,例如热点促销商品的信息,就能够首先刷到缓存里面。

6、分布式技术

在上面提到了分布式缓存和分布式服务。所谓的分布式,就是把不一样的功能拆分到不一样的服务器去完成。要注意的是,分布式并非只有好处没有坏处。

一、分布式意味着服务调用必须经过网络,这可能带来比较严重的性能损耗。

二、分布式事务给业务的一致性要求带来很大挑战。

7、集群技术

说的简单点,网站经过集群的方式将多台提供相同服务的服务器当作一个总体对外提供服务,经过路由技术决定到底该访问那一台服务器。所谓集群的伸缩性,就是能够在访问压力大的时候,向集群中添加服务器以缓解压力;当访问压力变小的时候,能够把部分服务器分流出去,以节省成本。

集群提升了系统的总体可用性,当发现集群中的某个机器不可用的时候,能够将其从服务器剔除并发出告警。

灰度发布:是集群应用中的一个技巧,即网站新功能发布的时候不中断对外服务。先关闭服务器集群中部分机器的路由,更新软件包,重启服务,启动路由,当这部分新功能验证没有bug后,再用相似的办法更新其余服务器的服务。

8、异步

异步的设计思路是:用户请求发出后,服务端将请求加入消息队列中,直接返回,由单独的线程去处理队列中的请求。由于没有直接和数据库进行交互,因此可以很好改善响应速度,在高并发的时刻有很好的削峰做用。

异步消息队列的思想来源于事件驱动机制,即不依靠简单直接的函数调用来实现功能,而是借助事件消息的通讯完成模块之间的通讯,极大地下降了模块之间的耦合性

分布式消息队列:队列是一种先进先出的数据结构,分布式消息队列能够看作将这种数据结构部署到独立的服务器上。应用程序可使用远程访问接口分布式消息队列,进行消息存取操做,进而实现分布式的消息存取操做。

分布式消息队列利用发布-订阅模式工做。消息生产者经过远程访问接口将消息推送给消息度激烈服务器,消息队列服务器将消息写入本地内存后当即返回成功响应给消息生产者。消息队列服务器,查找消息订阅列表,找到须要给消息的消息消费者,并将消息队列中的消息以FIFO的方式发送给消息消费者。

异步的问题在于,后台线程在处理队列中的请求的时候可能会出现校验、操做数据库失败。例如在订单提交流程中,就不能直接给用户显示订单提交成功,取而代之,能够显示“您提交的订单已被接受,咱们会尽快反馈订单处理进度,请关注短信或者邮箱”。

目前异步消息处理框架有阿里的消息中间件RocketMQ(http://alibaba.github.io/RocketMQ-docs/document/design/RocketMQ_design.pdf)等等。

RocketMQ介绍:http://www.cnblogs.com/mingziday/p/5182551.html

9、其余提升性能的方法

一、代码优化

多线程编程,web服务器也是采用多线程的方式处理用户的并发请求的:避免全局变量,合理使用,无状态对象设计;

启用对象池、链接池(阿里Druid数据链接池),减小没必要要的资源损耗。

二、存储性能优化

采用RAID技术,提升数据读写的并发率、安全性

三、操做系统和文件系统

商用Linux操做系统并非专门针对web服务器进行设计,这就须要咱们对Linux的一些设定进行调优,以提升web服务器的数据访问性能。例如修改linux参数提升Tcpsocket使用的系统内存、修改最大并发连接数等等。

四、页面静态化

让访问不通过Java系统,只在到达web服务器以后就直接返回了,这样咱们缓存的是html页面,不是java数据。这就要求把html页面中cookies、时间、动态内容单独抽取出来。这些抽取出来的内容如何再组装起来呢,有两种方式,ESI和CSI。

ESI:在Web服务器上作动态内容请求,并将请求插入到html页面中,当用户拿到页面的时候已是一个完整的页面了。

CSI:在用户拿到页面以后,再单独发送一个js异步请求获取动态数据,服务器性能会更好,可是用户体验上有些延迟。

经过ESI组织成的html页面也能够缓存起来,这样用户直接冲缓存中直接拿到html,至关于到一个静态网站简单取一份数据而已,不涉及具体的逻辑计算,访问效率是很高的。可是天下没有完美的解决方案,这种状况要考虑cache失效问题。

10、其余技术

一、Session管理

http协议是一种无状态协议,而业务老是有状态的,好比购物车、用户登陆信心等等,在一个集群的应用服务器中,如何维持session是个必需要考虑的问题。经常使用的方法有session复制、session绑定(会话粘滞)、cookies记录session等。

最可靠的方式是使用独立的session服务器,即利用独立部署的session服务器管理一切session请求。

二、搜索引擎

Apache Lucene,是一款开源的全文检索系统(http://www.cnblogs.com/xing901022/p/3933675.html)

搜索引擎的原理,将热点数据经过同步方法从数据库中读取到硬盘/缓存里面。而后对这些数据创建高效的索引,经过全文检索算法,就可以快速定位出来。

三、服务幂等性

服务重复调用和第一次调用产生的结果相同。

例如一次调用服务超时失败了,但实际上该服务已经执行完成了。这个时候业务层面会尝试从新操做,就须要和第一次操做的时候产生同样的结果。

参考文献

《大型网站技术架构:核心原理与案例分析》

《淘宝技术十年》

《构建高性能WEB站点》

相关文章
相关标签/搜索