0%

集群

集群

一、负载均衡

集群中的应用服务器(节点)通常被设计成无状态,用户可以请求任何一个节点。

负载均衡器会根据集群中每个节点的负载情况,将用户请求转发到合适的节点上。

负载均衡器可以用来实现高可用以及伸缩性:

  • 高可用:当某个节点故障时,负载均衡器会将用户请求转发到另外的节点上,从而保证所有服务持续可用;
  • 伸缩性:根据系统整体负载情况,可以很容易地添加或移除节点。

负载均衡器运行过程包含两个部分:

  1. 根据负载均衡算法得到转发的节点;
  2. 进行转发。

负载均衡算法

1. 轮询(Round Robin)

轮询算法把每个请求轮流发送到每个服务器上。

下图中,一共有 6 个客户端产生了 6 个请求,这 6 个请求按 (1, 2, 3, 4, 5, 6) 的顺序发送。(1, 3, 5) 的请求会被发送到服务器 1,(2, 4, 6) 的请求会被发送到服务器 2。


该算法比较适合每个服务器的性能差不多的场景,如果有性能存在差异的情况下,那么性能较差的服务器可能无法承担过大的负载(下图的 Server 2)。


2. 加权轮询(Weighted Round Robbin)

加权轮询是在轮询的基础上,根据服务器的性能差异,为服务器赋予一定的权值,性能高的服务器分配更高的权值。

例如下图中,服务器 1 被赋予的权值为 5,服务器 2 被赋予的权值为 1,那么 (1, 2, 3, 4, 5) 请求会被发送到服务器 1,(6) 请求会被发送到服务器 2。


3. 最少连接(least Connections)

由于每个请求的连接时间不一样,使用轮询或者加权轮询算法的话,可能会让一台服务器当前连接数过大,而另一台服务器的连接过小,造成负载不均衡。

例如下图中,(1, 3, 5) 请求会被发送到服务器 1,但是 (1, 3) 很快就断开连接,此时只有 (5) 请求连接服务器 1;(2, 4, 6) 请求被发送到服务器 2,只有 (2) 的连接断开,此时 (6, 4) 请求连接服务器 2。该系统继续运行时,服务器 2 会承担过大的负载。


最少连接算法就是将请求发送给当前最少连接数的服务器上。

例如下图中,服务器 1 当前连接数最小,那么新到来的请求 6 就会被发送到服务器 1 上。


4. 加权最少连接(Weighted Least Connection)

在最少连接的基础上,根据服务器的性能为每台服务器分配权重,再根据权重计算出每台服务器能处理的连接数。

5. 随机算法(Random)

把请求随机发送到服务器上。

和轮询算法类似,该算法比较适合服务器性能差不多的场景。


6. 源地址哈希法 (IP Hash)

源地址哈希通过对客户端 IP 计算哈希值之后,再对服务器数量取模得到目标服务器的序号。

可以保证同一 IP 的客户端的请求会转发到同一台服务器上,用来实现会话粘滞(Sticky Session)


转发实现

1. HTTP 重定向

HTTP 重定向负载均衡服务器使用某种负载均衡算法计算得到服务器的 IP 地址之后,将该地址写入 HTTP 重定向报文中,状态码为 302。客户端收到重定向报文之后,需要重新向服务器发起请求。

缺点:

  • 需要两次请求,因此访问延迟比较高;
  • HTTP 负载均衡器处理能力有限,会限制集群的规模。

该负载均衡转发的缺点比较明显,实际场景中很少使用它。


2. DNS 域名解析

在 DNS 解析域名的同时使用负载均衡算法计算服务器 IP 地址。

优点:

  • DNS 能够根据地理位置进行域名解析,返回离用户最近的服务器 IP 地址。

缺点:

  • 由于 DNS 具有多级结构,每一级的域名记录都可能被缓存,当下线一台服务器需要修改 DNS 记录时,需要过很长一段时间才能生效。

大型网站基本使用了 DNS 做为第一级负载均衡手段,然后在内部使用其它方式做第二级负载均衡。也就是说,域名解析的结果为内部的负载均衡服务器 IP 地址。


3. 反向代理服务器

