写点什么

大流量时代,如何规划系统流量提升可靠性

  • 2023-04-28
    广东
  • 本文字数:3649 字

    阅读完需:约 12 分钟

大流量时代,如何规划系统流量提升可靠性

本文分享自华为云社区《大流量时代,如何规划系统流量提升可靠性》,作者:breakDawn 。

透明多级分流系统


对系统流量进行规划, 要注意以下 2 个原则


  1. 尽可能减少单点部件, 或者减少到达单点部件的流量或者作用

  2. 奥卡姆剃刀原则,确定有再有必要的时候才去使用,避免过度设计

1 客户端缓存


即对于某些资源, 在客户端就做缓存,客户端不去重复请求。


1.1 强制缓存


类似 HTTP 协议里在 header 里用到的两种标签,且都是服务端强行控制的,基于时间的

Expires


服务端直接返回数据不会变动的截止时间。


缺点:受限于客户端本地时间、无法表示不缓存除非强制改时间戳、无法表示是否是私有资源(避免私有资源被其他节点缓存)


Cache-Control


这个请求头使用 max-age、private、no-cache 等标签解决了 Expires 里的 3 个缺点。


1.2 协商缓存


协商缓存需要考虑是否真的发生变化。 协商和强制可以共同存在,即强制失效的时候就可以用上协商。

协商缓存不仅存在于地址输入、跳转,也存在 F5 中(但如果 Ctrl+F5 强制刷新则会让缓存失效)


Last-Modified


告诉客户端资源的最后修改时间, 客户端再次请求时也会对这个时间做修改


如果服务端发现在那个时间之后资源未变动,返回 304 Not Modified


如果有变动,就返回 OK,并携带完整的资源


ETag


需要对资源计算哈希值,客户端发请求也会带上自己存的 ETag,每次会比对资源的哈希值是否一致,不一致则返回新资源。


Etag 是一致性最强的本地缓存机制,但也是性能最差的。

2 传输通道优化


本章节大部分以熟知的 HTTP 协议作为主要传输通道协议,讲解如何进行优化


2.1 连接数优化


HTTP 是基于 TCP 的,每次都是重新建立一个 TCP 连接。 因此前端开发人员开发了很多小优化,来减少请求次数,例如雪碧图、分段文档、合并 Ajax 请求之类的。


HTTP1.0 里的长连接(keep-alive 连接复用)为什么不能解决这个问题?


因为存在队首阻塞问题,本质上是基于 FIFO 复用连接, 1 个请求卡住了,后面 9 个请求都阻塞住了,但如果同时支持返回,在顺序混乱的情况下无法正常处理


HTTP2.0 的多路复用解决了这个问题


  • 以帧作为最小粒度单位,每个帧都携带流 ID 识别是哪个流

  • 客户端可以很容易在不同流中重组 HTTP 请求和响应报文


2.2 传输压缩


HTTP 很早就支持 GZip 压缩来减少大资源的传输量


HTTP1.0 中, 持久连接和传输压缩无法一起使用, 因为压缩后无法识别资源是否传输完毕。


HTTP1.1 中引入了“分块传输编码”,来进行资源结束的判断。


2.3 用 UDP 来加快网络传输


HTTP/3 中,希望能替换掉 HTTP on TCP 的依赖、谷歌推出了快速 UDP 网络连接, 即 QUIC


  • QUIC 以 UDP 为基础, 可靠传输能力由自己实现

  • QUIC 专门面向移动设备支持, 移动设备的 ip 地址经常会切换,使用 ip 作为定位不合适, 因此提出了连接标识符来保持连接。

  • 对于不支持 QUIC 的情况,支持回退为 TCP 连接,实现兼容

3 内容分发网络 CDN


CND 可以解决 互联网系统跨运营商、跨地域物理距离所导致的时延问题,为网站流量带宽起到分流、减负的作用。


主要包含以下 4 个工作部分


3.1 路由解析


