大型网站技术架构笔记

第1篇 概述

1 大型网站架构演化

1.1 大型网站软件系统的特点

  • 高并发,大流量
  • 高可用
  • 海量数据
  • 用户分布广泛,网络情况复杂
  • 安全环境恶劣
  • 需求快速变更,发布频繁
  • 渐进式发展

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

1.2.1 初始阶段的网站架构

图1.1 初始阶段的网站架构

1.2.2 应用服务和数据服务分离

图1.2 应用服务和数据服务分离

1.2.3 使用缓存改善网站性能

网站访问特点和现实世界的财富分配一样遵循二八定律:80%的业务访问集中在20%的数据上

图1.3 网站使用缓存

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

图1.4 应用服务器集群部署

1.2.5 数据库读写分离

图1.5 数据库读写分离

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

图1.6 网站使用反向代理和CDN加速访问

CDN和反向代理的基本原理都是缓存,区别在于:

  • CDN部署在网络提供商的机房,使用户在请求网站服务时,可以从距离自己最近的网络提供商机房获取数据;
  • 而反向代理则部署在网站的中心机房,当用户请求到达中心机房后,首先访问的服务器是反向代理服务器,如果反向代理服务器中缓存着用户请求的资源,就将其直接返回给用户。

使用CDN和反向代理的目的都是尽早返回数据给用户,一方面加快用户访问速度,另一方面也减轻后端服务器的负载压力。

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

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

1.2.8 使用NoSQL和搜索引擎

图1.8 使用NoSQL系统和搜索引擎

1.2.9 业务拆分

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

图1.9 应用拆分

1.2.10 分布式服务

图1.10 分布式服务

1.3 大型网站架构演化的价值观

业务成就了技术,事业成就了人

1.4 网站架构设计误区

  1. 一味追随大公司的解决方案
  2. 为了技术而技术
  3. 企图用技术解决所有问题
    • 12306真正的问题其实不在于它的技术架构,而在于它的业务架构
    • 在售票方式上引入了排队机制、整点售票调整为分时段售票
    • 技术是用来解决业务问题的,而业务的问题,也可以通过业务的手段去解决

2 大型网站架构模式

  • 关于什么是模式,这个来自建筑学的词汇是这样定义的:“每一个模式描述了一个在我们周围不断重复发生的问题及该问题解决方案的核心。这样,你就能一次又一次地使用该方案而不必做重复工作”。
  • 模式的关键在于模式的可重复性

2.1 网站架构模式

2.1.1 分层

2.1.2 分割

2.1.3 分布式

  • 分布式应用和服务
  • 分布式静态资源
  • 分布式数据和存储
  • 分布式计算
  • 分布式配置
  • 分布式锁
  • 分布式文件

2.1.4 集群

2.1.5 缓存

  • CDN
  • 反向代理
  • 本地缓存
  • 分布式缓存

使用缓存有两个前提条件:

  1. 数据访问热点不均衡,某些数据会被更频繁的访问,这些数据应该放在缓存中
  2. 数据在某个时间段内有效,不会很快过期,否则缓存的数据就会因已经失效而产生脏读,影响结果的正确性

2.1.6 异步

2.1.7 冗余

2.1.8 自动化

  • 自动化代码管理
  • 自动化测试
  • 自动化安全检测
  • 自动化部署
  • 自动化监控
  • 自动化报警
  • 自动化失效转移
  • 自动化失效恢复
  • 自动化降级
  • 自动化分配资源

2.1.9 安全

2.2 架构模式在新浪微博的应用

图2.1 新浪微博的系统架构

2.3 小结

好的设计绝对不是模仿,不是生搬硬套某个模式,而是对问题深刻理解之上的创造与创新,即使是“微创新”,也是让人耳目一新的似曾相识。山寨与创新的最大区别不在于是否抄袭,是否模仿,而在于对问题和需求是否真正理解与把握。

3 大型网站核心架构要素

关于什么是架构,一种比较通俗的说法是“最高层次的规划,难以改变的决定”

从这个意义上说,人生规划也是一种架构。选什么学校、学什么专业、进什么公司、找什么对象,过什么样的生活,都是自己人生的架构。

具体到软件架构,维基百科是这样定义的:“有关软件整体结构与组件的抽象描述,用于指导大型软件系统各个方面的设计”

3.1 性能

衡量网站性能有一系列指标,重要的有响应时间、TPS、系统性能计数器等

3.2 可用性

事实上任何网站都不可能达到完全的7×24可用,总会有一些故障时间,扣除这些故障时间,就是网站的总可用时间,这个时间可以换算成网站的可用性指标,以此衡量网站的可用性,一些知名大型网站可以做到4个9以上的可用性,也就是可用性超过99.99%

3.3 伸缩性

衡量架构伸缩性的主要标准就是是否可以用多台服务器构建集群,是否容易向集群中添加新的服务器。加入新的服务器后是否可以提供和原来的服务器无差别的服务。集群中可容纳的总的服务器数量是否有限制。

3.4 扩展性

衡量网站架构扩展性好坏的主要标准就是在网站增加新的业务产品时,是否可以实现对现有产品透明无影响,不需要任何改动或者很少改动既有业务功能就可以上线新产品。不同产品之间是否很少耦合,一个产品改动对其他产品无影响,其他产品和功能不需要受牵连进行改动。

