《大型网站技术架构--核心原理与案例分析》读书心得

一、大型网站架构演化

初始阶段的网站架构(单台服务器)-> 应用服务器和数据服务分离(数据库和文件服务器都单独成一个服务器) -> 使用缓存改善网站性能(本地缓存、分布式缓存) -> 使用应用服务器集群改善网站的并发处理能力 -> 数据库读写分离 -> 使用反向代理(网站中心机房)和CDN(网络运营商那里)加速网站响应(缓存静态、热点内容)->使用分布式文件系统和分布式数据库系统(更常用的是业务分库) ->使用NoSQL和搜索引擎 -> 业务拆分 ->分布式服务

二、大型网站架构模式

1、分层

软件在横向方面进行切分

2、分割

软件在纵向方面进行分割。
业务拆分:大型网站为了应对日益复杂的业务场景,通过使用分而治之的手段将整个网站业务分成不同的产品线,分归不同的业务团队负责。
具体到技术上,也会根据产品线划分,将一个网站拆分成许多不同的应用,每个应用独立部署。应用之间可以通过一个超链接建立关系,也可以通过消息队列进行数据分发,当然最多的还是通过访问同一个数据存储系统来构成一个关联的完整系统。

3、分布式

分层和分割的一个主要目的就是为了切分后的模块便于分布式部署,即将不同模块部署在不同的服务器上,通过远程调用协同工作。
1) 分布式应用和服务
将分层和分割后的应用和服务模块分布式部署。
2)分布式静态资源
3)分布式数据和存储
4)分布式计算
Haddoop的MapReduce分布式计算框架。

4、集群

5、缓存

1)CDN:Content Distribute Network,内容分发网络。
2)反向代理
3)本地缓存
使用缓存的前提:一是数据访问热点不均衡;二是数据在某个时间段内有效,不会很快过期。
4)分布式缓存
网站数据库几乎都是按照有缓存的前提进行负载能力设计的,所以缓存的可用性至关重要。避免缓存雪崩这种故障

6、异步

在分布式系统中,多个服务器集群通过分布式消息队列实现异步,分布式消息队列可以看做内存队列的分布式部署。
异步架构的典型是生产者消费者模式,两者不存在直接调用,只要保持数据结构不变,彼此功能实现可以随意变化而不受影响。
特性:提高系统可用性;加快网站响应速度;消除并发访问高峰。

7、冗余

冗余包括冷备份、热备份、灾备数据中心,另外其实集群也简介实现了应用的冗余。

8、自动化

发布过程自动化:自动化代码管理、自动化测试、自动化安全检查、自动化部署。
自动化监控:自动化报警、自动化失效转移、自动化失效恢复、自动化降级、自动化分配资源。

9、安全

通过密码和手机校验码进行身份验证;Https对网络通讯进行加密;对存储的敏感数据加密(例如用户密码);对敏感信息、垃圾信息进行过滤;对交易转账等重要操作进行风险控制。

三、大型网站核心架构要素

架构:最高层次的规划,难以改变的决定。这些规划和决定奠定了事物未来发展的方向和最终的蓝图。
软件架构:有关软件整体结构和组件的抽象描述,用于指导大型软件系统各个方面的设计。
性能、可用性、伸缩性、扩展性、安全是网站架构最核心的五个要素。

1、性能

衡量性能的指标:
响应时间、TPS、系统性能计数器等。
性能优化的方法:

  • 浏览器端:可以通过浏览器缓存、页面压缩、合理布局页面、较少Cookie传输等手段优化;CDN、反向代理服务器等缓存热点文件;
  • 应用服务器端:本地缓存、分布式缓存;异步操作;集群等;
  • 代码层面:通过多线程、内存管理等手段优化;
  • 数据库服务器端:索引、缓存、SQL优化等。而NoSQL通过优化数据模型、存储结构、伸缩性等更有优势。

2、可用性

网站高可用的主要手段是冗余,所以衡量一个系统架构设计是否满足高可用的目标,就是假设系统中任何一台或多台服务器宕机时,以及出现各种不可预期的问题时,系统整体是否依然可用。

