作者 | Trung Anh Dang

译者 | 弯月

出品 | CSDN(ID:CSDNnews)

设计一个能够支持数亿用户的系统并非易事,对软件架构师来说是一个很大的挑战。

以下是本文涵盖的一些主题:

  • 从最简单的开始:一个服务器搞定一切。

  • 可扩展性的艺术:向外扩展,向上扩展。

  • 扩展关系数据库:主从复制、主主复制、联合、分片、反规范化和 SQL 调优。

  • 使用哪个数据库:NoSQL 还是 SQL?

  • 高级概念:缓存、CDN、geoDNS.等。

本文不打算讨论高性能计算中常见的问题,例如容错、可靠性、高可用性等。

下面,我们开始。

从零开始

下图是我设计的一个最基本的应用。最简单的方法是将整个应用程序部署在一个服务器上。这可能也是我们大多数人入门时期采用的方式。

  • 一个网站(包括 API)在Apache(或 Tomcat)之类的Web服务器上运行。

  • 一个Oracle(或 MySQL)之类的数据库。

同一台物理机器上同时拥有网络服务器和数据库服务器

但是,这样的架构存在以下缺点:

  • 如果数据库出现故障,系统就会出现故障。

  • 如果网络服务器出现故障,整个系统就会出现故障。

在这种情况下,我们没有故障转移和冗余。一旦服务器宕机就会导致整个系统宕机。

使用 DNS 服务器解析主机名和 IP 地址

在上图中,为了获取托管系统的服务器IP地址,用户(或客户端)需要连接到 DNS系统。在获得 IP 地址后,请求将直接发送到我们的系统。

每次访问网站时,计算机都会执行 DNS 查找。

通常,域名系统(Domain Name System,DNS)服务器都会使用托管公司提供的付费服务,无需在自己的服务器上运行。

可扩展性的艺术

由于数据量、工作量(例如交易数量)以及用户数量的增加等多种原因,我们的系统必须具备可扩展性。

可扩展性通常意味着能够通过添加更多资源来处理更多用户、客户端、数据、事务或请求,同时还不会影响用户体验。

我们必须决定如何扩展系统。在我们的这个例子中,有以下两种扩展类型:向上扩展(scale-up)和向外扩展(scale-out)。

向上扩展 vs 向外扩展

向上扩展:向现有服务器添加更多内存和 CPU

向上扩展也称为“垂直扩展”,指的是系统的资源最大化,以扩展其处理不断增加的负载的能力。例如,我们可以通过添加内存和CPU来增强服务器的能力。

如果我们的服务器拥有8GB内存,则只需更换或添加硬件就可以轻松升级到32GB甚至128GB。

垂直扩展的方法有很多,如下所示:

  • 通过向 RAID 阵列添加更多硬盘来增加 I/O 容量。

  • 通过使用固态硬盘(SSD)来改善 I/O 的访问时间。

  • 使用具有更多处理器的服务器。

  • 通过升级网络接口或安装其他接口来提高网络吞吐量。

  • 通过增加内存来减少 I/O 的操作。

对于小型系统来说,垂直扩展是一个不错的选择,因为硬件升级的成本较低,但这种方式也有如下限制:

  • 不可能无限扩展单个服务器的能力。主要取决于操作系统以及服务器的内存总线宽度。

  • 在升级系统的内存时,必须关闭服务器,因此,如果系统只有一台服务器,停机是不可避免的。

  • 功能强大的计算机通常比流行的硬件贵很多。

向上扩展不仅适用于硬件,同时也适用于软件,例如,优化查询和应用程序代码。

承受不了的一台服务器?

随着用户数量的增长,一台服务器是远远不够的。这时,我们需要考虑将单个服务器分成多个服务器。

随着用户数据增长,一台服务器永远都不够

这种架构有以下优点:

  • Web 服务器和数据库服务器可以分别调优;

  • Web 服务器需要更好的 CPU,而数据库服务器则需要更多内存;

  • Web 层和数据层可以使用单独的服务器,并独立地扩展。

向外扩展:添加任意数量的硬件和软件实体

向外扩展也称为“横向扩展”,我们可以向资源池添加更多实体(机器、服务)。水平扩展比垂直扩展更难实现,因为我们需要在构建系统之前考虑好。

通常,水平扩展的初始成本较高,因为即使是最基本的功能也需要多台服务器来处理,但后期的回报更丰富。因此,我们需要权衡利弊。

  • 增加服务器数量意味着需要维护的资源也更多。

  • 需要修改系统的代码,以实现在多台服务器上的并行处理和工作负载分摊。

