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

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


    从单个服务开始   

千里之行,始于足下,让我们从最简单的单个服务开始。所有的内容都在一台服务器上运行,包括 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,一经查实,立即删除!

相关文章

SQL Server T-SQL编程:数据库用户与安全设置

目录 一、数据库的注册、用户建立 二 、用户安全设置:角色

原百万访问量博客http://blog.chinaunix.net/uid/20656672.html不再维护(10年前数百篇oracle/teradata性能优化、故障处理案例)...

原博客地址http://blog.chinaunix.net/uid/20656672.html不再维护(数百篇oracle/teradata性能优化、故障处理原创文章)转载于:https://www.cnblogs.com/zhjh256/p/5497797.html

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

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

LRU算法

1 LRU算法 LRU(Least recently used,最近最少使用)根据数据的历史访问记录来进行淘汰数据,思想是“如果数据最近被访问过,那么将来被访问的几率也更高”。 2 具体实现过程 新数据插入到链表头部; 每当缓存命中(即缓存数据被访问),则将数据移到链表头部; 当链表满…

Scala-2.13.0 安装及配置

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

检测python进程是否存活

crontab -e */3 * * * * /data/log_realtime/check.sh > /data/log_realtime/check.log 2>&1 1 0 1 * * /data/jx3log_import_realtime/shutdown.sh 说明:每3分钟检查一次进程是否存在,每个月1号0点1分杀掉进程,重启 check.sh cd …

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

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

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

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

集合学习

List集合:ArrayList集合基于动态数组结构,查询优,LinkedList 基于链表结构 数据移动优。是一个有序的队列集合 set集合:HashSet和TreeSet 。是一个无序不重复集合 Map集合:HashMap和TreeMap。是一个KEY-VALUE映射的集合…

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

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

T-SQL编程基础之一:变量与基本语句

一个标准的计算机语言,大概要提供的必要主要功能是:变量说明、分支判断、循环和输入输出结果。T-SQL也一样,具有这些功能,只不过T-SQL的输入和输出不是界面,而是表。 完全精确描述一个计算机语言,大概要很厚的书才能做到,好在目前这些书籍的发行也很多,许多书描述的都…

Java之volatile如何保证可见性和指令重排序

1 我们先了解CPU缓存 CPU缓存为了解决CPU运算速度与内存读写速度不匹配的问题,因为CPU运算速度要比内存读写速度快得多 一次主内存的访问通常在几十到几百个时钟周期一次L1高速缓存的读写只需要1~2个时钟周期一次L2高速缓存的读写也只需要数十个时钟周期 CPU大多数…

bigpipe提升网站响应速度

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

mysql 添加用户_mysql创建用户与授权

一、创建用户CREATE USER usernamehost IDENTIFIED BY password;说明username:你将创建的用户名host:指定该用户在哪个主机上可以登陆,如果是本地用户可用localhost,如果想让该用户可以从任意远程主机登陆,可以使用通配…

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

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

T-SQL编程基础之二:条件选择、循环编程

1. 条件判断以及GOTO语句 条件判断是计算机语言的重要功能,在T-SQL中,条件判断的语句是: if 条件 … else … 或者是: if 条件 … 注意写法和C类似,但条件描述不使用()也可以。如果是在一个条件里执行多条语句,则要构造复合语句,复合语句是在BEGIN…EDN中构造…

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

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

AspNetCore开源中间件-VueRouterHistory

前言用过VueRouter路由组件的应该都知道,VueRouter有hash和history两种模式。hash模式会在url中插入#,history模式下url则看上去更加简洁美观。如果想要支持history模式则必须要后端服务进行配合。常用后端服务器配置方式请参考 后端配置例子后端配置例子…

T-SQL编程基础之三:游标(Cursor)编程

SQL是一种面向集合操作的语言,大多情况下,一个SQL语句将会操作数据库表里的很多数据,基本上,一个数据库的程序员脑子里应该想的是如何整体操作一个表或者是几个表。 但也有一些情况下,试图整表操作是不现实的,需要一行一行处理数据,这种情况下,SQL语言提供了所谓游标的…

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

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