设计一个支持百万用户的系统

设计一个支持数百万用户的系统是非常有挑战性的, 这是一个需要不断调整和优化的过程, 接下来的内容中, 我将构建一个系统, 从单个用户开始,到最后支持数百万的用户。


    从单个服务开始   

千里之行,始于足下,让我们从最简单的单个服务开始。所有的内容都在一台服务器上运行,包括 Web 程序, 数据库,缓存 等等, 如下图

0d3634ae8e9e8eebc5cb1a3b5c304e3a.png

我们看一下它的工作流程。

006c0a9ff444a65aa0d58ab64dbd120f.png

1.用户通过域名访问网站, 比如, api.mysite.com, 通常情况下, 域名解析服务 (DNS) 是由第三方提供的付费服务, 而不是我们的服务器所提供的。2.返回 IP 地址给浏览器或者移动设备, 比如, 15.125.23.214。3.通过 IP 地址, 发送 Http 请求到我们的 Web 服务器。4.Web 服务器返回 html 或者 json 内容, 浏览器进行渲染。


    分离数据库   

随着用户量的增长,此时一台服务器已经独木难支,我们需要两台服务器, 一个用于 Web 服务, 一个用于数据库。

77852486122f642297331b0501a084f2.png


    数据库选型   

您可以选择关系型数据库和非关系型数据库,那它们都有什么特点呢?

关系型数据库也称为关系型数据库管理系统 (RDBMS) 或 SQL 数据库,最常见的有 MySQL、Oracle 、PostgreSQL、Sql Server 等,可以通过 SQL 进行跨表查询。

而非关系型数据库也称为 NoSQL 数据库,最常见的有 Redis、 CouchDB,Neo4j、Cassandra、HBase、Amazon DynamoDB 等。它们分为四类:键值(Key-Value)存储数据库、列存储数据库、文档型数据库、图(Graph)数据库。

对于大多数开发人员来说,通常会选择关系型数据库。而非关系型数据库更适合以下几种情况:

•应用程序需要超低延迟。
•数据是非结构化的,或者没有任何关系数据。
•只需要序列化和反序列化数据(JSON、XML、YAML 等)。
•需要存储海量数据。


    垂直缩放 、 水平缩放   

垂直缩放,又称为 "纵向扩展" (scale up), 是指升级服务器资源, 比如 CPU, RAM 等。而水平缩放又称为 "横向扩展" (scale out), 是指添加服务器到资源池中。

30b342470a3dd7e56ac6a334861250cb.png

当流量比较少的时候, 选择纵向扩展就足够了,因为它足够简单,不过也有很大的局限性。

•纵向扩展有硬件限制, 无限制的升级 CPU 和内存是不现实的。•纵向扩展没有高可用,如果一台服务器出现故障,网站或者应用就会直接崩溃。

而流量较大的时候,横向扩展是更好的选择,多个服务器也保证了高可用。如何让这些服务器更好的提供服务,我们还需要做负载均衡。


    Load balancer   

负载均衡器可以平均分配流量给每台服务器,如下

2ac50cde96297cb0723ab376a836b632.png

我们水平扩展了 Web 服务,并引入了负载均衡器,来应对快速增长的网站流量, 并提供了高可用的服务。

现在,Web 层看上去不错,但是不要忘了,当前的设计只有一个数据库,并不支持故障转移和冗余。而数据库复制是一种常见的技术,可以解决这个问题。


    Database replication   

数据库复制是把数据复制、传输到另外一个数据库,最终形成一个分布式数据库。用户可以访问到相同的信息,从而提高一致性、可靠性和性能。

通常它们之间是主/从(master/slave) 的关系,一主多从,主节点支持读写操作,而从节点仅支持读取操作,如下

5b666d559f559ce3142b681ecdb9892c.png

引入了数据库复制, 让我们看看现在网站整体的设计。

d55d5a820d78178aa023b16fc83444b8.png

1.用户从 DNS 获取到 Load balancer 的 IP 地址,并连接到 Load balancer。
2.Http 请求被路由到服务器1 或者 服务器2。
3.使用数据库复制,进行读写分离。
现在,web 服务和数据库都已经做了优化,看上去不错!
接下来,还需要提升 web 的加载和响应时间,我们可以使用 CDN 缓存静态资源, 包括 js、css、image 等。

    Content delivery network (CDN)   