使用负载均衡器来平衡所有节点之间的流量

负载均衡器是一种专门的硬件或软件组件,可将流量分散到服务器集群中,以提高系统(包括但不限于应用程序、网站或数据库)的响应能力和可用性。

使用负载均衡器来平衡所有节点之间的流量

通常,负载均衡器位于客户端与服务器之间,接收传入的网络和应用程序流量,并通过各种算法在多个后端服务器之间分配流量。所以,它也可以用在多种地方,例如;Web 服务器与数据库服务器之间,以及客户端与 Web 服务器之间。

HAProxy 和 NGINX 是两种流行的开源负载均衡软件。

负载均衡技术是一种保证容错的方法,可按如下方式提高可用性:

  • 如果服务器 1 离线,所有流量都将路由到服务器 2 和服务器 3。网站不会离线。此时你需要向服务器池添加一个健康的新服务器,以平衡负载。

  • 当流量快速增长时,你只需要在 Web 服务器池中添加更多服务器,负载均衡器就会将流量路由到新的服务器上。

负载均衡器采用各种策略和工作分配算法来优化负载的分配,如下所示:

  • 轮转:在这种情况下,每个服务器按先进先出 (FIFO) 的顺序接收请求。

  • 最少连接数:请求将被定向到连接数量最少的服务器。

  • 最快响应时间:请求将被定向到响应时间最快(最近或频繁)的服务器。

  • 加权:更强大的服务器收到的请求比较弱的服务器更多。

  • IP Hash:在这种情况下,根据计算的客户端 IP 地址的哈希值将请求重定向到服务器。

平衡多个服务器间请求的最直接的方法是使用硬件设备:

  • 直接向共享 IP 添加服务器,或删除服务器。

  • 可以根据需要进行负载平衡。

软件负载平衡比硬件负载平衡器更为廉价。这里的负载均衡在第 4 层(网络层)和第 7 层(应用层)运行。

  • 第 4 层:负载均衡器使用网络层的 TCP 协议提供的信息。这一层的负载均衡在选择服务器时通常不会查看请求内容。

  • 第 7 层:可以根据查询字符串、cookie 或任何头部信息平衡请求,也可以使用源地址、目标地址等常规的层信息来平衡请求。

扩展关系数据库

在简单的系统中,我们可以使用Oracle 或 MySQL之类的关系型数据库来保存数据项。但是关系数据库系统有其自身的挑战,尤其是当我们需要扩展它们时。

有许多技术可以扩展关系数据库:主从复制、主主复制、联合、分片、非规范化和 SQL 调优。

  • 复制指的是一种将相同数据的多个副本存储在不同的机器上的技术。

  • 联合(或功能分区)会按功能拆分数据库。

  • 分片是一种与分区相关的数据库架构模式,可以将不同的数据放在不同的服务器上,不同的用户可以访问不同的数据。

  • 反规范化可以将数据写入多个表,从而避免昂贵的连接,以牺牲部分写入性能为代价来提高读取性能。

  • SQL 调优。

主从复制

主从复制技术能够将数据从一台数据库服务器(主服务器)复制到一台或多台数据库服务器(从服务器),如下图所示。

主节点更新

  • 更新数据时,客户端需要连接到主服务器。

  • 接着,数据会被复制到从服务器,直到所有数据在服务器之间保持一致。

这种方法仍然存在一些瓶颈:

  • 如果主服务器由于某种原因宕机,仍然可以通过从服务器读取数据,只不过无法写入新数据了。

  • 我们需要额外的算法来将从服务器提升为主服务器。

下面是一些解决方案,可以实现只有一台服务器处理更新请求的情况。

  • 同步解决方案:数据修改事务需要等到所有服务器都接受后才提交(分布式事务),因此不会在故障转移时丢失数据。

  • 异步解决方案:提交 -> 延迟 -> 复制到的其他服务器,因此在故障转移时可能会丢失一些数据更新。

如果同步解决方案太慢,则可以改为异步解决方案。

主主复制

每个数据库服务器都可以与其他服务器同时担任主服务器。在某个时间点,所有主服务器进行同步,以确保它们保存了正确以及最新的数据。

节点读写数据库

主主复制的优势在于:

  • 如果某个主服务器出现故障,其他数据库服务器可以正常运行,而且还可以担负起主服务器的责任。当数据库服务器重新上线后,可以通过复制来更新数据。

  • 主站可以位于多个物理站点,并且可以分布在整个网络中。

