系统设计题总结(二)

参考:

https://blog.csdn.net/tassardge/article/details/82949812

https://blog.csdn.net/tassardge/article/details/95900244

https://blog.csdn.net/tassardge/article/details/83039032

 

 

 

 

 

系统设计面试题 之 如何设计Instagram

本文翻译自https://www.educative.io/collection/page/5668639101419520/5649050225344512/5673385510043648

1.什么是Instagram

Instagram是一个社交网络服务,用户可以在这个网站上上传和分享他们的照片和视频。Instagram的用户能设置他们的分享内容为所有人可见或者部分人可见。向所有人分享的照片或视频可以被任何用户查看,但是向部分人分享的内容仅仅能被部分人查看。Instagram也能够让它的用户们通过其他社交媒体比如Facebook,Twitter,Flickr和Tumblr分享内容。

2.系统的需求和设计目标

在本题中,我们将主要解决以下问题:
功能性需求:
1.用户能够上传/下载/查看照片;
2.用户能够基于标题搜索照片/视频;
3.用户能够关注其他用户;
4.这个系统能够为用户生成和显示“推送新闻(News Feed)”,“推送新闻(News Feed)”由该用户关注的所有用户的最新照片/视频组成。
非功能性需求:
1.该系统的服务应该是高可用的;
2.对于“推送新闻(News Feed)”,系统可接受的延迟是200毫秒;
3.本系统对一致性的要求略低;如果用户暂时没看到其他用户更新的内容,也是可以接受的;
4.本系统应该高度可靠,并且任何上传的照片/视频永远不能丢失。
本文不讨论的问题:为图片添加标签,根据标签搜索照片,注释照片,推荐关注的用户,建议反馈,等等。

3.一些设计考虑

本系统是一个read-heavy的系统,所以我们的设计重点是确保该系统能够快速的获取照片。
1.因为用户能上传大量的照片,所以对存储的有效管理是设计该系统的关键点;
2.用户查看照片的延时应该满足设计要求;
3.数据应该100%可靠。如果用户上传了一张照片,那么系统应该保证该照片永远不丢失。

4.存储容量预估

假设我们有5亿用户,每天有1百万活跃用户;
每天都会有2百万新照片上传,也就是每秒有23张新照片上传;
假设平均的照片文件大小为200KB;
每天上传的照片占用的空间为 2000000 * 200KB = 400 GB
10年需要的空间为:400GB * 365 (days a year) * 10 (years) ~= 1425TB

5.系统整体设计

我们需要考虑两个使用场景,一是上传照片;二是查看/搜索照片。我们的服务需要使用面向对象存储服务器来保存照片,还需要一些数据库服务器存储照片的元数据。

6.数据库schema

在面试中尽早定义数据库schema能帮助你更好的理解不同组件间的数据流,并且能为后面的数据分区提供指导。
“User”表用来保存用户相关的数据、用户上传的照片和用户关注的其他用户。“Photo”表用来保存与照片相关的所有数据;我们要为PhotoID和 CreationDate创建索引,因为我们要获取最近的照片。


很明显,以上的数据库schema需要做join操作,所以我们可以用关系型数据库存储以上的数据库schema,比如MySql。但是如果我们选用关系型数据库的话,日后我们扩展系统的时候,会遇到很多问题。所以,在此我们选择NoSql数据库。具体原因请google(SQL vs. NoSQL)。
我们可以把照片存储在类似HDFS或者S3的分布式存储设备上。
我们可以把该数据库schema保存于基于key-value的分布式存储设备上,这样可以尽显NoSql的优势。所有和照片有关的元数据都会被存于一张表中,这张表的key可以是PhotoID,value可以是一个包含了PhotoLocation、UserLocation和CreationTimestamp的对象。
我们需要一个表UserPhoto保存用户和照片之间的关系,这样就可以知道谁拥有这些照片。我们还需要一个表UserFollow保存用户关注的人的列表。对于这两张表,我们可使用宽列数据存储(wide-column-store)如Cassandra。对于UserPhoto表,key是UserID,value是用户拥有的PhotoIDs的列表,这个列表被保存在不同的列族中。对于UserFollow表,我们也采用类似的schema。
一般来说,Cassandra或者key-value存储会提供一定数量的冗余存储以提供可靠性。另外,数据删除操作不会立即生效,因为数据在被永久删除前会保留几天以支持数据恢复。

