1、威尼斯网站:微服务架构的风险,架构的背后自然是解决人因面对大型网站特性而带来的问题

威尼斯网站 4

2. 使用用户泳道来隔离错误

我们也希望我们的组件能够快速失效(fail
fast),因为我们不希望等到断开的实例直到超时。没有什么比挂起的请求和无响应的界面更令人失望。这不仅浪费资源,而且还会让用户体验变得更差。我们的服务是互相调用的,所以在这些延迟叠加前,应该特别注意防止那些超时的操作。

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

使用反向代理和CDN加速网站响应:CDN
和反向代理的基本原理都是缓存
,区别在于:

  1. CDN部署在网络提供商的机房;
  2. 反向代理则部署在网站的中心机房;

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

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

优点:减轻应用负载压力,异地缓存有效解决不同地方用户访问过慢的问题;
缺点:成本大幅增加,架构进一步复杂化,也维护难度进一步增大,静态文件缓存更新失效问题;
技术点:CDN、反向代理方案;

随需应变 – 可扩展架构


可扩展性:在对现有系统影响最小的情况下,系统功能可持续扩展或者提升的能力
实现可扩展的手段:低耦合,高内聚

4. 监控应用程序性能

①、动态环境和分布式系统-如微服务将导致更高的故障机会。

分布式服务化##

拆分应用和DB之后,其实还是会有很多问题。不同的站点,里面可能会有相同逻辑和功能的代码。当然,对于一些基础的功能我们可以封装DLL或者Jar包去到处提供引用,但是这种强依赖也很容易造成一些问题(版本问题、依赖关系等处理起来非常麻烦)。

既然每一个应用系统都需要执行许多相通的业务操作,比如用户管理、商品管理等,那么可以将这些共用的业务提取出来,独立部署。这样,传说中的SOA的价值就得到体现了。

分布式服务化(解耦,去重复)

优点:服务统一管理,提供重用度;
缺点:应用架构更复杂;
技术点:业务抽取拆分、服务化技术方案;

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

  • 事件驱动架构(Event Driven Architecture)

    • 定义:通过在低耦合的模块之间传输事件消息,以保持模块的松散耦合,并借助事件消息的通信完成模块间合作。典型的场景是生产着消费者模型
  • 分布式消息队列

首先要站在客户的角度去分析你的程序性能。从外部网络进行监控测试,可以模拟真实的用户体验。同时,还可以根据查询和事务操作上执行次数和耗时数据,来监控程序的内部工作情况。

可靠性有很多层次和方面,因此针对你的团队找出合适的解决方案是相当重要的。你应该将可靠性成为业务决策流程中的一个因素,并为此分配足够的预算和时间。

如何网站架构##

首先,什么是大型网站架构呢?

其实大型网站架构的概念对于每一个开发者来说很笼统、很模糊,正如盲人摸象,看到的、了解到的只是很小的一部分,大部分情况下我们只是负责架构中的一小块内容,所以很难清晰地给出具体定义。这就是所谓“不识庐山真面目
只缘身在此山中”的尴尬吧。所以我们要跳出来,站在宏观的角度,从整体到细节实现来认识大型网站架构。

那么从宏观的角度怎么去认识大型网站架构呢?正如前面几篇《细品架构系列》所描述对架构的认识,按照问题识别—>概念认知—>架构切分的思路,来分析大型网站架构的诞生:

  1. 问题识别:当前什么问题、谁的问题、问题边界;
  2. 概念认知:通过分析问题,会产生哪些概念,统一概念认知,达成沟通交流规范;
  3. 架构切分:根据概念来解决问题,如何架构切分,产生哪些架构,提出具体解决方案;

PS:上面的三个步骤具体如何识别、认知、切分,请详细参考前面几篇《细品架构系列》文章,可能使你会对架构有重新的认识。

在进行分析大型网站架构的演进之路前,首先我们要明确的两个价值观:

  1. 核心价值:随网站所需灵活应对;大型网站不是从无到有一步就搭建好一个大型网站,而是能够伴随小型网站业务的渐进发展,慢慢地演化成一个大型网站;
  2. 驱动力量:网站的业务发展—业务成就了技术,事业成就了人,而不是相反;

