大型网站架构的演进

大型网站是指访问量和数据量都是海量级别的网站系统,大型网站每天的页面浏览量(PV)、访问量都十分巨大,需要支持高并发;此外,大型网站的数据量也十分巨大,本身的业务也很复杂,需要的技术也最复杂,如:分布式、缓存、读写分离、分库分表、SOA等等。

但是,万丈高楼平地起,大型网站也是由简单的单机系统逐渐构建起来的,所为本文就介绍一下大型网站的演进过程,以及演进过程中遇到的问题及应对策略。(本文的技术栈为Java、MySQL)

1 单机应用

在数据量和访问量都很小的网站初期,一般会把多个软件都跑在同一个机器上面,即所谓的单机系统。此时,我们可能使用容器 tomcatjboss等,然后直接使用 JSP/ Servlet技术,或者开源框架组合 SSHSSM,最后再选用数据库来存储数据,如: mysqlsqlserveroracledb2等。综上所述,一个小型的单机系统就可以运行了。

图1

2 应用和数据库分离

随着网站的应用逐渐复杂,系统的访问量增大,服务器的负载压力变大,就需要升级系统,提高负载能力。有资金实力的,可以增加单机性能,但是在超过一定的限度后,性价比较低。此时,增加机器是一个不错的解决方法,即有效提升系统负载能力,又有较高的性价比。

在增加机器后,可以把应用和数据库拆开放到不同的机器上,不仅可以提高单机的负载能力,也可以提高容灾能力。

图2

3 应用服务器集群

随着访问量继续加大,单机应用已经无法满足负载需求,此时,可以增加应用服务器的数量,从单台变为多台,把用户的请求分散到不同的服务器中,来提高负载能力。在应用服务器集群中,不可避免的会遇到服务器出现故障的情况,其中 keepalived是一款故障切换软件,配合 ipvsadm即可以切换故障,又可以做负载均衡,功能十分强大。

图3

系统演变到这里会遇到一些问题,即:如何决定某台服务器来响应当前用户的请求,以及在应用集群中会话状态如何保持或者同步。

下面主要介绍一下会话( Session)的同步问题。

3.1 Session Sticky

把同一个用户在一个回话中的请求都分配到固定的服务器中处理,就可以避免跨服务器的 Session问题,常用算法有: sh(原地址散列)、 dh(目标地址散列)等。

优点:实现简单

缺点: Session在应用服务器重启后消失

图4

3.2 Session Replication

在应用集群中复制 Session,使得每个服务器都保存有全部用户的 Session数据。

优点:不需要实现算法来实现请求转发

缺点:复制 Session时带宽消耗较大,当访问量大时, Session要占用大量内存

图5

3.3 Session 集中存储

Session集中存储到一个地方,提供给所有的应用服务器访问,保证了不同服务器访问到的 Session数据是一样的,适用于访问量比较大的场景中。

优点:解决了 Session复制占用内存和带宽的问题,某台应用服务器的故障不会影响其它服务器正常使用 Session

缺点:读取 Session时引入了网络操作,增加了延时和不稳定性,如果存储 Session的机器或者集群出现问题,将严重影响系统使用

图6

3.4 Cookie Based

Session存储在 Cookie中,用户请求时,服务器根据 Cookie来生成对应的 Session数据。

优点:实现简单,基本不需要维护

缺点: cookie长度有限制,安全性较差,消耗额外的带宽

图7

4 读写分离

当网站的访问量继续提高,数据库的读写压力就增大了,但对于数据库来说,无法简单的应用集群来解决压力问题,因为数据会不一致,所以常用的解决方案就是读写分离。其中,写库走主库,事务中的读也要走主库,其它的读操作可以使用从库。

图8

数据库的读写分离带来的问题有主从数据库的数据同步问题,针对这个问题,可以采用 MySQL自带的主从模式实现主从复制,也可以使用数据库中间件 MyCAT

5 引入搜索引擎

数据库的模糊查找比较影响性能,即使做了读写分离,依然存在这个问题,用户在查找数据时,常常用到模糊搜索,一般使用 like来实现,但是代价比较大,所有可以使用搜索引擎来实现,来解决模糊查找的 问题。

优点:大大提高查询速度