7.数据大小预估

我们来估计一下10年后每张表的数据容量以及我们需要占用多少存储空间。

User: 假设每个“int”和“dateTime”是4 Bytes,那么User表中的每行是68 Bytes:
UserID (4 bytes) + Name (20 bytes) + Email (32 bytes) + DateOfBirth (4 bytes) + CreationDate (4 bytes) + LastLogin (4 bytes) = 68 bytes
如果我们有5亿用户的话,那么我们需要32GB的空间。
500 million * 68 ~= 32GB

Photo: Photo表的每行是284 Bytes:
PhotoID (4 bytes) + UserID (4 bytes) + PhotoPath (256 bytes) + PhotoLatitude (4 bytes) + PhotLongitude(4 bytes) + UserLatitude (4 bytes) + UserLongitude (4 bytes) + CreationDate (4 bytes) = 284 bytes
如果用户每天上传2百万新照片的话,那么Photo表每天增加0.5GB:
2M * 284 bytes ~= 0.5GB per day
所以,Photo表10年共需要1.88 TB存储空间。

UserFollow: UserFollow表中的每一行是8 Bytes。如果我们有5亿用户并且平均每个用户关注500个其他用户的话,UserFollow表将需要895 GB的空间。
500 million users * 500 followers * 8 bytes ~= 1.82TB

10年内这些表需要的全部存储空间大概是3.7 TB:
32GB + 1.88TB + 1.82TB ~= 3.7TB

8.组件设计

照片上传(写操作)可能比较慢,因为上传操作会写磁盘;而读操作会比较快,特别是在有缓存的情况下。

我们知道web服务器有连接数限制,所以我们设计系统的时候需要非常注意。因为上传操作速度比较慢,所以用户的上传操作可能会消耗掉所有可用的连接数。如果系统忙于应付写操作的话,那么“读”请求会无法得到处理。如果web服务器在任意时间点能处理最大500个连接的话,这就意味着它无法同时处理多于500个并发的“上传”或者“读”请求。为了处理这种极端情况,我们可以用把处理“读”和“写”请求的服务分开。我们可以用不同的服务器分别处理“读”和“写”请求,这样就不会阻塞住系统。

把“读”和“写”请求分开处理还可以让我们独立地扩展和优化这些服务。

9.可靠性和冗余

本系统的设计目标是不能丢失文件。所以,对于每个用户上传的文件我们需要保存多份拷贝;这样如果一个存储服务器失效了,那么我们仍然能从其他存储服务器上获取另一份拷贝。

这个原则也适用于系统的其他组件。如果系统要有高可用性,那么系统中运行的服务需要有多份拷贝。这样,如果一个服务死掉的话,系统依然是可用的并且仍然可以提供服务。所以,冗余可以消除系统的单点故障。

如果服务在任何时间点只需要运行一个实例的话,那么我们可以再运行该服务一个冗余的实例,但是该冗余实例不处理任何请求。一旦主服务出了问题,这个冗余的实例可以立刻通过“故障转移”(Failover)接管过来。

在系统中创建冗余可以移除系统的单点故障,并且提供功能的备份以防万一。假设在生产环境中有同一个服务的两个实例;如果其中一个失效或者降级了,那么系统可以通过“故障转移”(Failover)让另一个实例接管。“故障转移”(Failover)可以自动触发也可以手动触发。

10.数据分片

下文将讨论元数据分片的不同设计方法。