用户的静态资源请求访问 CDN 是通过 DNS 解析来完成的,甚至可能一个网站会有各种不同地域的 CDN 域名解析地址返回, 通过你的路由配置会自动选择符合地域的 ip 地址


3.2 内容分发


如何分发内容有两种方式:


  1. 主动分发, 通过 CND 服务商提供的接口主动推送自己的资源,这样你需要额外编写资源推动的代码。大型活动例如双 11 会优先考虑主动分发预先准备资源。

  2. 被动回源, 由用户访问触发,当发现没有资源时,CDN 会去源站请求并返回,则用你不需要新写相关代码,只要在 CDN 那边支持回源你的源站即可。小型站点基本都是用这个方法。


如何更新资源有两种方式:


  1. 超时被动失效,CDN 的资源都有有效期,超时了就回源获取

  2. 手工主动失效, CDN 服务商提供缓存失效接口,主动触发失效并进行被动回源更新。


现在一般是 1 和 2 结合使用,二者不冲突

4 负载均衡


负载均衡有两种大类


  • 四层负载均衡


指的是计算机七层模型中四层及以下的均衡策略结合


即 数据链路层 + 网络层 均可做均衡


  • 七层负载均衡


指的是在应用层通过实际代码做均衡


4.1 数据链路层负载均衡(四层负载均衡)


  • 通过链路层上的均衡器替换 MAC 地址,进行链路层的均衡

  • 各负载节点的 IP 是一样的(相同的虚拟 IP)

  • 返回时无需经过均衡器,直接返回即可(因为目标 ip、源 ip 基本没变)


缺点:


必须是同一个子网内,无法跨 VLAN,只能作为最接近数据中心的均衡器


4.2 网络层负载均衡(四层负载均衡)


有两种方式:


IP 隧道模式


均衡器在 IP 报文外面包了一层新的 header,header 里指定了目标机器的实际 ip 或者小网 ip。 接收机器要支持解 header,且同样要求作为返回的虚拟 ip 是一致的,也是直接返回无需经过均衡器。


缺点:


  1. 用到的服务器都要支持隧道解包能力(linux 系统现在都支持)

  2. 虚拟 ip 仍然有较大限制,需要人工介入管理众多机器


NAT 模式


NAT 模式中,就是进行真正的 ip 转换, 且返回时也要返回给 NAT 进行 ip 转换,这样只需要针对 NAT 进行人工管理即可。


缺点在于 NAT 容易成功性能瓶颈


SNAT 会修改源 IP 改为 NAT 的 ip, 可以做到对业务真正透明, 但是代价是如果需要对源 IP 做限制时容易有问题, 因为所有的来源 ip 都是一样的了。


4.3 应用层负载均衡(七层负载均衡)


也叫做七层代理(应用层代理),因为这个负载均衡属于反向代理(即部署在服务端的代理,对客户端不感知)


不适合做下载站、视频站等流量应用


如果瓶颈在服务计算能力,则可以考虑做应用层均衡期


七层代理除负载均衡外的其他功能:


  • 支持做 CDN 类似的缓存能力

  • 施行智能化路由,根据 URL 或者特定用户做特殊服务

  • 抵御安全工具,提前过滤攻击报文

  • 链路治理


4.4 负载均衡策略


轮询均衡


轮流分配,从 1 到 N 再到 1


适用于所有服务器硬件配置完全相同,服务请求需要相对均衡


权重轮询


根据服务器权重分配周期内的轮询次数


随机均衡


适用于数据量足够大的相对均衡分布


权重随机均衡


提升权重高的随机率


一致性哈希均衡


适用于服务器经常可能掉线或者加入,可以避免哈希键全部更新的情况


响应速度均衡


定期探测各个服务器的响应速度,根据速度分配权重


最少连接数均衡


根据连接数分配权重, 适用于长时处理服务例如 FTP 等


软件均衡器包括基于操作系统内核的 LVS、 基于应用程序的 Nginx、KeepAlive、HAProxy


硬件均衡器包括 F5、A10 等公司提供的硬件负载均衡产品