3、伸缩性

所谓伸缩性是指通过不断向集群中加入服务器的手段来缓解不断上升的用户并发访问压力和不断增长的数据存储需求。

4、扩展性

网站的扩展性架构直接关注网站的功能性需求,快速响应需求变化。核心是不同产品之间要解耦。
网站可扩展架构的主要手段是事件驱动架构(主要实现是消息队列)和分布式服务(业务和可复用服务分离开,通过分布式服务框架调用)。

5、安全性

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

1、性能测试

网站性能测试的主要指标:响应时间、并发数、吞吐量、性能计数器等。

性能测试是一个总称,具体可以细分为:性能测试、负载测试、压力测试、稳定性测试
性能测试以系统初期规划的性能指标为预期目标,对系统不断施加压力,验证系统在资源可接受范围内,是否能达到性能预期。
稳定性测试:被测试系统在特定硬件、软件、网络环境下,给系统加载一定业务压力,是系统运行一段较长时间,以此检测系统是否稳定。


2、性能优化

1)性能分析

  • 检查日志:检查请求处理的各个环节的日志,分析哪个环节响应时间不合理、超过预期;
  • 检查监控数据:检查监控数据,分析影响性能的主要要素是内存、磁盘、网络还是CPU,是代码问题还是架构设计不合理,或者系统资源确实不足。

2)性能优化

(1) Web前端性能优化

浏览器访问优化

  • 减少http请求:http是无状态的应用层协议,减少http请求数目可有效提高访问性能。可以通过合并CSS、合并JavaScript、合并图片来减少http请求。
  • 使用浏览器缓存:将CSS、JavaScript、Logo、图标这些更新频率较低的静态资源缓存在浏览器中,可以极好的改善性能。为了及时更新,可以修改该文件名字,然后在更新HTML中的引用。
  • 启用压缩:会对服务器和浏览器产生一定的压力。
  • CSS放在页面最上面、JavaScript放在页面最下面:CSS放上面,方便页面渲染的时候,CSS能提前下载,JavaScript要看是否影响页面的解析情况而定。
  • 减少Cookie传输:太大的Cookie会影响数据传输。

CDN加速
CDN本质仍然是一个缓存,而且将数据缓存在离用户最近的地方。所以CDN是部署在网络运营商的机房。CDN一般缓存一些静态资源:图片、文件、CSS、Script脚本、静态网页等。

反向代理

(2)应用服务器性能优化

分布式缓存
 网站优化第一定律:优先考虑使用缓存优化性能。
缓存主要存放那些读写比很高、变化很少的数据。一般第缓存设置时效时间,但会导致一定时间的数据不一致。
缓存本质是一个内存Hash表,网站应用中,数据缓存以一对Key、Value的形式存储在内存Hash表中。Hash表的数据读写时间复杂度是O(1)。Hash表是软件开发中常用的一种数据结构,期设计思想在很多场景下都可以应用。

分布式缓存案例1--JBoss Cache:通常将应用程序和缓存部署在同一台服务器上,并且分布的缓存之间同步更新。
分布式缓存案例2--Memcached:优点是分布缓存之间互不通信(结合一致性Hash算法),使用简单的通信协议(TCP或UDP)和通信序列化协议(XML或JSON)。内存管理采用LRU算法。

异步操作
使用消息队列将调用异步化。消息队列服务器处理速度远快于数据库,并且比数据库有更好的伸缩性。
 高并发时,任何可以晚点做的事情都应该晚点再做!

使用集群

代码优化

  • 多线程:充分利用CPU在磁盘IO或网络IO堵塞时候的效率。
  • 资源复用:包括单例(Singleton)和对象池(Object Pool),例如数据库的连接池、Web请求的线程池(Thread Pool);
  • 数据结构:采用Hash表。字符串Hash散列算法有Time33算法。
  • 垃圾回收:

存储性能优化

  • 机械硬盘 VS. 固态硬盘
  • B+树 VS. LSM树:数据的索引存储结构;关系型数据库主要使用B+树,NoSQL采用LSM树。
  • RAID VS. HDFS:RAID技术在传统关系型数据库及文件系统中使用比较广发,但在大型网站采用的NoSQL及分布式文件系统中,相当于间接实现了RAID的相关功能。HDFS以块(Block)为单位管理文件内容,默认是64M(操作系统默认是512字节)。

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

1、网站可用性度量与考核

1) 网站不可访问原因
DNS会被劫持、CDN服务器可能会挂掉、网站服务器可能会宕机、网络交换机可能会失效、硬盘会损坏、网卡会松掉、甚至机房会停电、空调会失灵、程序会有BUG、黑客会攻击、促销会引来大量访问、第三方合作伙伴的服务会不可用......

2)网站可用量度量
4个9 99.99%可用 一年大约最多53分钟不可用;
3个9 99.9%可用 一年大约最多9个小时不可用;
2个9 99%可用 一年大约最多88个小时不可用;

3)网站可用性考核
可用性指标对外是承诺,对内是考核。

2、高可用的网站架构

主要手段是数据和服务的冗余备份及失效转移。

3、高可用的应用

  • 通过负载均衡进行无状态服务的失效转移
  • 应用服务器集群的Session管理
    Web应用中将这些多次请求修改使用的上下文对象称作为会话(Session)
    有Session复制、Session绑定(通过Hash算法)、利用Cookie记录Session、Session服务器(实际上是将应用服务器的状态分离)。

4、高可用的服务

可服用的服务模块为业务产品提供基础公共服务。高可用的服务策略:

  • 分级管理
  • 超时设置
  • 异步调用
  • 服务降级
  • 幂等性设计
    必须在服务层保证服务重复调用和调用一次的结果相同,即服务具有幂等性。
    有些服务天然具有幂等性,例如将性别设置为男,不管设置多少次,结果都一样。但是对于转账交易等操作,问题就比较复杂,需要通过交易编号信息进行服务调用有效性校验,只有有效的操作才能继续进行。

5、高可用的数据

CAP原理,数据的一致性可以分为如下几点:

  • 数据强一致
  • 数据用户一致:在各个副本可能不一样,但是终端用户访问时,通过纠错和校验机制,可以确定一个一致且正确的数据返回给用户。
  • 数据最终一致:系统经过一段时间(通常是一个比较短的是时间段)的自我恢复和修正,数据最终会达到一致。

数据备份:数据异步热备(就是通常所说的Master-Slave同步机制、读写分离)

失效转移:如果存储不对等,那么就需要重新计算路由,选择存储服务器。

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

1)代码控制
分支开发、主干发布:目前在开源技术社区,Git作为版本控制工具,正逐步取代SVN的地位。

2)预发布验证
预发布服务器是一种特殊用途的服务器,它和线上的正式服务器唯一的不同就是没有配置在负载均衡服务器上,外部用户无法访问。单预发布验证操作的是真实的数据,可能会出现不可预测的问题。

3)灰度发布
每天只发布一部分服务器,观察运行稳定没有故障,再逐步发布完毕。这种手段也被称为AB测试

7、网站运行监控

 不允许没有监控的系统上线,运维没有监控的网站,犹如驾驶没有仪表的飞机。

1)监控数据采集

  • 用户行为日志收集
    • 服务器端日志收集
    • 客户端浏览器日志收集
  • 服务器性能监控
  • 运行数据报告

2)监控管理

  • 系统报警
  • 失效转移
  • 自动优雅降级

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

1、网站架构的伸缩性设计

网站的伸缩性设计可分为两类,一类是根据功能进行物理分离实现伸缩,一类是单一功能通过集群实现伸缩。前者是不同的服务器部署不同的服务,提供不同的功能;后者是集群内的多台服务器部署相同的服务,提供相同的功能。

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

纵向分离(分层后分离)
横向分离(业务分割后分离)

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

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

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

  • HTTP重定向负载均衡
  • DNS域名解析负载均衡:许多DNS支持基于地理位置的域名解析,可将域名解析成距离用户地理最近的一个服务器地址。但因为DNS是多级解析,变化生效的时间较长。
  • 反向代理负载均衡
  • IP负载均衡:在网络层通过修改请求目标地址进行负载均衡。
  • 数据链路层负载均衡:在通信协议的数据链路层修改mac地址进行负载均衡。也称直接路由方式(DR)。集群素有服务器虚拟IP地址都和负载均衡服务器的IP相同。在Linux平台上最好的链路层负载均衡开源产品是LVS(Linux Virtual Server)