a. 基于UserID分区 如果我们基于UserID分片,那么我们可以将同一个用户的全部照片元数据保存于同一个分片上。如果一个数据库分片是1 TB,那么我们需要4个分片来保存3.7 TB的数据。另外,为了更好的性能和扩展性,假设我们保留10个分片。
所以我们可以通过UserID对10取余来找到对应的ShardID,从而保存数据。为了唯一的识别系统中的任意照片,我们可以在PhotoID后面追加ShardID。
那么我们如何生成PhotoID?每个数据库分片都有各自的auto-increment sequence用以生成PhotoID,并且由于我们会追加ShardID到每个PhotoID,因此我们能保证每个PhotoID在系统中都是唯一的。
这种数据库分片设计会有什么问题?
我们如何处理热点用户?有的人会关注热点用户,并且人们往往会查看热点用户上传的每一张照片。
有些用户相对于其他用户会上传大量照片,这会导致存储的不均匀分布。
如果我们无法将一个用户的全部照片的元数据保存于一个分片的话,那我们就只得把用户照片的元数据存放于不同的分片上,这会不会导致更高的延迟?
另外,把一个用户的全部照片的元数据存储于同一个分片上可能会导致一个问题是,如果保存元数据的分片失效了或者该分片的负载很高导致延时很大的话,那么该用户的全部数据就都不可用了。

b. 基于PhotoID分区 我们先生成唯一的PhotoID,然后再通过PhotoID对10取余找到ShardID,这就能解决以上问题。我们不必追加ShardID到PhotoID,因为PhotoID本身在系统中就是唯一的。
那么我们如何生成PhotoID呢?在每个分片中设置auto-incrementing sequence毫无意义,因为我们是先生成PhotoID,再通过PhotoID找到分片。解决方法是,我们可以运行一个独立的数据库实例以生成自动增长的PhotoID。假设我们的PhotoID是64位,那么我们可以定义一个只有64位ID列的表。如果一张新的照片被上传到系统,我们可以插入一行到这个表中并且取这个ID为新的照片的PhotoID。
那么这个生成PhotoID的数据库实例会不会有单点失败?是的,有可能。解决方法是,我们可以定义两个数据库实例,一个生成偶数ID,另一个生成奇数ID。
我们可以添加一个负载均衡器用来轮流调度这两个数据库实例。这两个数据库实例可能生成的ID数目不一样,但是这对系统不会造成任何问题。我们可以把这个设计思想用于系统的其他表比如Users表、Photo-Comments表或者其他组件上。

如果将来数据大幅增长怎么办?我们可以在物理数据库服务器中创建多个逻辑分区来应对未来的数据增长。由于每个物理数据库服务器可以运行多个数据库实例,所以我们可以为各个逻辑分区运行各自独立的数据库实例。如果我们发现一个数据库服务器数据大量增长,就可以把该服务器的一些逻辑分区迁移到另一个服务器。我们可以维护一个配置文件(或者一个数据库)来把我们的逻辑分区映射到数据库服务器;这样我们就可以容易地移动分区。任何时候只要我们想移动一个分区,我们只需要升级这个配置文件以声明改动就行。

11.“推送新闻(News Feed)”

一个用户的“推送新闻(News Feed)”是由该用户关注的所有用户的最近的、最受欢迎的照片组成的。

生成“推送新闻(News Feed)”的基本流程如下。假设用户的“推送新闻(News Feed)”需要包含100张照片。那么我们的应用服务器首先要获取一张该用户关注的所有用户的列表,并且获取每个用户的最近的100张照片的元数据。然后,应用服务器会提交这些照片的元数据到我们的排名算法,该算法会基于照片的时间和用户的喜好来选择前100张照片并且返回给用户。这个流程的问题在于延时会比较高,因为我们需要查询多个表并基于查询结果做排序/合并/排名。为了提高效率,我们可以预先生成“推送新闻(News Feed)”并且将结果保存于另一个表。

预生成“推送新闻(News Feed)”:我们可以用一台专用服务器不断地生成用户的“推送新闻(News Feed)”,并且把结果保存于一个UserNewsFeed表中。这样,一旦需要返回“推送新闻(News Feed)”给用户的时候,我们只要查询一下这张表并返回结果就行了。