还有,大型网站架构演进必须避免的几个误区:

  1. 一味追随大公司的解决方案;
  2. 为了技术而技术–>常见问题;
  3. 企图用技术解决所有问题:技术是用来解决业务问题的,而业务的问题,也可以通过业务的手段去解决;

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

  • HTTP重定向负载均衡
  • DNS域名解析负载均衡
  • 反向代理负载均衡
  • IP负载均衡
  • 数据链路层负载均衡
  • 负载均衡算法
    • 轮询
    • 加权轮询
    • 随机
    • 最小链接
    • 原地址散列

7. 尽可能少的使用关系型数据库RDBMS特性

威尼斯网站 1微服务故障独立

分库分表##

最后,再介绍一个大型互联网公司都用的绝技–分库分表。个人经验,不是业务发展和各方面非常迫切,不要轻易走这一步

因为分库分表谁都会干,关键是拆完之后怎么办。目前,市面上还没有完全开源免费的方案,能让你一劳永逸地解决数据库拆分问题。

分库分表:

  1. 横向拆分;
  2. 纵向拆分;
  3. 分布式数据库访问层;
  4. 数据库中间件(代理);

典型攻击方式

  • XSS攻击(跨站脚本攻击)
    • 黑客通过篡改网页,注入恶意HTML脚本,在用户浏览网页时,控制用户浏览器进行恶意操作的一种攻击方式
    • 分类: 1) 反射型; 2) 持久型
    • 解决方法:1) 消毒; 2) HttpOnly
  • 注入攻击
    • 分类: 1) SQL注入攻击; 2) OS注入攻击
    • 解决方法:1) 消毒; 2) 参数绑定
  • CSRF攻击(跨站点请求伪造)
    • 攻击者通过跨站请求,以合法用户的身份进行非法操作
    • 解决方法: 识别请求者身份:1) 表单Token; 2) 验证码; 3)
      Referer check
  • 其他攻击方式
    • Error
      Code,可能显示异常堆栈,从而暴露危险信息,解决方法:使用统一的500页面
    • HTML注释,注释可能会暴露危险信息,解决方法:code
      review或者自动扫描
    • 文件上传,可能上传病毒文件,解决方法:设置上传文件白名单,只允许上传指定类型的文件
    • 路径遍历,
      在URL中使用相对路径,遍历系统未开放的目录和文件,解决方法:
      将资源文件部署在独立的服务器上,使用独立域名

一定要在产品部署前,执行负载与性能测试。虽然这不会发现所有问题(这也是为什么我们需要回滚
Rollback的能力),但它很值得做。

1、微服务架构的风险

应用垂直拆分##

随着业务越来越复杂,网站的功能越来越多,虽然部署层面是采用的集群,但是应用程序架构层面还是“集中式”的,这样会导致很多耦合,不便于开发、维护,而且容易“一荣俱损”。所以,通常会把网站拆分出不同的子站点来单独宿主。

通过分而治之的手段将整个网站业务分成不同的产品线,如首页、商铺、订单、卖家、买家等拆分成不同的产品线,分归不同的业务团队负责。各个应用之间可以通过建立一个超链接建立关系,也可以通过消息队列进行数据分发。

应用垂直拆分(分压,解耦)

优点:降低耦合、分压;
缺点:应用架构复杂;
技术点:业务抽取拆分;

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

  • 需要将超大型的、复杂系统查分成可独立部署的模块,从而降低耦合性
  • Web Service与企业分布式服务
    • Web Service比较臃肿,可以考虑使用REST
    • 或者使用开源的解决方案,例如Dubbo

责任编辑:

在工业领域中,常使用舱壁将划分为几个部分,以便在有某部分船体发生破裂时,其他部分依然能密封安然无恙。

数据库读写分离##

单台数据库也感觉快撑不住了,一般都会尝试做“读写分离”。由于大部分互联网“读多写少”的特性所决定的。Salve的台数,取决于按业务评估的读写比例。

数据库读写分离

优点:简单有效、降低数据库单台压力;
缺点:读写分离,增加程序难度,架构变复杂,维护难度增加;
技术点:数据库主从同步部署,扩展数据访问模块,实现读写分离;