负载均衡算法:轮询、加权轮询、随机、最少连接、源地址散列。

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

Memcached分布式缓存集群。
 计算机的任何问题都可以通过增加一个虚拟层来解决。计算机网络的7层协议,每一层协议都可以看做是下一层协议的虚拟层;计算机操作系统可以看做是计算机硬件的虚拟层;Java虚拟机可以看做是操作系统的虚拟层;分层的计算机软件架构事实上也是利用虚拟层的概念。

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

缓存+读写分离+业务分库

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


除了数据库主从读写分离,前面提到的业务分割模式也可以用在数据库,不同业务数据表部署在不同的数据库集群上,即俗称的数据分库。这种方式的制约条件是跨库的表不能进行Join操作。
数据分片:将一张表拆分分别存储到多个数据库中。主要的工具有Amoeba和Cobar。

2)NoSQL数据库的伸缩性设计

NoSQL放弃了关系数据库的两大重要基础:以关系代数为基础的结构化查询语言(SQL)和事务一致性保证(ACID)。而强化其它一些大型网站更关注的特性:高可用和可伸缩性。主要的产品有Apache HBase。

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

减低软件系统耦合性是最关键的思考方式。
 软件架构师最大的价值不在于掌握了多少先进技术,而在于具有将一个大系统分成N个低耦合的子模块的能力,这些子模块包含横向的业务模块,也包含纵向的基础技术模块。这种能力一部分源自专业的技术和经验,还有一部分源自架构师对业务场景的理解、对人性的把握、甚至对世界的认知。
模块分布式部署以后具体聚合方式主要有分布式消息队列和分布式服务

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

事件驱动架构:通过在低耦合的模块之间传输时间消息,以保持模块的松散耦合,并借助时间消息的通信完成模块间的合作。生产者消费者模式,分布式消息队列等。开源的分布式消息队列产品有Apache ActiveMQ

2、利用分布式服务打造可服用的业务平台

纵向拆分相对比较简单,通过梳理业务,将较少相关的业务剥离,使其成为独立的Web应用。而对于横向拆分,不但需要识别可复用的业务,设计服务接口,规范服务依赖关系,还需要一个完善的分布式服务管理框架。

1)Web Service与企业级分布式服务

Web Service 用以整合异构系统及构建分布式系统,通过SOAP(Simple Object Access Protocol,简单对象访问协议)和服务提供者通信,使用相关的服务。

2)分布式服务框架设计

目前国内的开源分布服务框架是阿里巴巴的Dubbo

3、可扩展的数据结构

NoSQL的ColumnFamily(列族)

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

网站安全主要包括各种Web攻击和信息泄露(被黑客拖库)。

  • 全球大约70%的Web应用攻击都来自XSS攻击和SQL注入攻击。
  • Referer Check:HTTP请求头的Referer域中记录着请求来源,可以通过检查来源,验证其是否合法。很多网站使用这个功能实现图片防盗链(如果图片访问的页面不是来自自己的网页就拒绝)
  • Web应用防火墙: ModSecurity
  • 信息加密:单向散列加密(MD5、SHA)、对称加密(DES、RC算法)、非对称加密(RSA算法)
  • 信息过滤和反垃圾:文本匹配、分类算法(贝叶斯分类算法)黑名单
  • 电子商务风险控制:规则引擎、统计模型
    统计模型:目前主要使用,根据历史交易中的欺诈交易信息训练分类算法,然后将经过采集加工后的交易信息输入分类算法,即可得到交易风险分值。由于统计模型采用模糊识别,并不精确匹配欺诈类型规则,因为对新出现的交易欺诈有一定的预测性。

九、案例分析

秒杀系统架构图

