一次因網絡引起的詭異GC問題,DBA該怎麼做?

我們在日常工作中,就像西天取經的僧人,總是會遇到各式各樣的“妖怪”。這些“妖怪”總是一個又一個的阻擋在我們面前,你必須想辦法擊敗它們。

聽說小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查看網絡延遲類的問題了。

你注意看,這是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幾,這說明是業務的壓力上來導致的延遲。

這裏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%。這個發現是非常重要的。

在網上搜索一番,可以發現大量的網卡軟中斷導致的網絡延遲。

小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

至於綁定方式,因爲購買的是華爲服務器,在華爲服務器的性能優化最佳的附錄裏面,會有網卡中斷綁定的方法介紹。

操作方法有點複雜:

① 首先我們需要停止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的負載,但是會產生等待時間。

自適應模式使網卡能夠自動調節中斷聚合,在我們的機器上可以看到是沒開啓的。在自適應模式下,驅動程序將檢查流量模式和內核接收模式,並在運行中估算合併設置,以防止數據包丟失。這裏我們可以建議啓動自適應模式。

# 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多年數據庫開發運維經驗。

本文由 dbaplus 社羣授權轉載。

原文鏈接

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

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章