固若金汤 – 安全架构


威尼斯网站 2

7、重试逻辑(Retry Logic)

消息队列##

应用、服务之间还是会出现一些依赖问题,这时候,高吞吐量的解耦利器出现了

消息队列(服务间异步解耦 高吞吐量)

优点:提高吞吐量、应用、服务之间解耦;
缺点:存在消息消费延迟问题;
技术点:消息队列技术方案;

性能测试方法

  • 性能测试,以系统设计初期规划的性能指标为预期目标,对系统不断增压,验证系统在资源可接受范围内,是否能达到性能预期
  • 负载测试,对系统不断的增加并发请求,知道系统的某项或者多项性能指标达到安全临界值
  • 压力测试,超过安全负载的情况下,继续对系统增压,直到系统崩溃或者不能再处理任何请求
  • 稳定性测试,在特定硬件、软件、网络情况下,给系统加载一定压力,是系统运行较长一段时间,来观察系统是否稳定
  1. 从一开始就重视质量工作

在微服务体系架构中,我们希望服务可以快速、单独地失效。为了在服务层面隔离故障,我们可以使用隔板模式(bulkhead
pattern)。可以在本文稍后看到相关介绍。

集中式缓存、Session集中存储##

加机器谁都会加,关键是加完之后得有效果,加完之后可能会引发一些问题。例如非常常见的:集群应用之间页面输出缓存和本地缓存一致性的问题,Session保存的问题……

集中式缓存 Session集中存储

优点:应用之间缓存、Session一致,存储无限制,可以扩展;
缺点:不如本地缓存访问快,缓存服务器、Session服务器等仍存在单点问题;
技术点:缓存服务器部署、Session集中存储方案;

大型网站架构演化发展过程

  • 初始阶段,一般使用LAMP来搭建,所有资源存放在一台服务器上
  • 应用服务和数据服务分离,有独立的数据库服务器
  • 使用缓存改善网站性能,依据是二八定律:80%的业务访问集中在20%的数据上
    • 这里需要考虑哪些数据适合缓存
    • 缓存可以是本地缓存,也可以是远程分布式缓存
  • 使用应用服务器集群改善网站的并发处理能力
    • 如果能通过增加一台服务器的方式来改善负载压力,就可以以同样的方式持续增加服务器来不断改善系统性能,从而实现系统的可伸缩性
    • 这里需要考虑使用哪些负载均衡的策略
      *数据库读写分离
    • 缓存中的数据,如果更新过快,那么会持续刷新缓存,从而降低性能
    • 可以利用主流数据库提供的主从热备功能,通过配置两台数据库的朱从关系,将一台数据库服务器上的数据同步到另外一台上面
  • 使用反向代理和CDM加速网络响应
    • CDN和反向代理的基本原理都是缓存
    • CDN部署在网络提供商的机房,用户在请求网络服务时,可以从距离自己最近的网络提供商机房获取数据
    • 反向代理部署在网站的中心机房,当用户的请求到达中心机房后,首先访问的服务器是反向代理服务器,如果反向代理服务器中缓存着用户请求的资源,那么就将其直接返回给用户
  • 使用分布式文件系统和分布式数据库系统
    • 网站常用的数据库拆分手段是业务分库,即将不同业务的数据库部署到不同的物理服务器上
  • 使用NoSQL和搜索引擎
  • 业务拆分,使用分而治之的手段将整个网站业务分成不同的产品线
  • 分布式服务

在多个层上尽可能地使用缓存,如数据库前的对象缓存(例如:memcached),或是页面内容缓存(例如:squid),边缘缓存(例如:Akamai)。

我们可以通过外部观察去判断应用实例是否健康。你可以多次调用Get/health的端点或者通过自身服务的报告获得相关信息。现在的服务发现解决方案会持续从实例中收集健康信息,并且设置负载均衡的路由,让其只指向健康的实例组件。

大型网站目标##

既然说到了大型网站的特性,那么解决这些特性带来的问题要达到什么目标呢?如下:

大型网站架构目标

每个目标背后面临着技术、设计、维护等诸多方面的挑战;
而目标本身的期望值也会根据实际情况进行调整,这也意味着网站架构建设是个不断调整的过程。