一旦这些服务器需要为一个用户生成“推送新闻(News Feed)”,它们可以查询UserNewsFeed表以找到该用户最新的“推送新闻(News Feed)”。然后,我们基于该时间点之后的数据按照以上步骤生成新的“推送新闻(News Feed)”。

有哪些不同的方法发送“推送新闻(News Feed)”给用户?

1. Pull: 客户端可以一定频率或者手动方式直接向服务器请求“推送新闻(News Feed)”。这种方式的问题在于,a)只有客户端发送了请求,客户端的“推送新闻(News Feed)”才会更新;b)如果服务器端没有数据更新的话,那么大多数客户端请求只会得到空响应。

2. Push: 一旦服务器端的数据更新了,服务器就会推送“推送新闻(News Feed)”到客户端。客户端需要维护一个Long Poll请求以接收数据更新。这种方式的问题在于,如果一个用户被大量的其他用户关注或者一个明星用户拥有数百万粉丝的话,服务器端的推送压力会很大。

3. 复合(Hybrid): 复合(Hybrid)方式结合了Pull和Push的优点。对于有大量粉丝的用户,他们可以用Pull方式获取“推送新闻(News Feed)”;对于只有少量粉丝的用户,我们采用Push方式推送更新。另一种复合(Hybrid)方式是,服务器端以一定频率推送“推送新闻(News Feed)”给所有用户;对于有很多粉丝的用户,他们将采用一定频率的Pull模式获取更新。

12.如何基于分片数据生成"推送新闻(News Feed)"

为指定的用户生成“推送新闻(News Feed)”的最重要的要求之一是基于该用户关注的所有用户的列表获取最新的照片。为此我们需要一种有效的方法来按照照片的创建时间为照片排序。我们可以把照片的创建时间追加为PhotoID的一部分。因为我们对PhotoID创建了索引,所以我们能很快基于索引找到最新的PhotoID。
在此我们可以使用时间戳。假设我们的PhotoID由两部分构成:一是时间戳;二是auto-incrementing sequence。为创建PhotoID,我们可以使用当前时间戳并从我们在第10节中提到的键值生成数据库中获取一个auto-incrementing ID。然后,我们可以基于PhotoID算出ShardID,也就是PhotoID对10取余;我们可以把照片的元数据存放于该分片。

那么一个PhotoID需要多少存储字节?假设我们的时间戳从今天开始,那么我们需要多少字节来存储一个单位为秒的50年后的时间戳呢?
86400(秒) * 365(天) * 50(年)  => 1,600,000,000
我们需要31个比特位来存储这个数字。平均而言,用户每秒会上传23张照片;我们可以分配9个比特位来存放auto incremented sequence。所以,每秒钟我们能存储至多512张照片,也是2的9次方。另外,我们每秒钟可以重置一次auto incremented sequence。

13.缓存与负载均衡

我们的服务需要一个海量照片发送系统以服务分布于全球的用户。我们的服务需要大量的分布于世界各地的照片缓存服务器和CDN,这样用户就可以从就近的服务器获取推送内容。

我们可以引入缓存来存放元数据库中的热点数据。在此我们可以使用Memcache,应用服务器在访问数据库之前可以先检查缓存中是否有需要的数据。LRU对我们的系统来说是一种可行的缓存策略。基于此策略,最旧的数据会被最先丢弃。

我们如何建立更有效的缓存机制呢?假设我们使用2-8原则,那么每天有20%的照片会产生80%的流量,这就意味着一部分照片是非常受欢迎的,大部分人都会访问这些照片。因此我们可以考虑缓存每天的20%的照片和其元数据。

译后记:

