一、大型网站系统的特点

高并发,大流量

需要面对高并发用户,大流量访问。 Google 日均 PV 35 亿,日 IP 访问数 3 亿;腾讯 QQ 的最大在线用户数 1.4 亿

( 2011 年数据)。

高可用

系统 7 x 24 小时不间断服务。

海量数据

需要存储、管理海量数据,需要使用大量服务器。 Facebook 每周上传的照片数量接近 10 亿,百度收录的网页数

目有数百亿, Google 有近百万台服务器为全球用户提供服务。

用户分布广泛,网络情况复杂

许多大型互联网站都是为全球用户提供服务的,用户分布范围广,各地网络情况千差万别。在国内,还有各个运营 商网络互通难的问题。

安全环境恶劣

由于互联网的开放性,使得互联网站更容易受到攻击,大型网站几乎每天都会被黑客攻击。

需求快速变更,发布频繁

和传统软件的版本发布频率不同,互联网产品为快速适应市场,满足用户需求,其产品发布频率高。一般大型网站的产品每周都有新版本发布上线,中小型网站的发布更频繁,有时候一天会发布几十次。

渐进式发展

几乎所有的大型互联网网站都是从一个小网站开始,渐进地发展起来的。 Facebook 是扎克伯格同学在哈佛大学的 宿舍里开发的;Google 的第一台服务器部署在斯坦福大学的实验室;阿里巴巴是在马云家的客厅诞生的。好的互联网产品都是慢慢运营出来的,不是一开始就开发好的,这也正好与网站架构的发展演化过程对应。

二、大型网站架构演化发展历程

大型网站的技术挑战主要来自于庞大的用户,高并发的访问和海量的数据,任何简单的业务一旦需要处理数以 P 计的数据和面对数以亿计的用户,问题就会变得很棘手。大型网站架构主要解决这类问题。

初始阶段的网站架构

大型网站都是从小型网站发展而来,网站架构也是一样,是从小型网站架构逐步演化而来。小型网站最开始没有太多人访问,只需要一台服务器就绰绰有余

应用程序、数据库、文件等所有资源都在一台服务器上。

应用服务和数据服务分离

随着网站业务的发展,一台服务器逐渐不能满足需求:越来越多的用户访问导致性能越来越差,越来越多的数据导 致存储空间不足。这时就需要将应用和数据分离。应用和数据分离后整个网站使用3 台服务器:应用服务器、文件服务器和数据库服务器。这 3 台服务器对硬件资源的要求各不相同:

应用服务器需要处理大量的业务逻辑,因此需要更快更强大的 CPU ;

数据库服务器需要快速磁盘检索和数据缓存,因此需要更快的磁盘和更大的内存;

文件服务器需要存储大量用户上传的文件,因此需要更大的硬盘。

应用和数据分离后,不同特性的服务器承担不同的服务角色,网站的并发处理能力和数据存储空间得到了很大改善,支持网站业务进一步发展。但是随着用户逐渐增多,网站又一次面临挑战:数据库压力太大导致访问延迟,进而影响整个网站的性能,用户体验受到影响。这时需要对网站架构进一步优化。

使用缓存改善网站性能

网站访问的特点和现实世界的财富分配一样遵循二八定律: 80% 的业务访问集中在 20% 的数据上。既然大部分业务访问集中在一小部分数据上,那么如果把这一小部分数据缓存在内存中,就可以减少数据库的访问压力,提高整个网站的数据访问速度,改善数据库的写入性能了。 网站使用的缓存可以分为两种:缓存在应用服务器上的本地缓存和缓存在专门的分布式缓存服务器上的远程缓存。

本地缓存的访问速度更快一些,但是受应用服务器内存限制,其缓存数据量有限,而且会出现和应用程序争用内存的情况。

远程分布式缓存可以使用集群的方式,部署大内存的服务器作为专门的缓存服务器,可以在理论上做到不受内存容量限制的缓存服务。

使用缓存后,数据访问压力得到有效缓解,但是单一应用服务器能够处理的请求连接有限,在网站访问高峰期,应用服务器成为整个网站的瓶颈。

使用应用服务器集群改善网站的并发处理能力