但服务器的更新能力受限于主服务器。

联合

联合(或功能分区)会按功能拆分数据库。例如,你可以拥有三个数据库,分别用于论坛、用户和产品,这样就可以减少每个数据库的读写流量,从而减少复制延迟。

按功能拆分数据库

更小的数据库可以将更多的数据保存在内存中,这样可以改善缓存的局部性,进而提高缓存命中率。由于没有单一的中央主序列化写入,你可以实现并行写入,从而提高吞吐量。

分片

分片(也称为数据分区)是一种将大数据库分成许多小块的技术,每个数据库只能管理数据的一个子集。

在理想情况下,每个用户都使用不同的数据库节点。这种方式助于提高系统的可管理性、性能、可用性和负载均衡。

  • 每个用户只需与一台服务器对话,因此可以快速获得服务器的响应。

  • 服务器之间的负载均衡更好,例如,如果我们有五台服务器,则每台服务器只需处理 20% 的负载。

在实践中,有许多不同的技术可以将数据库分解为多个小块。

水平分区

这种技术会将不同的行放入不同的表中。例如,如果我们将用户的个人资料存储在一个表中,则可以将ID小于1000的用户存储在一个表中,同时将ID大于1001且小于2000的用户存储在另一个表中。

不同行放入不同表中

纵向分区

在这种情况下,我们根据服务器中保存的与特定功能相关的表来划分数据。例如,如果我们正在构建一个类似 Instagram 的系统,我们需要在数据库中存储与用户、上传的照片以及他们关注的人相关的数据,我们可以将用户个人资料信息放在一个数据库服务器上,将好友列表放在另一个服务器上,而第三个服务器上则保存照片。

把划分数据存储在相应的表中

基于目录的分区

如果想以松散耦合的方式解决这个问题,则需要创建一个查找服务,该服务知道当前的分区模式,并拥有一份每个实体到其所属的数据库分片的映射。

当数据存储的扩展超出单个存储节点的可用资源,或者需要通过减少数据存储的竞争来提高性能时,我们就可以采用这种方法。但请记住,分片技术存在以下一些常见问题:

  • 多表连接会变得更加昂贵,并且在某些情况下无法实现。

  • 分片会损害数据库参照完整性。

  • 数据库架构变更可能会变得非常昂贵。

  • 数据分布不均匀,有些分片的负载很高。

反规范化

反规范化会以牺牲部分写入性能为代价来提高读取性能。数据的冗余副本会被写入多个表,以避免昂贵的多表连接。

当数据的分布采用联合和分片等技术之后,跨数据中心的管理连接会进一步增加复杂性。反规范化可以规避这种复杂的连接。

在大多数系统中,读取的次数大大超过了写入的次数,比例为 100:1,甚至 1000:1。因此,每当读取涉及复杂的数据库连接时,就可能会非常昂贵,并在磁盘操作上花费大量时间。

有些关系数据库,比如 PostgreSQL 和 Oracle 支持物化视图,它们会存储冗余信息,并保持冗余副本一致。

使用哪个数据库?

在数据库领域,有两种主要的解决方案:SQL 和 NoSQL。二者的构建方式、存储信息的类型以及使用的存储方法都不同。

SQL

关系数据库以行和列的形式存储数据。每一行包含关于一个实体的所有信息,每一列包含所有的单独数据点。

最流行的关系数据库包括 MySQL、Oracle、MS SQL Server、SQLite、Postgres 以及 MariaDB等。

NoSQL

NoSQL又称为非关系数据库。这些数据库通常分为五个主要类别:键值数据库、图数据库、列数据库、文档数据库以及 Blob 数据库。

键值存储数据库

数据存储在键值对数组中。“键”是链接到“值”的属性名称。常见的键值存储包括 Redis、Voldemort 和 Dynamo。

文档数据库

在这些数据库中,数据存储在文档中(而不是表中的行和列),并且这些文档归类成集合。每个文档可以具有完全不同的结构。

常见的文档数据库包括 CouchDB 和 MongoDB。

宽列数据库

列式数据库中,没有“表”,只有列,它们是行的容器。与关系数据库不同,我们不需要预先知道所有的列,每一行也不必具有相同的列数。

列式数据库最适合分析大型数据集,常见的有 Cassandra 和 HBase。

图数据库