反向代理服务器位于源服务器前面,用户的请求需要先经过反向代理服务器才能到达源服务器。反向代理可以用来进行缓存、日志记录等,同时也可以用来做为负载均衡服务器。

在这种负载均衡转发方式下,客户端不直接请求源服务器,因此源服务器不需要外部 IP 地址,而反向代理需要配置内部和外部两套 IP 地址。

优点:

  • 与其它功能集成在一起,部署简单。

缺点:

  • 所有请求和响应都需要经过反向代理服务器,它可能会成为性能瓶颈。

4. 网络层

在操作系统内核进程获取网络数据包,根据负载均衡算法计算源服务器的 IP 地址,并修改请求数据包的目的 IP 地址,最后进行转发。

源服务器返回的响应也需要经过负载均衡服务器,通常是让负载均衡服务器同时作为集群的网关服务器来实现。

优点:

  • 在内核进程中进行处理,性能比较高。

缺点:

  • 和反向代理一样,所有的请求和响应都经过负载均衡服务器,会成为性能瓶颈。

5. 链路层

在链路层根据负载均衡算法计算源服务器的 MAC 地址,并修改请求数据包的目的 MAC 地址,并进行转发。

通过配置源服务器的虚拟 IP 地址和负载均衡服务器的 IP 地址一致,从而不需要修改 IP 地址就可以进行转发。也正因为 IP 地址一样,所以源服务器的响应不需要转发回负载均衡服务器,可以直接转发给客户端,避免了负载均衡服务器的成为瓶颈。

这是一种三角传输模式,被称为直接路由。对于提供下载和视频服务的网站来说,直接路由避免了大量的网络传输数据经过负载均衡服务器。

这是目前大型网站使用最广负载均衡转发方式,在 Linux 平台可以使用的负载均衡服务器为 LVS(Linux Virtual Server)。

参考:

二、集群下的 Session 管理

一个用户的 Session 信息如果存储在一个服务器上,那么当负载均衡器把用户的下一个请求转发到另一个服务器,由于服务器没有用户的 Session 信息,那么该用户就需要重新进行登录等操作。

Sticky Session

需要配置负载均衡器,使得一个用户的所有请求都路由到同一个服务器,这样就可以把用户的 Session 存放在该服务器中。

缺点:

  • 当服务器宕机时,将丢失该服务器上的所有 Session。


Session Replication

在服务器之间进行 Session 同步操作,每个服务器都有所有用户的 Session 信息,因此用户可以向任何一个服务器进行请求。

缺点:

  • 占用过多内存;
  • 同步过程占用网络带宽以及服务器处理器时间。


Session Server

使用一个单独的服务器存储 Session 数据,可以使用传统的 MySQL,也使用 Redis 或者 Memcached 这种内存型数据库。

优点:

  • 为了使得大型网站具有伸缩性,集群中的应用服务器通常需要保持无状态,那么应用服务器不能存储用户的会话信息。Session Server 将用户的会话信息单独进行存储,从而保证了应用服务器的无状态。

缺点:

  • 需要去实现存取 Session 的代码。


参考:

限制字符长度,生成二维码

可以拿到分享数据信息

没有必要复用分享短链

image-20220416174125946

image-20220416174240956

image-20220416174304268

永久重定向,会默认链接不超时,浏览器直接找缓存中的url

image-20220416180838143

一次调用50ms

广域请求 80ms

请求延迟通常200ms

用户信息可以用消息中间件改成离线

长短链接可以互为kv(如果支持用户自定义短链接)

10ms的话最好将短长链接映射放在本地server中

可以用布隆过滤器查询长链接是否被分配过。

可靠性: 冗余备份

安全性:不用自增用hash

Server 需要写redis 与 mysql 需要三次网络调用其延迟 至少100ms以上,同时考虑短域名系统的全球化,跨越过远的广域网络请求,延迟再增加80ms以上,因此预估一次请求延迟在200ms。

  1. 过期后将失效
  2. 短域名是唯一的
  3. 支持自定义短域名,长度在7个字符(不含域名长度),由[0-9,a-z,A-Z]等字符组成
  4. QPS
    1. 写 DAU = 100M -> QPS = 100M * 0.1/ 86400 = 1K -> 峰值 2k -> 预估值 = 4K
    2. 读 DAU = 100M -> QPS = 100M * 10 / 86400 = 115k -> 峰值230k-> 预估值460k
    3. 这是一个读多写少的系统
  5. 延迟 = 10ms以内
  6. 存储 = 128+7 = 100 bytes/条 1500 60 60 24 * 365 = 20T/年
  7. 可靠性: 5个9(可运维性, 可扩展性,迭代效率)
  8. 安全性: 防止被人爬取,盗用数据