缺点:增加了维护工作,需要自己实现索引的构建过程,需要维护搜索引擎集群

图9

6 添加缓存

随着网站访问量的进一步加大,数据库的压力越来越大,每次访问都和数据库交互,会十分影响系统的响应速度,所以可以使用缓存技术。针对热点数据,直接从内存中取出来返回,加快响应速度。常用的缓存技术方案有: MemcachedRedis等。

针对缓存的不同机制,可以分为数据缓存页面缓存

6.1 数据缓存

大型网站添加缓存主要用来分担数据库的读压力,一般情况下,缓存中存放的是 热数据,而不是全部数据。缓存的更新方式是在更新数据库时,同步的更新缓存,保持缓存中的数据和数据库中的数据是一致的。当缓存容量不够时,根据 LRU原则清除部分缓存数据。

图10

6.2 页面缓存

最终展示给用户的是页面,对于一些访问量特别高的动态页面,也可以采用缓存技术,将页面缓存起来,利用 ESI规范,加快请求的响应。

优点:减轻数据库压力,大幅度提高访问速度

缺点:需要维护缓存服务器,提高了编码的复杂性

7 引入分布式存储系统

在需要大容量、高并发、容灾支持的系统中,常用的关系型数据库并不是十分合适,所以需要新的存储系统,即分布式存储系统,包括下面 3种:

7.1 分布式文件系统

在分布式环境中由多个节点组成的功能与单机系统一样的文件系统,它是弱格式的,如: MongoDBFastDFSHDFS

7.2 分布式 Key-Value系统

比分布式文件系统会更加格式化一些,提供了高性能的半结构化的数据存储支持

7.3 分布式数据库

格式化最规范的存储方式,支持大容量和高并发

图11

8 数据库的拆分

在网站的业务越来越复杂,数据量也越来越大时,所有的业务都存储的单一的数据库中,但是单一的数据库或者已经做了读写分离但是依然无法满足系统性能的要求,解决这样的数据库瓶颈问题,可以采用数据的垂直拆分水平拆分

8.1 水平拆分

数据的水平拆分是把同一张表的数据拆分到多个数据库中。

优点:解决数据量爆炸性增长,数据库单表容量有限的问题

缺点:存在 SQL路由的问题,及夸数据库的事务问题

针对缺点的解决方法可以采用数据库中间件 MyCAT,也可以不用数据库的自增主键,自定义唯一主键的方式

图12

8.2 垂直拆分

数据的垂直拆分是把数据库中的不同业务拆分到不同的数据库中

优点:解决了数据库的压力,可以更加业务特点做优化

缺点:需要维护多个数据库,针对复杂业务需求会降低查询性能,存在跨数据的 join和事务问题

解决方案是尽量避免跨数据库的事务,或者采用单一查询,也可以利用 MyCat的跨库方案来解决

图13

9 拆分应用

当业务越来越多,应用系统会变得十分庞大,这时就需要考虑如何避免系统变臃肿而难以维护,拆分应用是一个不错的解决方案。根据业务把应用拆开,从一个应用变成多个应用,各个业务不存在直接的调用情况。但是拆分应用,不可避免地存在着冗余代码的问题。

图14

10 SOA架构

对于系统中不同的业务,以及一些公共的业务部分,还可以进一步优化,比如采用 SOA架构,把这些业务进一步拆分出来,形成服务化的结构,不仅可以解决冗余代码的问题,也可以使不同业务间调用解耦。

图15

11 引入消息中间件

消息中间件提供了消息的异步和解耦的功能,是分布式系统中完成消息收发的基础软件,常用的有: DubboActiveMQ,配合 ZooKeeper使用,可以使系统解耦更彻底,并且也可以做消息的分析、网站的成长预测等。

图16


大型网站的演进基本如上所述,但是也没有固定的模式,也不会适合所有的网站,具体选择哪种模式还要根据业务量和遇到的问题做具体的分析。但是,熟悉常见的网站演进模式,在遇到具体的问题时,可以快速找到适合自己网站的架构。(文中的图片来自互联网,版权归原作者所有)

参考资料

《大型网站系统与Java中间件实践》

阿里P9架构师简述从单机至亿级流量大型网站系统架构的演进过程

热心留言

电子邮件地址不会被公开。