3.5 安全性

第2篇 架构

4 瞬时响应:网站的高性能架构

4.1 网站性能测试

4.1.2 性能测试指标

表4.1 常用系统操作响应时间表

操作 响应时间
打开一个网站 几秒
在数据库中査询一条记录(有索引) 十几毫秒
机械磁盘一次寻址定位 4毫秒
从机械磁盘顺序读取1MB数据 2微秒
从SSD磁盘顺序读取1MB数据 0.3毫秒
从远程分布式缓存 Redis读取一个数据 0.5毫秒
从内存中读取1MB数据 十几微秒
Java程序本地方法调用 几微秒
网络传输2KB数据 1微秒

System Load即系统负载,指当前正在被CPU执行和等待被CPU执行的进程数目总和,是反映系统忙闲程度的重要指标

  • 当Load值低于CPU数目的时候,表示CPU有空闲,资源存在浪费
  • 当Load值高于CPU数目的时候,表示进程在排队等待CPU调度,表示系统资源不足,影响应用程序的执行性能

4.1.3 性能测试方法

图4.3 性能测试曲线

图4.4 并发用户访问响应时间曲线

4.2 Web前端性能优化

4.2.1 浏览器访问优化

  1. 减少http请求
  2. 使用浏览器缓存
  3. 启用压缩
  4. CSS放在页面最上面、JavaScript放在页面最下面
  5. 减少Cookie传输

4.2.2 CDN加速

CDN(Content Distribute Network,内容分发网络)的本质仍然是一个缓存,而且将数据缓存在离用户最近的地方,使用户以最快速度获取数据,即所谓网络访问第一跳

4.2.3 反向代理

4.3 应用服务器性能优化

4.3.1 分布式缓存

网站性能优化第一定律:优先考虑使用缓存优化性能。

缓存的本质是一个内存Hash表,网站应用中,数据缓存以一对Key、Value的形式存储在内存Hash表中。Hash表数据读写的时间复杂度为O(1)

分布式缓存架构

  • 一种是以JBoss Cache为代表的需要更新同步的分布式缓存
  • 一种是以Memcached为代表的不互相通信的分布式缓存

4.3.2 异步操作

任何可以晚点做的事情都应该晚点再做。

4.3.3 使用集群

4.3.4 代码优化

  1. 多线程

一台服务器上启动多少线程合适呢?假设服务器上执行的都是相同类型任务,针对该类任务启动的线程数有个简化的估算公式可供参考:

启动线程数=[任务执行时间/(任务执行时间(IO等待时间)]]CPU内核数

编程上,解决线程安全的主要手段有如下几点

  • 将对象设计为无状态对象
  • 使用局部对象
  • 并发访问资源时使用锁
  1. 资源复用
  • 单例(Singleton)
  • 对象池(Object Pool)
  1. 数据结构

比较好的字符串Hash散列算法有Time33算法,即对字符串逐字符迭代乘以33,求得Hash值,算法原型为:

hash(i) = hash(i-1) * 33 + str[i]

图4.16 通过MD5计算HashCode

  1. 垃圾回收

4.4 存储性能优化

4.4.1 机械硬盘vs. 固态硬盘

  • 机械硬盘,通过马达驱动磁头臂,带动磁头到指定的磁盘位置访问数据,由于移动磁头臂的次数相差巨大,性能表现差别也非常大
  • 固态硬盘又称作SSD或Flash硬盘,数据存储在可持久记忆的硅晶体上,因此可以像内存一样快速随机访问

4.4.2 B+树 vs. LSM树

为了改善数据访问特性,文件系统或数据库系统通常会对数据排序后存储,加快数据检索速度,这就需要保证数据在不断更新、插入、删除后依然有序,传统关系数据库的做法是使用B+树

图4.21 LSM树原理示意图

LSM树可以看作是一个N阶合并树

在LSM树上进行一次数据更新不需要磁盘访问,在内存即可完成,速度远快于B+树

4.4.3 RAID vs. HDFS

RAID(廉价磁盘冗余阵列)技术主要是为了改善磁盘的访问延迟,增强磁盘的可用性和容错能力

图4.22 常用RAID技术原理图

表4.3 几种RAID技术比较

RAID类型 访问速度 数据可靠性 磁盘利用率
RAID0 很快 很低 100%
RAID1 很慢 很高 50%
RAID10 中等 很高 50%
RAID5 较快 较高 (N-1)/N
RAID6 较快 较(RAID5)高 (N-2)/N

在HDFS(Hadoop 分布式文件系统)中,系统在整个存储集群的多台服务器上进行数据并发读写和备份,可以看作在服务器集群规模上实现了类似RAID的功能,因此不需要磁盘RAID

HDFS配合MapReduce等并行计算框架进行大数据处理时,可以在整个集群上并发读写访问所有的磁盘,无需RAID支持

5 万无一失:网站的高可用架构

5.1 网站可用性的度量与考核

5.1.1 网站可用性度量

网站不可用时间(故障时间)=故障修复时间点网故障发现(报告)时间点
网站年度可用性指标=(11网站不可用时间/年度总时间)年100%

对于大多数网站而言

  • 2个9是基本可用,网站年度不可用时间小于88小时
  • 3个9是较高可用,网站年度不可用时间小于9小时
  • 4个9是具有自动恢复能力的高可用,网站年度不可用时间小于53分钟
  • 5个9是极高可用性,网站年度不可用时间小于5分钟