存储层

  1. 存储介质 数据表的业务逻辑非常简单,没必要使用关系型数据库,可以更换为持久化kv引擎 比如rocksDB,如果考虑数据分析的需求,则可以将数据构建离线的ELK导入数仓。
  2. 构建索引 写入时要判断长域名是否存在,因此要对长域名建立索引,读取时要根据短域名查询长域名因此也要在redis中维护短域名到长域名的倒排索引。
  3. 为了应对极高的写入QPS,必须使用分片技术, 使用短域名7位62进制的特性,进行一致性哈希,来计算写入分片位置,读取时也用相同的哈希算法。

缓存层

  1. 读多写少 的系统中,可以使用缓存技术来降低延迟, 尽量保证所有请求在缓存中完成
  2. 对于判断长域名是否存储过,以及短域名是否被分配过可以构建布隆过滤器
  3. 如果对延迟非常苛刻,完全可以使用本地缓存, 在本地维护一个LRU缓存来存储长短域名映射
  4. 短域名数据的变化非常缓慢,可以考虑静态化技术,把数据发送给服务节点以文件的方式同步

业务层

  1. 通过尾号分片将ID生成器分布式化,基于预处理的思路可以分段缓存一部分未分配的短域名
  2. 分布式ID生成需要使用zk等组件处理数据一致性的问题
  3. 使用lua脚本降低对redis的减少网络调用次数

拓扑层

  1. 利用地理位置的局部性,将同一地区的请求都路由到最近的机房访问,降低广域延迟
  2. 可以支持跨机房全球化的多重分片,来应对同一地区QPS过高问题,使用7位数字中的首位进行一致性哈希(其哈希空间为62),后6位进行本机房内的rocksDB 节点的分片。

系统设计问题

需求约束

输入 输出

非需求约束

可用性:当某个节点故障时,负载均衡器会将用户请求转发到另外的节点上,从而保证所有服务持续可用。

延迟:一般都是100ms-200ms

一致性:一般指读写一致性,读的时候一定读最新的写则是高一致性

可靠性:数据不能丢失,需要主从复制与冗余备份

数据库模式

NOSQL VS SQL

SQL模式固定不灵活 适合垂直扩展,也就是换更强的cpu 更大的内存等等,但水平扩展很麻烦

NOSQL 模式灵活,水平扩展更简便

SQL 坚决符合ACID特性,而NoSQL为了更好的性能和扩展性会牺牲一部分

用SQL的理由

ACID特性

数据结构固定,不需要大量增长

用NoSQL的理由

不必预先定义类型

需要利用云计算,要好扩展性的系统

开发迅速,可以慢慢扩展

数据库可以体现可靠性:NoSQL会维持一定数量的备份以保证可靠性

组件设计

一般都是读写分离,有专门的读服务器与写服务器

  • QPS: Queries per second ,每秒查询量, 可以通过日活推断
    • 日活数量如果为1亿(100M),写请求,猜测每个用户平均每天写请求为0.1次, QPS = 100M*0.1/86400 =1K,1K是一个平均值,推断峰值为2K/s,因为系统的用户量可能一直在增长,因此要预估一个1.5倍-2倍的QPS也就是4K/s。
    • 猜测读请求每天10次,大概预估值为460K
    • 一般都是读多写少
    • 通过集群进行优化,读写分离,复制,分片
  • 延迟 : 一般都是100ms-200ms

    • 使用缓存
    • 直接发送给服务节点本地存储
    • 使用布隆过滤器
  • 存储 :每秒请求数 请求大小 60 60 24 * 365

  • 可靠性 :可扩展性,可运维性 主从复制,冗余备份
  • 安全性 : 防止被人爬取,盗用数据 不要让别人得到规律

缓存服务器CDN

欢迎关注我的其它发布渠道