这些数据库常用于存储关系最适合用图表示的数据。数据保存在拥有节点(实体)、属性(关于实体的信息)和线(实体之间的连接)的图结构中。

常见的图数据库包括 Neo4J 和 InfiniteGraph。

Blob 数据库

Blob 数据库就好像文件的键/值存储,可通过API访问,如 Amazon S3、Windows Azure Blob Storage、Google Cloud Storage、Rackspace Cloud Files 或 OpenStack Swift 等。

如何选择数据库?

数据库技术的选择没有统一的标准。这就是为什么许多企业同时使用 SQL 和 NoSQL 数据库来满足不同需求的原因。

如何选择?

水平扩展 Web 层

以上,我们谈到了数据层的扩展,下面我们来看看Web层的扩展。为了扩展Web层,我们需要将用户会话(状态)的数据存储在关系数据库或 NoSQL 等数据库中,将用户会话(状态)的数据移出 Web 层。这也称为无状态架构。

无状态系统很简单

不要使用有状态的架构。

我们必须尽可能选择无状态架构,因为状态的实现限制了可扩展性,降低了可用性,并增加了成本。

在上述情况下,负载均衡器的效率最高,因为它可以选择任何服务器来处理请求。

高级概念

缓存

负载均衡可以帮助你在数量不断增加的服务器上进行水平扩展,但缓存能够更好地利用现有资源,在后续请求期间更快地提供数据。

如果数据不在缓存中,则从数据库中获取,然后将其保存到缓存中并从中读取

通过向服务器添加缓存,我们可以避免直接从服务器读取网页或数据,从而减少响应时间,并降低服务器的负载。这也有助于提升应用程序的可扩展性。

缓存可以应用于许多层,例如数据库层、Web 服务器层和网络层。

内容交付网络(Content Delivery Network,CDN)

CDN 服务器保存着内容(如图像、网页等)的缓存副本,并选择地理位置最近的服务器处理请求。

使用CDN 可以缩短了用户的页面加载时间,因为数据都是从地理位置最近的服务器上加载的。这也有助于提高内容的可用性,因为数据存储在多个位置。

CDN 的使用缩短了用户的页面加载时间,因为数据是在最接近它的位置检索的

CDN 服务器向Web 服务器发出请求以验证缓存的内容,并在需要时更新缓存。缓存的内容通常是静态的,例如 HTML 页面、图像、JavaScript 文件、CSS 文件等。

进军全球市场

当应用开始进军全球市场时,你需要在世界各地建立和运维数据中心,以确保产品可以全天候不间断地提供服务。传入的请求被路由到基于 GeoDNS 的“最佳”数据中心。

当应用走向全球

GeoDNS 是一项 DNS 服务,允许根据客户的位置将域名解析为 IP 地址。从亚洲连接的客户端获得的IP地址可能不同于从欧洲连接的客户端。

综合

通过迭代应用本文中的技术,例如无状态架构、应用负载均衡器、尽可能多地使用缓存数据、支持多个数据中心、在 CDN 上托管静态资产、通过分片扩展数据库规模等。我们就可以轻松地将系统扩展到 1 亿用户。

缩放是一个迭代过程

原文链接:https://levelup.gitconnected.com/how-to-design-a-system-to-scale-to-your-first-100-million-users-4450a2f9703d

参考链接:

  • https://httpd.apache.org

  • http://tomcat.apache.org

  • https://www.oracle.com/database/

  • https://www.mysql.com

  • https://en.wikipedia.org/wiki/Domain_Name_System

  • https://www.facebook.com/note.php?note_id=10150468255628920

☞马斯克亲口承认:自动驾驶的开发难度超乎想象;ofo 因不退还用户押金被罚 5 万;Firefox Lite 已死|极客头条☞高通新 CEO 上任,高调放话对标苹果 M1!
☞千亿企业的真实业务思考,名校大厂高手同台 PK,“马栏山杯”国际音视频算法大赛来袭!