5.1.2 网站可用性考核

表5.1 网站故障分类权重表示例

分类 描述 权重
事故级故障 严重故障,网络整体不能用 100
A级故障 网站访问不畅或核心功能不可用 20
B级故障 非核心功能不可用,或者核心功能少数用户不能用 5
C级故障 以上故障以外的其他故障 1

故障分的计算公式为:故障分 = 故障时间(分钟) * 故障权重

5.2 高可用的网站架构

5.3 高可用的应用

5.3.1 通过负载均衡进行无状态服务的失效转移

5.3.2 应用服务器集群的Session管理

  1. Session复制
    • 由于所有用户的Session信息在每台服务器上都有备份,在大量用户访问的情况下,甚至会出现服务器内存不够Session使用的情况
  2. Session绑定
    • 利用负载均衡的源地址Hash算法实现,负载均衡服务器总是将来源于同一IP的请求分发到同一台服务器上
    • 也可以根据Cookie信息将同一个用户的请求总是分发到同一台服务器上
  3. 利用Cookie记录Session
  4. Session服务器
    • 这种解决方案事实上是将应用服务器的状态分离,分为无状态的应用服务器和有状态的Session服务器,然后针对这两种服务器的不同特性分别设计其架构
    • 对于有状态的Session服务器,一种比较简单的方法是利用分布式缓存、数据库等

5.4 高可用的服务

  1. 分级管理
  2. 超时设置
  3. 异步调用
  4. 服务降级
  5. 幂等性设计

5.5 高可用的数据

5.5.1 CAP原理

图5.10 CAP原理

在大型网站应用中,数据规模总是快速扩张的,因此可伸缩性即分区耐受性必不可少,在大型网站中,通常会选择强化分布式存储系统的可用性(A)和伸缩性(P),而在某种程度上放弃一致性(C)。

5.5.2 数据备份

冷备的优点是简单和廉价,成本和技术难度都较低。缺点是不能保证数据最终一致,同时也不能保证数据可用性

数据热备可分为两种:异步热备方式和同步热备方式

关系数据库热备机制就是通常所说的Master-Slave同步机制

5.5.3 失效转移

失效转移操作由三部分组成:

  1. 失效确认
  2. 访问转移
  3. 数据恢复

5.6 高可用网站的软件质量保证

5.6.1 网站发布

这相当于要求给飞行中的飞机换个引擎,既不能让飞机有剧烈晃动(影响用户体验),也不能让飞机降落(系统停机维护),更不能让飞机坠毁(系统故障网站完全不可用)。

5.6.2 自动化测试

5.6.3 预发布验证

5.6.4 代码控制

  1. 主干开发、分支发布
  2. 分支开发,主干发布

5.6.5 自动化发布

5.6.6 灰度发布

灰度发布也常用于用户测试,即在部分服务器上发布新版本,其余服务器保持老版本(或者发布另一个版本),然后监控用户操作行为,收集用户体验报告,比较用户对两个版本的满意度,以确定最终的发布版本。这种手段也被称作AB测试。

5.7 网站运行监控

“不允许没有监控的系统上线”,这是许多网站架构师在做项目上线评审时常说的一句话。

5.7.1 监控数据采集

  1. 用户行为日志收集
    • 服务器端日志收集
    • 客户端浏览器日志收集
  2. 服务器性能监控
    • 网站使用比较广泛的开源性能监控工具是Ganglia
  3. 运行数据报告

5.7.2 监控管理

  • 系统报警
  • 失效转移
  • 自动优雅降级,淘宝每年一次的“双十一”促销活动主动关闭“评价”、“确认收货”等非核心功能,以保证交易功能的正常进行,就可以看作是一种优雅降级。

6 永无止境:网站的伸缩性架构

大型网站不是一开始就是大型网站的,而是从小型网站逐步演化而来的

6.1 网站架构的伸缩性设计

一般说来,网站的伸缩性设计可分成两类:

  1. 根据功能进行物理分离实现伸缩,是不同的服务器部署不同的服务,提供不同的功能
  2. 单一功能通过集群实现伸缩,是集群内的多台服务器部署相同的服务,提供相同的功能

6.1.1 不同功能进行物理分离实现伸缩

  • 纵向分离(分层后分离):将业务处理流程上的不同部分分离部署
  • 横向分离(业务分割后分离):将不同的业务模块分离部署

6.1.2 单一功能通过集群规模实现伸缩

当一头牛拉不动车的时候,不要去寻找一头更强壮的牛,而是用两头牛来拉车。

6.2 应用服务器集群的伸缩性设计

6.2.1 HTTP重定向负载均衡

图6.5 HTTP重定向负载均衡原理

HTTP重定向服务器是一台普通的应用服务器,其唯一的功能就是根据用户的HTTP请求计算一台真实的Web服务器地址,并将该Web服务器地址写入HTTP重定向响应中(响应状态码302)返回给用户浏览器。

  • 优点是比较简单
  • 缺点是浏览器需要两次请求服务器才能完成一次访问,性能较差;重定向服务器自身的处理能力有可能成为瓶颈,整个集群的伸缩性规模有限;使用HTTP302响应码重定向,有可能使搜索引擎判断为SEO作弊,降低搜索排名

