国产精品电影_久久视频免费_欧美日韩国产激情_成年人视频免费在线播放_日本久久亚洲电影_久久都是精品_66av99_九色精品美女在线_蜜臀a∨国产成人精品_冲田杏梨av在线_欧美精品在线一区二区三区_麻豆mv在线看

RabbitMQ處理過慢,原來是一個SQL緩存框架導致的GC頻繁觸發

存儲 存儲軟件
處理過慢原因有很多,可能是干活的人少了,也可能這些人摸魚去了,總之工作不飽和,接下來看看這幫人有沒有摸魚,從 線程池 看起。

[[434658]]

一、背景

1. 講故事

上個月底,有位朋友微信找到我,說他的程序 多線程處理 RabbitMQ 時過慢,幫忙分析下什么原因,截圖如下:

這問題拋出來,有點懵逼,沒說CPU爆高,也沒說內存泄漏,也沒說程序卡死。。。鬼知道為啥 Rabbitmq 處理過慢哈?????? 

既然沒有一個緣由,那就往 freeze 這個方向去找吧,上 windbg 說話。

二、Windbg 分析

1. 尋找 freeze 原因

處理過慢原因有很多,可能是干活的人少了,也可能這些人摸魚去了,總之工作不飽和,接下來看看這幫人有沒有摸魚,從 線程池 看起。

  1. 0:000> !tp 
  2. CPU utilization: 81% 
  3. Worker Thread: Total: 187 Running: 172 Idle: 0 MaxLimit: 32767 MinLimit: 8 
  4. Work Request in Queue: 0 
  5. -------------------------------------- 
  6. Number of Timers: 0 
  7. -------------------------------------- 
  8. Completion Port Thread:Total: 1 Free: 1 MaxFree: 16 CurrentLimit: 1 MaxLimit: 1000 MinLimit: 8 

從輸出中看,當前的 CPU=81%, 大概率是這個程序引起的,既然 CPU 過高,可能是某些計算密集型操作,可能是大量鎖導致的上下文切換,也可能是 GC 頻繁觸發所致。

2. 是 GC 觸發嗎?

本系列到這里,我相信有很多朋友應該知道如何從線程棧上看是否為 GC 觸發所致,用命令 ~*e !dumpstack 經過一通尋找,發現是 214 號線程觸發了 GC,如下圖所示:

用 !dumpstack 輸出的信息太多,為了讓信息更加簡化,改用 !clrstack。

  1. 0:214> !clrstack  
  2. OS Thread Id: 0x290c (214) 
  3.         Child SP               IP Call Site 
  4. 000000bb2983c7d0 00007ffed8c3e335 System.Text.UTF8Encoding.GetString(Byte[], Int32, Int32) 
  5. 000000bb2983c810 00007ffe7aaecee9 StackExchange.Redis.RedisValue.op_Implicit(StackExchange.Redis.RedisValue) 
  6. 000000bb2983c860 00007ffe7aaecd92 xxxx.Util.Helper.RedisHelper.ConvertObj[[System.__Canon, mscorlib]](StackExchange.Redis.RedisValue) 
  7. 000000bb2983c8f0 00007ffe7abc3997 xxxx.Util.Helper.RedisHelper+c__DisplayClass29_0`1[[System.__Canon, mscorlib]].b__0(StackExchange.Redis.IDatabase) 
  8. 000000bb2983ca20 00007ffe7aaeaca0 xxxx.Util.Helper.RedisHelper.Do[[System.__Canon, mscorlib]](System.Func`2<StackExchange.Redis.IDatabase,System.__Canon>) 
  9. 000000bb2983caa0 00007ffe7abc3762 xxxx.Util.Helper.RedisHelper.HashGet[[System.__Canon, mscorlib]](System.String, System.String) 
  10. 000000bb2983cb40 00007ffe7abc2f3d xxxx.Implementation.xxx.GetCompany(System.String) 
  11. ... 
  12. 000000bb2983e170 00007ffe7ad2fadf xxx.xxx.MQ.xxx+c__DisplayClass21_0`1[[System.__Canon, mscorlib]].b__1() 
  13. 000000bb2983e1c0 00007ffed8c11862 System.Threading.Tasks.Task`1[[System.__Canon, mscorlib]].InnerInvoke() 
  14. 000000bb2983e220 00007ffed8c10937 System.Threading.Tasks.Task.Execute() 
  15. 000000bb2983e260 00007ffed8bc674e System.Threading.ExecutionContext.RunInternal(System.Threading.ExecutionContext, System.Threading.ContextCallback, System.Object, Boolean) 
  16. 000000bb2983e330 00007ffed8bc65e7 System.Threading.ExecutionContext.Run(System.Threading.ExecutionContext, System.Threading.ContextCallback, System.Object, Boolean) 
  17. 000000bb2983e360 00007ffed8c10bdd System.Threading.Tasks.Task.ExecuteWithThreadLocal(System.Threading.Tasks.Task ByRef) 
  18. 000000bb2983e410 00007ffed8c10303 System.Threading.Tasks.Task.ExecuteEntry(Boolean) 
  19. 000000bb2983e450 00007ffed8bcfa10 System.Threading.ThreadPoolWorkQueue.Dispatch() 
  20. 000000bb2983e8e8 00007ffed9d465d3 [DebuggerU2MCatchHandlerFrame: 000000bb2983e8e8]  

