凉山网站建设杭州模板网站建设系统

当前位置: 首页 > news >正文

凉山网站建设,杭州模板网站建设系统,网站建设与推广方式,建设网站的情况说明作者信息#xff1a; 唐聪、王超凡#xff0c;腾讯云原生产品中心技术专家#xff0c;负责腾讯云大规模 TKE 集群和 etcd 控制面稳定性、性能和成本优化工作。 王子勇#xff0c;腾讯云专家级工程师#xff0c; 腾讯云计算产品技术服务专家团队负责人。 概况 作为当前中国… 作者信息 唐聪、王超凡腾讯云原生产品中心技术专家负责腾讯云大规模 TKE 集群和 etcd 控制面稳定性、性能和成本优化工作。 王子勇腾讯云专家级工程师 腾讯云计算产品技术服务专家团队负责人。 概况 作为当前中国广泛使用的云视频会议产品腾讯会议已服务超过 3 亿用户能高并发支撑千万级用户同时开会。腾讯会议数百万核心服务都部署在腾讯云 TKE 上通过全球多地域多集群部署实现高可用容灾。在去年用户使用最高峰期间为了支撑更大规模的并发在线会议的人数腾讯会议与 TKE 等各团队进行了一轮新的扩容。 然而在这过程中一个简单的 etcd 进程重启操作却触发了一个的诡异的 K8s 故障不影响用户开会影响新一轮后台扩容效率本文介绍了我们是如何从问题现象、到问题分析、大胆猜测排除、再次复现、严谨验证、根治隐患的从 Kubernetes 到 etcd 底层原理从 TCP RFC 草案再到内核 TCP/IP 协议栈实现一步步定位并解决问题的详细流程最终定位到是特殊场景触发了内核 Bug。 希望通过本文让大家对 etcd、Kubernetes 和内核的复杂问题定位有一个较为深入的了解掌握相关方法论同时也能让大家更好的了解和使用好 TKE通过分享我们的故障处理过程提升我们的透明度。 背景知识 首先给大家简要介绍下腾讯会议的简要架构图和其使用的核心产品 TKE Serverless 架构图。 腾讯会议极简架构图如下: 腾讯会议重度使用的 TKE Serverless 架构如下: 腾讯会议几乎全部业务都跑在 TKE Serverless 产品上Master 组件部署在我们metacluster 中K8s in K8s)超大集群可能有10多个 APIServeretcd 由服务化的 etcd 平台提供APIServer 访问 etcd 链路为 svc - cluster-ip - etcd endpoint。业务各个 Pod 独占一个轻量级的虚拟机安全性、隔离性高业务无需关心任何 Kubernetes Master、Node 问题只需要专注业务领域的开发即可。 问题现象 在一次资源扩容的过程中腾讯会议的研发同学晚上突然在群里反馈他们上海一个最大集群出现了业务扩容失败收到反馈后研发同学第一时间查看后还看到了如下异常: ● 部分 Pod 无法创建、销毁 ● 某类资源 Get、list 都是超时 ● 个别组件出现了 Leader Election 错误 ● 大部分组件正常少部分控制器组件有如下 list pvc 资源超时日志 k8s.io/client-go/informers/factory.go:134: Failed to watch *v1.PersistentVolumeClaim: failed to list *v1.PersistentVolumeClaim: the server was unable to return a response in the time allotted, but may still be processing the request (get persistentvolumeclaims) 然而 APIServer 负载并不高当时一线研发同学快速给出了一个控制面出现未知异常的结论。随后 TKE 团队快速进入攻艰模式开始深入分析故障原因。 问题分析 研发团队首先查看了此集群相关变更记录发现此集群在几个小时之前进行了重启 etcd 操作。变更原因是此集群规模很大在之前的多次扩容后db size 使用率已经接近 80%为了避免 etcd db 在业务新一轮扩容过程中被写满因此系统进行了一个经过审批流程后的一个常规的调大 etcd db quota 操作并且变更后系统自检 etcd 核心指标正常。 我们首先分析了 etcd 的接口延时、带宽、watch 监控等指标如下图所示 etcd P99 延时毛刺也就 500ms节点带宽最大的是平均 100MB/s 左右初步看并未发现任何异常。 随后又回到 APIServer一个在请求在 APIServer 内部经历的各个核心阶段(如下图所示): ● 鉴权 校验用户 token、证书是否正确 ● 审计 ● 授权 检查是否用户是否有权限访问对应资源 ● 限速模块 1.20 后是优先级及公平管理 ● mutating webhook ● validating webhook ● storage/cache ● storage/etcd 请求在发往 APIServer 前client 可能导致请求慢的原因: ● client-go 限速client-go 默认 qps 5, 如果触发限速则日志级别 4 以上高版本 client-go 日志级别 3 以上可以看到客户端日志中有打印 Throttling request took 相关日志 那到底是哪个阶段出现了问题导致 list pvc 接口超时呢 ● 根据 client QPS 很高、并且通过 kubectl 连接异常实例也能复现排除了 client-go 限速和 client 到 apiserver 网络连接问题 ● 通过审计日志搜索到不少 PVC 资源的 Get 和 list 5XX 错误聚集在其中一个实例 ● 通过 APIServer Metrics 视图和 trace 日志排除 webhook 导致的超时等 ● 基于 APIServer 访问 etcd 的 Metrics、Trace 日志确定了是 storage/etcd 模块耗时很长但是只有一个 APIServer 实例、某类资源有问题 那为什么 etcd 侧看到的监控延时很低而 APIServer 访问 etcd 延时很高而且只是某类资源出现问题不是所有资源呢 首先我们查看下 APIServer 的 etcd 延时统计上报代码 (以 Get 接口为例) 它统计的是整个 Get 请求(实际调用的是 etcd Range 接口)从 client 发出到收到结果的耗时包括了整个网络链路和 etcd RPC 逻辑处理耗时。 而 etcd 的 P99 Range 延时是基于 gRPC 拦截器机制实现的etcd 在启动 gRPC Server 的时候会注册一个一元拦截器实现延时统计在 RPC 请求入口和执行 RPC 逻辑完成时上报延时也就是它并不包括 RPC 请求在数据接收和发送过程中的耗时相关逻辑封装在 monitor 函数中简要逻辑如下所示: 最后一个疑问为什么是某类资源出现问题? APIServer 在启动的时候会根据 Kubernetes 中的每个资源和版本创建一个独立etcd client并根据配置决定是否开启 watch cache每个 client 一般 1 个 TCP 连接一个 APIServer 实例会高达上百个 etcd 连接。etcd client 与 etcd server 通信使用的是 gRPC 协议而 gRPC 协议又是基于 HTTP/2 协议的。 PVC 资源超时Pod、Node 等资源没超时这说明是 PVC 资源对应的底层 TCP 连接/应用层 HTTP/2 连接出了问题。 在 HTTP/2 协议中消息被分解独立的帧Frame交错发送帧是最小的数据单位。每个帧会标识属于哪个流Stream流由多个数据帧组成每个流拥有一个唯一的 ID一个数据流对应一个请求或响应包。如上图所示client 正在向 server 发送数据流 5 的帧同时 server 也正在向 client 发送数据流 1 和数据流 3 的一系列帧。一个连接上有并行的三个数据流HTTP/2 可基于帧的流 ID 将并行、交错发送的帧重新组装成完整的消息。 也就是通过 HTTP/2 的多路复用机制一个 etcd HTTP/2 连接可以满足高并发情况下各种 client 对 PVC 资源的查询、创建、删除、更新、Watch 请求。 那到底是这个连接出了什么问题呢 明确是 APIServer 和 etcd 的网络链路出现了异常之后我们又有了如下猜测 ● 异常实例 APIServer 所在节点出现异常 ● etcd 集群 3 个节点底层网络异常 ● etcd HTTP/2 连接最大并发流限制 单 HTTP/2 连接最大同时打开的并发流是有限制的 ● TCP 连接触发了内核未知 bug连接疑似 hang 住一样 ● ….. 然而我们对 APIServer 和 etcd 节点进行了详细的系统诊断、网络诊断除了发现 etcd 节点出现了少量毛刺丢包并未发现其他明显问题当前 etcd 节点也仅使用了 13 的节点带宽但是请求依然巨慢因此基本可以排除带宽超限导致的请求超时。 etcd HTTP/2 连接最大并发流限制的特点是此类资源含有较大的并发请求数、同时应有部分成功率不应全部超时。然而通过我们一番深入排查通过审计日志、Metrics 监控发现 PVC 资源的请求绝大部分都是 5XX 超时错误几乎没有成功的同时我们发现了一个 CR 资源也出现了连接异常但是它的并发请求数很少。基于以上分析etcd HTTP/2 连接最大并发流限制猜测也被排除。 问题再次陷入未知此刻就要寄出终极杀器——抓包大法来分析到底整个 TCP 连接链路发生了什么。 要通过抓包来分析具体请求首先我们就要面临一个问题当前单个 APIServer 到 etcd 同时存在上百个连接我们该如何缩小范围定位到具体异常的 TCP 连接呢要定位到具体的异常连接主要会面临以下几个问题 数据量大APIServer 大部分连接都会不停的向 etcd 请求数据而且部分请求的数据量比较大如果抓全量的包分析起来会比较困难。新建连接无法复现该问题只影响个别的资源请求也就是只影响存量的几个长链接增量连接无法复现。APIServer 和 etcd 之间使用 https 通信解密困难无法有效分析包的内容由于长链接已经建立已经过了 tls 握手阶段同时节点安全管控限制短时间不允许使用 ebpf 等 hook 机制因此无法拿到解密后的内容。 为了定位到具体的异常连接我们做了以下几个尝试 首先针对响应慢的资源不经过 Loadbalancer直接请求 APIServer 对应的 RS将范围缩小到具体某一个 APIServer 副本上针对异常的 APIServer 副本先将它从 Loadbalancer 的后端摘掉一方面可以尽快恢复业务另一方面也可以避免有新的流量进来可以降低抓包数据量PS摘掉 RS 的同时Loadbalancer 支持发双向 RST可以将客户端和 APIServer 之间的长链接也断掉。对异常的 APIServer 副本进行抓包抓取 APIServer 请求 etcd 的流量同时通过脚本对该异常的 APIServer 发起并发查询只查询响应慢的资源然后对抓包数据进行分析同一时间点 APIServer 对 etcd 有大量并发请求的长连接即为异常连接。 定位到异常连接后接下来就是分析该连接具体为什么异常通过分析我们发现 etcd 回给 APIServer 的包都很小每个 TCP 包都是 100 字节以下 通过 ss 命令查看连接的 TCP 参数发现 MSS 居然只有 48 个字节 这里简单介绍下 TCP MSS(maximum segment size)参数, 中文名最大分段大小单位是字节它限制每次网络传输的数据包的大小一个请求由多个数据包组成MSS 不包括 TCP 和 IP 协议包头部分。TCP 中还有一个跟包大小的参数是 MTU(maximum transmission unit)中文名是最大传输单位它是互联网设备路由器等可以接收的最大数据包的值它包括 TCP 和 IP 包头以及 MSS。 受限于 MTU 值大小最大1500MTU 减去 TCP 和 IP 包头云底层网络转发所使用的协议包头MSS 一般在1400左右。然而在我们这里如下图所示对 ss 统计分析可以看到有 10 几个连接 MSS 只有 48 和 58。任意一个请求尤其是查询类的都会导致请求被拆分成大量小包发送应用层必定会出现各类超时错误client 进而又会触发各种重试最终整个连接出现完全不可用。 在确定是 MSS 值过小导致上层各种诡异超时现象之后我们进一步思考是什么地方改掉了 MSS。然而 MSS 协商是在三次握手中建立的存量的异常连接比较难找到相关信息。 内核分析过程 抓包分析 为了进一步搞清楚问题发生的根本原因我们在风险可控的情况下在业务低峰期凌晨1点主动又做了一次相似的变更来尝试复现问题。从抓到的包看 TCP 的选项发现 MSS 协商的都是比较大没有特别小的情况 仅 SYN SYNack 包带有 MSS 选项并且值都大于 1000 排除底层网络设备篡改了 MSS 造成的问题。 内核分析 那内核当中什么地方会修改 MSS 的值 假设一开始不了解内核代码但是我们能知道这个 MSS 字段是通过 ss 命令输出的那么可以从 ss 命令代码入手。该命令来自于 iproute2 这个包搜索下 MSS 关键词 可知在 ss 程序中通过内核提供的 sock_diag netlink 接口 查询到的信息。在tcp_show_info函数中做解析展示 可知 MSS 字段来自内核的 tcpi_snd_mss。 之后从内核里面查找该值赋值的地方 2 2749 net/ipv4/tcp.c tcp_get_infoinfo-tcpi_snd_mss tp-mss_cache; 继续找mss_cache的赋值位置 只有2处第一处是tcp_init_sock中调用当中的赋值是初始值tcp_mss_DEFAULT 536U, 与抓到的现场不匹配直接可忽略。 第二处 这里面可能 2 个地方会影响一个是pmtu, 另外一个是 tcp_bound_to_half_wnd.
抓包里面没明显看到 MTU 异常造成的流异常反馈信息。聚焦在窗口部分 这里有个很可疑的地方。若是窗口很小那么最后会取窗口与68字节 -tcp_header_len 的最大值tcp_header_len 默认 20 字节的话刚好是 48 字节。和咱们抓包看到的最小的 MSS 为 48 一致 嫌疑很大。 那什么地方会修改最大窗口大小 TCP 修改的地方并不多tcp_rcv_synsent_state_process中收到 SYN 包修改(状态不符合我们当前的 case另外主要的是在tcp_ack_update_window函数中收 ack 之后去更新 分析收到的 ack 包我们能发现对方通告的窗口, 除了 SYN 之外都是29字节 SYN 包里面能看到放大因子是 按理说计算出来的窗口按照 if (likely(!tcp_hdr(skb)-syn))nwin tp-rx_opt.snd_wscale; 计算应该是14848字节但是从 MSS 的体现看似乎这个 scale 丢失了。实际上对比正常和异常的连接发现确实 TCP 的 scale 选项在内核里面真的丢了 从 ss 里面对比正常和异常的连接看不仅仅是 window scale 没了连 timestamp, sack 选项也同时消失了很神奇 我们来看看 ss 里面获取的这些字段对应到内核的什么值 ss 代码 对应到内核 tcp_get_info 函数的信息 那内核什么地方会清空 window scale 选项 搜索把 wscale_ok 改为 0 的地方实际上并不多我们可以比较轻易确定是 tcp_clear_options 函数干的 static inline void tcp_clear_options(struct tcp_options_received *rx_opt) {rx_opt-tstamp_ok rx_opt-sack_ok 0;rx_opt-wscale_ok rx_opt-snd_wscale 0; } 他同时会清空 ts, sack, scale 选项 和我们的场景再匹配不过。 搜索 tcp_clear_options 的调用方主要在tcp_v4_conn_request和cookie_check_timestamp 两个地方具体调用位置的逻辑都和 SYN cookie 特性有较强关联性。 if (want_cookie !tmp_opt.saw_tstamp)tcp_clear_options(tmp_opt); bool cookie_check_timestamp(struct tcp_options_received *tcp_opt,struct net *net, bool ecn_ok) {/ echoed timestamp, lowest bits contain options */u32 options tcp_opt-rcv_tsecr TSMASK;if (!tcp_opt-saw_tstamp) {tcp_clear_options(tcp_opt);return true;} 两个条件都比较一致看起来是 SYN cookie 生效的情况下对方没有传递 timestamp 选项过来实际上按照 SYN cookie 的原理发送给对端的回包中会保存有编码进 tsval 字段低 6 位的选项信息就会调用 tcp_clear_options 清空窗口放大因子等选项。 从系统日志里面我们也能观察到确实触发了 SYN cookie 逻辑 所以根因终于开始明确etcd 重启触发了大量 APIServer 瞬间到 etcd 的新建连接短时间的大量新建连接触发了 SYN cookie 保护检查逻辑。但是因为客户端没有在后续包中将 timestamp 选项传过来造成了窗口放大因子丢失影响传输性能 客户端为什么不在每一个包都发送 timestamp而是只在第一个 SYN 包发送 首先我们来看看 RFC 规范协商了 TCP timestamp 选项后是应该选择性的发还是每一个都发 答案是后续每一个包 TCP 包都需要带上时间戳选项。 那么我们的内核中为什么 SYN 包带了 TCP timestamp 选项但是后续的包没有了呢 搜索 tsval 关键词 可以看到 tcp_syn_options 函数中主动建连时候会根据 sysctl_tcp_timestmps 配置选项决定是否开启时间戳选项。 查看客户端系统该选项确实是打开的符合预期 net.ipv4.tcp_timestamps 1 那为什么别的包都不带了呢客户端角度发了 SYN带上时间戳选项收到服务端 SYNack 以及时间戳走到 tcp_rcv_synsent_state_process 函数中调用 tcp_parse_options 解析 TCP 选项 这里就算服务端回包带了 TCP 时间戳选项本机也要看两个 sysctl ● sysctl_tcp_timestamps 这个比较好理解。内核标准的。 ● sysctl_tcp_wan_timestamps 这个看起来是针对外网打开时间戳的选项很诡异。 此处就会有坑了如果 wan_timestamps 选项没打开saw_tstamp 不会设置为1 后续也就不会再发送 TCP 时间戳选项。 查看 wan_timestamps 设置确实默认是关闭的 net.ipv4.tcp_wan_timestamps 0 所以这里真相也就明确了因为 tcp_timestamps 选项打开所以内核建连是会发送时间戳选项协商同时因为 tcp_wan_timestamps 关闭在使用非私有网段的情况下会造成后续的包不带时间戳云环境容器管控特殊网段的原因。 和 SYN cookie 的场景组合在一起最终造成了 MSS 很小性能较差的问题。 tcp_wan_timestamps 是内部的特性是为了解决外网时间戳不正确而加的特性TKE 团队发现该问题后已反馈给相关团队优化当前已经优化完成。 总结 本文问题表象APIServer 资源请求慢看似比较简单实则在通过 APIServer Metrics 指标、etcd Metrics 指标、APIServer 和 etcd Trace 日志、审计日志、APIServer 和 etcd 源码深入分析后排除了各种可疑原因最后发现是一个非常底层的网络问题。 面对底层网络问题在找到稳定复现的方法后我们通过抓包神器 tcpdump丰富强大的网络工具 iproute2 包iproute2 包中的 ss 命令能够获取 TCP 的很多底层信息比如 rtt窗口因子重传次数等对诊断问题很有帮助再结合TCP RFC、linux 源码代码面前无秘密不管是用户态工具还是内核态多团队的协作成功破案。 通过此案例更让我们深刻体会到永远要对现网生产环境保持敬畏之心任何操作都可能会引发不可预知的风险监控系统不仅要检测变更服务核心指标更要对主调方的核心指标进行深入检测。 参与本文问题定位的还有腾讯云网络专家赵奇园、内核专家杨玉玺。 【腾讯云原生】云说新品、云研新术、云游新活、云赏资讯扫码关注同名公众号及时获取更多干货