GuilinDev

Large Scale Internet App Technologies

28 June 2020

互联网产品的特点可以说有以下:

  • 用户多,分布广泛
  • 大型互联网的流量很大
  • 海量的数据,包括业务数据和性能数据
  • 容易受到网络攻击
  • 迭代快

等等,互联网应用实现高性能,高可用,可扩展和可伸缩就非常重要了。这几个指标分别来看看定义:

  • 高性能,以用户为中心,提供快速的网页访问体验。主要参数有较短的响应时间,较大的并发处理能力,较高的吞吐量,稳定的性能参数。 可分为前端优化,应用层优化,代码层优化,存储层优化等等。
    • 前端优化:网站业务逻辑之间的部分,包括减少Http请求数,使用浏览器缓存,启用压缩,Css Js位置,Js异步,减少Cookie传输; CDN加速,反向代理;
    • 应用层优化,处理网站业务的服务器,使用缓存,异步,集群;
    • 代码优化:合理的架构,多线程,资源复用(对象池,线程池等),良好的数据结构,JVM调优,单例,Cache等;
    • 存储优化:缓存,固态硬盘,光纤传输,优化读写,磁盘冗余,分布式存储(HDFS),NOSQL等;
  • 高可用,互联网应用应该在任何时候都可以正常访问。正常提供对外服务。因为大型网站的复杂性,分布式,廉价服务器,开源数据库,操作系统等特点。 要保证高可用是很困难的,也就是说网站的故障是不可避免的。如何提高可用性,就是需要迫切解决的问题。首先,需要从架构级别,在规划的时候,就考虑可用性。 行业内一般用几个9表示可用性指标。比如:
    • 99%,两个9,一年宕机时间87.7小时;
    • 99.9%,三个9,一年宕机时间8.8小时;
    • 99.99% 四个9,一年宕机时间52.6分钟;
    • 99.999%,五个9,一年宕机时间5.3分钟;

    一般需要满足四个9。不同层级使用的策略不同,一般采用冗余备份和失效转移解决高可用问题:

    • 应用层:一般设计为无状态的,对于每次请求,使用哪一台服务器处理是没有影响的。一般使用负载均衡技术(需要解决Session同步问题),实现高可用。
    • 服务层:负载均衡,分级管理,快速失败(超时设置),异步调用,服务降级,幂等设计等。
    • 数据层:冗余备份(冷,热备[同步,异步],温备),失效转移(确认,转移,恢复)。数据高可用方面著名的理论基础是CAP理论(持久性,可用性,数据一致性[强一致,用户一致,最终一致])
  • 高扩展,可以方便的进行功能模块的新增/移除,提供代码/模块级别良好的可扩展性。
    • 模块化,组件化:高内聚,内耦合,提高复用性,扩展性。
    • 面向接口:定义稳定的接口,在接口不变的情况下,内部结构可以“随意”变化。
    • 设计模式:应用面向对象思想,原则,使用设计模式,进行代码层面的设计。
    • 消息队列:模块化的系统,通过消息队列进行交互,使模块之间的依赖解耦。
    • 分布式服务:公用模块服务化,提供其他系统使用,提高可重用性,扩展性
  • 可伸缩,是指在不改变原有架构设计的基础上,通过添加/减少硬件(服务器)的方式,提高/降低系统的处理能力。
    • 应用层:对应用进行垂直或水平切分。然后针对单一功能进行负载均衡(DNS,HTTP[反向代理],IP,链路层)。
    • 服务层:与应用层类似;
    • 数据层:分库,分表,NOSQL等;常用算法Hash,一致性Hash。

另外安全性和敏捷性也需要额外考虑。

演进模式可以根据这篇文章支撑亿级用户的大型互联网架构:从0到1的演化过程来学习。

大型互联网系统架构演化过程

这个文章分别从单机系统(一个应用服务器,几百个用户)->数据库与应用程序分离(应用程序和数据库分开部署,万级用户)->使用缓存改善性能(分布式缓存,本地缓存,十万级别)->使用反向代理,CDN,DB读写分离等(百万级别)->分布式文件系统和分布式数据库(千万级别)->使用搜索引擎,NoSQL,消息队列和分布式服务(亿级用户)

举例,设计一个云上的Kafka系统

在云上运行时的基本原则之一是确保应用程序的高可用。 实现此目的的一种常见方法是将应用程序的部署分布在多个故障域(Failure Domain)中。 在公共云环境中,可用区(Availability Zone, AZ)可以用作故障域。我们可以使用多个可用区来为应用程序提供容错能力。 像HDFS这样的分布式系统传统上是使机架感知的,以通过在数据中心内的多个机架之间分布副本来提高容错能力。 但是,在云环境中运行时,通常将AZ用作机架信息。这样就可以将数据副本分布在多个可用区中,从而在出现故障的情况下提供容错能力。尽管跨可用区复制数据可提供容错能力,但以可用区传输成本的形式确实要付出额外的代价。 在Pinterest,我们广泛地将Kafka用作可伸缩的,容错的分布式消息总线,以为诸如用户动作计数和更改数据捕获(CDC)之类的关键服务提供动力。由于我们的Kafka规模很大,因此我们需要注意AZ传输成本并尽可能高效地运行,因此我们专注于减少跨AZ传输的数据量。

当Kafka集群的代理分布在多个可用区中时,会导致三种类型的交叉可用区网络流量:

  1. 代理间复制流量
  2. 来自不同可用区的生产者的流量
  3. 来自不同可用区的消费者的流量

在上述三种流量类型中,我们需要1,以实现容错;但是,2和3是不希望有的副作用,会引起额外的成本,从理论上讲,这些成本可以消除。如下: Kafka集群

有两种潜在的方法可以解决此问题。

  • 方法1

我们只能让生产者和消费者为领导者共享相同可用区的分区写入/读取数据,以使其更具成本效益。

  • 方法2

另外,我们可以部署AZ特定的Kafka集群,但是要实现这一点,任何其他实时消费者都需要使他们的业务逻辑AZ知道。 为了简单起见,我们选择采用方法1,因为它最小化了代码和堆栈更改。通过查找我们要读取/写入的分区的领导者经纪人的机架信息,并更改生产者和消费者的分配逻辑,可以实现生产者/消费者AZ意识。 在Kafka中,经纪人的机架信息是PartitionInfo元数据对象的一部分,该对象与Kafka客户(消费者和生产者)共享。因此,我们在Kafka集群中部署了机架感知功能,每个代理在该集群中将其所在的可用区作为节点机架信息发布。 我们从针对Kafka,测井代理和S3运输机的最大生产者和消费者应用程序开始了这项计划。

最后的设计 Kafka设计