单服务器模型

重点:只有一台Web服务器,所有的访问和数据处理都在这台服务器上处理。

用户访问过程:

1. 浏览器或客户端输入访问URL,一般是以域名形式进行访问。

2. DNS域名解析,拿到服务器的IP地址。

3. 根据IP地址访问服务器。

4. 服务器返回结果。

单服务器带数据库模型

重点:增加了一台单独的数据库服务器,用于缓解Web服务器上数据访问压力。一般使用关系型数据库,如MySQL。

关于垂直扩展与水平扩展

垂直扩展指增加单个服务器的处理能力,比如堆内存,堆CPU核心,堆SSD等。水平扩展指增加更多的服务器,通过负载均衡的手段将流量分布到各个服务器上,从而提高并发能力。

流量较小时,垂直扩展效果显著,且操作简单。但随着流量的增加,垂直扩展将很快触顶,因为硬件的机能是有上限的,不能无限叠加,这时只能寻求水平扩展。并且垂直扩展不具备容错(failover)和冗余(redundancy)能力,如果服务器挂了,整个系统也就不可用了。

增加负载均衡

重点:通过负载均衡将流量平均分布到一组服务器上,降低单个服务器的压力,并且使系统具备了容错能力。当两个服务器中的任何一个挂掉时,流量可以转发到另一台上,由此提高了可用性。

此方案下服务器一般位于内网中,需要使用反向代理才能让外面的设备访问到。

增加冗余数据库

重点:使用数据库复制(Database Replication)技术,增加数据层的并发能力和容错能力,提高可用性。

通常有一个主数据库,提供只写操作,有多个从数据库,提供只读操作。主从数据库之间通过数据库复制技术保证数据同步。

所有对数据的增加、删除、修改操作都发生在主数据库上,从数据库只负责同步主数据库的内容,然后提供查询功能,由于读的频率一般比写高很多,所以从数据库的数量一般要比主数据库多。

为提高可用性,当所有的从数据库都挂掉时,主数据库也可以临时提供查询功能,当主数据库挂掉时,可以将某个从数据库临时提升成主数据库。

阶段设计一

重点:增加了负载均衡和数据库复制。

增加缓存

缓存用于临时存储数据,避免每次访问都从数据库中查询。由于缓存往往速度比较快,对于一些使用,或是查询代价较高的数据,可以存储在缓存中,以提高响应速度。

缓存层

收到响应后,Web服务器首先查询缓存,看有没有对应的结果。如果有,则把缓存中的结果发给客户。如果没有,则查询数据库,并将查询的结果保存到缓存中,这样下次访问时就可以从缓存中取数据。

使用缓存要考虑以下几点:

1. 使用场景。缓存适用于读多写少的场景,并且由于缓存一般存储在内存里,关机时会丢失,所以不要用缓存做数据持久化。

2. 过期策略。删除过期数据,以节省内存。当过期时间设置得较小时,数据会被频繁加载,当过期时间设置得较大时,数据会积压。

3. 缓存一致性。保持缓存数据与持久存储的数据的一致性,做法是确保每次更新数据库时都同步更新缓存。

4. 容错。单个缓存结点容易造成单点故障(single point of failure, SPOF),为此,可以设置一组缓存结点,或是为单个结点超额配置一定比例的内存,以应对突发情况。

5. 淘汰策略。缓存满时,如何删除数据。常见的有LRU(least-recently-used), LFU(least-frequently-used), FIFO(first-in-first-out)。

CDN

地理分布不同的一组服务器构造成的网络,用于就近分发数据。CDN一般用于加速静态资源的加载,比如图片,视频,CSS/Javascript文件等。CDN也可以用于动态视频的加速,比如直播流量。

当用户向CDN请求数据时,CDN上的服务器首先判断当前有没有对应的数据,如果有则直接返回内容,如果没有,则向服务器请求数据,然后保存在CDN服务器上。一般使用HTTP头部的Time-to-Live字段来描述内容在CDN上的过期时间。

使用CDN时要考虑以下几点:

1. 成本。CDN网络一般是第三方服务商提供的,根据流量计算费用。CDN应该用来存储那些经常要使用的内容。

2. 过期策略。对于时间敏感的内容,如果过期时间太长,则有可能会过期,如果过期时间太短,则会频繁在CDN和服务器之间同步内容。

3. CDN应急策略。当CDN挂掉时,如何处理。一般来说,CDN挂掉后,客户端应该能检测到,并且将网络请求转发到原始服务器上。

