网站技术架构读书笔记-架构

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

网站性能是客观的指标,可以具体提现到响应时间,吞吐量等技术指标,同时也是主观的感受,而感受则是一种与具体参与者相关的微妙的东西,用户的感受和工程师的感受不同,不同的用户感受也不同。

4.1 网站性能测试

性能测试是性能优化的前提和基础,也是性能优化结果的检查和度量标准。不同视角下的网站性能有不同的标准,也有不同的优化手段。

4.1.1 不同视角下的网站性能

  • 用户视角的网站性能:

image.png

在实践中,使用一些前端架构优化手段,通过优化页面HTML样式,利用浏览器端的并发和异步特性,调整浏览器缓存策略,使用CDN服务,反向代理等手段,使浏览器尽快的显示用户感兴趣的内容,尽可能近地获取页面内容,即使不优化应用程序和架构,也可以很大程度地改善用户视角下的网站性能。

  • 开发人员视角的网站性能

开发人员关注的主要是应用程序本身及其相关子系统的性能,包括响应延迟,系统吞吐量,并发处理能力,系统稳定性等技术指标。

主要优化手段有使用缓存加速数据读取,使用集群提供吞吐能力,使用异步消息加快请求响应及其实现削峰,使用代码优化手段改善程序性能。

  • 运维人员视角的网站性能

运维人员更关注技术设施性能和资源利用率,如网络运营商的带宽能力,服务器硬件的配置,数据中心网络架构,服务器和网络带宽的资源利用率等。

主要优化手段有建设优化骨干网,使用高性价比定制服务器,利用虚拟化技术优化资源利用等。

4.1.2 性能测试指标

不同的视角下有不同的性能标准,不同的标准有不同的性能测试指标,从开发和测试人员的视角,网站性能测试的主要指标有响应时间,并发数,吞吐量,性能计数器等。

  • 响应时间:指应用执行一个操作需要的时间,包括从发出请求开始到收到最后响应数据所需要的时间。

  • 并发数:指系统能够同时处理请求的数目,这个数字也反映了系统的负载特性。

    网站系统用户数 >> 网站在线用户数 >> 网站并发用户数

    测试程序通过多线程模拟并发用户的办法来测试系统的并发处理能力,为了真实模拟用户的行为,测试程序并不是启动多线程然后不同地发送请求,而是在两次请求之间加入一个随机等待时间,这个时间被称作思考时间。

  • 吞吐量:指单位时间内系统处理的请求数量,体现系统的整体处理能力。

    TPS:每秒事务数是一个常用良华指标,此外还有HPS(每秒HTTP请求数),QPS:每秒查询数等。

在系统并发数由小逐渐增加的过程中,系统吞吐量显示逐渐增加,达到一个极限后,随着并发数的增加反而下降,达到系统奔溃点后,系统资源耗尽,吞吐量为零。而这个过程中,响应时间则是先保持小幅上升,到达吞吐量极限后,快速上升,到达系统奔溃点后,系统失去响应。

  • 性能计数器:该指标是描述服务器或操作系统性能的一些数据指标。包括System Load对象线程数内存使用CPU使用磁盘网络I/O等指标。对这些指标设置报警阈值,当监控系统发现性能计数器超过阈值时想人员报警,即使处理异常。

    • System Load:即系统负载,指当前正在被CPU执行和等待被CPU执行的进程数目综和,是反映系统忙闲程度的重要指标。多核CPU的情况下,完美情况是所有CPU都在使用,没有进程在等待处理,所有Load的理想值是CPU的数目。该值表示最近1分钟,10分钟,15分钟的运行队列平均进程数。

4.1.3 性能测试方法

具体可细分为性能测试,负载测试,压力测试,稳定性测试。

  • 性能测试:以系统设计初期规划的性能指标为预期目标,对系统不断施加压力,验证系统在资源可接受范围内,是否能达到性能预期。
  • 负载测试:对系统不断增加并发请求以增加系统压力,直到系统的某项或多项性能达到安全临界值,如某种资源以及呈饱和状态,这时继续对系统施加压力,系统的处理能力不但不能提高,反而会下降。
  • 压力测试:超过安全负载的情况下,对系统继续施加压力,知道系统崩溃或不能再处理任何请求,以此获得系统最大压力承受能力。
  • 稳定性测试:被测试系统在特定硬件,软件,网络环境条件下,给系统加载一定业务压力,使系统运行一段较长时间,以此测试系统是否稳定。为了更好的模拟生产环境,稳定性测试也应不均匀地对系统施加压力。

性能测试是一个不断对系统增加访问压力,以获得系统性能指标,最大负载能力,最大压力承受能力的过程。

性能测试曲线:

image.png

性能测试反映的是系统在实际生产环境中使用时,随着用户并发访问数量的增加,系统的处理能力。与性能曲线相对应的是用户访问的等待时间。

image.png

4.1.4 性能测试报告。

测试结果应能够反映上述性能测试曲线的规律,可以得到系统性能是否满足设计目标和业务需求。

4.1.5 性能优化策略

    1. 性能分析: 与排查一个程序的性能瓶颈的手法基本相同,检查请求处理的各个环节的日志,分析哪个环节响应时间不合理,超过预期;然后检查监控数据,分析影响性能的主要因素是内存,磁盘,网络,还是CPU,是代码问题还是架构设计不合理,或者系统资源确实不足。
    1. 性能优化:根据网站分层架构,可分为Web前端性能优化应用服务器性能优化存储服务器性能优化3大类。

4.2 Web前端性能优化

一般来说这部分指网站业务逻辑之前的部分。主要优化手段有优化浏览器访问,使用反向代理,CDN等。

4.2.1 浏览器访问优化

    1. 减少http请求:合并css,合并js,合并图片。
    1. 使用浏览器缓存:这只HTTP头中的Cache-Control和Expores属性来缓存文件。使用浏览器缓存策略的网站在更新静态资源时,应采用批量更新的方法,比如需要更新10个图标文件应一个一个逐步更新,并有一定的隔间时间,以免用户浏览器突然大量缓存失效,集中更新缓存,造成服务器负载骤增,网络堵塞的情况。
    1. 启用压缩:大部分文本文件的压缩率可达80%以上。使用GZip或Br。压缩对服务器和浏览器产生一定的压力,在通信带宽良好,而服务器资源不足的情况下要权衡考虑。
    1. CSS置顶,JS置底。
    1. 减少Cookie传输:访问静态文件或者不必要的cookie信息很浪费网络资源。可以考虑静态资源使用独立域名访问,避免请求静态资源时发送Cookie。

4.2.2 CDN加速

本质仍然是一个缓存,而且将数据缓存在离用户最近的地方。

image.png

CDN能够缓存的一般是静态资源,图片,文件,css,脚本,静态网页等,但这些文件访问频度很高,将其缓存在CDN可吉大改善网页的打开速度。

4.2.3 反向代理

传统代理服务器位于浏览器一侧,代理浏览器将HTTP请求发送到互联网,而反向代理服务器位于网站机房一侧,代理网站Web服务器接收HTTP请求。

image.png

除了安全功能,代理服务器也可以通过配置缓存功能加速Web请求。当魂村内容有变化时,通过内部通知机制通知反向代理缓存失效,反向代理会重新加载最新的动态内容再次缓存起来。此外,反向代理也可以实现负载均衡的功能,而通过负载均衡构建的应用集群可以提高系统总体处理能力,进而改善网站高并发情况的性能。

4.3 应用服务器性能优化

优化手段主要有缓存,集群,异步等。

4.3.1 分布式缓存