CDN 是一个用于交付静态内容的网络服务,分布在不同的地理位置。当用户访问网站时,距离最近的 CDN 服务器提供静态资源,可以很好的改善网站的加载时间。

8a854f48d483f6199b682e80b05d9777.png

另外,对于数据库来说,我们也可以把一些热点数据添加到缓存中,这样可以减轻数据库的压力。

现在,我们的系统加了两层缓存。

0c44c24bcc28e5fad4a04ad9d6bfc6f9.png

1.对于静态资源,由 CDN 提供而不是 Web 服务器。2.通过缓存数据来减少对数据库的访问。


    无状态 Web 层   

现在我们的 Web 应用是有状态的服务,什么意思呢?假如用户在 Server 1 进行了登陆, 那后续也只能在 Server1 请求资源,因为只有 Server1 才拥有用户的会话信息,每个 Web 服务的状态都是独立的、隔离的。

ceb40cd2349a21eaaf234b58a41699c9.png

我们需要把这些状态移出 Web层,通常单独保存在关系型数据库或者 NoSQL, 这样 Web 层就变成了无状态的。

b29c95dd24e0bf7ba88959edb43c7b9c.png

这样做有什么好处呢?在无状态的架构中,来自用户的 Http 请求可以发送到任何 Web 服务器,而状态信息统一保存在单独的共享存储中。无状态系统更简单、更容易扩展。

e14abe439e26114e24eedbcbf6cf422c.png


    数据中心   

您的网站受到越来越多人的关注,用户也迅速发展,并扩展到全球。

如何为各个地区的用户都提供满意的服务?您可以在不同的地区设置多个数据中心。

如下图,我们分别在东、西两个地区配置了单独的数据中心, DC1、DC2。

6c55821d02bd1f80e276d8d726134319.png

看上去不错!但是如何引导用户去不同的数据中心呢?答案是:DNS, 是的,众所周知,DNS 可以把我们网站的域名解析为 IP 地址,而使用 GeoDNS, 可以根据用户请求所在的位置,解析为不同的地区的 IP 地址。把用户引导到离他最近的数据中心,来达到加速的目的。

d2ce6dcb9144ea8d37872974891090c5.png

另外,如果某个数据中心发生重大事故,导致集群故障,我们可以把所有的流量都引导到健康的数据中心,这种架构就是我们常说的 "异地多活"。


    Message queue   

当需要进行解耦时,引入消息队列通常是优先考虑的, 它支持异步通信,当您有耗时的任务需要处理时,可以通过生产者把消息发送到消息队列,Web 服务可以尽快的响应用户的请求,而消费者可以异步地去处理这些耗时任务。

4b18382ca5e8df7fb6b971ab51659279.png


    日志、指标、自动化   

当网站的流量越来越大时,就必须要引入监控工具了。

日志:监控错误日志很重要,它可以帮助您发现系统问题。您可以把日志统一发送到日志中心,这样便于分析和查看。

指标:收集各种各样的指标,可以帮助我们更好的理解业务和系统。

•系统指标::CPU、内存、磁盘 I/O,数据库等等。•业务指标:每日用户、活跃度等等。

自动化,当系统变得庞大且复杂时,我们需要引入自动化工具,CI/CD 很重要,自动化构建、测试、部署可以极大的提高开发人员的生产力。

现在,我们的系统引入了消息队列,以及一些监控和自动化工具。

93a8be723d055ea8276f436949e44a07.png


    Database Sharding   

数据库的数据每天都在大步的增长,我们的数据库已经不堪重负了,是时候扩展数据库了,数据库分片是个很好的方案。

在下面的示例中,我们使用了哈希函数来进行分片, 根据不同的 user_id, 把数据平均分配到 4个数据库中。

58d85051754c82d050f443489a42aca9.png

现在,我们看一下数据库的数据。

46ce9012cc60b007363938d113ed628d.png

使用数据库分片的方案时,有一个要考虑的重要因素是分片键(sharding key), 或者叫分区键,比如上面的 user_id,因为可以通过 sharding key 找到相对应的数据库,另外,我们要选择一个可以均匀分布数据的键。