有了问题,也定了伟大的目标,那么网站在不同阶段面对不同的问题,是如何解决的?又是如何一步步成长为大型网站架构,实现这些伟大的目标呢?

网站架构的伸缩性设计

  • 不同功能进行物理分离实现伸缩
  • 单一功能通过集群规模实现伸缩

3. 使用多层次的缓存

我们可以说,通过使用超时来实现微服务中的快速失败是一种反模式,这是应该避免的。可以使用基于操作的成功/失败统计次数的熔断模式,而不是使用超时。

数据服务与应用分离##

市场反响还不错,用户量每天在增长,数据库疯狂读写,逐渐发现一台服务器快撑不住了。于是,决定把数据服务和APP做分离

数据服务与应用分离

优点:简单有效、方便维护、提高不同Server对硬件资源的利用率;
缺点:存在单点、谈不上高可用;
技术点:文件服务器部署、数据库服务器,扩展数据访问模块;

分离后三台 Server 对硬件资源的需求各不相同:

  1. 应用服务器:需要更快更强大的 CPU;
  2. 数据库服务器:需要更快的硬盘和更大的内存;
  3. 文件服务器:需要更大的硬盘;

不同视角下的网站性能

  • 用户视角
    • 主要是端到端的感觉
    • 主要通过前段优化的手段来提升用户体验
  • 开发人员视角
    • 主要关注应用程序本身以及相关子系统的性能,包括响应延迟、系统吞吐量、并发处理能力、系统稳定性等
    • 主要优化手段:
      使用缓存加速数据读取、使用集群提高吞吐能力、使用异步消息加快请求响应、使用代码优化提升程序性能
  • 运维人员视角
    • 主要关注基础设施性能和资源利用率
    • 主要优化手段:
      建设优化骨干网、使用高性价比定制服务器、利用虚拟化技术优化资源利用率

确保有强大的学习文化,当问题出现时,一定要确保找到问题根源,
才能最终修复问题。

实施和运维可靠的服务并不容易。这需要你付出很多努力,还要花费公司更多的成本。

使用NoSQL和搜索引擎##

到这里,已经基本做到了DB层面和应用层面的横向扩展了,可以开始关注一些其它方面,例如:站内搜索的精准度,对DB的依赖,开始引入全文索引、NoSQL

NoSQL和搜索引擎都是源自互联网的技术手段,对可伸缩的分布式特性具有更好的支持。应用服务器则通过一个统一数据访问模块访问各种数据,减轻应用程序管理诸多数据源的麻烦。

使用NoSQL和搜索引擎

优点:降低DB依赖;
缺点:单点问题,谈不上高可用;
技术点:NoSQL、搜索引擎、分布式;

到目前为止,一个能够承载日均百万级访问量的中型网站架构基本介绍完了。

万无一失 – 高可用架构


网站的可用性描述网站可以有效访问的特性,它不同于易用性

12. 问题根源分析

限流是指在一段时间内,定义某个客户或应用可以接收或处理多少个请求的技术。例如,通过限流,你可以过滤掉产生流量峰值的客户和微服务,或者可以确保你的应用程序在自动扩展(Auto
Scaling)失效前都不会出现过载的情况。

如何保证高可用##

在做扩展满足了基本的性能需求后,我们会逐渐关注“可用性”(也就是我们通常听别人吹牛时说的SLA、几个9)。如何保证真正“高可用”,也是个难题。

对关键应用/服务,做集群冗余负载,这也是保证高可用比较常用的手段:

  1. 文件系统、数据库系统集群;
  2. 静态内容服务器集群;
  3. CDN服务器集群;
  4. 反向代理服务器集群;
  5. 负载均衡调度器集群;
  6. 分布式NoSQL服务器集群;
  7. 搜索引擎服务器集群;
  8. 分布式缓存服务器集群;
  9. 分布式Session服务器集群;

使用集群冗余负载 保证高可用

优点:集群负载,保证高可用;
缺点:数据一致性、数据有状态问题;
技术点:负载调度器、集群方案;

截止目前为止,都没有怎么去改动应用程序的架构,或者说通俗点,都不怎么需要大面积的修改代码。