在整个应用中,缓存无处不在,既存在于浏览器,也存在于应用服务器和数据库服务器;既可以对数据缓存,也可以对文件缓存,还可以对页面片段缓存。网站性能优化第一定律:优先考虑使用缓存优化性能。

    1. 缓存的基本原理:一方面缓存访问速度快,另一方面还起到减少逻辑处理时间的作用。缓存的本质是一个内存Hash表,网站应用中,数据缓存以一对Key,Value的形式存储在内存Hash表中。Hash表数据读写的时间复杂度为O(1)。

Hash存储:
image.png

数据写入缓存图示:

image.png

网站数据访问通常遵循二八定律,80%的访问落在20%的数据上。将热点数据缓存起来可以很好的改善系统性能,提高数据读取速度,降低存储访问压力。

    1. 合理使用缓存:
    • 频繁修改的数据:一般来收,数据的读写臂在2:1以上,即写入一次缓存,在数据更新前至少读取两次,缓存才有意义。
    • 没有热点的访问:如果系统访问数据没有热点,那么缓存就没有意义。
    • 数据不一致与脏读:缓存失效期间可能会有数据不一定问题。
    • 缓存可用性:随着业务的发展,缓存会承担大部分数据访问的压力,当缓存崩溃时,数据库会因为完全不能承受如此大的压力而宕机导致站点不可用。这也就是缓存雪崩。发生这种故障,甚至不能重启缓存服务器与数据库服务来恢复访问。实践中,有得网站通过缓存热备等手段提高缓存可用性:当某台缓存服务器宕机时,将缓存访问切换到热备服务器上。但是这种设计有违缓存的初衷,缓存根本就不应该被当做一个可靠的数据源来使用。可以通过分布式缓存服务器集群在一定程度上改善缓存的可用性。产品在设计之初就需要一个明确的定位:什么是产品要实现的功能,什么不是产品提供的特性。在产品漫长的生命周期中,会有形形色色的困难和诱惑来改变产品的发展方向,左右摇摆,什么都想做的产品,最后有可能成为一个失去生命力的四不像。
    • 缓存预热:缓存中存放的是热点数据,热点数据又是缓存系统利用LRU对不断访问的数据筛选淘汰出来的,这个过程需要较长时间。新启动的缓存系统在重建缓存的过程中,系统的性能与负载都不太好,最好在缓存启动时就把热点数据加载好。这个缓存预加载手段叫做缓存预热。
    • 缓存穿透:因为不恰当的业务或者恶意攻击持续高并发的请求某个不存在的数据,缓存中没有保存该数据,所有的请求都会落到数据库上,甚至崩溃。一个简单的对策就是讲不存在的数据也缓存起来,其value值为null。
    1. 分布式缓存架构
      分布式缓存指缓存部署在多个服务器组成的集群中,以集群方式提供缓存服务,其架构方式有两种,一种是以JBoss Cache为代表的需要更新同步的分布式缓存,一种是以Memcached为代表的不互相通信的分布式缓存。
  • JBoss Cache的分布式缓存在集群中所有服务器中保存想通的缓存数据,当某台服务器有缓存数据更新的时候,会通知集群中其他机器更新缓存数据或清除缓存数据。
    image.png

    JBoss通常将应用程序和缓存部署在同一台服务器上,应用程序可从本地快速获取缓存数据,但受限于单一服务器内存空间,而且集群较大时,缓存更新信息需要同步到集群所有机器,代价极大。因此这种方案更多见于企业应用系统中,而很少在大型网站使用。

  • Mem-cached采用集中式的缓存集群管理,也被称作乎不通信的分布式架构方式。缓存与应用分离部署。缓存系统部署在一组专门的服务器上。应用程序通过一致性Hash等路由算法选择缓存服务器远程访问缓存数据,缓存服务器之间不通信,缓存集群的规模可以很容易地实现扩容,具有良好的可伸缩性。优点:设计简单,性能优异,高度可伸缩,丰富的客户端程序,高性能的网络通信(基于Libevent模块),高效的内存管理。

    image.png

    远程通信设计需要考虑两方面的要素,一:通信协议,即TCP/UDP/HTTP协议。二:通信序列化协议,数据传输的两端,必须使用彼此可识别的数据序列化方式才能使通信得以完成。如XML, JSON等文本序列化协议,或者Proto-buffer等二进制序列化协议。

    memcached使用TCP协议,UDP也支持,其序列化协议则是一套基于文本的自定义协议,非常简单。memcached之后,许多NoSQL产品都借鉴了后直接支持这套协议。

    memcached使用固定空间分配。它将内存空间氛围一组slab,每个slab又抱恨一组chunk,同一个slab里的每个chunk的大小是固定的,拥有想通大小chunk的slab被组织在一起,叫做slab_class。

    image.png

    存储数据时,根本数据的大小寻找一个大于Size的最小chunk将数据写入,这样就避免了内存碎片管理的问题,内存的分配和释放都是以chunk为单位的。它也采用LRU算法释放最近最久违背访问的数据占用的空间,缺点就是带来了内存的浪费。一个chunk只能存一个数据,其他空间就浪费了。如果启动参数配置不合理,浪费是惊人的。

4.3.2 异步操作

使用消息队列调用异步化,可改善网站的扩展性。事实上,使用消息队列还可以改善系统的性能。
image.png

image.png

在使用消息队列的情况,在高并发下减少写数据库的压力,较少响应的延迟。
消息队列具有很好的削峰作用,即通过异步处理,将短时间高并发产生的事务消息存储在消息队列中,从而削平高峰期的并发事务。在促销等业务中合理的使用消息队列可以很好的削峰。

image.png

由于数据写入消息队列后立即返回给用户,数据在后续的业务校验,写数据库等操作可能失败,因此在使用消息队列进行异步处理后,需要适当修改业务流程进行配合,如订单提交后,订单数据写入消息队列,不能立即返回用户订单提交成功,需要在消息队列的订单消费者进程真正处理完该订单,甚至商品出库后,再通过email或sms消息通知用户订单成功,一面交易纠纷。

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

4.3.3 使用集群

在网站高并发访问的场景下,使用负载均衡技术为一个应用构建一个又多台服务器组成的服务器集群,将并发访问请求分发到多台服务器上处理,避免单一服务器因负载压力过大而响应换面,使用户请求具有更好的响应延迟特性。目的使服务器的并发请求数目控制在最佳运行区间,获得最佳的访问请求延迟。

利用负载均衡技术改善性能

4.3.4 代码优化

  • 多线程:从资源利用的角度看,使用多线程的原因主要有两个:IO阻塞与多CPU。
    一台服务器上启动线程数参考,假设服务器上执行的都是相同类型的任务:启动线程数=[任务执行时间/(任务执行时间-IO等待时间)]*CPU内核数。最佳启动线程数和CPU内核数量成正比,和IO阻塞时间成反比。如果任务都是CPU及酸性任务,那么线程数最多不超过CPU内核数,因为启动最多线程,CPU也来不及调度;相反如果是任务需要等待磁盘操作,网络响应,那么多启动线程有助于提高任务并发度,提高系统吞吐能力,改善系统性能。多线程带来的问题:线程安全,编程上,解决线程安全的主要手段有如下几点:
    • 将对象设计为无状态对象
    • 使用局部对象:即在方法内部创建对象
    • 并发访问资源时使用锁:通过锁的方式是多线程并发操作转化为顺序操作,从而避免资源被并发修改。
  • 资源复用:尽量减少哪些开销很大的系统资源的创建和销毁,如数据库连接,网络通信连接,线程,复杂对象等。从变成角度,资源复用主要有两种模式:单例和对象池。
  • 数据结构:在不同场景下中合理使用恰当的数据结构,灵活组合各种数据结构改善数据读写和计算特性可极大优化程序的性能。HashCode越随机三列,Hash表的冲突就越少,读写性能就越高,目前比较好的Hash三列算法有Time33, 还有使用MD5获取原始字符串信息指纹,然后使用Hash计算得到HashCode可以较好的解决字符串相近HashCode相近的问题。
  • 垃圾回收:堆栈用于存储存储线程上下文信息,如方法参数,局部变量等。堆则是存储对象的内存空间,对象的创建和释放,垃圾回收就在这里进行。