1)第10节写得不好,不知道作者到底希不希望所有数据在一个分片上
2)下面是我搜集的文中的一些概念的链接:
文件存储与对象存储的区别
https://www.zhihu.com/question/21536660
sql与nosql的区别
https://www.jianshu.com/p/b32fe4fe45a3
列式存储
https://blog.csdn.net/dc_726/article/details/41143175
数据分片
http://blog.zhaojie.me/2010/03/sharding-by-id-characteristic.html
 

 

 

 

 

 

 

系统设计面试题之 怎么设计一个打分系统

上周我参加了一个面试,其中有一道系统设计题:某公司的内网有个质询系统。该公司的每个职员都可以对本公司的任何部门的任何事件提问题,并且所有的其他职员都能看到这些问题,还可以对问题打分,打分的范围是一颗星到五颗星。现在让我们来设计打分系统,不用考虑提问功能。

以下是面试官给出的基本的测试用例:
1.用户可以对任意一个问题评分,打分范围是一颗星到五颗星;
2.公司的分析部门需要一个查询api,这个api可以:
a.查询某条问题的平均分;
b.查询某个问题的top 10的高分以及用户名;
c.查看某个用户评过分的所有问题;

注意:
1.这个公司的职员有几十万之多,因此评分系统需要考虑性能问题。并且每天早上上班的时候是评分系统负载最大的时间点。
2.不需要考虑安全问题。
3.所有数据都需要长期保存,不用考虑删除问题。

以下是我的设计:
1.数据库的设计:
数据库有4个表,如下图。

comments表,用来记录问题,每条问题都有一个唯一的id;user表用来保存用户的信息,每个用户都有唯一的id。这两个表都是RMDB表,因为他们的数据相对来说比较固定,不会被频繁修改。

rating_comments表,用来记录用户对每个问题的评分。如果这个表使用RMDB的话,它与comments表和user表做join的成本会很高;而且这个表必然需要对用户id和问题id做索引以加速查询,又因为这个表的数据会被频繁的更新,所以维护索引的开销会很大。因此,这个表会使用基于key-value的NoSQL DB。key就是问题的id,value是一个队列,这个队列的每条记录包含两个字段,一个字段是uid,也就是用户id,另一个字段是分数,所以队列中的一条记录就是一个用户对某个问题的打分,这个队列按照分数高低排序,所以对于某个问题,我们可以很容易的找到它的最高分和最低分。

rating_user表,也用来记录用户对每个问题的评分。基于与rating_comments表同样的原因,这个表也使用基于key-value的NoSQL DB。不过,与rating_comments表的区别在于,这个表的key是用户id,队列的每条记录是由问题id和问题的分数组成的。很明显,这个表的数据相对于rating_comments表是冗余的。这个表的目的是加速对于某个用户打过分的问题的查询。

2.评分系统的架构如下图。分为4层,其中每一层都可以扩展为load balancer+多台服务器的模式。
层一:web server
层二:write api 和 search api
层三:memcache
层四:数据库,包含RMDB和NOSQL DB

3.业务流程:
1)用户可以对任意一个问题评分,打分范围是一颗星到五颗星;
a.用户向web server发请求

b.web server向write api发请求
c.write api根据用户id和问题id以及用户的评分更新rating_comments表和rating_user表

2)查询某条问题的平均分;
a.用户向web server发请求
b.web server向search api发请求
c.search api根据问题id来查询rating_comments表,返回一个用户打分队列,使用队列中的数据计算平均分并返回结果。

3)查询某个问题的top 10的高分以及用户名
a.用户向web server发请求
b.web server向search api发请求
c.search api根据问题id来查询rating_comments表,返回一个用户打分队列,使用队列中的已排序数据返回top 10的最高分以及对应的用户。

4)查看某个用户评过分的所有问题
a.用户向web server发请求
b.web server向search api发请求
c.search api根据用户id来查询rating_user表,返回一个打分队列,使用队列中的所有问题id就是用户打分过的问题。

4. write api:
write api server 提供以下接口:
bool save_score(int question_id, int user_id, int score)
question_id就是问题的id,user_id就是用户的id,score就是用户的打分。write api server提供这个接口给web server,用户用这个接口给问题打分。