使用集群是网站解决高并发、海量数据问题的常用手段。当一台服务器的处理能力、存储空间不足时,不要企图去更换更强大的服务器,对大型网站而言,不管多么强大的服务器,都满足不了网站持续增长的业务需求。这种情况下,更恰当的做法是增加一台服务器分担原有服务器的访问及存储压力。

对网站架构而言,只要能通过增加一台服

务器的方式改善负载压力,就可以以同样的方式持续增加服务器不断改善系统性能,从而实现系统的可伸缩性 。应用服务器实现集群是网站可伸缩架构设计中较为简单成熟的一种,如下图所示:

通过负载均衡调度服务器,可以将来自用户浏览器的访问请求分发到应用服务器集群中的任何一台服务器上,如果 有更多用户,就在集群中加入更多的应用服务器,使应用服务器的压力不再成为整个网站的瓶颈。

数据库读写分离

网站在使用缓存后,使对大部分数据读操作访问都可以不通过数据库就能完成,但是仍有一部分读操作(缓存访问 不命中、缓存过期)和全部的写操作都需要访问数据库,在网站的用户达到一定规模后,数据库因为负载压力过高而成为网站的瓶颈。 目前大部分的主流数据库都提供主从热备功能,通过配置两台数据库主从关系,可以将一台数 据库服务器的数据更新同步到另一台服务器上。网站利用数据库的这一功能,实现数据库读写分离,从而改善数据 库负载压力。

应用服务器在写数据的时候,访问主数据库,主数据库通过主从复制机制将数据更新同步到从数据库,这样当应用 服务器读数据的时候,就可以通过从数据库获得数据。为了便于应用程序访问读写分离后的数据库,通常在应用服务器端使用专门的数据访问模块,使数据库读写分离对应用透明。

使用反向代理和 CDN 加速网站响应

随着网站业务不断发展,用户规模越来越大,由于中国复杂的网络环境,不同地区的用户访问网站时,速度差别也极大。有研究表明,网站访问延迟和用户流失率正相关,网站访问越慢,用户越容易失去耐心而离开。为了提供更 好的用户体验,留住用户,网站需要加速网站访问速度。主要手段有使用 CDN 和方向代理。

使用分布式文件系统和分布式数据库系统

任何强大的单一服务器都满足不了大型网站持续增长的业务需求。数据库经过读写分离后,从一台服务器拆分成两台服务器,但是随着网站业务的发展依然不能满足需求,这时需要使用分布式数据库。文件系统也一样,需要使用分布式文件系统。

分布式数据库是网站数据库拆分的最后手段,只有在单表数据规模非常庞大的时候才使用。不到不得已时,网站更常用的数据库拆分手段是业务分库,将不同业务的数据部署在不同的物理服务器上。

使用 NoSQL 和搜索引擎

随着网站业务越来越复杂,对数据存储和检索的需求也越来越复杂,网站需要采用一些非关系数据库技术如 NoSQL 和非数据库查询技术如搜索引擎。

业务拆分

大型网站为了应对日益复杂的业务场景,通过使用分而治之的手段将整个网站业务分成不同的产品线。如大型购物 交易网站都会将首页、商铺、订单、买家、卖家等拆分成不同的产品线,分归不同的业务团队负责。

具体到技术上,也会根据产品线划分,将一个网站拆分成许多不同的应用,每个应用独立部署。应用之间可以通过 一个超链接建立关系(在首页上的导航链接每个都指向不同的应用地址),也可以通过消息队列进行数据分发,当然最多的还是通过访问同一个数据存储系统来构成一个关联的完整系统

分布式微服务

随着业务拆分越来越小,存储系统越来越庞大,应用系统的整体复杂度呈指数级增加,部署维护越来越困难。由于 所有应用要和所有数据库系统连接,在数万台服务器规模的网站中,这些连接的数目是服务器规模的平方,导致数据库连接资源不足,拒绝服务。

既然每一个应用系统都需要执行许多相同的业务操作,比如用户管理、商品管理等,那么可以将这些共用的业务提取出来,独立部署。由这些可复用的业务连接数据库,提供共用业务服务,而应用系统只需要管理用户界面,通过分布式服务调用共用业务服务完成具体业务操作。如下图所示:

java同时几万人登录设计_java同时几万人登录设计

三、拆分 VS 集群

1. 拆分:不同的 多台服务器上面部署不同的服务模块 ,模块之间通过 RPC 通信和调用,用于拆分业务功能,独立 部署,多个服务器共同组成一个整体对外提供服务。