4.4 存储性能优化

海量的数据读写对磁盘访问会造成巨大压力。

4.4.1 机械硬盘vs固态硬盘

4.4.2 B+树vsLSM树

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

目前许多NoSQL产品采用LSM树作为主要数据结构。

4.4.3 RAIDvsHDFS

RAID(链家磁盘冗余阵列)技术主要是为了改善磁盘的访问延时,增强磁盘的可用性和容错能力。目前服务器级别的计算机都支持插入多块磁盘,通过使用RAID技术,实现数据在多块磁盘上的并发读写和数据备份。

HDFS(Hadoop分布式文件系统)中,系统在整个存储集群的多台服务器上进行数据并发读写和备份,可以看做在服务器集群规模上实现了类似RAID的功能,因此不需要磁盘RAID。HDFS以块Block为单位管理文件内容,一个文件被分割成若干个Block,当应用程序写文件时,每写完一个Block,HDFS就将其自动复制到另外两台机器上,保证每个Block有三个副本,相当于实现了RAID1的数据复制功能。

4.5 小结

归根结底,技术是为业务服务的,技术选型和架构决策依赖业务规划乃至企业战略规划,离开业务发展的支撑和驱动,技术走不远,甚至还会迷路。

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

网站的可用性描述网站可有效防伪的特性。大型网站的不可用事故直接影响功能四形象和利益。

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

网站的页面能完整呈现在最终用户的面前,需要经过很多歌环节,任何一个环节出问题,都可能导致网站页面不可访问。要保证一个网站永远完全可用几乎是一件不可能完成的使命。

5.1.1 网站可用性度量

网站不可用也被称作网站故障,业界通常用多少个9来衡量网站的可用性。qq服务4个9。早年twitter可用性不足2个9。

网站不可用时间 = 故障修复时间点-故障发现时间点

网站年度可用性指标 = (1 - 网站不可用时间 / 年度总时间) * 100%

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

由于可用性影响因素很多,对于网站整体而言,达到4个9,乃至5个9的可能性除了过硬的技术,大量的设备资金投入和工程师的责任心,还要有个好运气。

5.1.2 网站可用性考核

可用性指标是网站架构设计的重要指标,对外是服务承诺,对内是考核指标。指标具体到每个工程师的考核,更多的是使用故障分。所谓故障分是指对网站故障进行分类甲醛甲酸故障责任的方法。故障分=故障时间(分钟) * 故障权重。

image.png

5.2 高可用的网站架构

互联网贡多的采用PC级服务器,开源的数据库和操作系统,廉价的商业级服务器出现硬件孙欢的概率较高,硬件故障是常态,网站的高可用架构设计的主要目的就是保证服务器硬件故障时服务依然可用,数据依然保存并能够被访问。

实现高可用架构的主要手段是数据和服务的冗余备份及失效转移。

一个典型的网站设计通常遵循三层基本划分的架构模型:

image.png

典型的分层模型是三层,即应用层,服务层,数据层;各层之间具有相对独立性,应用层主要负责具体业务逻辑处理;服务层负责提供可复用的服务;数据层负责数据的存储于访问。

小型站点会把应用层于服务层部署在一起,在复杂的大型网站架构中,划分粒度更小,但通常还是会把服务分化到三层中。

image.png

位于应用层的服务器通常为了应对高并发的访问请求,会通过负载均衡设备将一组服务器组成一个集群共同对外提供服务,当负载均衡设备通过心跳检测等手段监控到某台应用服务器不可用时,就将其从集群列表中剔除,并将请求分发到集群中其他可用的服务器上,使整个集群保持可用,从而实现应用高可用。

位于服务层的服务器情况和应用层的服务器类似看也是通过集群方式实现高可用,只是这些服务器被应用层通过分布式服务调用框架访问,分布式服务调用框架会在应用层客户端程序中实现软件负载均衡,并通过服务注册中心对提供服务的服务器进行心跳检测,发现有服务不可用,立即通知客户端程序修改服务访问列表,剔除不可用的服务器。

位于服务层的服务器情况比较特殊,数据服务器上存储着数据,为了保证服务器宕机时数据不丢失,数据访问服务不中断,需要在数据写入时进行数据同步复制,将数据写入多台服务器上,实现数据冗余备份。当数据服务器宕机时,应用程序将访问切换到有备份数据的服务器上。

不仅要考虑硬件损坏引起的宕机,还有网站升级发布引起的宕机。

5.3 高可用应用

应用层也叫业务逻辑层,应用的一个显著特点是应用的无状态性。
所谓的无状态是指应用服务器不保存业务的上下文信息,而仅根据每次请求提交的数据进行相应的业务逻辑处理,多个服务实例之间完全对等,请求提交到任意服务器,处理结果都是完全一样的。

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

不保存状态的应用给高可用的架构设计带来了巨大遍历,不保存状态那么所有服务器完全对等,当任意一台服务器宕机时,可以采取失效转移。

对于应用服务器集群,实现这种服务器可用状态实时监测,自动转移失败任务的机制是负载均衡。通过负载均衡手段,将流量和数据分摊到一个集群组成的多台服务器上,以提高整体的负载处理能力。

负载均衡在应用层实际上起到了系统高可用的作用,因此即使某个应用访问量非常少,志勇一台服务器提供服务就绰绰有余,但如果需要保证该服务高可用,也必须至少部署两台服务器,使用负载均衡技术构建一个小型的集群。

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

应用服务器的高可用件架构设计主要基于服务无状态的这一特性,但业务总是有状态的。 Web应用中降至多次请求修改使用上下文对象称作会话Session。

集群环境下,Session管理主要有一下几种手段。

    1. Session复制:早期系统使用较多,机器在急群众的几台服务器之间同步Session对象,方法虽然简单,但当集群规模较大时,大量的通信进行Session复制,占用服务器大量资源,Session信息太多占用内存。
    1. Seesion绑定:利用负载均衡的源地址Hash算法实现,同一个IP请求分发到同一台服务器。但是当某台服务器宕机,状态就会丢失,负载均衡服务器也提供使用源地址负载均衡算法,但很少使用。
    1. 利用Cookie记录Session:方法简单方便,但客户端可能会禁用Cookie,每次请求带Cookie浪费资源影响性能,Cookie大小有限制。
    1. Session服务器:可用性搞,伸缩性好,性能不错,无信息大小限制。
      image.png