6.2.2 DNS域名解析负载均衡

图6.6 DNS域名解析负载均衡原理

  • 优点是将负载均衡的工作转交给DNS,省掉了网站管理维护负载均衡服务器的麻烦,同时许多DNS还支持基于地理位置的域名解析,即会将域名解析成距离用户地理最近的一个服务器地址,这样可加快用户访问速度,改善性能
  • 缺点是目前的DNS是多级解析,修改了DNS的A记录,要使其生效也需要较长时间;而且DNS负载均衡的控制权在域名服务商那里,网站无法对其做更多改善和更强大的管理

6.2.3 反向代理负载均衡

图6.7 反向代理负载均衡原理

  • 优点是和反向代理服务器功能集成在一起,部署简单
  • 缺点是反向代理服务器是所有请求和响应的中转站,其性能可能会成为瓶颈

6.2.4 IP负载均衡

在网络层通过修改请求目标地址进行负载均衡

图6.8 IP负载均衡原理

关键在于真实物理Web服务器响应数据包如何返回给负载均衡服务器

  • 一种方案是负载均衡服务器在修改目的IP地址的同时修改源地址,将数据包源地址设为自身IP,即源地址转换(SNAT),这样Web服务器的响应会再回到负载均衡服务器
  • 另一种方案是将负载均衡服务器同时作为真实物理服务器集群的网关服务器,这样所有响应数据都会到达负载均衡服务器

6.2.5 数据链路层负载均衡

在通信协议的数据链路层修改mac地址进行负载均衡,又称作直接路由方式(DR)

图6.9 数据链路层负载均衡原理

使用三角传输模式的链路层负载均衡是目前大型网站使用最广的一种负载均衡手段。在Linux平台上最好的链路层负载均衡开源产品是LVS(Linux Virtual Server)

6.2.6 负载均衡算法

  • 轮询(Round Robin,RR)
  • 加权轮询(Weighted Round Robin,WRR)
  • 随机(Random)
  • 最少连接(Least Connections)
  • 源地址散列(Source Hashing)

6.3 分布式缓存集群的伸缩性设计

6.3.1 Memcached分布式缓存集群的访问模型

图6.10 Memcached分布式缓存访问模型

6.3.2 Memcached分布式缓存集群的伸缩性挑战

本来加入新的缓存服务器是为了降低数据库的负载压力,但是操作不当却导致了数据库的崩溃。如果不对问题和解决方案有透彻了解,网站技术总有想不到的陷阱让架构师一脚踩空。遇到这种情况,用某网站一位资深架构师的话说,就是“一股寒气从脚底板窜到了脑门心”。

6.3.3 分布式缓存的一致性Hash算法

图6.11 一致性Hash算法原理

图6.12 增加节点后的一致性Hash环结构

计算机的任何问题都可以通过增加一个虚拟层来解决

图6.13 使用虚拟节点的一致性Hash环

在实践中,一台物理服务器虚拟为多少个虚拟服务器节点合适呢?一般说来,经验值是150,当然根据集群规模和负载均衡的精度需求,这个值应该根据具体情况具体对待

6.4 数据存储服务器集群的伸缩性设计

6.4.1 关系数据库集群的伸缩性设计

图6.14 MySQL集群伸缩性方案

比较成熟的支持数据分片的分布式关系数据库产品主要有

Cobar的伸缩有两种:

  • Cobar服务器集群的伸缩
  • MySQL服务器集群的伸缩

6.4.2 NoSQL数据库的伸缩性设计

HBase为可伸缩海量数据储存而设计,实现面向在线业务的实时数据访问延迟。HBase的伸缩性主要依赖其可分裂的HRegion及可伸缩的分布式文件系统HDFS实现。

图6.19 HBase架构

图6.20 HBase数据寻址过程时序图

6.5 小结

高手定律:这个世界只有遇不到的问题,没有解决不了的问题,高手之所以成为高手,是因为他们遇到了常人很难遇到的问题,并解决了。所以百度有很多广告搜索的高手,淘宝有很多海量数据的高手,QQ有很多高并发业务的高手,原因大抵如此。一个100万用户的网站,不会遇到1亿用户同时在线的问题;一个拥有100万件商品网站的工程师,可能无法理解一个拥有10亿件商品网站的架构。
救世主定律:遇到问题,分析问题,最后总能解决问题。如果遇到问题就急匆匆地从外面挖一个高手,然后指望高手如探囊取物般轻松搞定,最后怕是只有彼此抱怨和伤害。许多问题只是看起来一样,具体问题总是要具体对待的,没有银弹,没有救世主。所以这个定律准确地说应该是“没有救世主定律”。

7 随需应变:网站的可扩展架构

扩展性(Extensibility)

  • 指对现有系统影响最小的情况下,系统功能可持续扩展或提升的能力
  • 是系统架构设计层面的开闭原则(对扩展开放,对修改关闭)

伸缩性(Scalability)

  • 指系统能够通过增加(减少)自身资源规模的方式增强(减少)自己计算处理事务的能力

7.1 构建可扩展的网站架构

开发低耦合系统是软件设计的终极目标之一

7.2 利用分布式消息队列降低系统耦合性

7.2.1 事件驱动架构