如果上面那些手段都用光了,还是支撑不住怎么办?不停的加机器也不是办法啊?

大型网站核心架构要素


  • 性能
    • 一个性能问题可能会导致网站用户严重流失
    • 衡量性能的指标:响应时间、TPS、系统性能计数器等
  • 可用性
    • 没有网站可以完美的7*24运行
    • 网站高可用结构的前提是必然会出现服务器宕机,儿高可用设计的目标是当服务器宕机时,服务或者应用依然可用
    • 必要的手段是集群,即冗余
  • 伸缩性,即通过不断向集群中加入服务器的手段来环节不断上升的用户并发访问压力和不断增长的数据存储需求
    • 衡量标准:是否可以构建集群;是否可以方便的向集群中添加新的服务器
  • 扩展性,直接关注网站的功能,保证可以快速响应需求变更
    • 衡量标准: 网站增加新的业务产品时,是否对现有业务透明无影响
  • 安全性
    • 衡量标准:
      针对现存和潜在的各种攻击和窃密手段,是否可以有效的应对

11. 容量规划 / 扩展峰值

威尼斯网站 3限流器可以阻止流量峰值

大型网站特性##

既然说的是大型网站架构,那么架构的背后自然是解决人因面对大型网站特性而带来的问题。这样可以先给大家说下大型网站的特性,这些特性带来的问题就是人要解决的问题

  1. 高并发、大流量:PV 量巨大;
  2. 高可用:7*24 小时不间断服务;
  3. 海量数据:文件数目分分钟 xxTB;
  4. 用户分布广泛,网络情况复杂:网络运营商;
  5. 安全环境恶劣:黑客的攻击;
  6. 需求快速变更,发布频繁:快速适应市场,满足用户需求;
  7. 渐进式发展:慢慢地运营出大型网站;

信息加密技术以及密钥管理

  • 单项散列加密,包括MD5、SHA等
  • 对称加密, 包括DES算法、RC算法等
  • 非对称加密, 包括RSA算法等
  • 密钥安全管理
    • 将密钥和算法放在一个独立的服务器上,甚至做成一个专用的硬件设置,对外提供加密和解密服务
    • 将加解密算法放在应用系统中,密钥则放在独立服务器中,在存储时,将密钥切分成数片,分别存储在不同的介质中

10. 不能回滚注定失败

你应该小心地为应用程序和客户端添加重试逻辑,因为更大量的重试操作可能会使事情变得更糟,甚至阻止应用程序恢复。

应用服务集群##

数据库层面是缓解了,但是应用程序层面也出现了瓶颈,由于访问量增大,加上早期程序员水平有限写的代码也很烂,人员流动性也大,很难去维护和优化。所以,很常用的办法还是“堆机器”。

应用出现瓶颈 负载均衡集群

优点:增加服务器和HA机制,系统性能及可用性得到保证;
缺点:应用之间缓存、Session一致性问题;
技术点:负载均衡;

通过集群解决高并发、海量数据问题的常用手段,实现系统的可伸缩性。通过负载均衡调度器,可将用户访问分发到集群中的某台
Server 上,应用服务器的负载压力不再成为整个网站的瓶颈。

可扩展的数据结构

同步调用会同时将两种不同服务的可用性捆绑在一起。如果其中一者产生错误或是堵塞,另一者也会受到影响。

回退代码并不是坏事情。你不应该在生产环境中部署有问题的代码,并且应该琢磨哪里出错了。当必要时候应该果断回退代码,这越早越好。

网站架构总结#

上面讲述了在网站业务发展的不同阶段,会面临不同的问题,针对不同的问题,会选择不同的架构。大型网站架构就是在不同阶段时解决不同问题的过程中慢慢演进来的。

最后几句话,送给有缘的你:

  1. 一切以解决业务目标为首要任务;
  2. 没有以业务为目标的任何架构、技术,都是毫无意义的耍流氓;
  3. 再牛逼的架构、再牛逼的技术,不能够解决业务的问题,你也只能算是会架构、会技术的工匠,而不能算是真正意义上的架构师;
  4. 业务成就了技术,平台成就了人,事业成就了人,而不是相反;

本文思维导图,如下:

