一次因网络引起的诡异 GC 问题,DBA 该怎么做?

阅读数:951 2019 年 11 月 7 日 08:00

一次因网络引起的诡异GC问题,DBA该怎么做?

本文由 dbaplus 社群授权转载。

我们在日常工作中,就像西天取经的僧人,总是会遇到各式各样的“妖怪”。这些“妖怪”总是一个又一个的阻挡在我们面前,你必须想办法击败它们。

听说小 A 同学最近遇到了一个很妖的问题,就这个问题我们来采访一下小 A 同学。

小 B:你觉得 RAC GC 问题一般在什么情况下会产生?

小 A:这个问题嘛其实很简单,我们要先从 Oracle RAC 的机制说起,RAC 是一种共享磁盘的体系结构,多个服务器上的实例会同时打开数据库,并缓存磁盘中的数据。而当在一个节点上执行 SQL,需要请求的 buffer 在 remote 实例上时,就会使用心跳进行传输。此时在本地节点上可能就会观察到 GC 类的等待事件。一般大量 GC 问题都是应用交叉访问引起的。

小 B:那这一次的 GC 问题是应用交叉访问导致的吗?

小 A:这次并不是,因为很多时候我们观察到系统权限类的 SQL 语句也在等待大规模的 gc buffer busy acquire。

小 B:系统语句?

小 A:对,就是下面这个语句,他也产生了很多的 GC。