事件驱动架构(Event Driven Architecture):通过在低耦合的模块之间传输事件消息,以保持模块的松散耦合,并借助事件消息的通信完成模块间合作,典型的EDA架构就是操作系统中常见的生产者消费者模式。在大型网站架构中,具体实现手段有很多,最常用的是分布式消息队列

图7.1 利用消息队列实现的事件驱动架构

7.2.2 分布式消息队列

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

图7.2 分布式消息队列架构原理

  • 在伸缩性方面,由于消息队列服务器上的数据可以看作是被即时处理的,因此类似于无状态的服务器,伸缩性设计比较简单。将新服务器加入分布式消息队列集群中,通知生产者服务器更改消息队列服务器列表即可。
  • 在可用性方面,为了避免消费者进程处理缓慢,分布式消息队列服务器内存空间不足造成的问题,如果内存队列已满,会将消息写入磁盘,消息推送模块在将内存队列消息处理完以后,将磁盘内容加载到内存队列继续处理。

7.3 利用分布式服务打造可复用的业务平台

  • 纵向拆分:将一个大应用拆分为多个小应用,如果新增业务较为独立,那么就直接将其设计部署为一个独立的Web应用系统。
  • 横向拆分:将复用的业务拆分出来,独立部署为分布式服务,新增业务只需要调用这些分布式服务,不需要依赖具体的模块代码,即可快速搭建一个应用系统,而模块内业务逻辑变化的时候,只要接口保持一致就不会影响业务程序和其他模块。

图7.4 业务及模块拆分独立部署的分布式服务架构

7.3.1 Web Service与企业级分布式服务

图7.5 WebService架构原理

7.3.2 大型网站分布式服务的需求与特点

对于大型网站,除了Web Service所提供的服务注册与发现,服务调用等标准功能,还需支持

  • 负载均衡
  • 失效转移
  • 高效的远程通信
  • 整合异构系统
  • 对应用最少侵入
  • 版本管理
  • 实时监控

7.3.3 分布式服务框架设计

大型网站需要更简单更高效的分布式服务框架构建其SOA(Service Oriented Architecture面向服务的体系架构)

图7.6 分布式服务框架Dubbo的架构原理

7.4 可扩展的数据结构

没有办法能够做到可扩展的数据结构设计呢?无需修改表结构就可以新增字段呢?许多NoSQL数据库使用的ColumnFamily(列族)设计就是一个解决方案

  • ColumnFamily是一种面向列族的稀疏矩阵存储格式

表7.1 ColumnFamily数据存储格式

7.5 利用开放平台建设网站生态圈

图7.7 开放平台架构原理

7.6 小结

网站通过不断试错,在残酷的市场中寻找自己的竞争优势,持续地推出新功能

8 固若金汤:网站的安全架构

8.1 道高一尺魔高一丈的网站应用攻击与防御

攻击新浪微博的手段被称作XSS攻击,它和SQL注入攻击构成网站应用攻击最主要的两种手段,全球大约70%的Web应用攻击都来自XSS攻击和SQL注入攻击

8.1.1 XSS攻击

XSS攻击即跨站点脚本攻击(Cross Site Script),指黑客通过篡改网页,注入恶意HTML脚本,在用户浏览网页时,控制用户浏览器进行恶意操作的一种攻击方式

  • 一种是反射型,攻击者诱使用户点击一个嵌入恶意脚本的链接,达到攻击的目的
  • 另外一种XSS攻击是持久型XSS攻击,黑客提交含有恶意脚本的请求,保存在被攻击的Web站点的数据库中,用户浏览网页时,恶意脚本被包含在正常页面中,达到攻击的目的

图8.1 反射型XSS攻击

图8.2 持久型XSS攻击

XSS防攻击也是非常复杂的。主要手段有如下两种

  • 消毒:即对某些html危险字符转义,如“>”转义为“&gt”、“<””转义为“&lt”等
  • HttpOnly:即浏览器禁止页面JavaScript访问带有HttpOnly属性的Cookie。HttpOnly并不是直接对抗XSS攻击的,而是防止XSS攻击者窃取Cookie

8.1.2 注入攻击

注入攻击主要有两种形式,SQL注入攻击和OS注入攻击

图8.3 SQL注入攻击

8.1.3 CSRF攻击

CSRF(Cross Site Request Forgery,跨站点请求伪造),攻击者通过跨站请求,以合法用户的身份进行非法操作,如转账交易、发表评论等

图8.4 CSRF攻击

CSRF的防御方法

  • 表单Token
  • 验证码
  • Referer check

8.1.4 其他攻击和漏洞

  • Error Code:也称作错误回显
  • HTML注释
  • 文件上传,最有效的防御手段是设置上传文件白名单,只允许上传可靠的文件类型
  • 路径遍历,防御方法主要是将JS、CSS等资源文件部署在独立服务器、使用独立域名,其他文件不使用静态URL访问,动态参数不包含文件路径信息

8.1.5 Web应用防火墙

ModSecurity是一个开源的Web应用防火墙,探测攻击并保护Web应用程序,既可以嵌入到Web应用服务器中,也可以作为一个独立的应用程序启动

  • 采用处理逻辑与攻击规则集合分离的架构模式
  • 处理逻辑(执行引擎)负责请求和响应的拦截过滤,规则加载执行等功能
  • 攻击规则集合则负责描述对具体攻击的规则定义、模式识别、防御策略等功能(可以通过文本方式进行描述)