從卦中信息看,程序在 RedisHelper.HashGet 操作的過程中觸發了 GC,我去,難道是從 redis 中讀了什么大數據?接下來用 !clrstack -a 看看到底從redis中讀了個啥?

  1. 0:214> !clrstack -a 
  2. OS Thread Id: 0x290c (214) 
  3.         Child SP               IP Call Site 
  4. 000000bb2983c860 00007ffe7aaecd92 xxx.Util.Helper.RedisHelper.ConvertObj[[System.__Canon, mscorlib]](StackExchange.Redis.RedisValue) 
  5.     PARAMETERS: 
  6.         this (0x000000bb2983c8f0) = 0x000000bb182da3d0 
  7.         value (0x000000bb2983c960) = 0x000000bb18440778 
  8.     LOCALS: 
  9.         0x000000bb2983c8c4 = 0x0000000000000000 
  10.         0x000000bb2983c8a0 = 0x0000000000000000 
  11.         0x000000bb2983c898 = 0x0000000000000000 
  12.  
  13. 0:214> !do 0x000000bb18440778 
  14. Name:        System.Byte[] 
  15. MethodTable: 00007ffed8db93d0 
  16. EEClass:     00007ffed87f4dc8 
  17. Size:        6679(0x1a17) bytes 
  18. Array:       Rank 1, Number of elements 6655, Type Byte (Print Array) 
  19. Content:     {"ID":104x,"Code":"130x","xxx":"1304","xxx":"8888","Name":"...............","xxx":"...............","MqConnStr" 

可以看到,redis 讀了大概 6.6 k 的數據,才這么點數據,我還以為 幾十M 呢 ??????, 要說這點東西就能觸發GC,我是不相信的 。

3. 到底是什么誘使了 GC 觸發 ?

那這個 罪魁禍首 到底是誰呢?其實仔細想一想,GC觸發無非就是將對象從 gen0 推到 gen1,然后由 gen1 推到 gen2,那朋友的這個 RabbitMQ 處理慢,肯定是觸發了多次GC,才有了這個肉眼可見的處理慢。

這里就有一個突破點,既然觸發多次GC,那gen2上肯定有很多帶根的對象,所以從這里入手比較好,用 !dumpgen 命令查看。

  1. 0:214> !dumpgen 2 -stat 
  2.        Count      Total Size      Type 
  3. ------------------------------------------------- 
  4.       87,738     24,925,316   System.Int32[] 
  5.      509,643     56,399,716   System.String 
  6.       83,077     65,760,888   System.Reflection.Emit.__FixupData[] 
  7.    2,158,346     69,067,072   System.Reflection.Emit.GenericMethodInfo 
  8.       92,388    172,765,392   System.Object[] 
  9.      796,870    179,587,796   **** FREE **** 
  10.   14,030,441    336,730,584   System.RuntimeMethodHandle 
  11.      428,376    348,743,274   System.Byte[] 

我去,gen2 上居然有 1.4 kw 的對象,這太讓人好奇了,接下來隨便抽幾個 address ,看看它的引用根是個啥?

  1. 0:214> !dumpgen 2 -type System.RuntimeMethodHandle 
  2. Object             MT                    Size   Name 
  3. ------------------------------------------------------------------- 
  4. 000000bac9f8fe68   00007FFED8DB9978        24   System.RuntimeMethodHandle 
  5. 000000bac9f8fe80   00007FFED8DB9978        24   System.RuntimeMethodHandle 
  6. 000000bac9f8fe98   00007FFED8DB9978        24   System.RuntimeMethodHandle 
  7. 000000bac9f8feb0   00007FFED8DB9978        24   System.RuntimeMethodHandle 
  8. 000000bac9f8fec8   00007FFED8DB9978        24   System.RuntimeMethodHandle 
  9. ... 
  10. 000000baca1af510   00007FFED8DB9978        24   System.RuntimeMethodHandle 
  11. 000000baca1af548   00007FFED8DB9978        24   System.RuntimeMethodHandle 
  12. 000000baca1af560   00007FFED8DB9978        24   System.RuntimeMethodHandle 
  13. 000000baca1afd90   00007FFED8DB9978        24   System.RuntimeMethodHandle 
  14. 000000baca1afde0   00007FFED8DB9978        24   System.RuntimeMethodHandle 
  15.  
  16. 0:214> !gcroot 000000baca1afde0 
  17. Thread 187c0: 
  18.     000000baeeb5cb30 00007ffed8ba9c60 System.Collections.Generic.Dictionary`2[[System.__Canon, mscorlib],[System.__Canon, mscorlib]].FindEntry(System.__Canon) 
  19.         rsi:  
  20.             ->  000000baca4c6ef0 System.Collections.Generic.Dictionary`2[[System.Tuple`4[[System.String, mscorlib],[System.String, mscorlib],[System.Int32, mscorlib],[System.Int32, mscorlib]], mscorlib],[System.Delegate, mscorlib]] 
  21.             ->  000000badab3b8a0 System.Collections.Generic.Dictionary`2+Entry[[System.Tuple`4[[System.String, mscorlib],[System.String, mscorlib],[System.Int32, mscorlib],[System.Int32, mscorlib]], mscorlib],[System.Delegate, mscorlib]][] 
  22.             ->  000000baca1b5210 System.Func`2[[System.Data.IDataReader, System.Data],[xxx.BAR_AccountDC, xxxx]] 
  23.             ->  000000baca1ae8b0 System.Reflection.Emit.DynamicMethod+RTDynamicMethod 
  24.             ->  000000baca1ae7f8 System.Reflection.Emit.DynamicMethod 
  25.             ->  000000baca1b51b0 System.RuntimeMethodInfoStub 
  26.             ->  000000baca1b4a18 System.Reflection.Emit.DynamicResolver 
  27.             ->  000000baca1aea60 System.Reflection.Emit.DynamicScope 
  28.             ->  000000baca1aea78 System.Collections.Generic.List`1[[System.Object, mscorlib]] 
  29.             ->  000000baca1b3b20 System.Object[] 
  30.             ->  000000baca1afde0 System.RuntimeMethodHandle 

從引用鏈看,它是被 Dictionary 所持有,那我們就 dump 一下這個 dictionary,看看是個啥。

  1. 0:214> !do 000000baca4c6ef0 
  2. Name:        System.Collections.Generic.Dictionary`2[[System.Tuple`4[[System.String, mscorlib],[System.String, mscorlib],[System.Int32, mscorlib],[System.Int32, mscorlib]], mscorlib],[System.Delegate, mscorlib]] 
  3. MethodTable: 00007ffe7a937f18 
  4. EEClass:     00007ffed87f7cb8 
  5. Size:        80(0x50) bytes 
  6. File:        C:\Windows\Microsoft.Net\assembly\GAC_64\mscorlib\v4.0_4.0.0.0__b77a5c561934e089\mscorlib.dll 
  7. Fields: 
  8.               MT    Field   Offset                 Type VT     Attr            Value Name 
  9. 00007ffed8dc3e30  400182a        8       System.Int32[]  0 instance 000000badaaa2c10 buckets 
  10. 00007ffed9874d38  400182b       10 ...non, mscorlib]][]  0 instance 000000badab3b8a0 entries 
  11. 00007ffed8dc3e98  400182c       38         System.Int32  1 instance            83000 count 
  12. 00007ffed8dc3e98  400182d       3c         System.Int32  1 instance            83000 version 
  13. 00007ffed8dc3e98  400182e       40         System.Int32  1 instance               -1 freeList 
  14. 00007ffed8dc3e98  400182f       44         System.Int32  1 instance                0 freeCount 
  15. 00007ffed8d9a430  4001830       18 ...Canon, mscorlib]]  0 instance 000000baca2ec958 comparer 
  16. 00007ffed8d9c550  4001831       20 ...Canon, mscorlib]]  0 instance 0000000000000000 keys 
  17. 00007ffed8dcef28  4001832       28 ...Canon, mscorlib]]  0 instance 0000000000000000 values 
  18. 00007ffed8dc1c98  4001833       30        System.Object  0 instance 0000000000000000 _syncRoot 
  19.  
  20. 0:214> !objsize 000000baca4c6ef0 
  21. sizeof(000000baca4c6ef0) = 1116325152 (0x4289c520) bytes (System.Collections.Generic.Dictionary`2[[System.Tuple`4[[System.String, mscorlib],[System.String, mscorlib],[System.Int32, mscorlib],[System.Int32, mscorlib]], mscorlib],[System.Delegate, mscorlib]]) 

可以看到,當前dict 的 size= 8.3w,總大小為 1.1G, 然后用 !mdt 抽查一下字典內容。

可以看出,字典中的item大概都是 key= select * from xxx where AccountNo= xxxx, value = Func ,

4. 查看源碼

從 !gcroot 中知道當前根在 187c0 號線程,然后我們通過線程棧去尋找下源碼。

  1. 0:089> ~~[187c0]s 
  2. ntdll!NtWaitForSingleObject+0xa: 
  3. 00007ffe`e9ea06fa c3              ret 
  4. 0:089> !clrstack  
  5. OS Thread Id: 0x187c0 (89) 
  6.         Child SP               IP Call Site 
  7. 000000baeeb5caa0 00007ffed9718dfe System.Tuple`4[[System.__Canon, mscorlib],[System.__Canon, mscorlib],[System.Int32, mscorlib],[System.Int32, mscorlib]].System.Collections.IStructuralEquatable.GetHashCode(System.Collections.IEqualityComparer) 
  8. 000000baeeb5cb00 00007ffed8ba90a7 System.Collections.Generic.ObjectEqualityComparer`1[[System.__Canon, mscorlib]].GetHashCode(System.__Canon) 
  9. 000000baeeb5cb30 00007ffed8ba9c60 System.Collections.Generic.Dictionary`2[[System.__Canon, mscorlib],[System.__Canon, mscorlib]].FindEntry(System.__Canon) 
  10. 000000baeeb5cba0 00007ffed8bc53a4 System.Collections.Generic.Dictionary`2[[System.__Canon, mscorlib],[System.__Canon, mscorlib]].TryGetValue(System.__Canon, System.__Canon ByRef) 
  11. 000000baeeb5cbe0 00007ffe7abd8069 xxx.Internal.Cache`2[[System.__Canon, mscorlib],[System.__Canon, mscorlib]].Get(System.__Canon, System.Func`1<System.__Canon>) 
  12. 000000baeeb5cc50 00007ffe7abd6d52 xxx.Database+d__49`1[[System.__Canon, mscorlib]].MoveNext() 
  13. 000000baeeb5ccd0 00007ffed733768e System.Linq.Enumerable.FirstOrDefault[[System.__Canon, mscorlib]](System.Collections.Generic.IEnumerable`1<System.__Canon>) 
  14. 000000baeeb5cd40 00007ffe7af5489e xxx.xxx.ParsePapPayDebitRecord(xxx, xxx.BAR_AccountDC ByRef, System.String ByRef, xxx ByRef, Boolean, xxx, Boolean) 
  15. ... 

從線程棧看,程序做了一個 db 查詢的操作,源碼大概如下:

  1. public static InvalidTxnCode ParsePapPayDebitRecord(xxx) 
  2.     sql = "select * FROM  [dbo].[xxx]  where AccountNO = '" + transRecord.AccountNO + "'"
  3.  IEnumerable<BAR_AccountDC> enumerable3 = new YiBll<BAR_AccountDC>(transRecord.AccountNO).QuerySql(sql); 

問題就出現在這個 sql 拼接上,底層的框架為了提高 mapping 速度,將 sql 和與之對應的 Func<DataReader,Data>  做了緩存處理,由于每次sql都不一樣,這就導致底層的 dict越來越大,直到目前的 1.1 G。

三、總結

總的來說,本次事故是由于不斷增長的 dict 在不斷的擠壓小對象堆,加之程序多線程火力全開分配對象導致gc在小對象堆上的頻繁回收造成的 rabbitmq 處理過慢。

修改辦法就是將 sql 參數化。

  1. sql = "select * FROM [dbo].[xxx] where AccountNO = '" + transRecord.AccountNO + "'"

改成:

  1. sql = "select * FROM [dbo].[xxx] where AccountNO = @AccountNO";  

最后提一下,這個dump有一定的迷惑性,因為觸發GC的線程并不是罪魁禍首,它只不過是壓死駱駝的那最后一根稻草罷了。

 

責任編輯:武曉燕 來源: 一線碼農聊技術
相關推薦

2020-11-12 07:32:53

JavaScript

2017-04-17 11:07:19

GC數組動態擴容

2025-02-17 09:22:16

MySQLSQL語句

2022-12-10 22:52:54

Redis緩存數據

2016-02-02 10:31:03

華三/大安全

2017-06-06 15:13:07

2022-12-14 07:32:40

InnoDBMySQL引擎

2025-03-20 14:18:57

AI算法模型

2021-02-07 08:13:18

@DateTimeFo@NumberFormSpring

2017-06-27 08:41:04

JVM設計缺陷GC

2022-05-05 08:55:12

工業物聯網IIoT

2023-05-22 15:58:11

2024-02-06 09:30:25

Figma矩形矩形物理屬性

2018-04-02 15:13:21

網絡

2023-02-15 08:17:38

2024-04-30 08:22:51

Figma圖形編輯變換矩陣

2021-02-02 09:13:11

索引SQL數據庫

2018-07-02 10:07:08

2020-05-26 08:52:36

Java JVM多態

2020-03-23 08:30:12

程序員男友感受
點贊
收藏

51CTO技術棧公眾號

高清不卡一区| 日韩av网站电影| 国产乱码精品一区二区三区忘忧草| 欧美日韩一区二区综合| 97精品视频在线看| 欧美精品一区二区三区久久久竹菊| 国产韩国精品一区二区三区| 欧美疯狂party性派对| 鲁大师精品99久久久| 亚州国产精品| 91精品精品| 亚洲国产免费看| 亚洲美女少妇无套啪啪呻吟| 久久国产高清| 蜜乳av一区二区| 盗摄精品av一区二区三区| 99久久99久久精品国产片果冻 | 亚洲丰满在线| 色一情一乱一伦一区二区三区丨| 欧美精品123| 99久热在线精品视频| 男女激情无遮挡| 老司机性视频| 国产高清美女一级毛片久久| 日本最新在线视频| 自拍偷拍亚洲| 亚洲精品日韩久久| eeuss国产一区二区三区| 亚洲天堂中文字幕| 欧美日本一道本在线视频| 久久视频免费在线播放| 日韩精品av一区二区三区| 国产精品二区三区| 日韩免费中文字幕| 亚洲一区二区三区欧美| 午夜丝袜av电影| 日本一区免费| 超碰97在线看| 中文字幕在线免费专区| 三上悠亚一区二区| 蜜桃一区二区三区在线| 国产精品国产精品国产专区不片| 精品日韩在线一区| 99理论电影网| 色偷偷免费视频| 亚洲网址在线观看| 成人aa视频在线观看| 日韩一区二区三区在线观看| 欧美激情亚洲一区| 精品一区二区日本| 免费一区二区三区在线观看| 国产高清不卡| 激情自拍一区| 一个色在线综合| 久久在线观看视频| 欧美精品尤物在线| 免费观看黄色网| 黄色成人小视频| 天堂蜜桃91精品| 欧美性xxxx| 97超碰蝌蚪网人人做人人爽| 佐佐木明希av| 漫画在线观看av| 一区二区三区四区五区在线| 亚洲高清在线精品| 2021久久精品国产99国产精品| 国产福利视频在线播放| 俺来也官网欧美久久精品| 久久国产精品毛片| 日韩一本二本av| 日韩高清av| 麻豆传媒在线观看| 欧美日韩精品| 色悠久久久久综合欧美99| 国产精品女视频| 樱花在线免费观看| 国产精品7m凸凹视频分类| 亚洲色图.com| 国产91色在线|| 免费一级淫片| 亚洲色图网站| 91精品国产全国免费观看| 久久99精品久久久久久三级| 麻豆视频在线免费观看| 美女精品网站| 亚洲精品在线看| 欧美亚洲色图视频| 国产精品高清乱码在线观看| 精品一区二区三区蜜桃| 亚洲国产精品悠悠久久琪琪| 亚洲不卡一卡2卡三卡4卡5卡精品| 国内精品不卡| 日韩高清中文字幕一区| 亚洲国产精品99| a√天堂在线观看| 亚洲成a人片77777在线播放 | 国产精品电影一区二区三区| 欧美又大又硬又粗bbbbb| julia中文字幕久久亚洲蜜臀| 美女精品一区| 久久精品影视伊人网| 国产中文字幕在线视频| 成人国产精品免费网站| 国产综合第一页| 第四色婷婷基地| 唐人社导航福利精品| 夜夜嗨网站十八久久| 在线视频欧美精品| 国产欧美在线看| 啊啊啊一区二区| a级在线观看| 69久成人做爰电影| 欧美影院在线| 精品成人在线| 美女久久久久久久久久久| 在线观看免费版| 亚洲视频一二区| 日韩精品福利片午夜免费观看| 欧美日韩有码| 欧美日韩国产va另类| 国产va在线视频| 在线观看国产日韩| 免费在线看污| 综合激情一区| 在线看欧美日韩| jizz国产| 久久精品盗摄| 欧美国产日韩精品| 欧美视频综合| 奇米精品一区二区三区在线观看| 中文字幕欧美日韩在线| 2020中文字幕在线| 亚洲激情网站| 欧美激情一区二区三区高清视频| 日夜干在线视频| 激情小说亚洲一区| 国产日韩欧美电影在线观看| 19禁羞羞电影院在线观看| 国产精品三级av| 久热国产精品视频一区二区三区| 国产在线|日韩| 欧美日韩国产首页| 男女男精品视频站| 精品一区二区综合| 亚洲综合中文字幕68页| 亚洲黑人在线| 欧美一区二区三区视频免费 | 欧美一级片网址| 欧美色电影在线| 九色porny自拍| 伊人久久国产| 欧美喷水一区二区| 福利在线国产| 国产精品网站在线| 国产黄色激情视频| 国产真实久久| 国产精品尤物福利片在线观看| 91麻豆精品国产综合久久久| 亚洲福利视频免费观看| 国产区在线视频| 亚洲电影一级黄| 男女18免费网站视频| 中文字幕国产精品一区二区| 樱空桃在线播放| 日本 国产 欧美色综合| 久久精品一二三区| 国产精品xvideos88| 成人两性免费视频| 国产成人一区| 国产精品一区久久| 国产日产精品一区二区三区四区的观看方式 | yellow视频在线观看一区二区| 91精品啪在线观看国产手机| 日韩中文字幕网站| 国产黄色一区| 久久精品99国产精品酒店日本 | 国内视频精品| 国产丝袜一区二区三区| 男人天堂网视频| 日韩精品永久网址| 日韩av影院在线观看| 国产盗摄在线视频网站| 欧美伦理视频网站| 宅男网站在线免费观看| 亚洲第一级黄色片| 欧美精品日韩www.p站| 高潮久久久久久久久久久久久久| 97精品视频在线| 欧美成人激情| 91在线观看免费观看| 99亚洲精品| 艳母动漫在线免费观看| 成人h版在线观看| 欧美国产激情视频| 中文字幕五月欧美| 青青草免费在线| 亚洲国产精品久久91精品| 欧美黄色网络| 成人www视频在线观看| 日韩成人dvd|