5.4 高可用的服务

  1. 分级管理:运维上将服务器进行分级管理,核心应用和服务有限使用更好的硬件,在运维响应速度上也格外迅速。同事在服务部署上也进行必要的隔离,避免故障的连锁反应。低优先级的服务通过启动不同的线程或者部署在不同的虚拟机上进行隔离,而高优先级的服务则需要部署在不同的物理机上,核心服务和数据甚至需要部署在不同低于的数据中心。
  2. 超时设置:在应用程序中设置服务调用的超时时间,一旦超时,通信框架就抛出异常,应用程序根据服务调度策略,可选择继续重试或将请求转移到提供相同服务的其他服务器上。
  3. 异步调用:应用对服务的调用通过消息队列等一部方式完成,避免一个服务失败导致整个应用请求失败的情况。当然不是所有服务器调用都可以异步调用。
  4. 服务降级:站点访问高峰期,为了保证核心应用和功能的正常运行,需要对服务进行降级。降级有两种手段:拒绝服务及关闭服务。
    • 拒绝服务:拒绝低优先级应用的调用,减少服务调用并发数,确保核心应用正常使用;或者随机拒绝部分请求调用。
    • 关闭功能:干部部分不重要的服务,或者服务内部关不部分不重要的功能,以节约系统开销,为重要的服务和功能让出资源。
  5. 幂等性设计:服务重复调用是无法避免的,应用层也不需要关心服务是否真的失败,只要没有收到调用成功的响应,就可以认为调用失败,并重试服务调用。因此必须在服务层保证服务重复调用和调用一次产生的结果相同,即服务具有幂等性。比如转账交易等操作,问题就会比较复杂,需要通过交易编号等信息进行服务调用有效性校验,只有有效的操作才能继续执行。

5.5 高可用的数据

保证数据存储高可用的手段主要是数据备份和失效转移机制。

关于缓存服务的高可用,在实践中争议很大,一种观点认为缓存已经成为网站数据服务的重要组成部分,事实上承担了业务中绝大多数的数据读取访问服务,缓存服务失效可能会导致数据库负载过高而宕机进而影响整个网站的可用性,因此缓存服务需要实现和数据存储服务同样的高可用。另一种观点认为,缓存服务不是数据存储服务,缓存服务器宕机引起缓存数据丢失导致服务器负载压力过高应该通过其他手段解决,而不是提高缓存服务本身的高可用。

5.5.1 CAP原理

为了保证数据的高可用,网站通常会牺牲另一个也很重要的指标:数据一致性。

高可用的数据有如下几个层面的含义:

  • 数据持久化
  • 数据可访问性
  • 数据一致性:由于网络,服务器,软件出现故障导致部分副本写入不成功出现的数据不一致。
    • 数据强一致:各个副本的数据在物理存储中总是一致的。
    • 数据用户一致:即数据在物理存储中的各个副本的数据可能是不一致,但终端用户访问时,通过纠错和校验机制,可能确定一个一致且正确的数据返回。
    • 数据最终一致:即物理存储的数据可能是不一致的,终端用户访问到的数据可能也是不一致的,但系统经过一段时间的自我恢复和修正,数据最终会达到一致。

CAP原理认为:一个提供数据服务的存储系统无法同事满足数据一致性,数据可用性,分区耐受性这灿哥条件。

image.png

CAP原理对于可伸缩的分布式系统设计具有重要意义,在系统设计开发过程中, 不恰当地迎合葛总需求,企图打造一个完美的产品,可能会UI使设计进入两难境地,难以为继。

因为难以满足数据强一致性,网站通常会综合成本,技术,业务场景等条件,结合应用服务和其他的数据监控与纠错功能,使存储系统达到用户一致,保证最终用户访问数据的正确性。

5.5.2 数据备份

数据冷备:定期将数据复制到存储介质并物理保管,如果系统存储损坏,那么就从冷备的存储设备中恢复数据。优点:简单,廉价,成本,技术难度低。缺点:不能保证数据最终一致。同时也不能保证数据可用性,从冷备恢复需要较长时间。

数据热备:

  • 异步热备方式:指多份数据副本的写入操作异步完成,应用程序收到数据服务系统的写操作成功响应时,只写成功了一份,存储系统将会异步地写其他副本,该过程可能会失败。数据写入时,由主存储服务器的写操作代理模块将数据写入本机存储系统后立即返回写操作成功响应,然后通过异步线程将写操作数据同步到从存储服务器。
    image.png
  • 同步热备方式:指多份数据副本的写入操作同步完成。存储服务客户端在写多份数据的时候,并发操作,这意味着多份数据的总写操作延迟是响应最慢的那台存储服务器的响应延迟。其性能和异步热备方式差不多
    image.png

关系数据库热备机制就是Master-Slave同步机制。这样不但解决了数据备份问题,还改善了数据库系统的性能,实践中,通常使用读写分离的方法访问Slave和Master数据库,写操作只访问Master数据库,读操作只访问Slave数据库。

5.5.3 失效转移

数据服务器集群中任何一台服务器宕机,那么应用程序针对这台服务器的所有读写操作都需要重新路由到其他服务器,保证数据访问不会失败,这个过程叫做失效转移。失效转移操作由三部分组成:失效确认,访问转移,数据恢复。

  • 1.失效确认:系统确认一台服务器是否宕机的手段有两种:心跳检测和应用程序访问失败报告。
    image.png

    对于应用程序的访问失败报告,控制中心还需要再一次发送心跳检测进行确认,以免错误判断服务器宕机,因为一旦进行失效转移,意味着数据存储多份副本不一致还需要进行后续一系列的复杂操作。

  • 2.访问转移:失效确认后,就需要将数据读写访问重新路由到其他服务器上。

    1. 数据恢复必须将副本的数据恢复到系统设定的值,否则再有宕机可能无法访问转移了。

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

在站点运维实践中,除了网络,服务器等硬件故障导致的高可用性风险外,还有来自软件系统本身的风险。

5.6.1 网站发布

尽最大能力保证用户体验,平滑重启发布服务。通常使用发布脚本来完成发布。

image.png

5.6.2 自动化测试

目前大部分站点都采用Web自动化测试技术,使用自动测试工具或脚本完成测试。常用的有Selenium,puppeteer。也可以自行开发一键完成系统部署,测试数据生成,测试执行,测试报告生成等全部测试过程。

5.6.3 预发布验证

由于线下与线上环境有差别,因此在网站发布时,并不是把所有测试通过的袋面包直接发布到线上服务器,而且先发布到预发布机器上进行预发布验证,执行一些典型的业务流程,确认系统没有问题后才正式发布。

预发布服务器和线上的正式服务器唯一的不同就是没有配置在负载均衡服务器上,外部用户无法访问。

image.png

工程师可以通过配置计算机hosts文件绑定域名IP关系后直接使用IP地址访问预发布服务器。

预发布所操作的数据均是正式数据,谨慎操作。

5.6.4 代码控制

git对分布式开发,分支开发等有更好的支持,避免提交分支发现差别太大难以merge。

5.6.5 自动化发布

人的干预越少,自动化程度越高,引入故障的可能性就越小。

5.6.6 灰度发布

为了避免在集群规模很庞大,出现故障引起无法在短时间内回滚的问题,大型网站会使用灰度发布模式。将集群服务器氛围若干部分,每天只发布一部分服务器,观察状态,没有故障后继续发布一部分,知道集群全部发布完毕,期间如有问题只回滚已发布的一部分服务器即可。

image.png

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

5.7 网站运行监控

不允许没有监控的系统上线。

5.7.1 监控数据采集

广义上的网站监控涵盖所有非直接业务行为的数据采集与管理,包括供数据分析师和产品设计师使用的网站用户行为日志,业务运行数据,以及供运维工程师和开发工程师使用的系统性能数据等。

  • 1.用户行为日志收集:指用户在浏览器上所做的所有操作及其所在的操作环境,包括用户操作系统与浏览器版本信息,IP,页面访问路径,页面停留时间等,这些数据对统计网站PV/UV指标,分析用户行为,优化网站设计,个性化营销与推荐等非常重要。收集手段:
    • 服务器端日志收集
    • 客户端浏览器日志收集
    1. 服务器性能监控:如系统Load,内存占用,磁盘IO,网络IO等尽早做出故障预警。目前网站使用比较广泛的开源性能监控工具Ganglia。
    1. 运行数据报告一些与具体业务场景相关的技术和业务指标,比如缓冲命中率,平均响应延迟时间,每分钟发送邮件数目,待处理的任务总数等。