看起来不错!不过这种方案也给系统带来的复杂性和新的挑战,当数据越来越多,增加了数据库节点之后,我们需要重新进行数据分片。比如 useri_id % 5, 此时,为了保证哈希函数的正确路由,我们需要移动数据库大量的数据。

我们可以使用一致性哈希技术,来解决上面的问题,重新分片后,只需要移动一小部分数据即可,当然一致性哈希本文就不做详细的介绍了。

让我们看看最终的系统设计。

dbfcd229f505d8e9ad2178fe5df3ba3a.png


   总结   

构建一个健壮的架构系统,其实是一个迭代的过程,为了支持数百万的用户的架构,我们需要做到以下几点:

•保证 Web 层无状态•尽可能的缓存数据•异地多活,配置多个数据中心•使用分片扩展数据库•监控系统并使用自动化工具

希望对您有用!

译:等天黑

作者:Alex Xu

来源:《System Design Interview》

cf9954393992d875287d407ab1e24936.png

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/287785.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

《零基础看得懂的C语言入门教程 》——(九)C语言二维数组与循环嵌套

一、学习目标 了解二维数组的使用方法了解循环嵌套的使用方法 目录 C语言真的很难吗?那是你没看这张图,化整为零轻松学习C语言。 第一篇:(一)脱离学习误区 第二篇:(二)C语言没那么…

Scala-2.13.0 安装及配置

Scala 简介 Scala 是一门多范式(multi-paradigm)的编程语言,设计初衷是要集成面向对象编程和函数式编程的各种特性。 Scala 运行在Java虚拟机上,并兼容现有的Java程序。 Scala 源代码被编译成Java字节码,所以它可以运…

中科大镜像源_JETPACK4.4安装软件和备份镜像的方法介绍

一、使用SDK Manager的文件夹安装Jetson软件(以NX为例)当JETPACK安装出现错误的时候,可以尝试下面的安装办法,前提是JETPACK4.4完整安装(即本文第三节的下载已经完成),并且选择JETSON NX的相关的下载已经完成。安装步骤:1、$cd /n…

站在前人的肩膀上重新透视C# SpanT数据结构

先谈一下我对Span的看法, Span是指向任意连续内存空间的类型安全、内存安全的视图,可操作的滑动窗口。Span和Memory都是包装了可以在pipeline上使用的结构化数据的内存缓冲器,他们被设计用于在pipeline中高效传递数据。定语解读这里面许多定语&#xff0…

《零基础看得懂的C语言入门教程 》——(十)C语言的指针原来是这样

一、学习目标 了解指针的概念了解指针的使用方法了解双重指针 目录 C语言真的很难吗?那是你没看这张图,化整为零轻松学习C语言。 第一篇:(一)脱离学习误区 第二篇:(二)C语言没那…

bigpipe提升网站响应速度

2019独角兽企业重金招聘Python工程师标准>>> 主要思想就是通过异步 发起一次请求,后端不关闭输出流,多个线程处理各自任务,然后分别发送到客户端。 https://github.com/4rnold/Demo-Project/tree/master/bigpipe-demohttps://gith…

《零基础看得懂的C语言入门教程 》——(十一)C语言自定义函数真的很简单

一、学习目标 了解C语言的自定义函数的使用方法了解C语言自定义函数的传参了解C语言自定义函数的返回值 目录 C语言真的很难吗?那是你没看这张图,化整为零轻松学习C语言。 第一篇:(一)脱离学习误区 第二篇&#xf…

**【ci框架】精通CodeIgniter框架

http://blog.csdn.net/yanhui_wei/article/details/25803945 一、大纲 [php] view plaincopy1、codeigniter框架的授课内容安排 2、codeigniter框架的简介 |-----关于框架的概念 |-----使用CI框架的好处 |-----为什么选择CI框架 3、codeigniter框架…

《假如编程是魔法之零基础看得懂的Python入门教程 》——(一)既然你选择了这系列教程那么我就要让你听得懂

一、前言 几个月前编写了一份python语言入门的博文,近期重新审阅了一遍发现编写的质量太过随意,可能对于一部分人并不是非常友好,故此重新编写Python语言的零基础教程。 本篇教程将会尽量把一些专业术语给读者讲解清楚,并且让读…