图8.5 ModSecurity架构原理

8.1.6 网站安全漏洞扫描

网站安全漏洞扫描工具是根据内置规则,构造具有攻击性的URL请求,模拟黑客攻击行为,用以发现网站安全漏洞的工具

8.2 信息加密技术及密钥安全管理

信息加密技术可分为三类:单项散列加密、对称加密和非对称加密

8.2.1 单向散列加密

单向散列加密是指通过对不同输入长度的信息进行散列计算,得到固定长度的输出,这个散列计算过程是单向的,即不能对固定长度的输出进行计算从而获得输入信息

图8.6 单向散列加密

图8.7 密码保存与验证

彩虹表(人们常用密码和对应的密文关系表)

常用的单向散列算法有MD5、SHA等

8.2.2 对称加密

对称加密是指加密和解密使用的密钥是同一个密钥(或者可以互相推算)

图8.8 对称加密

对称加密通常用在信息需要安全交换或存储的场合,如Cookie加密、通信加密等

  • 优点是算法简单,加解密效率高,系统开销小,适合对大量数据加密
  • 缺点是如何安全的交换密钥是个难题
  • 常用的对称加密算法有DES算发、RC算法等

8.2.3 非对称加密

不同于对称加密,非对称加密和解密使用的密钥不是同一密钥,其中一个对外界公开,被称作公钥,另一个只有所有者知道,被称作私钥。用公钥加密的信息必须用私钥才能解开,反之,用私钥加密的信息只有用公钥才能解开

  • 通常用在信息安全传输,数字签名等场合
  • 在实际应用中,常常会混合使用对称加密和非对称加密
    • 先使用非对称加密技术对对称密钥进行安全传输,然后使用对称加密技术进行信息加解密与交换
    • 而有时,对同一个数据两次使用非对称加密,可同时实现信息安全传输与数字签名的目的。
  • 非对称加密的常用算法有RSA算法等。HTTPS传输中浏览器使用的数字证书实质上是经过权威机构认证的非对称加密的公钥

图8.9 非对称加密

8.2.4 密钥安全管理

实践中,改善密钥安全性的手段有两种

  • 一种方案是把密钥和算法放在一个独立的服务器上,甚至做成一个专用的硬件设施,对外提供加密和解密服务
  • 另一种方案是将加解密算法放在应用系统中,密钥则放在独立服务器中

图8.10 密钥安全管理

8.3 信息过滤与反垃圾

8.3.1 文本匹配

文本匹配主要解决敏感词过滤的问题

  • Trie算法的本质是确定一个有限状态自动机
  • 另一种更简单的实现是通过构造多级Hash表进行文本匹配

图8.11 敏感词过滤树

8.3.2 分类算法

贝叶斯分类算法,这是一种利用概率统计方法进行分类的算法,也被称作是朴素贝叶斯算法(Native Bayes)

ARCS算法(Association Rule Clustering System)

8.3.3 黑名单

黑名单可以通过Hash表实现,该方法实现简单,时间复杂度小,满足一般场景使用

在对过滤需求要求不完全精确的场景下,可用布隆过滤器代替Hash表。布隆过滤器通过一个二进制列表和一组随机数映射函数实现

8.4 电子商务风险控制

8.4.1 风险

  • 账户风险
  • 买家风险
  • 卖家风险
  • 交易风险

8.4.2 风控

风控的手段也包括自动和人工两种

机器自动风控的技术手段

  1. 规则引擎:是一种将业务规则和规则处理逻辑相分离的技术
  2. 统计模型:使用分类算法或者更复杂的机器学习算法进行智能统计。目前大型网站更倾向于使用统计模型进行风控

图8.14 基于规则引擎的风险控制系统

图8.15 基于统计模型的风险控制系统

第3篇 案例

9 淘宝网的架构演化案例分析

9.1 淘宝网的业务发展历程

图9.2 2003年的淘宝网首页

图9.3 2004年淘宝网首页

图9.4 2012年淘宝网首页

9.2 淘宝网技术架构演化

图9.5 2003年淘宝网架构

图9.6 2004年淘宝网架构

图9.7 2006年的淘宝架构

表9.1 淘宝主要开源系统

项目名 描述
Tair 分布式 Key/Value存储引擎,分为持久化和非持久化两种使用方式
TFS 一个分布式文件系统,适用于海量小文件存储
OceanBase 分布式数据库系统,支持千亿级别的读写事务
TDDL 对应用透明的分库分表层和具有众多特性的动态数据源

这也再一次验证了辩证法关于事物发展的否定之否定及螺旋式上升的普遍规律,仿佛回到原点,但一切已经完全不同了。

10 维基百科的高性能架构设计分析

10.1 Wikipedia网站整体架构

图10.2 Wikipedia 架构图

  • GeoDNS:基于开源域名服务器软件BIND(Berkeley Internet Name Domain)的增强版本,可将域名解析到离用户最近的服务器
  • LVS:基于Linux的开源负载均衡服务器
  • Squid:基于Linux的开源反向代理服务器
  • Lighttpd:开源的应用服务器,较主流的Apache服务器更轻量、更快速。实践中,有许多网站使用Lighttpd作为图片服务器

10.2 Wikipedia性能优化策略

10.2.1 Wikipedia前端性能优化