5 服务端缓存


引入缓存的理由:


  • 减缓 CPU 计算压力

  • 缓存 IO 压力


这 2 个缓解只是能峰值时的压力缓解,如果普通的响应都很慢,那就算用了缓存也意义不大。


5.1 缓存的几个属性


缓存需要选型,选型时需要根据实际场景选择你匹配的缓存熟悉


吞吐量


JDK8 改进后的 ConcurrentHashMap 是并发场景下吞吐量最高的缓存容器,但除了吞吐量其他的能力就很弱了。


缓存状态更新思路:


  • GuavaCache: 同步处理机制,在访问数据时一并更新,分段加锁减少竞争

  • Caffeine:异步日志提交机制,参考数据库日志,并且还有环形缓冲区容忍有损失的状态变更,读性能非常快, 使用多读少写的情况。


命中率和淘汰策略


基础的三种淘汰方案:


  • FIFO:先进先出,简单实现,但对于高频访问的缓存命中率低,越常用到越可能先进入队列

  • LRU:优先淘汰最久未被访问,基于时间, 用 HashMap+链表 List 实现,但每个缓存都要记录时间,且可能淘汰短期内正好没访问且价值高的数据

  • LFU:优先淘汰最不频繁使用,基于使用次数,可以解决 LRU 的缺点。


自身缺点:


  1. 每个缓存专门维护要更新次数的计数器,维护开销大还有加锁问题(LRU 的更新时间不需要考虑加锁,直接覆盖最新即可)

  2. 如果某个缓存某时期访问很高,比其他缓存高了一个数量级,后面不再使用,想淘汰很困难

为了解决上面 2 个缺点,有 2 个新的策略:


  • TinyLFU: 解决修改计数器的开销问题, 采用 Sketch 分析访问数据,用少量数据估计全体数据特征,采用滑动时间窗、热度衰减等处理

  • W-Tinfy-LFU: 结合了 LRU+LFU 的特点, 考虑热度和时间。


分布式能力


分布式缓存介绍了复制式缓存 JbossCache 以及集中式缓存 Memcached。


jbosscache 的缺点在于写入性能太差,容易因为网络同步速度跟不上写入速度,导致内存中积累过多待发对象引发 omm


memcached 是 C 语言实现的,好处在于读写性能高,缺点在于数据结构太过紧密,非常依赖序列化做跨语言传输,如果 100 个字段中的 1 个字段发生更新,要把 100 个字段都发出去更新


redis 基本打败了各种分布式缓存,成为首选。


对于 redis 等分布式缓存, 是不会追求一致性 C 的


如果一定要一致性 C, 那应该选用 zk 或者 etcd 等分布式协调框架(但他们一般就不会拿来做缓存,因为高并发下吞吐量太低,没有可用性)


进程内缓存和分布式缓存通常结合使用,但容易出现二者数据不一致,写维护策略导致缓存对开发者而言不透明。


一种设置原则是 变更以分布式缓存中的数据为主,访问以进程内缓存的数据优先。


大致做法是数据发生变动时, 在分布式缓存内推送通知, 让一级缓存失效。


访问缓存时,提供封装好的一二级联合查询接口, 让开发者对一二级缓存不感知。


5.2 缓存风险


缓存穿透


大量不存在的缓存打进来


要么是支持对不存在的数据缓存空值


要么是引入布隆过滤器


缓存击穿


同一时间瞬间涌现很多请求,访问数据库有但是缓存里没有的数据,此时可能直接打穿数据库(缓存生效是有延迟的)


可以是用锁、队列来完成同步


对于热点缓存,提前预处理或者配置策略


点击关注,第一时间了解华为云新鲜技术~

发布于: 刚刚阅读数: 2
用户头像

提供全面深入的云计算技术干货 2020-07-14 加入

生于云,长于云,让开发者成为决定性力量

评论

发布
暂无评论
大流量时代,如何规划系统流量提升可靠性_后端_华为云开发者联盟_InfoQ写作社区