Lework Study hard, improve every day.

学习周报「2023」8月

2023-08-01
lework
本文 5302 字,阅读全文约需 16 分钟

以每周一个节点,记录知识点。

2023-08-14~18

条件型 CORS 响应下因缺失 Vary: Origin 导致的缓存错乱问题

现象:

​ 在同一个浏览器下,先打开了foo.taobao.com上的一个页面,访问了我们的资源 https://static.taobao.com/1.jpg,这个资源被浏览器缓存了下来,和资源内容一起缓存的还有Access-Control-Allow-Origin: https://foo.taobao.com响应头。这时又打开 bar.taobao.com上的一个页面,这个页面也要访问那个资源 https://static.taobao.com/1.jpg,这时它会读取本地缓存,读到的 Access-Control-Allow-Origin头是缓存下的 https://foo.taobao.com 而不是自己想要的 https://bar.taobao.com,这时就报跨域错误了,虽然它应该是能访问到这份资源的。

解决方案:

使用 Vary: Origin 让同一个 URL 有多份缓存

​ 有一个 HTTP 响应头叫Vary,vary 这个单词的意思是”变化”、”不同”的意思,Vary响应头就是让同一个 URL 根据某个请求头的不同而使用不同的缓存。比如常见的Vary: Accept-Encoding表示客户端要根据Accept-Encoding请求头的不同而使用不同的缓存,比如 gizp 的缓存一份,未压缩的缓存为另一份。

​ 在 CORS 的场景下,我们需要使用Vary: Origin来保证不同网站发起的请求使用各自的缓存。比如从foo.taobao.com发起的请求缓存下的响应头是:

Access-Control-Allow-Origin: https://foo.taobao.com
Vary: Origin

的话,bar.taobao.com在发起同 URL 的请求就不会使用这份缓存了,因为Origin请求头变了。还有<img>标签发起的非 CORS 请求缓存下的响应头是:

Vary: Origin

的话, 在使用 XHR 发起的 CORS 请求也不会使用那份缓存,因为Origin请求头从无到有,也算是变了。

Fetch 规范中专门讲了Vary: Origin在 CORS 响应中该如何使用 https://fetch.spec.whatwg.org/#cors-protocol-and-http-caches,其中第一段是:

If CORS protocol requirements are more complicated than setting Access-Control-Allow-Origin to * or a static origin, Vary is to be used.

翻译一下就是“如果你的 Access-Control-Allow-Origin响应头不是简单的写死成了*或者某一个特定的源(就是我总结的条件型 CORS 响应),那么你就应该加上Vary: Origin响应头。

云产品的缓存配置

现在很多静态今天资源都会使用云产品的CDN做缓存,所以不仅后端要配置跨域标识,CDN也要配置。

​ CDN上配置

​ 在自定义HTTP响应头页签,单击添加,根据下表中的参数含义设置自定义HTTP响应头。

Access-Control-Allow-Origin: https://*.aliyun.com,http://*.aliyun.com

Access-Control-Allow-Methods: GET,POST,PUT,DELETE,HEAD,OPTIONS

Access-Control-Allow-Headers: *

Access-Control-Allow-Credentials: true

Access-Control-Max-Age: 300

Vary: Origin

​ OSS上配置

​ 在创建跨域规则面板,将来源设置为*.aliyun.com允许Methods全部勾选,允许Headers设置为*暴露Headers设置为ETagx-oss-request-id缓存时间设置为300,选中返回Vary: Origin,然后单击确定

知识点:

无条件型 CORS 响应

​ 将Access-Control-Allow-Origin固定写死为*(允许任意网站访问)、或者特定的某一个源(只允许这一个网站访问),不论请求头里的 Origin是什么,甚至没有 Origin也一样返回那个值。

条件型 CORS 响应

​ 条件型 CORS 响应又分为两种情况:

  1. 区分对待有无 Origin请求头

​ 有Origin请求头才会返回Access-Control-Allow-Origin响应头,没有就不返回。

  1. 区分对待不同的 Origin请求头

​ 如果想允许特定的某些个网站访问自己的资源,由于Access-Control-Allow-Origin被设计为不支持返回多个源,这就需要根据 Origin请求头的值来动态的判断出要不要加 Access-Control-Allow-Origin了。

​ 比如我们想只允许 *.taobao.com 下的页面访问,当接受到的请求包含 Origin: https://foo.taobao.com时,需要返回 Access-Control-Allow-Origin: https://foo.taobao.com;当接受到的请求包含Origin: https://bar.taobao.com时,需要返回 Access-Control-Allow-Origin: https://bar.taobao.com;当接受到的请求包含 Origin: https://foo.tmall.com时,就不返回Access-Control-Allow-Origin头了。

其他知识

  • https://zhuanlan.zhihu.com/p/38972475

  • 跨源资源共享(CORS)https://developer.mozilla.org/zh-CN/docs/Web/HTTP/CORS

2023-08-14~18

k8s 监控丢点现象

问题定位

当 Prometheus 按照ServiceMonitor 设置的采集频率10s去采集cAdvisor 提供的数据时,如果在此期间 cAdvisor 没有进行数据更新,则Prometheus会采集到与上次采集时间戳和值相同的情况,Prometheus 就只会记录一条数据。这就是cAdvisor “丢点”的本质。cAdvisor的刷新频率由 housekeeping相关参数 和 抖动 机制确定。