5.其他:
1)对于平均分,其实可以再增加一个average_score表,包含两个字段:一个是问题id,另一个是平均分;每次用户调用write api打分的同时也更新这个平均分表。这个平均分表可以加速对平均分的查询。

2)面试官反复强调一个问题可能会被大量的用户打分,问我,我的设计是否合理?我觉得挺合理的,使用key-value nosql数据库存储问题以及打分队列,不会有性能问题。然后反复问我,我对这个设计是否满意?我觉得没啥大问题。后来时间不够,就没有深入讨论search api。
 

 

 

 

 

 

 

 

 

系统设计面试题 之 如何设计一个能扩展到百万用户级别的系统

本文翻译自https://github.com/donnemartin/system-design-primer/blob/master/solutions/system_design/scaling_aws/README.md
因为原文有很多重复内容并且组织比较零散,所以译文调整了部分原文顺序,并整理了很多过于琐碎的内容。

第一步:用例和约束
在面试过程中我们应该向面试官询问和讨论用例和约束。但是本文由于没有面试官可以讨论,我们会定义一些用例和约束。

1. 用例
本题中我们将处理下面的用例:
1)用户发送读或者写请求
2)服务要处理并存储用户数据,然后返回结果
3)服务需要从一个少量用户的系统升级至百万用户
4)讨论当一个系统从少量用户升级至百万用户的过程中的一般扩展模式
5)服务有高可用性
解决用例3,4和5需要不断运行Benchmark/负载测试并且分析瓶颈。

2. 约束和假设
这部分内容大部分省略,太琐碎。

第二步:总体设计
总体设计包含了所有必要的组件。

第三步:设计核心组件
假设我们只需要服务1-2个用户,那么我们就只需要一台服务器,这台服务器上安装了数据库和web服务器。当我们需要升级的时候只需要做垂直升级就行了。另外,如果我们的数据是关系型数据,那么可以选用MySQL数据库。防火墙只打开必要的端口:80,443和22。

第四步 扩展我们的设计
1.Users+
1)假设
我们的用户数量在上升并且服务器的负载也在增加。我们的测试和分析结果显示,MySQL数据库占用了大量的内存和CPU资源,而用户内容正在不断占用磁盘空间。
到目前为止,我们一直采用垂直升级。不幸的是,这种升级方式比较昂贵并且不允许MySQL数据库和Web服务器单独扩展。
2)目标
我们的目标是减轻服务器的负载并且允许独立扩展。为此我们可以把静态内容单独存储到一个面向对象存储服务器上,并且我们可以把MySQL数据库移动到一台单独的服务器上。但这么做的缺点是,系统的复杂度上升了,并且我们需要额外的安全措施来确保新增服务器的安全。
3)把静态内容分开存放
我们可以考虑使用面向对象存储例如S3来保存静态内容。S3的扩展性和可靠性都很高,并且服务器端是加密的。User files、JS、CSS、Images和Videos都可以移动到S3。
4)把MySQL数据库移动到一台单独的服务器上
5)系统的网络安全
我们需要加密传输的数据,并且我们可以考虑使用虚拟私有云。我们可以为Web服务器分配公有网址,这样它可以从internet发送和接收数据;我们要为其他的服务器分配私有网址,他们不访问外网;对于每台服务器我们只开放列在白名单的IP的端口。

2.Users++
1)假设
我们的测试结果显示网站的性能瓶颈在我们的唯一的一台web服务器上。在峰值期间这台服务器的响应会很慢,并且有时候会无响应。因此我们需要更高的可用性和冗余。
2)目标
我们可能只需要以下的一种或者几种方法来解决假设中的问题。
a.我们可以使用水平扩展来处理不断增加的系统负载和解决单点故障问题。
我们可以增加负载均衡器(例如ELB)。ELB的可用性很高;如果你配置自己的负载均衡器的话,你可以把它们配置为active-active或者active-passive类型;我们可以让负载均衡器来处理SSL认证,这样可以降低后端服务器的负载并简化认证管理。
我们可以让web服务器群分布于多个地区以提高系统冗余性。
我们可以让MySQL服务器群分布于多个地区以提高系统冗余性。
b.我们可以把应用服务器从web服务器中分离出来;
我们可以单独地配置web服务器群和应用服务器群;web服务器群和应用服务器群可以有各自的负载均衡器;我们可以把应用服务器分为Read API服务器和Write API服务器。
c.我们可以把静态内容(和部分动态内容)移动到CDN上以减少系统负载和延迟。