网站前端是指应用服务器(也就是PHP服务器)之前的部分,包括DNS服务、CDN服务、反向代理服务、静态资源服务等

图10.3 Wikipedia的前端架构

Wikipedia前端架构的核心是反向代理服务器Squid集群

Wikipedia CDN缓存的几条准则为:

  • 内容页面不包含动态信息,以免页面内容缓存很快失效或者包含过时信息
  • 每个内容页面有唯一的REST风格的URL,以便CDN快速查找并避免重复缓存
  • 在HTML响应头写入缓存控制信息,通过应用控制内容是否缓存及缓存有效期等

10.2.2 Wikipedia服务端性能优化

除了硬件改善,Wikipedia还使用许多其他开源组件对应用层进行如下优化

  • 使用APC,这是一个PHP字节码缓存模块,可以加速代码执行减少资源消耗
  • 使用Imagemagick进行图片处理和转化
  • 使用Tex进行文本格式化,特别是将科学公式内容转换成图片格式
  • 替换PHP的字符串查找函数strtr(),使用更优化的算法重构

10.2.3 Wikipedia后端性能优化

后端优化最主要的手段是使用缓存

  • 热点特别集中的数据直接缓存到应用服务器的本地内存中
  • 缓存数据的内容尽量是应用服务器可以直接使用的格式,比如HTML格式
  • 使用缓存服务器存储session对象
  • 相比数据库,Memcached的持久化连接非常廉价,如有需要就创建一个Memcached连接

作为存储核心资产的MySQL数据库,Wikipedia也做了如下优化:

  • 使用较大的服务器内存
  • 使用RAID0磁盘阵列以加速磁盘访问
  • 将数据库事务一致性设置在较低水平,加快宕机恢复速度
  • 如果Master数据库宕机,立即将应用切换到Salve数据库,同时关闭数据写服务,这意味着关闭词条编辑功能

11 海量分布式存储系统Doris的高可用架构设计分析

Doris是一个海量分布式KV存储系统

  • 其设计目标是支持中等规模高可用、可伸缩的KV存储集群
  • 跟主流的NoSQL系统HBase相比(Doris0.1 vs. HBase0.90),Doris具有相似的性能和线性伸缩能力,并具有更好的可用性及更友好的图形用户管理界面

11.1 分布式存储系统的高可用架构

图11.1 Doris的整体架构

系统整体上可分为如下三个部分

  • 应用程序服务器:是存储系统的客户,对系统发起数据操作请求
  • 数据存储服务器:是存储系统的核心,负责存储数据、响应应用服务器的数据操作请求
  • 管理中心服务器:是一个由两台机器组成的主-主热备的小规模服务器集群,主要负责集群管理,对数据存储集群进行健康心跳检测;集群扩容、故障恢复管理;对应用程序服务器提供集群地址配置信息服务等

图11.2 Doris系统调用时序模型

11.2 不同故障情况下的高可用解决方案

11.2.1 分布式存储系统的故障分类

  • 瞬时故障:引起这类故障的主要原因是网络通信瞬时中断、服务器内存垃圾回收或后台线程繁忙停止数据访问操作响应
  • 临时故障:引起这类故障的主要原因是交换机宕机、网卡松动等导致的网络通信中断;系统升级、停机维护等一般运维活动引起的服务关闭;内存损坏、CPU过热等硬件原因导致的服务器宕机
  • 永久故障:引起这类故障的主要原因只有一个:硬盘损坏,数据丢失

11.2.2 正常情况下系统访问结构

图11.3 正常情况下Doris访问模型

11.2.3 瞬时故障的高可用解决方案

图11.4 Doris瞬时故障解决方案

图11.5 Doris瞬时失效访问模型

11.2.4 临时故障的高可用解决方案

图11.6 Doris临时故障解决方案

图11.7 Doris临时故障访问模型

图11.8 临时故障恢复期间Doris访问模型

11.2.5 永久故障的高可用解决方案

图11.9 永久故障恢复期间Doris访问模型

12 网购秒杀系统架构设计案例分析

12.1 秒杀活动的技术挑战

  1. 对现有网站业务造成冲击
  2. 高并发下的应用、数据库负载
  3. 突然增加的网络及服务器带宽
    • 假设商品页面大小200K(主要是商品图片大小),那么需要的网络和服务器带宽是2G(200K×10,000)
  4. 直接下单

12.2 秒杀系统的应对策略

  1. 秒杀系统独立部署
  2. 秒杀商品页面静态化
  3. 租借秒杀活动网络带宽
  4. 动态生成随机下单页面URL

12.3 秒杀系统架构设计

  1. 如何控制秒杀商品页面购买按钮的点亮
    • 解决办法是使用JavaScript脚本控制
  2. 如何只允许第一个提交的订单被发送到订单子系统

图12.3 秒杀商品点亮过程

图12.4 秒杀下单流程

图12.5 秒杀系统的整体架构

12.4 小结

13 大型网站典型故障案例分析

一位网站资深架构师曾经说过:在互联网公司呆一年,相当于在传统软件公司呆三年

13.1 写日志也会引发故障

  • 应用程序自己的日志输出配置和第三方组件日志输出要分别配置
  • 检查log配置文件,日志输出级别至少为Warn,并且检查log输出代码调用,调用级别要符合其真实日志级别
  • 有些开源的第三方组件也会不恰当地输出太多的Error日志,需要关闭这些第三方库的日志输出