5.7.2 监控管理

监控数据除了用作性能评估,集群伸缩性预测等,还可以根据实时监控数据进行风险预警,并对服务器进行失效转移,自动负载调整,最大化利用集群所有机器资源。

  • 系统报警:超过设置阈值通过邮件,短信,语音等报警。
  • 失效转移:发现故障的情况下主动通知应用进行失效转移。
  • 自动优雅降级:为了应付突然爆发的访问高峰,主动关闭部分功能,释放部分系统资源,保证网站核心功能正常访问的一个手段。

5.8 小结

事务总是先求生存,再求发展。保证网站可用,万无一失,任重而道远。

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

伸缩性指不需要改变网站的软硬件设计,仅仅通过改变部署的服务器数量就可以扩大或者缩小网站的服务处理能力。

6.1 网站架构的伸缩性设计

网站的架构发展史就是一部不断向网站添加服务器的历史。一般来说,网站的伸缩性设计可分成两类,一类是根据功能进行物理分离实现伸缩,一类是单一功能通过集群实现伸缩。前者是不同的服务器部署不同的服务,提供不同的功能;后者是集群内的多台服务器部署想相同的服务,提供相同的功能。

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

image.png

通过物理上分离不同的网站功能,实现网站伸缩性的手段,不仅可以在网站发展早期,而且可以再网站发展的任何阶段使用。具体又分成如下两种情况、

  • 纵向分离(分层后分离):将业务处理流程上的不同部分分离部署,实现系统伸缩性。

    image.png

  • 横向分离(业务分割后分离):将不同的业务模块分离部署,实现系统伸缩性。

    image.png

    横向分离的粒度可以非常小,甚至可以一个关键网页部署一个独立服务。如电商产品详情页,搜索列表等。

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

将不同功能分离部署可以实现一定程度的伸缩性,随着业务增长,单一的服务器也不能满足业务规模的要求。因此不惜使用服务器集群。

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

集群伸缩性又分为应用服务器集群伸缩性和数据服务器集群伸缩性。这两种集群由于对数据状态管理的不同,技术实现也有非常大的区别。而数据服务器集群也可以分为缓存数据服务器集群和存储数据服务器集群,这两种集群的伸缩性设计也不大相同。

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

应用服务器应该设计成无状态的,即应用服务器不存储请求上下文信息,这样可以把用户请求按照某种规则分发到集群的不同服务器上,就可以构成一个应用服务器集群。

如果HTTP请求分发装置可以感知或者可以配置集群的服务器数量,可以及时发现集群中新上线或下线的服务器,并能像新上线的服务器分发请求,停止向已下线的服务器分发请求,那么就实现了应用服务器集群的伸缩性。该请求分发装置被称作负载均衡服务器。

负载均衡是网站必不可少的基础技术手段,不但可以实现网站的伸缩性,同事还改善网站的可用性。实现负载均衡的基础技术不外以下几种。

6.2.1 HTTP重定向负载均衡

image.png

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

优点:实现简单。缺点:一次访问需要两次请求才能完成,性能较差;重定向服务器自身的处理能力有可能成为瓶颈,整个集群的伸缩性有限。使用302重定向,有可能是搜索引擎判断为SEO作弊。在实践中此方案使用并不多。

6.2.2 DNS域名解析负载均衡

image.png

每次域名解析请求都会根据均衡算法计算一个不同的IP地址返回,这样A记录中配置的多个服务器就构成一个集群,并可以实现负载均衡。

DNS域名解析负载均衡的优点:省掉网站管理维护负载均衡服务器的麻烦,交给了DNS,同时许多DNS还支持基于地理位置的域名解析,将距离最近的服务器地址返回给用户。缺点:目前的DNS是多级解析,每一级DNS都可以缓存A记录,当下线某台服务器后,即使修改了DNS的A记录,要使生效也需要较长时间,导致访问失败。而且DNS负载均衡控制权在域名服务商,网站无法对其多改善与强大的管理。

大型网站总是部分使用DNS域名解析,利用域名解析作为低一级负载均衡手段,即域名解析得到的一组服务器并不是实际提供Web服务的物理服务器,而是同样提供负载均衡的内部服务器,这组内部负载均衡服务器再进行负载均衡,将请求分发到真实的Web服务器上。

6.2.3 反向代理负载均衡

image.png

利用反向代理缓存资源以改善网站性能。实际上,在部署位置上,反向代理服务器处于Web服务器前面(这样才可以能缓存Web响应,加速访问),这个位置也正好是负载均衡服务取得位置,所以大多数反向代理服务器同时提供负载均衡的功能。

由于反向代理服务器转发请求在HTTP协议层面,因此也叫应用层负载均衡。有点:和反向代理服务器功能集成在一起,部署简单。缺点:反向代理服务器是所有请求和响应的中转站,其性能可能会成为瓶颈。

6.2.4 IP负载均衡

image.png

用户请求数据包到达负载均衡服务器114.100.80.10后,负载均衡服务器在操作系统内核进程获取网络数据包,根据负载均衡算法计算得到一台真实Web服务器10.0.0.1,然后将数据目的IP地址修改为10.0.0.1,不需要通过用户进程处理,真实Web应用服务器处理完成后,响应数据包回到负载均衡服务器,负载均衡服务器再将数据包源地址修改为自身的IP地址(114.100.80.10)发送给用户浏览器。

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

IP负载均衡在内核进程完成数据分发,较反向代理负载均衡有更好的性能。但是由于所有请求响应都经过负载均衡服务器,集群的最大响应数据吞吐量不得不受限于负载均衡服务器网卡带宽。对于提供下载服务或者视频服务等需要传输大量数据的网站而言,难以满足需求。

6.2.5 数据链路层负载均衡

指在通信协议的数据链路层改mac地址进行负载均衡。

image.png

这种数据传输方式又称作三角传输模式,负载均衡数据分发过程中不修改IP地址,只修改目的的mac地址,通过配置真是物理服务器建所有机器虚拟IP和负载均衡服务器IP地址一致,从而达到不修改数据包的源地址和目的地址就可以进行数据分发的目的,由于实际处理请求的真真实物理服务器IP和数据请求目的一致,不需要通过负载均衡服务器进行地址转换,可将响应数据包直接返回给用户浏览器,避免负载均衡网卡带宽成为瓶颈。这个负载均衡方式又称为直接路由方式(DR)。

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

6.2.6 负载均衡算法

常用的集中负载均衡算法:

    1. 轮询:依次分发到没太应用服务器,适合所有服务器硬件都相同的场景。
    1. 加权轮询:适合服务器硬件资源不同的场景。
    1. 随机:随机分配到各个应用服务器。也有加权随机。
    1. 最少链接:记录每个应用服务器正在处理的连接数,将新到的请求分发到最少链接的服务器。也有加权最少链接。
    1. 源地址散列:根据请求来源的IP地址进行Hash计算,得到应用服务器,这样来自同一个IP地址总在同一个服务器上处理,该请求的上下文可以存储在这台服务器上,在一个会话周期内重复使用,从而实现会话粘滞。

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

和所有服务器都部署相同应用服务器集群不同,分布式缓存服务器集群中不同服务器中缓存的数据各不相同,缓存访问请求不可以在缓存服务器急群众任意一台处理,必须先找到缓存有需要数据的服务器,然后才能访问。这个特点会严重制约分布式缓存集群的伸缩性设计。因为新上线的缓存服务器没有缓存任何数据,而已下线的缓存服务器还缓存着网站的许多热点数据。