环形队列

在网上看到一篇比较好的介绍队列的文章,地址为:http://www.cnblogs.com/kubixuesheng/p/4104802.html 特此感谢原创作者,以下均为摘抄。 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 1、…

Blazor University (19)使用 RenderFragments 模板化组件 —— 数据传递

原文链接:https://blazor-university.com/templating-components-with-renderfragements/passing-data-to-a-renderfragement/将数据传递给 RenderFragment源代码[1]到目前为止,我们使用了仅包含子标记的 RenderFragments,然后在渲染组件时按…

《零基础看得懂的C语言入门教程 》——(十二)原来结构体是这么回事

一、学习目标 了解C语言的结构体的使用方法了解C语言结构体的结构的赋值了解多种C语言结构体变量的赋值方法和取值方法 目录 C语言真的很难吗?那是你没看这张图,化整为零轻松学习C语言。 第一篇:(一)脱离学习误区 第…

mysql关系数据库引擎_MySQL数据库引擎详解

作为Java程序员,MySQL数据库大家平时应该都没少使用吧,对MySQL数据库的引擎应该也有所了解,这篇文章就让我详细的说说MySQL数据库的Innodb和MyIASM两种引擎以及其索引结构。也来巩固一下自己对这块知识的掌握。Innodb引擎Innodb引擎提供了对数…

Java之synchronized的JVM底层实现原理精简理解

1 synchronized的JVM底层原理实现的精简理解 Java 虚拟机中的synchronized基于进入和退出Monitor对象(也称为管程或监视器锁)实现, 无论是显式同步(synchronized作用在同步代码块,有明确的 monitorenter 和 monitorexit 指令) 还是…

三分钟掌握Actor和CSP模型

点击上方蓝字进行关注前文传送门:《三分钟掌握共享内存模型和 Actor模型》, 一直想比较Actor模型与golang的CSP模型,经过一段时间的实战记录了本文。Actor vs CSP模型• 传统多线程的的共享内存(ShareMemory)模型使用l…

DateTimeToUnix/UnixToDateTime 对接时间转换

问题&#xff0c;通过毫秒数来解析出时间&#xff1a;&#xff08;很多对接的时候经常需要用到&#xff09; <?php $MyJson {"jingdong_vas_subscribe_get_responce":{"code":"0","item_code":"FW_GOODS-2236-1","…

【学生选课系统经典】VB与SQLSERVER连接:Windows应用工程案例

实验任务描述 1 用VB6访问SQLSERVER数据库(两种安全模式); 2 用VB6完成数据库指定表上的数据显示; 3 用VB6完成数据库指定表上的数据插入、删除和更新; 4 用VB6完成SQLSERVER2008数据库用户验证。 一、数据库系统 该实验中,所要求的数据库名称为SCHOOL,总共涉及以下表:

《假如编程是魔法之零基础看得懂的Python入门教程 》——(二)魔法实习生第一步了解魔杖的使用

学习目标 了解什么是开发环境了解python语言的环境安装了解python语言编程的编辑器工具 目录 第一篇&#xff1a;《假如编程是魔法之零基础看得懂的Python入门教程 》——&#xff08;一&#xff09;既然你选择了这系列教程那么我就要让你听得懂 第三篇&#xff1a;《假如编…

mysql5.7 only_full_group_by_Mysql5.7及以上版本 ONLY_FULL_GROUP_BY报错的解决方法

近期在开发过程中&#xff0c;因为项目开发环境连接的mysql数据库是阿里云的数据库&#xff0c;而阿里云的数据库版本是5.6的。而测试环境的mysql是自己安装的5.7。因此在开发过程中有小伙伴不注意写了有关group by的sql语句。在开发环境中运行是正常的&#xff0c;而到了测试环…

一款高速的NET版的离线免费OCR

PaddleOCR.Onnx一款基于Paddle的OCR&#xff0c;项目使用ONNX模型&#xff0c;速度更快。本项目同时支持X64和X86的CPU上使用。本项目是一个基于PaddleOCR的C代码修改并封装的.NET的工具类库。包含文本识别、文本检测、基于文本检测结果的统计分析的表格识别功能&#xff0c;同…