13.2 高并发访问数据库引发的故障

  • 首页不应该访问数据库,首页需要的数据可以从缓存服务器或者搜索引擎服务器获取
  • 首页最好是静态的

13.3 高并发情况下锁引发的故障

  • 使用锁操作要谨慎

13.4 缓存引发的故障

  • 当缓存已经不仅仅是改善性能,而是成为网站架构不可或缺的一部分时,对缓存的管理就需要提高到和其他服务器一样的级别

13.5 应用启动不同步引发的故障

  • 在应用程序中加入一个特定的动态页面(比如只返回OK两个字母),启动脚本先启动JBoss,然后在脚本中不断用curl命令访问这个特定页面,直到收到OK,才启动Apache

13.6 大文件读写独占磁盘引发的故障

  • 存储的使用需要根据不同文件类型和用途进行管理,图片都是小文件,应该使用专用的存储服务器,不能和大文件共用存储。批处理用的大文件可以使用其他类型的分布式文件系统

13.7 滥用生产环境引发的故障

  • 访问线上生产环境要规范,不小心就会导致大事故

13.8 不规范的流程引发的故障

  • 代码提交前使用diff命令进行代码比较,确认没有提交不该提交的代码
  • 加强code review,代码在正式提交前必须被至少一个其他工程师做过code review,并且共同承担因代码引起的故障责任

13.9 不好的编程习惯引发的故障

  • 程序在处理一个输入的对象时,如果不能明确该对象是否为空,必须做空指针判断
  • 程序在调用其他方法时,输入的对象尽量保证不是null,必要时构造空对象(使用空对象模式)

13.10 小结

软件设计有两种风格,一种是将软件设计得很复杂,以使其缺陷没那么明显;一种是将软件设计得很简单,以使其没有明显的缺陷

第4篇 架构师

14 架构师领导艺术

14.1 关注人而不是产品

  • 一群优秀的人做一件他们热爱的事,一定能取得成功
  • 寻找一个值得共同奋斗的目标,营造一个让大家都能最大限度发挥自我价值的工作氛围

14.2 发掘人的优秀

发掘人的优秀远比发掘优秀的人更有意义

14.3 共享美好蓝图

  • 蓝图应该是表述清楚的:产品要做什么、不做什么、要达到什么业务目标,都需要描述清楚。
  • 蓝图应该是形象的:产品能为用户创造什么价值、能实现什么样的市场目标、产品最终会长什么样,都需要形象地想象出来。
  • 蓝图应该是简单的:不管内部还是外部沟通,都能一句话说明白:我们在做什么。
  • 架构师要保持对目标蓝图的关注

14.4 共同参与架构

  1. 不要只有架构师一个人拥有架构
  2. 让其他人维护框架与架构文档

14.5 学会妥协

每次我在做项目迷失方向,五迷三道的时候,就会想起这个故事,提醒自己是来做软件的,来实现客户价值的,不是来证明谁对谁错的,不是来给黑熊XX的。

而当大家不再讨论架构的时候,表明架构已经融入到项目、系统和开发者中了,架构师越早被项目组遗忘,越表示架构非常成功;项目组越离不开架构师,越表示架构还有很多缺陷。

14.6 成就他人

我们活着不是为了工作,不是为了做设计、写程序,这些不是我们生活的目的。我们活着是为了成就我们自己,而要想成就自己,就必须首先成就他人。

15 网站架构师职场攻略

15.1 发现问题,寻找突破

新员工Tips

  1. 首先要做的事情是融入团队
  2. 最不需要做的事情就是证明自己的能力

15.2 提出问题,寻求支持

提出问题Tips

  1. 把“我的问题”表述成“我们的问题”
  2. 给上司提封闭式问题,给下属提开放式问题
  3. 指出问题而不是批评人
  4. 用赞同的方式提出问题
    • 用一种温和的方式提出问题“我非常赞同你的方案,不过我有一个小小的建议……”

15.3 解决问题,达成绩效

解决问题Tips

  1. 在解决我的问题之前,先解决你的问题
  2. 适当的逃避问题

16 漫话网站架构师

16.1 按作用划分架构师

  • 设计型架构师
  • 救火型架构师
  • 布道型架构师
  • Geek型架构师

16.2 按效果划分架构师

  • 夏尔巴人架构师
  • 斯巴达人架构师
  • 达官贵人架构师

16.3 按职责角色划分架构师

  • 产品架构师
  • 基础服务架构师,有时也被称为平台架构师
  • 基础设施架构师,一般有专门的称呼(如DBA等)

16.4 按关注层次划分架构师

  • 只关注功能的架构师
  • 关注非功能的架构师
  • 关注团队组织与管理的架构师
  • 关注产品运营的架构师
  • 关注产品未来的架构师

16.5 按口碑划分架构师

  • 最好的架构师
  • 好的架构师
  • 一般的架构师
  • 差的架构师
  • 最差的架构师

16.6 非主流方式划分架构师

  • 普通架构师
  • 文艺架构师
  • 1+1架构师

附录A 大型网站架构技术一览

图A.1 网站系统架构层次

附录B Web开发技术发展历程

图B.1 CGI程序调用时序模型

图B.2 MVC系统调用时序模型

后记

大型网站不是设计出来的,而是逐步发展演化出来的

References

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