必须让新上线的缓存服务器对整个分布式缓存集群影响最小,也就是说新加入缓存服务器后应使整个缓存服务器集群众已经缓存的数据尽可能还被访问到,这就是分布式缓存集群伸缩性设计的最主要的目标。

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

image.png

应用程序通过Memcached客户端访问Memcached服务器集群,Memcached客户端主要有一组API,Memcached服务器集群路由算法,Memcached服务器集群列表及通信模块构成。

其中路由算法负责根据应用程序输入的缓存数据KEY计算得到应该将数据写入到Memcached的哪台服务器(写缓存)或者应该从哪台服务器读数据。

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

简单的路由算法可以使用余数Hash:用服务器数目初一缓存数据KEY的Hash值,余数为服务器列表下标编号。由于HashCode具有随机性,因此使用余数Hash路由算法可保证缓存数据在整个Memcached服务器集群中比较均衡的分布。余数Hash几乎可以满足绝大多数的缓存路由需求。但当分布式缓存集群需要扩容的时候,就特别棘手了。

早网站业务中,大部分业务数据读操作请求事实上是通过缓存获取的,只有少量读操作请求会访问数据库,因为数据库的负载能力是以有缓存为前提而设计的。当大部分被缓存了的数据因为服务器扩容而不能正确读取时,这些数据访问的压力就落到了数据库的身上,这将大大超过数据库的负载能力,严重的可能会导致数据库宕机。这种情况下,不能简单重启数据库,网站也需要较长时间才能逐渐恢复正常。

一种解决方法是在网站访问量最少的时候扩容缓存服务器集群,这时候对数据库的负载冲击最小。然后通过模拟请求的方式逐渐预热缓存,是缓存服务器中的数据重新分布。另外一个钟解决方法就是一致性Hash算法。

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

一致性Hash算法通过一个叫做一致性Hash环的数据结构实现KEY到缓存服务器的Hash映射。

image.png

先构造一个长度为0~2^32的整数环,这个环被称作一致性Hash环,根据节点名称的Hash值,其分布范围同样为0-2^32,将缓存服务器节点放置在这个Hash环上。然后根据需要缓存的数据的KEY值计算得到其Hash值,然后在Hash换上顺时针查找距离这个KEY的Hash值最近的缓存服务器节点,完成KEY到服务器的Hash映射查找。

由于KEY是顺时针查找距离其最近的节点,因此新假日的节点只影响整个环中的一小段。

image.png

但是上述算法存在一个问题,如果4台机器的性能是一样的,NODE1的负载是NODE0与NODE3的一半,这显然不是我们想要的。

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

将没太物理缓存服务器虚拟为一组虚拟缓存服务器,将细腻服务器的Hash值放在Hash环上,KEY在环上先找到细腻服务器节点,再得到物理服务器的信息。这样新加入物理服务器节点时,是将一组细腻节点加入环中,如果虚拟节点的数目足够多的,这组虚拟节点将会影响同样多数目的已经在环上存在的虚拟节点,这些已经存在的虚拟节点又对应不同的物理节点。最终的结果:新加入一台缓存服务器,将会较为均匀地影响原来集群中已经存在的所有服务器。

image.png

虚拟节点越多,物理节点负载越均衡,新加入物理服务器对原有的物理服务器的影响越保持一致,这也是名字的由来。一把来说,虚拟150个虚拟节点合适,不过看业务具体情况。

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

数据存储服务器必须保证数据的可靠存储,任何情况下都必须保证数据的可用性和正确性。因此缓存服务器集群的伸缩性架构方案不能直接适用于数据库等存储服务器。

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

使用数据复制的MySql集群伸缩性方案。

image.png

除了数据库主从读写分离,前面提到的业务分割模式也可以用在数据库,不同业务数据表部署在不同的数据库集群上,即俗称的数据分库。这种方式的制约条件是跨库的表不能进行Join操作。

在大型网站的实际应用中,即使进行了分库和主从复制,对一些单表数据仍然很大的表,比如FB的用户数据库,淘宝的商品数据库,还需要进行分片,将一张表拆开分别存储在多个数据库中。目前在线业务应用中较成熟的支持数据分片的分布式关系数据库产品主要有Amoeba和Cobar。

image.png

Codar是一个分布式关系数据库访问代理,介于应用服务器和数据库服务器之间。Cobar也支持非独立部署,以lib的方式和应用程序部署在一起。应用程序通过JDBC驱动访问Cobar集群,Cobar服务器根据SQL和分库规则分解SQL,分发到MySQL集群不同的数据库上执行,每个MySQL实例都部署为主/从结构,保证数据高可用。

image.png

6.4.2 NoSQL数据库的伸缩性设计

直到大型网站遇到了关系数据库难以克服的缺陷--糟糕的海量数据处理能力及僵硬的设计约束,局面才有所改善。为了解决上述问题,NoSQL这一概念被提了出来,以一部关系数据库的不足。一般而言,NoSQL数据库产品都放弃了关系数据库的两大重要基础:以关系代数为基础的机构化查询语言SQL和事务一致性保证(ACID)。而强化其他一些大型网站更关注的特性:高可用性和可伸缩性。

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

6.5 小结

网站架构师必须对网站的商业目标,历史演化,技术路线了然于胸,甚至还需要综合考虑技术团队的只是储备和结构,管理层的战略愿景和规划,才能最终做出对网站伸缩性架构最合适的决策。

一个具有良好伸缩性架构设计的网站,其这几总是走在业务发展的前面,在业务需要处理更多访问的服务之前,就已经做好充足准备。当业务需要时,只需要购买或者租用服务器简单部署实施就可以了,反之,设计和技术走在业务的后面,采购来的机器根本就没办法加入集群,勉强加了进去,却发现瓶颈不在这里,系统整体处理能力依然上不去。

高手定律:这个世界只有遇不到的问题,没有解决不了的问题,高手之所以成为高手,是因为他们遇到了常人很难遇到的问题,并解决了。

救世主定律:遇到问题,分析问题,最后总能解决问题。如果遇到问题就急匆匆地从外面挖一个高手,然后指望高手如探囊取物般轻松搞定,最后怕是只有彼此抱怨和伤害。许多问题只是看爱来一样,具体问题总是要具体对待的,没有银弹,没有救世主。

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

经常有架构师混淆扩展性和伸缩性。

扩展性:指对现有系统影响最小的情况下,系统功能可持续扩展或提升的能力。表现在系统基础设施稳定不需要经常变更,应用之间较少依赖和耦合,对需要变更可以敏捷响应。它是系统架构设计层面的开闭原则:对扩展开房,对修改关闭,架构设计考虑未来功能扩展,当系统增加新功能时,不需要对现有系统的结构和代码进行修改。

伸缩性:指系统能够通过增加/减少自身资源规模的方式增强/减少自己计算处理事务的能力。如果这种增减是成比例的,就被称作现行伸缩性。在网站架构中,通常指利用集群的方式增加服务器数数量,提高系统的整体事务吞吐能力。

7.1 构建可扩展的网站架构

从语言发展到软件工具到各种开发框架,五部体现着降低软件系统耦合性这一终极目标。
度量一个开发框架,设计模式,变成语言优劣的重要尺度就是衡量它是不是让软件开发过程和软件产品更低耦合。

低耦合的系统更易扩展,低耦合的玫琳凯更容易复用,一个低耦合的系统设计也会让开发过程和维护变得更加轻松。

软件架构师最大的价值不在于掌握多少先进的技术,而在于具有将一个系统切分成N个低耦合的子模块的能力,这些子模块包含横向的业务模块,也包含纵向的基础技术模块。这种能力一部分院子专业的技术与经验,还有一部分院子架构师对业务场景的理解,对人性的把我,甚至对世界的认知。