3.Users+++
1)假设
我们的测试数据显示,我们的数据库由于大量的读请求而性能糟糕。
2)目标
我们可能只需要以下的一种或者几种方法来解决假设中的问题。
a.把以下数据移动到缓存服务器(例如Elasticache)中以降低负载和延迟:
一是访问频繁的MySQL数据。不过,请首先尝试打开MySQL的缓存;如果不能解决性能瓶颈的话,再考虑缓存服务器。
二是Web服务器的会话数据。这样web服务器就变成无状态的,从而可以自动扩展。
b.添加“MySQL读服务器(MySQL Read Replicas)”以降低“写服务器(write master)”的负载;
c.添加更多的web服务器和应用服务器以加快响应。
3)添加“MySQL读服务器(MySQL Read Replicas)”
a.“MySQL读服务器(MySQL Read Replicas)”可以帮助降低“写服务器(write master)”的负载;
b.我们需要在Web服务器上区分“读”和“写”的逻辑;
c.为“MySQL读服务器(MySQL Read Replicas)”服务器集群添加负载均衡器;
d.大多数的服务是“读”负载大于“写”负载的。

4.Users++++
1)假设
我们的测试数据显示,我们的网站流量在工作时间会急剧上升,但是下班后会急剧下降。所以,我们可以根据实际负载来自动启动或者关闭服务器。
2)添加自动扩展
a.为web服务器和应用服务器分别创建服务器集群,集群中的服务器应该分布于多个不同的区域,这样可以提高可用性。
b.设定集群服务器的上限和下限;
c.监控各台服务器的cpu负载、延时以及网络流量等日志以出发服务器的自动开启和关闭;
d.自动扩展的缺点是增加了系统的复杂性;另外,开启或者关闭服务器会有一定的延迟。

5.Users+++++
当用户进一步增加的时候,我们需要通过测试和性能分析找到瓶颈,而非盲目的优化。
a.如果我们的MySQL数据库持续增长,那么我们可以考虑只在数据库中保存最近一段时期的数据,而把其他时间的数据保存在数据仓库中(例如:Redshift)。诸如Redshift之类的数据仓库可以轻松处理每个月新增1TB的数据的情况。
b.我们可以通过扩展内存缓存服务器来处理平均每秒40000个读请求的负载。另外,该方法也能很好地处理非均匀分布的流量和流量峰值问题。注意:SQL“读服务器(Read Replicas)”可能会有缓存没有命中的情况,我们可能需要额外的SQL扩展方法来解决该问题。
c.当平均每秒有大于等于400写操作的时候,只有单台写服务器的SQL Master-Slave可能会无法应付,这时候我们需要额外的扩展方法。
d.我们也可以考虑把数据移动到NoSql数据库上以进一步解决大量的读写请求。

额外的数据库扩展方法包括:
a.Federation
b.分片
c.反范式
d.SQL调优

我们可以进一步划分应用服务器以更好地独立扩展。不需要实时完成的请求或者操作可以用Queues和Workers完成。例如,在照片服务中,照片上传和缩略图生成的功能可以被分开:
a.用户上传照片
b.应用服务器将一个job放入Queue
c.某台服务器上的Worker会把job从Queue中取出,然后创建缩略图,更新数据库,将缩略图保存入面向对象存储。

 

posted on 2021-02-05 21:26  秦羽的思考  阅读(477)  评论(0编辑  收藏  举报