程序员面试必备:如何设计大型网站系统及技术指标解析
码农有道作了部分修改
程序员在面试时,很多情况下面试官会考察你对于一个大型网站系统的设计思路。
我们首先要思考一个问题,什么样的网站属于大型网站呢?从网站的技术指标角度来考虑这个问题时,人们很容易犯一个毛病,那就是认为网站的访问量是衡量的指标。懂点行的人或许会认为,应该以网站在单位时间里的并发量的大小作为指标。如果按照这些标准来看,像 hao123 这样的网站就会被认为是大型网站了。
这种网站的访问量很大,并发数也很高。然而,它却能通过最为简单的 Web 技术来实现。只要将网站充分静态化,多部署几台服务器,即便地球上所有人都使用它,网站也能正常运行。
大型网站是技术与业务的结合。如果一个满足某些用户需求的网站,其技术难度很大或者业务难度很大,那么企业就必然会投入更多且更优秀的人力成本来实现它,这样的网站就是所谓的大型网站。
在互联网时代,构建一个大型网站是一项不可或缺的技能。目前,我所接触到的网站大多是读的内容远远多于写的内容。本文将逐步讲述如何使用 lamp 来构建一个完善的大型网站(读大于写)。
网站架构方面,我个人觉得最重要的有两方面考量。一方面是计算,另一方面是存储。其中有些是属于计算方面比较密集的,有些则是属于 IO 方面比较密集的。因此,接下来都将围绕计算和存储来阐述相关问题。
最简单的搭建
假设我们自己创业了,那么我们可能需要自己去搭建一个网站。
这个时候,我们得去租一个主机,像阿里云的虚拟主机之类的。对于网站而言,数据是极为重要的,所以得有一个备份。然而每天的 pv 肯定不会高,从理论上讲,只需要一台计算机器就可以了。因此,我们仅需 3 台机器就能构建出一个完整的架构。
从上图能够看到,在计算机器上主要部署了两部分内容。其中一部分是 webserver,像 niginx、lighttpd 等这类轻量级的都可以考虑;另一部分是 UI 逻辑处理部分。对于 lamp 架构,使用 php 语言来解决这个问题。由于数据是最为重要的,所以很明显 database 需要 2 台机器,一台作为主机,另一台用于做冗余备份。lamp使用mysql来存储数据。
增加数据缓存
我们的网站知名度提升后,每天的 pv 变得越来越大。这带来的问题是数据库压力逐渐增大。很显然,绝大多数网站的读流量要远远高于写流量。即便我们开启了 mysql 的 query cache,它也只是能在一定程度上通过降低 DB 机器 I 的操作来减轻 DB 服务器的压力。更可靠的做法是减少对 DB 服务器的请求。那么这个时候就需要使用cache.
cache 属于非关系型 kv 存储,在使用期间通常是进行内存操作。以下是架构的改进情况:
可以看出,ui 写数据时是直接写入到数据库的。而读数据时,首先会从 cache 读取,如果在 cache 中读取不到,就会从 database 读取。因为很有可能大部分数据通过直接访问 cache 就能够完成,所以这样做就能够大大降低数据库的压力。
增加计算机集群(计算方向)
整个系统的 pv 持续上涨。单台计算机器已无法满足需求。此时需通过增加计算机器来解决问题。为方便起见,可将此机器放入一个集群进行统一管理。
这个时候,我们或许要考虑两个问题,分别是负载均衡以及数据同步。负载均衡系统的难度相对较大,然而它却是不可或缺的。其中,最简单的方式可以借助 zookeeper 等对配置文件进行统一管理。对于节点下的多台机器,能够通过概率来简单地进行请求分发。数据同步也是一个难题,像 session 同步以及文件操作等情况都包含在内。
如果 N 台机器能撑住的 PV 为 X,那么 T 乘以 N 台机器基本能撑住 T 乘以 X 的 pv。这意味着架构需要具备横向扩展的能力。若机器数量增加一倍,然而撑住的峰值 pv 不能增加(接近)一倍,那么这个架构就是失败的架构,并非可扩展性的架构。
可以看出在负载均衡系统下能够挂载许多机器。好的扩展情况是,加入的机器数量是原来的多少倍,其计算能力就会相应地提高多少倍(暂不考虑存储的瓶颈)。
搭建简单的数据库集群(存储方向)
流量上升且计算能力提升时,需要提升数据库的能力。此时,我们可采用读写分离,也就有了主从之说。主库能够进行写操作,当然也肯定具备写的能力,从库只能提供读的服务。目前我们的主从延时在 20ms 以内。目前有不少这样的工具,例如 mysql proxy 等。下图展示的是 ui logic 对 dbproxy 的访问,图中存在些许错误,但这并不影响对其的理解。
如上图,dbproxy作用主要有3个:
读写分离:读主要读从库,而写只能是写主库。在实际设计时,我们需要考虑主从延时的情况,例如事务读必须读主库,在写完若干秒内最好读主库等。
负载均衡的作用是,它能够自动依据 dbproxy 所挂接的数据库来实现负载均衡。
dbproxy 维持着 sql 连接池,该连接池中存在与 db 的长连接。当请求到来时,能够直接从连接池中获取连接。
静态页面跨地域缓存
我们的网站有很多静态页面,更换频率是若干天一次。由于存在跨地域、跨机房的问题,外地用户访问时可能会较慢。因此,我们可以借助 cdn 等技术来缓存静态页面,这样既能减少对服务器的请求,又能加快外地以及不同机房用户的访问时间。
如上图所示,加入了静态页面缓存
跨地域跨机房设计
当我们的业务进一步拓展,有可能需要在不同地域进行机器部署。目前,我们主要有华北(北京)和华东机房(杭州、南京)这两个区域。进行跨地域部署,能够加快因区域差异而导致的访问过慢的问题。例如,广州访问北京机房的数据,其速度不如北京本地访问北京机房的速度快。在这种情况下,仍然主要从计算和存储这两个方面来进行阐述。
1:计算方向
除了该机房的标示以外,各个机房的机器部署应该完全一致。
2:存储方向
在我看来,对于那种读远远超过写的系统来说,最好是只有一个主库,同时有若干个从库。因此只需要在其他机房搭建从库,让从库从主库获取数据并进行同步就可以了。当然,这样做的代价就是主从时间比会比较长。当数据链路不稳定时,主从同步可能会超过 400ms,所以在设计的时候需要考虑到这一点。
当然cache等等也需要跨地域跨机房部署。
如图简要勾勒出了跨地域跨机房的一个部署方案。
通用服务的使用
随着业务拓宽,我们可能会有一些需要考虑新能的模块或者业务。
对于搜索业务,我们无法直接借助数据库的 select like 来达成目标。这就要求我们运用 C 等编译型语言去搭建其他系统。因此,我们需要依据业务进行架构调整,以便通过 http 等方式利用一些通用的、高性能计算方向的服务。
同样,基于业务发展等方面的考虑,我们有使用内存型数据库的需求,像 redis 等这类数据库。这些数据库属于存储领域的通用服务。
这些服务中,有些能够跨机房进行部署,并且各个机房之间没有耦合;而有些服务则相互之间存在耦合,例如像数据库的主库从库那样的情况。
其它考虑
除此以外,我们还需要有其他因素进行考虑
网站数据方面,主要有诸如 uv/pv 等内容。其有以下几种做法,一是借助像百度统计、Google 统计这类的第三方统计工具;二是对我们现有的系统日志进行统计,并且能够在此基础上进行更深入的数据挖掘。
安全性方面需要考虑网站是否存在 sql 注入、xss 漏洞、csrf 漏洞等情况。这对于网站而言极为关键。一旦有黑客攻入,其后果将不堪设想。对于管理员后台,最好不要开通外网权限,而应仅通过内网进行访问。
搜索引擎优化对网站有着重要作用。 后续可能会专门对百度的搜索引擎优化进行一些分析。
文章评论