复制代码
select event,p1,p2,p3 from v$session where sql_id='05uqdabhzncdc'
EVENT P1 P2 P3
---------------------------------------------------------------- ---------- ---------- ----------
gc buffer busy acquire 1 46842 1
gc buffer busy acquire 1 46842 1
gc buffer busy acquire 1 46842 1
gc buffer busy acquire 1 46842 1
gc buffer busy acquire 1 46842 1
gc buffer busy acquire 1 46842 1
gc cr request 1 46842 1
gc buffer busy acquire 1 46842 1
PLAN_TABLE_OUTPUT
------------------------------------------------------------------------------------------------------------------------------------------------------
SQL_ID 05uqdabhzncdc, child number 1
-------------------------------------
select role# from defrole$ d,user$ u where d.user#=:1 and
u.user#=d.user# and u.defrole=2 union select privilege# from sysauth$
s,user$ u where (grantee#=:1 or grantee#=1) and privilege#>0 and not
exists (select null from defrole$ where user#=:1 and
role#=s.privilege#) and u.user#=:1 and u.defrole=3
Plan hash value: 552533229
--------------------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
--------------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | | | 7 (100)| |
| 1 | SORT UNIQUE | | 2 | 30 | 7 (29)| 00:00:01 |
| 2 | UNION-ALL | | | | | |
| 3 | NESTED LOOPS | | 1 | 14 | 2 (0)| 00:00:01 |
|* 4 | TABLE ACCESS CLUSTER| USER$ | 1 | 7 | 1 (0)| 00:00:01 |
|* 5 | INDEX UNIQUE SCAN | I_USER# | 1 | | 1 (0)| 00:00:01 |
|* 6 | INDEX RANGE SCAN | I_DEFROLE1 | 1 | 7 | 1 (0)| 00:00:01 |
| 7 | NESTED LOOPS | | 1 | 16 | 2 (0)| 00:00:01 |
|* 8 | TABLE ACCESS CLUSTER| USER$ | 1 | 7 | 1 (0)| 00:00:01 |
|* 9 | INDEX UNIQUE SCAN | I_USER# | 1 | | 1 (0)| 00:00:01 |
| 10 | INLIST ITERATOR | | | | | |
|* 11 | INDEX RANGE SCAN | I_SYSAUTH1 | 1 | 9 | 1 (0)| 00:00:01 |
|* 12 | INDEX UNIQUE SCAN | I_DEFROLE1 | 1 | 7 | 1 (0)| 00:00:01 |
--------------------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
4 - filter("U"."DEFROLE"=2)
5 - access("U"."USER#"=:1)
6 - access("D"."USER#"=:1)
8 - filter("U"."DEFROLE"=3)
9 - access("U"."USER#"=:1)
11 - access((("GRANTEE#"=:1 OR "GRANTEE#"=1)) AND "PRIVILEGE#">0)
filter( IS NULL)
12 - access("USER#"=:1 AND "ROLE#"=:B1)

小 B:这个语句感觉没什么问题啊,这是查数据字典权限的,执行计划很好,关键表走的 UNIQUE SCAN,应该很快就返回结果的。

小 A:是的,正常情况都是秒出结果的,并不会产生 GC 等待。但是我们这个有点小异常,经常看到 100-200 个 GC 等待事件。

小 B:那究竟是什么问题呢?

小 A:我们先来看 AWR 报告吧,从 11.2.0.4 我们就可以通过来 Interconnect Ping Latency Stats 查看网络延迟类的问题了。

一次因网络引起的诡异GC问题,DBA该怎么做?

你注意看,这是 2 节点的 AWR 报告。报告里 ping 1 和 ping 3 节点的延迟非常的高。这里分别是做了 500 字节和 8KB 的 ping,平均延迟都是 30 几 ms 和 10 几 ms。我们在看 oswatch,从节点 1 到节点 2 的 traceroute 可以看到正常时间点是 0.1ms,慢的时候足足 5ms。

复制代码
<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<sid1_prvtnet_19.09.06.1000.dat
zzz ***Fri Sep 6 10:00:10 CST 2019
traceroute to 192.168.187.129 (192.168.187.129), 30 hops max, 60 byte packets
1 sid1-priv (192.168.187.129) 0.126 ms 0.103 ms 0.100 ms
traceroute to 192.168.187.130 (192.168.187.130), 30 hops max, 60 byte packets
1 sid2-priv (192.168.187.130) 5.015 ms 5.096 ms 5.074 ms <<<<<<<<<<<<<<<<<<<<<<<<<<<
traceroute to 192.168.187.131 (192.168.187.131), 30 hops max, 60 byte packets
1 sid3-priv (192.168.187.131) 1.286 ms 1.176 ms 1.156 ms
zzz ***Fri Sep 6 10:00:41 CST 2019
traceroute to 192.168.187.129 (192.168.187.129), 30 hops max, 60 byte packets

小 B:嗯,这么看来,是网络问题啊,网络延迟这么高,GC 高那应该是理所当然的!

小 A:错了,表面看是网络延迟问题,但是经过我们的验证发现,把数据库停下来之后,网络延迟就消失了。当没有业务运行的时候,延迟都在 0.00 几,这说明是业务的压力上来导致的延迟。

一次因网络引起的诡异GC问题,DBA该怎么做?

这里 bond0 是双网卡绑定的私网的地址。rxkb/s 是每秒收包的数量,而 txkb/s 是每秒发包的数量。这里数据库运行的时候每秒收发都上 100MB/S 了。

小 B:那这个问题,怎么处理的?

小 A:这个问题说实话是比较妖的,按照道理说这个网卡是万兆网卡,不至于 100MB/S 就处理不过来了,我们开始怀疑肯定是硬件之类的问题,或者是网络配置的问题,于是我们首先和其他数据库主机做了对比,就发现这个网卡的绑定模式和其他数据库不太一样。这个网卡的绑定模式是 4。

说到网卡绑定模式,主要有 7 种模式。分别是:

  • mode=0 round-robin 轮询策略 (Round-robin policy)
  • mode=1 active-backup 主备策略 (Active-backup policy)
  • mode=2 load balancing (xor) 异或策略 (XOR policy)
  • mode=3 fault-tolerance (broadcast) 广播策略 (Broadcast policy)
  • mode=4 lacp IEEE 802.3ad 动态链路聚合 (IEEE 802.3ad Dynamic link aggregation)
  • mode=5 transmit load balancing 适配器传输负载均衡 (Adaptive transmit load balancing)
  • mode=6 adaptive load balancing 适配器负载均衡 (Adaptive load balancing)

当前我们采取的是动态链路聚合模式,这种模式必须是两块网卡具备相同速率和双工模式才行。而且还需要交换机的支持。这种模式本身也没太大的问题,不过不是很常用。

一般应用的是 mode=0 的轮询策略、mode=1 的主备策略,还有 mode=6 的负载均衡方式。由于其他数据库使用的是 mode=1,唯独这个使用的是 mode 4,首先怀疑的就是这个点。

但是因为停机时间一个月只有一次,没有办法进行测试,这次大家集体商量之后,决定双网卡绑定工作模式改造的同时,把网卡、网卡插槽、网线都更换一下。彻底的排除硬件上网络可能出现的问题。

小 B:嗯,那做完这些操作之后,变好了吗?

小 A:没有,当我们把这些操作都做了,数据库启动之后,白天工作时间段延迟依旧很高。

小 B:额,那不是没找到问题的根源?

小 A:是的,我们又仔细的检查了一遍,这次发现主要来源于 oswatch 中的 mpstat,可以看到在业务高峰期 cpu 15 的 %soft,总是 100%。这个发现是非常重要的。

一次因网络引起的诡异GC问题,DBA该怎么做?

在网上搜索一番,可以发现大量的网卡软中断导致的网络延迟。

一次因网络引起的诡异GC问题,DBA该怎么做?

小 B:越来越精彩了,这块属于网络问题了,我们 DBA 遇到这种问题该怎么办呢?

小 A:我们要研究啊。DBA 什么事情都要干,必须追求卓越。

网卡与操作系统的交互其中一个就是方式就是中断,网卡在收到了网络信号之后,主动就发送中断到 cpu,而 cpu 会立即停止其他事情对这个中断信号进行处理。

由于数据包速率的增长,带来的中断渐渐超过了单个 cpu 核可处理的范围。从而导致了网络延迟和丢包。

在这里我还要提高 Linux 上的一个服务,叫做 irqbalance。该服务就是专门解决网卡性能问题的,用于优化中断分配,将中断尽可能的均匀的分发给各个 cpu core,充分利用 cpu 多核,提升性能。

虽然开启了这个服务,但是我们实际情况是网卡中断就绑定在特殊的 cpu 15 上面。我们必须把这个中断手动重新绑一下。这个就不得不提到中断亲缘性(smp_affinity)设置。只有 kernel 2.4 以后的版本才支持把不同的硬件中断请求(IRQs)分配到特定的 CPU 上,这个绑定技术被称为 SMP IRQ Affinity。当前操作系统版本是 RedHat 6,内核是 2.6 的。我们可以查看操作系统自带的说明:Linux-2.6.31.8/Documentation/IRQ-affinity.txt

至于绑定方式,因为购买的是华为服务器,在华为服务器的性能优化最佳的附录里面,会有网卡中断绑定的方法介绍。

一次因网络引起的诡异GC问题,DBA该怎么做?

操作方法有点复杂:

① 首先我们需要停止 irqbalance 服务。

复制代码
Service irqbalance off

② 确认哪块网卡是私有网卡,然后执行下列语句,查看分配给网卡的中断号。

复制代码
cat /proc/interrupts | grep -i ethx

③ 查看中断号和 cpu 绑定的情况,根据上面的中断号查看和 cpu 的亲缘性。

复制代码
cat /proc/irq/126/smp_affinity

④ 中断绑定,将 ethx 的 N 个中断绑定到不同的 cpu。

复制代码
echo 16 > /proc/irq/126/smp_affinity

如果觉得麻烦,可以直接使用华为驱动包中提供的脚本。

当然做了这个操作之后缓解了一下症状。之前都是压到一个 cpu 核上造成 100% soft,现在感觉还是压在一个核上,那么这个又是什么问题呢?在网上搜到了一篇美团点评的帖子,是这么理解这个问题的。

当给中断设置了多个 cpu core 后,它也仅能由设置的第一个 cpu core 来处理,其他的 cpu core 并不会参与中断处理,原因猜想是当 cpu 平行收包时,不同的核收取了同一个 queue 的数据包,但处理速度不一致,导致提交到 IP 层后的顺序也不一致,这就会产生乱序的问题,由同一个核来处理可以避免了乱序问题。

参考链接: https://tech.meituan.com/2018/03/16/redis-high-concurrency-optimization.html

小 B:问题还是没解决啊,看来也是有限制的。

小 A:是的,当然也可以优化,根据上面的文档,咱们也可以把 Oracle 数据库的 LMS 进程的亲缘性设置到指定的 cpu 上去,然后把中断设置到另外的 cpu 上去,互相不冲突就可以解决了。但是我们没这么做,因为 LMS 进程比较多,主机上出 cpu 也比较多,设置起来较为麻烦,我们最后是通过参数优化来解决的。

第一个优化方式,是 IRQ coalescing,中断合并主要是为了做延迟跟 cpu 开销之间的权衡。当网卡适配器收到一个帧之后,不会立即的对系统产生中断,而是等一段时间,收集到更多的包之后再一次性的处理,这会降低 cpu 的负载,但是会产生等待时间。

一次因网络引起的诡异GC问题,DBA该怎么做?

自适应模式使网卡能够自动调节中断聚合,在我们的机器上可以看到是没开启的。在自适应模式下,驱动程序将检查流量模式和内核接收模式,并在运行中估算合并设置,以防止数据包丢失。这里我们可以建议启动自适应模式。

复制代码
# ethtool -C ethx adaptive-rx on

第二个优化的手段是,UDP 根据源 IP 和目的 IP,按照哈希结果将数据流分发到网卡的不同接收队列中。

复制代码
# ethtool --config-ntuple ethx rx-flow-hash udp4 sdfn

在做了上面两个操作后,软中断的 cpu 使用率下降到了 30%-60% 之间,起到了明显的改善,处理中断的 cpu 只要不是 100%,网络延迟丢包也就不存在了。后续观察网络的延迟都是在 0.01ms 以下,数据库的 GC 等待事件也随之消失了。

小 B:嗯,这个问题真是麻烦啊,还好你们一直坚持排查。

小 A:那当然,DBA 得追求卓越,把问题都搞清楚然后再解决。虽然这个问题是一只很厉害的“妖怪”,一度让我们很困扰,但是打败了这只“妖怪”之后,我们像经历了一次脱胎换骨,对网络问题又加深了理解,还是收获很大的。

小 B:嗯,感谢分享,确实收获颇多,以后我也要像你一样在技术上追求卓越!

作者介绍

袁伟翔,新炬网络高级专家,长期服务于运营商,精通 Oracle 数据库故障诊断、内核技术,具有 10 多年数据库开发运维经验。

原文链接

https://mp.weixin.qq.com/s/961NCUu5Weg_qBRx4f859w

评论

发布