2. 集群:不同的 多台服务器上面部署相同的服务模块 ,通过分布式调度软件进行统一的调度,用于分流容灾, 降低单个服务器的访问压力。

四、微服务 VS SOA

单体应用: ALL IN ONE

微服务是一种架构风格,一个大型复杂软件应用由一个或多个微服务组成。系统中的各个微服务可被独立部署,各个微服务之间是松耦合的。每个微服务仅关注于完成一件任务并很好地完成该任务。在所有情况下,每个任务代表着一个小的业务能力

微服务,从本质意义上看,还是 SOA 架构。但内涵有所不同,微服务并不绑定某种特殊的技术,在一个微服务的系统中,可以有 Java 编写的服务,也可以有 Python 编写的服务,他们是靠 Restful 架构风格统一成一个系统的。所以微服务本身与具体技术实现无关,扩展性强。

五、前后端完全分离与 Rest 规范

http 是目前在互联网上使用最多的协议,没有之一。可是 http 的创始人一直都觉得,在过去 10 几年来,所有的人都 在错误的使用Http 。

这句话怎么说呢?如果说你要删除一个数据,以往的做法通常是 delete/{id} ,如果你要更新一个数据,可能是 Post 数据放Body ,然后方法是 update/{id} , 或者是 artichle/{id}?method=update 。

这种做法让我很暴燥,我觉得这个世界不该这样的,所有的人都在误解而且在严重错误的误解 Http 的设计初衷,好比是发明了火药却只用它来做烟花爆竹。 那么正确的使用方式是什么呢?如果你要看Rest 各种特性,你恐怕真的很难理解 Rest ,但是如果你看错误的使用 http的人倒底儿了哪些错,什么是 Rest 就特别容易理解了。

第一条,混乱。 一万个人心里有一万个 Url 的命名规则, Url 是统一资源定位符,重点是资源。而很多人却把它当成 了万金油,每一个独立的虚拟的网页都可以随意使用,各种操作都能够迭加。这是混乱的来源之一。

第二条,贪婪。 有状态和无状态全部混在一起。特别是在购物车或者是登录的应用中,经常刷新就丢失带来的用户 体验简直棒棒哒。每一个请求并不能单独的响应一些功能,很多的功能混杂在一起里。这是人性贪婪的本质,也是 各种Hack 的起源,只要能够把问题解决掉,总会有人用他认为最方便的方式去解决问题,比如说汽车门把手坏掉 了直接系根绳子当把手,emmmm 这样确实很棒啊。

第三条,无序。 返回的结果往往是很随意,各种错误信息本来就是用 Http 的状态码构成的,可是很多人还是喜欢把 错误信息返回在返回值中。最常见的就是Code和 Message ,当然对于这一点,我个人是保留疑问的,我的观点是,Http 本身的错误和服务器的内部错误还是需要在不断层面分开的,不能混在一起。可是在大神眼里并非如此, 这个再议。

六、 CAP 三进二和 Base 定理

关系型数据库遵循 ACID 规则

事务在英文中是 transaction ,和现实世界中的交易很类似,它有如下四个特性:

1 、 A (Atomicity) 原子性 原子性很容易理解,也就是说事务里的所有操作要么全部做完,要么都不做,事务成功的 条件是事务里的所有操作都成功,只要有一个操作失败,整个事务就失败,需要回滚。比如银行转账,从A 账户转 100元至 B 账户,分为两个步骤: 1 )从 A 账户取 100 元; 2 )存入 100 元至 B 账户。这两步要么一起完成,要么一起不完成,如果只完成第一步,第二步失败,钱会莫名其妙少了100 元。

2 、 C (Consistency) 一致性 一致性也比较容易理解,也就是说数据库要一直处于一致的状态,事务的运行不会改变 数据库原本的一致性约束。

3 、 I (Isolation) 独立性 所谓的独立性是指并发的事务之间不会互相影响,如果一个事务要访问的数据正在被另外一 个事务修改,只要另外一个事务未提交,它所访问的数据就不受未提交事务的影响。比如现有有个交易是从A 账户 转100 元至 B 账户,在这个交易还未完成的情况下,如果此时 B 查询自己的账户,是看不到新增加的 100 元的