本文思维导图

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

  • Memcached分布式缓存集群的访问模型
    • 用用程序通过Memcached客户端访问Memcached服务器集群,Memcached客户端主要由一组API、Memcached服务器集群路由算法、Memcached服务器集群列表以及通信模块构成
    • 路由算法负责根据应用程序输入的缓存数据KEY计算得到应该将数据写入到Memcached的哪台服务器(写缓存)或者应该从哪台服务器读数据(读缓存)
  • Memcached分布式缓存集群的伸缩性挑战
    • 挑战主要针对路由算法,当集群扩容时,如何保证路由算法可以得到新加入的服务器?
    • 解决方法:
      在网站访问量最少的时候扩容,然后通过模拟请求的方法逐渐预热缓存,使得缓存服务器中的数据重新分布
  • 分布式缓存的一致性Hash算法

架构扩展性的13条最佳实践

威尼斯网站 4变更管理-回滚部署

何为大型网站#

代码优化

  • 多线程
    • 需要注意线程安全问题,方法:1) 将对象设计成无状态对象;2)
      使用局部对象;3) 并发访问资源时使用锁
  • 资源复用
    • 主要是单例和资源池(对象池)
  • 数据结构,选择合适的算法
  • 垃圾回收
    • 合理设置垃圾回收策略

根据用户划分来创建硬件隔离的“泳道 Swim
Lanes”。这可以防止因为某个客户所产生的问题而影响其他客户,同时有助于诊断问题和代码发布。

微服务架构通过定义明确的服务边界,能有效地隔离故障。
和其他分布式系统一样,微服务在网络、硬件和应用层上都会存在更多的问题。由于服务之间是互相依赖,因此任何组件都可能出错导致用户不能访问。为尽可能减少部分中断带来的影响,我们需要构建容错能力强的服务,以从容应对发生的某些中断。

架构体系演进#

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

  • 数据存储服务器必须保证数据的可靠存储,任何情况下都必须保证数据的可用性和正确性
  • 关系数据库集群的伸缩性设计
    • 利用主从结构实现读写分离
    • 根据不同业务的数据,放到不同的数据库集群中,即数据库分库
    • 对于特别大的表,进行分片处理
  • NoSQL数据库的伸缩性设计
    • HBase

对于每一层、每一个服务,都要清楚它有多大容量。使用 扩展峰值(Scalability
Summits) 来规划容量的增长需求。

11、断路器(Circuit Breakers)

动静分离##

动静分离也是提高网站响应速度的一种常用方式。将动态请求与静态请求分离开,尽量减少对应用服务器的压力。同时,可以再进一步对静态请求,进行缓存,以加快响应速度。可以需要开发人员配合(把静态资源放独立站点下),也可以不需要开发人员配合(利用7层反向代理来处理,根据后缀名等信息来判断资源类型)。

使用动静分离

优点:减轻应用负载压力,针对静态文件缓存;
缺点:静态文件缓存更新失效问题;
技术点:动静分离、静态文件缓存方案;

瞬时响应 – 高性能架构


5. 复制数据库

在某些情况下,我们可能无法缓存数据,或者想对数据进行变更,但是操作最终失败了。在这种情况下,我们就可以选择重试操作,因为我们可以预期资源将在一段时间后恢复,或者负载均衡会将请求发送到健康的实例上。

单机时代##

草根时期,快速开发网站并上线。当然,通常只是先试水,用户规模也没有形成,经济能力和投入也非常有限应用程序、数据库、文件等所有资源都集中在一台
Server上
,典型案例:基于 LAMP 架构的 PHP 网站;

单机时代(纯依赖RDBMS)

优点:简单、快速迭代达成业务目标;
缺点:存在单点、谈不上高可用;
技术点:应用设计要保证可扩展;

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

网站的价值在于它能为用户提供什么价值,在于网站能做什么,而不在于它是怎么做的。因此对于小型网站来说,最需要做的是位用户提供好的服务来创造价值,得到用户的认可,从而活下去,野蛮生长。

  • 大型网站架构技术的核心价值是随网站所需灵活应对, 它是一个演化的过程
  • 驱动大型网站技术发展的主要力量是网站的业务发展,是业务成就了技术,而不是相反。因此要摒弃为了技术而技术的套路