如何设计一个能够扩展到百万用户的系统?相关推荐

  1. 图解:从单个服务器扩展到百万用户的系统

    作者 | Wolfram Hempel 翻译 | Join 你开发了一个网站(例如网上商店.社交网站或者其他任何东西),之后你把它发布到了网上,网站运行良好,每天有几百的访问量,能快速地相响应用户的请 ...

  2. 如何从单个服务器扩展到百万用户的系统?

    假如你开发了一个网站(例如网上商店.社交网站或者其他任何东西),之后你把它发布到了网上,网站运行良好,每天有几百的访问量,能快速地响应用户的请求. 但是有一天,不知道什么原因,你的网站出名了! 每分每 ...

  3. 搞定系统设计 01:从 0 到百万用户的系统

    如何从零开始设计一套可以服务百万用户的系统. 这是本书第一章的内容,浅显易懂,把常见的套路组合了一下,没有具体的技术细节,过一遍也没什么负担. 从单服务开始 俗话说:千里之行,始于足下.构建一个复杂系 ...

  4. 设计一个可扩展的用户登录系统

    在Web系统中,用户登录是最基本的功能.如何设计一个可扩展的用户登录系统呢?本文结合实际案例对用户登录系统设计进行多维度的讲解,帮助各设计者在应用中将复杂变得简单. 来源:廖雪峰的官方网站,作者:廖雪 ...

  5. 系统设计:如何从零用户扩展到百万用户

    设计一个支持百万用户的系统是具有挑战性的,这是一段需要不断改进和不断提升的旅程.在本章中,我们将构建一个支持单个用户的系统,并逐渐扩展以服务于数百万用户.阅读本章后,您将掌握一些技巧,帮助您解决系统设 ...

  6. 如何设计一个可扩展的优惠券功能

    本文主要分享了如何设计一个可扩展的优惠券功能. 一.功能特性介绍 1.每个条件的代码独立,相当于单独的实现类实现接口,就能通过配置添加到优惠券条件校验当中,支持多种条件灵活组合 2.新增一种使用条件可 ...

  7. 服务器系统怎么做高并发,QPS 高并发 如何设计一个支撑高并发大流量的系统?...

    QPS 高并发 如何设计一个支撑高并发大流量的系统? 高并发架构相关概念 什么是并发? 并发是指并发的访问,也就是某个时间点,有多少个访问同时到来: 通常如果一个系统的日PV在千万以上,有可能是一个高 ...

  8. Java设计一个简化的教师年终业绩考核系统

    利用JAVA设计一个简化的教师年终业绩考核系统 /* 该系统包括一个接口和三个类:一个接口Calculateable具有一个抽象方法getGrade(), 用于根据职工的工作量分数计算职工的业绩等级数 ...

  9. 如何设计一个亿级消息量的 IM 系统

    来源:https://xie.infoq.cn/article/19e95a78e2f5389588debfb1c IM核心概念 用户 :系统的使用者 消息 :是指用户之间的沟通内容.通常在IM系统中 ...

最新文章

  1. 东方日升重磅推出白色双玻组件 助力推动度电成本下滑
  2. 如何把百万级别的订单根据金额排序
  3. ISME:病原菌介导植物根际有益微生物群落组装
  4. Maven 的41种骨架功能介绍
  5. s2sh集成dataSource配置无效的问题 -Access denied for user 'sa'@'localhost'
  6. 用python给女朋友惊喜100天快乐_100天从 Python 小白到大神最良心的学习资源!
  7. linux怎么创建5个线程,简明Linux系统编程_5_创建线程(总第238期)
  8. python tkinter详解 博客园_python tkinter-布局
  9. [css] 为什么伪类的content不能被选中?
  10. 前端学习(2585):vue-cli创建项目
  11. 用户权限管理——DB设计篇
  12. 大数据解密之你的同事都跳槽到了哪些公司
  13. 一文详解中英文在NLP上的10大差异点
  14. mysql数据库重新命名
  15. 【2022年Spring全家桶】Spring5.x 框架详解
  16. 计算机管理 服务在哪,信息服务,教您哪里打开Internet信息服务(IIS)管理器
  17. photoshop cc 2014(附完整软件和方法)
  18. datav可视化大屏使用教程
  19. python利用matplotlib库绘制三维图学习
  20. 374C. Inna and Dima

热门文章

  1. mac上使用python 安装anaconda和pycharm
  2. 敏捷开发绩效管理之二:用中医理论管理团队及其绩效(绩效考核,团队管理,自组织团队)...
  3. 敏捷开发“松结对编程”实践之六:大型团队篇|后记(大型研发团队,学习型团队,139团队,师徒制度,人员招聘,职业生涯规划)...
  4. [hihocoder][Offer收割]编程练习赛46
  5. impala 使用记录
  6. MPMoviePlayerController属性,方法,通知整理
  7. 结构体,文件操作,指针,简单练习
  8. C语言显示系统时间的几个办法
  9. 新手必看!电脑文件管理八条小技巧
  10. ssh连接aix问题与解决