设计网站可扩展架构的核心思想是模块化,并在此基础之上,降低模块间的耦合性,提高模块的复用性。通过分层和分割的方式将软件分割为若干个低耦合的独立的组件模块,这些组件模块以消息传递及依赖调用的方式聚合成一个完整的系统。在大型网站中,这些模块通过分布式部署的方式,独立的模块部署在独立的服务器集群上,从物理上分离模块之间的耦合关系,进一步降低耦合性提高复用性。

模块分布式部署以后具体聚合方式主要有分布式消息队列和分布式服务。

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

思想:避免模块之间的直接调用,这样系统的可扩展性无疑是更好一些。

7.2.1 事件驱动架构

事件驱动架构(EDA):通过在低耦合的模块之间传输事件消息,以保持模块的松散耦合,并借助事件消息的通信完成模块间合作,典型的EDA架构就是操作系统中常见的生产者消费者模式。
image

7.2.2 分布式消息队列

可以看作将先进先出的数据结构机制部署在独立的服务器上。

image

目前开源和商业的分布式消息队列产品有很多,如ActiveMQ

在伸缩性方面,将新服务器加入分布式消息队列急群众,通知生产者服务器更改消息队列服务器列表即可。

在可用性方面,如果内存队列已满,会将消息写入磁盘,消息推送模块在将内存队列处理完以后,将磁盘内容加载到内存队列继续处理。

为了避免消息队列服务器宕机造成消息丢失,会将消息成功发送到消息队列的消息存储在消息生产者服务器,等消息真正被消息消费者服务器处理后才删除消息。在消息队列服务器宕机后,生产者服务器会选择分布式消息队列服务器急群众其他的服务器发布消息。

MQ可以很复杂比如支持企业服务总线ESB,支持面向服务的架构SOA等,也可以很简单,如使用mysql即可。

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

使用分布式服务是降低系统耦合度的另一个重要手段。
分布式消息队列通过消息对象分解系统耦合性,不同子系统处理同一个消息;分布式服务则通过接口分解系统耦合度,不同子系统通过相同的接口描述进行服务调用。

巨无霸应用系统的问题:

  1. 编译,部署困难。
  2. 代码分支管理困难
  3. 数据库连接耗尽
  4. 新增业务困难

解决方案就是拆分,将模块独立部署,降低系统耦合性。拆分可以分为纵向拆分和横向拆分两种。

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

纵向炒粉较为简单,梳理业务,剥离较独立的应用。而横向拆分,不但需要识别可复用的业务,设计服务接口,规范服务依赖关系,还需要一个完善的分布式服务管理框架。

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

Web Service 架构原理:
image

服务提供者通过WSDL向注册中心描述自己提供的服务接口属性,注册中心使用UDDI发布服务提供者提供的服务,服务请求者从注册中心检索到服务信息后,通过SOAP和服务提供者通信,使用相关服务。

但有以下缺点:

  1. 臃肿的注册于发现机制。
  2. 抵消的XML序列化手段。
  3. 开销相对较高的HTTP远程通信。
  4. 复杂的部署与维护手段。
    这些问题导致Web Service难以满足大型网站对系统高性能,高可用,易部署,易维护的要求。

7.3.2 大型网站分部署服务的需求与特点

除了提供的服务注册于发现,服务调用等标准功能,还需要分布式服务框架能够支持如下特性。

  1. 负载均衡
  2. 失效转移
  3. 高效的远程通信
  4. 整合异构系统
  5. 对应用最少侵入
  6. 版本管理:分布式服务框架需要支持服务多版本发布服务提供者先升级接口发布新版本的服务,并同时提供旧版本的服务供请求者调用,当请求者调用接口升级后才可以关闭旧版本服务。
  7. 实时监控:监控服务提供者和调用者的各项指标

7.3.3 分布式服务框架设计

以阿里开源的Dubbo为例:
image

服务消费者程序通过服务接口使用服务,而服务接口通过代理加载具体服务,具体服务可以使本地的代码模块,也可以使远程的服务,因此对应用较少侵入:应用程序只需要调用服务接口,服务框架根据配置自动调用本地货远程实现。

服务框架客户端模块通过服务注册中心加载服务提供者列表,查找需要的服务接口,并根据配置的负载均衡策略将服务调用请求发送到某台服务提供者服务器。如果服务调用失败,客户端模块会自动从服务提供者列表选择一个可提供同样服务的另一台服务器重新请求服务,实现服务的自动失效转移,保证服务高可用。

Dubbo的远程服务通信模块支持多种通信协议和数据序列化协议,使用NIO通信框架,具有较高的网络通信性能。

7.4 可扩展的数据结构

传统的关系数据库为了保证关系原酸的正确性,在设计数据库表结构的时候,就需要指定表的schema--字段名称,数据类型等,并要遵循特定的设计范式。这些规范带来的一个问题就是僵硬的数据结构南海意面对需求变更带来的挑战,有些应用系统设计者通过预先设计一些冗余字段来应对,不过显然这事一种糟糕的数据库设计。

许多NoSQL数据库使用的ColumbFamily列族设计就是一个解决方案。最早在Google的Bigtable中使用。

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

只靠自己很难满足所有用户的需求,大型网站为了更好的服务自己的用户,开发更多的增值服务,会把网站内部的服务封装成一些调用接口开放出去,供外部的第三方开发者使用,这个提供开放接口的平台被称作开放平台。

第三方开发者利用这些开放的接口开发应用程序或者网站,为更多的用户提供价值。网站,用户,第三方开发者互相新来,形成一个网站的生态圈,即为用户提供更多的价值,也提高了网站和第三方开发者的竞争能力和盈利能力。

image

  1. API接口:暴露给开发者使用的一组API,可以使RESTful,WebService, RPC等各种形式。
  2. 协议转换:将各种API输入转换成内部服务于可以识别的形式,并将内部服务的返回封装成API的格式。
  3. 安全:除了一般应用需要的身份识别,权限控制等安全手段,开放平台还需要分级的访问带宽限制,保证平台资源被第三方应用公平合理使用,也保护网站内部服务不会被外部应用拖垮。
  4. 审计:记录第三方应用的访问情况,并进行监控,计算等。
  5. 路由:将开放平台的各种访问路由映射到具体的内部服务。
  6. 流程:将一组离散的服务组织成一个上下文相关的新服务,隐藏服务细节,提供统一接口供开发者调用。

7.6 小结

马克思的劳动价值理论告诉我们,产品的内在价值在于劳动时间,劳动的时间不在于个体付出的劳动时间,而在于行业一个劳动时间,资本家只会为行业一般劳动时间买单,如果你的效率低于行业一般劳动时间,请自愿加班。反之则会有更多的时间做其他事情。

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

开放的互联网处处存在着安全的问题。

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

8.1.1 XSS攻击

XSS攻击即跨站点脚本攻击,指黑客通过篡改网页,注入恶意HTML脚本,在用户浏览网页时,控制用户浏览器进行恶意操作的一种攻击方式。
常见的XSS攻击类型有两种:

  1. 反射性:攻击者诱使用户点击一个嵌入恶意脚本的链接,打到攻击的目的。
    image
  2. 持久性XSS攻击,黑客提交含有恶意脚本的请求,保存在被攻击的Web站点的数据库中,用户浏览网页时,恶意脚本被包含在正常页面中,打到攻击的目的。
    image

防御手段:

  1. 消毒:XSS攻击者一般都是通过在请求中嵌入恶意脚本打到攻击的目的,这些脚本都是一般用户输入中不使用的,对某些html危险字符转移,如“>”转义为“&gt”,“<”转义为“&lt”等,就可以防止大部分攻击。为了避免对不必要的内容错误转义,如“3<5”中的“<”需要进行文本匹配后再转义,如“<img src=”才转义,消毒几乎是所有站点必备防攻击手段。
  2. HttpOnly:最高由微软提出,即浏览器进制页面js访问带有HttpOnly属性的Cookie。