解决方案

  1. cAdvisor 配置

    containers:// 参数设置
      - -allow_dynamic_housekeeping=false
      - -housekeeping_interval=1s
    
  2. ServiceMonitor上配置忽略指标自带时间戳

       
    spec:
      endpoints:
      - honorLabels: true
        // 忽略时间戳
        honorTimestamps: false
        interval: 10s
    

k8s 监控调优

图片

  • 【架构高可用】:集群维度的双副本 Prometheus 采集底层exporter数据,adapter多实例自动选主实现容灾。
  • 【数据持久化】:通过remoteWrite将数据存储到后端的VictoriaMetrics中进行持久化存储,Grafana使用VictoriaMetrics做为数据源展示和告警。
  • 【监控统一化】:通过remoteWrite将数据交由kafka-adapter转发到Kafka,由公司基础监控等服务通过消费Kafka中的数据来进行展示和告警。

优化项:

  1. 过滤未使用指标

     # 过滤  container_threads  开头的指标
        - action: drop
          regex: container_threads(.*)
          sourceLabels:
          - __name__
    
  2. 过滤低优先级 pod 相关指标

    # 过滤掉 monitoring namespace 下面 telegraf 这个daemosnet提供的 pod 的相关指标
        - action: drop
          regex: monitoring@telegraf(.*)
          separator: '@'
          sourceLabels:
          - namespace
          - pod
    
  3. 均衡 Prometheus 负载

    将监控 target 进行分类交由不同的组 Prometheus 采集,且每类 Prometheus 为双副本模式。

  4. 减少Prometheus存储数据时间

    监控数据的持久化存储都放在 VictoriaMetrics 上面, 故修改Prometheus采集的数据本地存储时间从7天改为2天。

vivo 容器集群监控系统优化之道 https://mp.weixin.qq.com/s/zHir-IiCEuS_4gmyKDry7Q

2023-08-01~04

k8s ipvs 出现 1s 延迟

问题定位

通过抓包分析,发现tcp 连接在连接复用时,会丢弃一个syn包,等待1s后才重新连接。

图片

ipvs 对端口的复用策略主要由内核参数 net.ipv4.vs.conn_reuse_mode 决定

其目的是:

​ 当 client ip:client port 复用发生时,对于 TIME_WAIT 状态下的 ip_vs_conn,进行重新调度,使得 connection 在 rs 上的分布更均衡,以提高性能。

​ 如果该 mode 是 0,则会复用旧 ip_vs_conn 里的 rs,使得连接更不均衡。所以当 conn_reuse_mode 为 0 表示启用 ipvs 连接复用,为 1 表示不复用.

conn_resue_mode=1 的 bug

​ 开启这个内核参数实际就表示 ipvs 转发时不做连接复用,每次新建的连接都会重新调度 rs 并新建 ip_vs_conn,但它的实现有个问题: 在新建连接时 (SYN 包),如果 client ip:client port 匹配到了 ipvs 旧连接 (TIME_WIAT 状态),且使用了 conntrack,就会丢掉第一个 SYN 包,**等待重传后 (1s) **才能成功建连,从而导致建连性能急剧下降。

conn_resue_mode=0 引发的问题

ipvs 连接复用有两个问题:

  1. 系统使用 conntrack 跟踪连接,conntrack 使用三元组(即源 IP、源端口、协议)定位具体连接,当客户端产生大量短连接时,其本身可能与之前的端口复用,而 TCP 在 conntrack 中的超时时间达 900s,也就是说 conntrack 中记录的连接可能存在很长时间,客户端过来的新连接极有可能复用老连接,此时已经 TIME_WAIT 的老连接无法响应请求,从而导致超时。只要有 client ip:client port 匹配上 ip_vs_conn (发生复用),就直接转发给对应的 rs,不管 rs 当前是什么状态,即便 rs 的 weight 为 0 (通常是 TIME_WAIT 状态) 也会转发,TIME_WAIT 的 rs 通常是 Terminating 状态已销毁的 Pod,转发过去的话连接就必然异常。
  2. 高并发下大量复用,没有为新连接没有调度 rs,直接转发到所复用连接对应的 rs 上,导致很多新连接被 “固化” 到部分 rs 上。

业务可能遇到的问题:

  1. 滚动更新连接异常。 被访问的服务滚动更新时,Pod 有新建有销毁,ipvs 发生连接复用时转发到了已销毁的 Pod 导致连接异常 (no route to host)。

  2. 滚动更新负载不均。 由于复用时不会重新调度连接,导致新连接也被 “固化” 在某些 Pod 上了。

  3. 新扩容的 Pod 接收流量少。 同样也是由于复用时不会重新调度连接,导致很多新连接被 “固化” 在扩容之前的这些 Pod 上了。

v5.9 以上的内核已修复上述 bug https://github.com/kubernetes/kubernetes/issues/93297

内核两个Patch

• ipvs: allow connection reuse for unconfirmed conntrack

​ 修改了ip_vs_conn_uses_conntrack()方法的逻辑,当使用unconfirmed conntrack时,返回false,这种修改针对了TIME_WAIT的conntrack。

• ipvs: queue delayed work to expire no destination connections if expire_nodest_conn=1

​ 提前了expire connection的操作,在destination被删除后,便开始将expire connection操作入队列。而不是等到数据包真正发过来时,才做expire connection,以此来减少数据包的丢失。

解决方案

通过升级系统和内核来根本解决此问题。此系统内核值情况

net.ipv4.vs.conn_reuse_mode = 1
net.ipv4.vs.conntrack = 1
net.ipv4.vs.expire_nodest_conn = 1
原文地址 https://lework.github.io/2023/08/01/journal/

Similar Posts

Comments