为了保证系统的安全,保持适度的公平公正即可。即使系统出了故障,也不应该给用户显示出错页面,而是显示秒杀活动结束页面,避免不必要的困扰。

十、典型故障案例分析

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

  • 写日志也会引发故障:硬盘空间的问题
  • 高并发访问数据库引发的故障:使用率高的查询数据进行缓存
  • 高并发情况下锁引发的故障:使用锁要谨慎;
  • 缓存引发故障:对缓存的管理要严格
  • 应用启动不同步引发故障:后台服务都要准备好,前台应用才能启动。
  • 大文件读写独占磁盘引发的故障:按照不同文件类型和用途进行管理和存放。
  • 滥用生产环境引发的故障:访问线上生产环境要规范。
  • 不规范流程引发的故障:代码提交前要用Diff命令进行代码比较(Code review)
  • 不好的编程习惯引发的故障:对Null进行检查。

文章摘录

  • 我们永远无法像传统行业一样,去精确估算,并按预先精确设计好的图纸去完成我们的产品。
  • 传统的企业应用系统主要面对的技术挑战是处理复杂凌乱、千变万化的所谓业务逻辑,而大型网站主要面对的技术挑战是处理超大量的而用户访问和海量的数据处理;前者的挑战来自功能性需求,后者的挑战来自非功能性的需求。
  • 过度承诺
  • NoSQL 和搜索引擎都是源自互联网的技术手段,对可伸缩的分布式特性具有更好的支持。应用服务器通过一个统一数据访问模块访问各种数据,减轻应用程序管理诸多数据源的麻烦。
  • LAMP技术:Linux+Apache+MySQL+PHP。
  • 是业务成就了技术,是事业成就了人,而不会相反。
  • 不能企图用技术解决所有问题,有时候需要从业务优化的角度来考虑。业务退后一小步,技术前进一大步。
  • 模式:“每一个模式描述了一个我们周围不断重复发生的问题及该问题解决方案的核心。这样,你就能一次又一次地使用该方案而不必做重复工作。”模式的关键在于模式的可重复性,问题与场景的可重复性带来解决方案的可重复使用。
  • 产品设计之初就需要一个明确的定位:什么是产品要实现的功能,什么不是产品提供的特征。在漫长的生命周期中,会有形形色色的困难和诱惑来改变产品的发展方向,左右摇摆、什么都想做的产品,最后有可能成为一个失去生命力的四不像。个人注:人生也是一样,对自己必须有正确的定位,有所为,有所不为。
  • 通信要考虑两方面,一是通信协议,是选择TCP还是UDP,抑或Http;二是通信序列化协议,数据传输的两段,必须使用彼此可识别的数据序列化方式才能使通信得以完成,例如XML、JSON等文本序列化协议。
    类比:不同国家的人通信,意思要选择某种语言(例如英语),二是要选择载体,是通过电话(音频),还是书信(文本),还是视频(视频)等。

  • Lucence:由Apache出品,Java开发的开源全文搜索引擎。
  • 一定要坚信:一群优秀的人做一件他们热爱的事,一定能取得成功。
  • 寻找一个值得共同奋斗的目标,营造一个让大家都能最大限度发挥自我价值的工作氛围。
  • 大多数人,都比自己以为的更优秀,有些优秀需要在合适的环境中才能被激发出来,比如做一些有挑战的事,和更优秀的人合作,抑或拥有了超越自我的勇气。
  • 蓝图应该写在软件架构设计文档的扉页、写在邮件的签名档,写在内部即时通信的公告上。
  • 对于技术细节的争论应该立即验证而不是继续讨论。
  • 要想成就自己,就必须首先成就他人。
  • “鱼是最后一个看见水的”,天天面对这些问题,反而不觉得有什么问题。
  • 对于大多数应用来说,开源的MySQL数据库已经绰绰有余了,而我们还在使用昂贵的Oracle。
  • 如何提出问题:
    • 把“我的问题”表述成“我们的问题”
    • 给上司提封闭式问题,给下属提开放式问题;
    • 指出问题而不是批评人;
    • 用赞同的方式提出问题:我非常赞同你的方案,不过我有一个小小的建议......