8.1.2 注入攻击

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

  • SQL注入攻击
    image

SQL注入攻击需要攻击者对数据库结构有所了解才能进行,攻击者获取数据库表结构信息的手段有如下几种。

  1. 开源
  2. 错误回显
  3. 盲注(群举猜测)

防御手段:

  1. 消毒:请求参数消毒是一种简单粗暴有效的手段,过滤请求数据中可能注入的SQL,如“drop table”,“\b(?:update\b.?\bset|delete\b\W?\bfrom)\b”等。
  2. 参数绑定:使用预编译手段,绑定参数是最好的防SQL注入的方法,母线很多ORM都实现了SQL预编译和参数绑定,攻击者的恶意SQL会被当做SQL的参数,而不是SQL命令被执行。
  • OS注入
    攻击者还根据具体应用,注入OS命令,编程语言代码等,利用程序漏洞打到攻击目的。

8.1.3 CSRF攻击

CSRF跨站请求伪造,攻击者通过跨站请求,以合法用户的身份进行非法操作。CSRF的主要手段是利用跨站请求,在用户不知情的情况下,以用户的身份伪造请求。其核心是利用了浏览器Cookie或服务器Session策略,盗取用户身份。

image

防御手段:

  1. 表单Token:CSRF是一个伪造用户请求的操作,所以需要构造用户请求的所有参数才可以。表单TOken通过在请求参数中增加随机数的方法来组织攻击者获取所有请求参数:在页面表单中增加一个随机数作为Token,每次响应页面的Token都不相同,从正常页面提交的请求会包含该Token值,而伪造的请求无法获得该值,服务器检查请求参数中Token的值是否存在并且正确以确定请求提交者是否合法。
  2. 验证码:更加简单高效的方法,请求提交时,需要用户输入验证码,以避免在用户不知情的情况下被攻击者伪造请求。但输入验证码是一个糟糕的用户体验,所以请在必要的时候使用,如支付。
  3. Referer check:通过检查请求头的Referer确认请求来源验证其是否合法。如图片防盗链就是利用Referer实现的。

8.1.4 其他攻击和漏洞

  1. Error Code:错误回显,通过故意制造非法输入,使系统运行时出错,获得异常信息,从而寻找系统漏洞进行攻击。防御手段:通过配置Web服务器参数,跳转500页面到专门的错误页面即可。
  2. HTML注释:发布前需要进行代码cr或自动扫描,避免HTML注释漏洞。
  3. 文件上传:如果上传的是可执行的程序并通过该程序获得服务器端命令执行能力,将是非常有破坏力的。防御手段:设置上传文件白名单,只允许上传可靠的文件类型,还可以修改文件名,使用专门的存储手段等。
  4. 路径遍历:攻击者在请求的URL中使用相对路径,遍历系统未开放的目录和文件。防御手段:将JS,CSS等资源文件部署在独立服务器,使用独立域名,其他文件不适用静态URL访问,动态参数不包含文件路径信息。

8.1.5 Web应用防火墙

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

8.1.6 网站安全漏洞扫描

网站安全漏洞扫描工具是根据内置规则,构造具有攻击性的URL请求,模拟和黑客攻击行为,用以发现网站安全漏洞的工具。许多大型网站的安全团队都有自己开发的漏洞扫描工具。

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

通常,为了保护网站的敏感数据,应用需要对这些信息进行加密处理,信息加密技术可分为三类:三项散列加密,对称加密和非对称加密。

8.2.1 单项散列加密

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

image

利用单项散列加密的特性,可以进行秘密加密保存,就算数据库被拖库,也不会泄露用户的密码信息。为了防止通过彩虹表等手段破解,可以使用加盐的方式增加破解难度。

常用的单项散列算法有MD5,SHA等。单项散列算法还有一个特点就是输入的任何微笑变化都会导致输出的完全不同,这个特性有时也会被用来生成信息摘要,计算具有高离散程度的随机数等用途。

8.2.2 对称加密

所谓对称加密是指加密和解密使用的秘钥是同一个秘钥(或者可以互相推算)。对称加密通常用在信息需要安全交互或存储的场合,如Cookie加密,通信加密等。

image

对称加密的优点是算法简单,加解密效率高,系统开销小,适合对大量数据加密。缺点是加解密使用同一个秘钥,远程通信的情况下如何安全的交互秘钥是个难题,如果秘钥丢失,那么所有的加密信息也就没有秘密可言了。

常用的对称加密算法有DES算法,RC算法等。对称加密是一种传统加密手段,也是最常用的加密手段,适用于绝大多数需要加密的场合。

8.2.3 非对称加密

非对称加密和解密使用的秘钥不是同一个秘钥,其中一个对外界公开,被称作公钥,另一个只有所有者知道,被称作私钥。用公钥几秒的信息必须用私钥才能解开,反之,用私钥加密的信息只有用公钥才能解开。不可能通过公钥计算获得私钥。

image

非对称加密技术通常用在信息安全传输,数字签名等场合。

在实际应用中,常常会混合使用对称加密和非对称加密。先使用非对称加密技术对对称秘钥进行安全传输,然后使用对称加密技术进行信息加解密与交换。而有时,对同一个数据两次使用非对称加密,可同时实现信息安全传输与签名的目的。

非对称加密常用的算法有RSA算法等。HTTPS用的数字证书实质上市经过权威机构认证的非对称加密的公钥。

8.2.4 秘钥安全管理

实践中,改善秘钥安全性手段有两种:

  1. 把秘钥和算法放在一个独立的服务器上,甚至做成一个专用的硬件设施,对外提供加密和解密服务,应用系统通过调用这个服务,实现数据的加解密。由于有专人维护,使得秘钥泄露概率大大降低。但成本较高,而且有可能会成为应用的瓶颈,每次及解密都要进行一次远程服务调用,系统性能开销也较大。
  2. 将加解密算法放在应用系统中,秘钥则放在独立服务器中,为了提高秘钥安全性,实际存储时,秘钥被切分成数片,加密后分别把哦哦存在不同存储介质中,兼顾秘钥安全性同事又改善了性能。

8.3 信息过滤与反垃圾

8.3.1 文本匹配

敏感词较少,则使用正则表达式,一般正则效率较差,基本上都是Trie树算法来解决,空间和实践复杂度都比较好的有双数组Trie算法。

另一个更简单的实现是通过构造多级Hash表进行文本匹配。缺点是Hash表会浪费部分内存空间,如果敏感词数量不多,还是可以接受的

可以对信息做降噪预处理然后在进行匹配来解决为了绕过敏感词检查而做的手脚。

8.3.2 分类算法

区分正常UGC与广告,正常邮件与垃圾邮件,比较简单实用的分类算法有贝叶斯分类算法。

分类算法除了用于反垃圾,还可用于信息自动分类,门户网站可用该算法对采集来的新闻进行自动分类。

8.3.3 黑名单

将被报告的垃圾邮箱地址放入黑名单。黑名单可以通过Hash表实现,该方法实现简单,时间复杂度小,满足一般场景使用。

在对过滤需求要求不完全精确的场景下,可用布隆过滤器代替Hash表。

8.4 电子商务风险控制

8.4.1 风险

  1. 账户风险
  2. 卖家风险
  3. 买家风险
  4. 交易风险

8.4.2 风控

  1. 规则引擎
  2. 统计模型
    image
    8.5 小结
    没有绝对的安全。
comments powered by Disqus