4 、 D (Durability) 持久性 持久性是指一旦事务提交后,它所做的修改将会永久的保存在数据库上,即使出现宕机也不会丢失。

CAP 三进二

在分布式系统中,讲究 C:Consistency (强一致性)、 A:Availability (可用性)、 P:Partition tolerance (分区容错 性)

CAP 的证明基于异步网络,异步网络也是反映了真实网络中情况的模型。真实的网络系统中,节点之间不可能保持 同步,即便是时钟也不可能保持同步,所有的节点依靠获得的消息来进行本地计算和通讯。这个概念其实是相当强的,意味着任何超时判断也是不可能的,因为没有共同的时间标准。之后我们会扩展CAP 的证明到弱一点的异步网 络中,这个网络中时钟不完全一致,但是时钟运行的步调是一致的,这种系统是允许节点做超时判断的。

CAP 的证明很简单,假设两个节点集 {G1, G2} ,由于网络分片导致 G1 和 G2 之间所有的通讯都断开了,如果不满足 P,则整个网络不可用,如果在 G1 中写,在 G2 中读刚写的数据, G2 中返回的值不可能 G1 中的写值。由于 A 的要求,G2 一定要返回这次读请求,由于 P 的存在,导致 C 一定是不可满足的。

CAP 理论就是说在分布式存储系统中,最多只能实现上面的两点。 而由于当前的网络硬件肯定会出现延迟丢包等问 题,所以 分区容忍性是我们必须需要实现的。

所以我们只能在一致性和可用性之间进行权衡,没有任何分布式系统能同时保证这三点。

C: 强一致性

A :高可用性

P :分布式容忍性

CA 传统 Oracle 数据库

AP 大多数网站架构的选择

CP Redis 、 Mongodb、zk 、consul

注意:分布式架构的时候必须做出取舍。 一致性和可用性之间取一个平衡。多余大多数 web 应用,其实并不需要 强一致性。

因此牺牲 C 换取 P ,这是目前分布式数据库产品的方向

一致性与可用性的决择

对于 web2.0 网站来说,关系数据库的很多主要特性却往往无用武之地

数据库事务一致性需求 很多 web 实时系统并不要求严格的数据库事务,对读一致性的要求很低,有些场合对写一 致性要求并不高。允许实现最终一致性。

数据库的写实时性和读实时性需求 对关系数据库来说,插入一条数据之后立刻查询,是肯定可以读出来这条数据 的,但是对于很多web 应用来说,并不要求这么高的实时性,比方说发一条消息之 后,过几秒乃至十几秒之后,我的订阅者才看到这条动态是完全可以接受的。

对复杂的 SQL 查询,特别是多表关联查询的需求 任何大数据量的 web 系统,都非常忌讳多个大表的关联查询,以及复杂的数据分析类型的报表查询,特别是SNS 类型的网站,从需求以及产品设计角 度,就避免了这种情况的产生。往往更多的只是单表的主键查询,以及单表的简单条件分页查询,SQL 的功能被极大的弱化了。

CAP 理论的核心是:一个分布式系统不可能同时很好的满足一致性,可用性和分区容错性这三个需求, 最多只能同 时较好的满足两个。 因此,根据 CAP 原理将 NoSQL 数据库分成了满足 CA 原则、满足 CP 原则和满足 AP 原则三 大类:

CA - 单点集群,满足一致性,可用性的系统,通常在可扩展性上不太强大。

CP - 满足一致性,分区容忍必的系统,通常性能不是特别高。

AP - 满足可用性,分区容忍性的系统,通常可能对一致性要求低一些。

java同时几万人登录设计_java同时几万人登录设计_02

BASE 定理

BASE 就是为了解决关系数据库强一致性引起的问题而引起的可用性降低而提出的解决方案。

BASE 其实是下面三个术语的缩写:

基本可用( Basically Available )

软状态( Soft state )

最终一致( Eventually consistent )

它的思想是通过让系统放松对某一时刻数据一致性的要求来换取系统整体伸缩性和性能上改观。为什么这么说呢, 缘由就在于大型系统往往由于地域分布和极高性能的要求,不可能采用分布式事务来完成这些指标,要想获得这些 指标,我们必须采用另外一种方式来完成,这里BASE 就是解决这个问题的办法

分布式一致性理论 paxos 、 raft 、 zab 算法

演示 Raft http://thesecretlivesofdata.com/raft /