4. 数据作废。当数据过期时,应当从CDN上删除数据。可以直接调用CDN提供的API来删除,或是对数据进行版本化处理,用新版本的数据替换旧版本的数据。

阶段设计二

重点:增加了缓存和CDN。静态文件存放在CDN上,数据层增加缓存。

无状态服务层

用于服务层水平扩展,将状态相关的数据(比如用户会话数据)从服务层中独立出来,用单独的服务器存储。集群中的其他服务器不保存会话状态,只提供服务。

Statefull架构

每个服务器都单独保存自己的用户会话数据,用户不能跨服务器访问,否则就要重新认证。

Statefull架构的关键是要保证用户每次都被导向同一个服务器,这一般在负载均衡服务器上通过粘性会话(sticky session)来实现。缺点是有额外开销,不利于扩展,且不好应付服务器挂掉的情况。

Stateless架构

所有服务器共享会话存储数据,这样用户的请求就可以被导向任何服务器进行处理。

阶段设计三

重点:服务层改为无状态设计,所有用户的会话数据通过单独的持久化数据库来存储。因为服务层为无状态数据,所以可以非常容易地根据流量实现自动扩展。

数据中心

分布于不同地址位置,用于为大范围的用户提供服务。基于用户的地址位置将请求导向就近的数据中心,如果某个数据中心宕机,请求会被导向另其他区域的数据中心。

设计数据中心应考虑的点:

1. 流量定向。基于用户的地址位置进行DNS解析,将用户请求导向最近的数据中心。

2. 数据同步。借助类似跨数据中心的数据库复制技术,保证各个数据中心的数据同步。

3. 测试与部署。借助自动化测试与部署工具保证多个数据中心的服务一致性。

消息队列

用于异步消息推送。为消息提供缓存和异步分发功能。一般分为发布者和订阅者,发布者创建消息,并将消息送入消息队列。订阅者(消费者)连接消息队列,获取消息。

消息队列用于组件之间的解耦合,提升系统的可伸缩性与稳定性。消息的生产者与消费者可独立运行,不需要管对方的状态。

日志分析、状态监测与自动化

日志:监控错误日志信息,识别系统错误。可使用专门的工具进行日志收集与分析,比如ELK。

状态监测:收集服务器的各项运行指标,比如CPU使用率,磁盘IO,数据库/缓存性能等,用于确定系统的运行状态。

自动化:用于提升效率,比如自动化测试与部署。持续集成是一个很不错的实践,通过自动化的代码集成,可以允许团队提早发现问题。

阶段设计四

重点:

1. 增加了消息队列,用于解耦合各个工作集群,提升容错能力。

2. 增加了日志分析、状态监测与自动化工具。

数据库扩展

垂直扩展

也称向上扩展,指堆配置,比如CPU, RAM, 硬盘等,存在以下限制:

1. 不能无限扩展。

2. 单点故障风险。

3. 费用。

水平扩展

也称分片,指增加更多的服务器。通过分片将大的数据库分成几个小的数据库,所有的库共享表设计,但数据是独立的。

下面是一个数据库分片设计,通过用户ID来进行分片,用对4取余的方式来确定将数据存储在哪个数据库。

设计数据库分片的关键是确定用哪个key进行分片。上面用的是user_id作为key进行分片。在选择sharding_key时,要确保能够将数据平均地分布到各个数据库上。

数据库分片技术是扩展数据库的一个有效手段,但并不完美,伴随有以下问题:

1. 数据分片。只有在单个数据库无法承载超量的数据访问压力时,才需要数据分片。某个分片可能会数据分布不平均的原因比其他分片更快速耗尽资源,当发生这种问题时,需要再重新设计分片策略并移动数据。哈希一致性是一个解决此问题的常用方法。

2. 名人效应。也称为热点key问题,对某个分片的超量访问可能导致服务器过载。对此问题,我们可能需要给名人单独分片,甚至再分片。

3. 联合与反规范化(de-normalization):数据库一旦分布,想要跨数据库进行联合查找就会比较困难。这里一般会采用将数据库反规范化的方式来实现在单一表上进行查找的功能。

阶段设计四

重点:增加了数据库分片,一些非关系型的数据被称到了NoSQL数据库中存储。

总结

系统伸缩设计的几点总结:

1. 保持web层无状态

2. 每层都留有冗余设计 

3. 尽量多得缓存数据

4. 支持多个数据中心

5. 使用CDN分布静态文件

6. 使用分片来扩展数据层

7. 将层按服务划分

8. 监控系统,并使用自动化工具























  • 无标签