记一次 .NET某游戏后端API服务 CPU爆高分析

2024-03-22 05:44

本文主要是介绍记一次 .NET某游戏后端API服务 CPU爆高分析,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

一:背景

1. 讲故事

前几天有位朋友找到我,说他们的API服务程序跑着跑着CPU满了降不下去,让我帮忙看下怎么回事,现在貌似民间只有我一个人专注dump分析,还是申明一下我dump分析是免费的,如果想学习.NET高级调试的分析技术,可以来我的训练营看看,话不多说,dump分析走起!

二:WinDbg分析

1. CPU 真的爆高吗

昨天录了一个小视频,大意就是作为分析师,不要过分的相信客户说的话,他们往往会把你带偏,你要有自己的分析思路和前进方向,所以需要以数据说话,首先用 !tp 观察下线程池。


0:030> !tp
CPU utilization: 60%
Worker Thread: Total: 18 Running: 3 Idle: 15 MaxLimit: 32767 MinLimit: 4
Work Request in Queue: 0
--------------------------------------
Number of Timers: 3
--------------------------------------
Completion Port Thread:Total: 3 Free: 1 MaxFree: 8 CurrentLimit: 1 MaxLimit: 1000 MinLimit: 4

从卦中可以看到当前的 CPU=60%,这个值说高也不高,说低也不低,接下来观察下这台机器的cpu核心数,可以用 !cpuid 观察。


0:030> !cpuid
CP  F/M/S  Manufacturer     MHz0  6,63,2  <unavailable>   22951  6,63,2  <unavailable>   22952  6,63,2  <unavailable>   22953  6,63,2  <unavailable>   2295

真的是无语,做游戏的不都是有钱的主,难道都在降本增效吗?既然到了 60%,说明有两个线程估计脱轨了,接下来就需要观察下那2个托轨线程都在做什么?

2. 脱轨线程在干嘛

要想观察每个线程都在做什么,可以使用 ~*e !clrstack 命令即可。


0:030> ~*e !clrstack
OS Thread Id: 0x3eec (30)Child SP               IP Call Site
0000001f8fbad610 00007ffd958535c3 System.Collections.Generic.HashSet`1[[System.__Canon, mscorlib]].Contains(System.__Canon)
0000001f8fbad680 00007ffd95372933 System.Web.HttpCookieCollection.EnsureKeyValidated(System.String, System.String)
0000001f8fbad6c0 00007ffd9483fa8d System.Web.HttpCookieCollection.Get(System.String)
0000001f8fbad700 00007ffd3d12b3da xxx.CookieHelper.Read(System.String)
...
OS Thread Id: 0x5cf0 (31)Child SP               IP Call Site
0000001f8d27d330 00007ffd958535b8 System.Collections.Generic.HashSet`1[[System.__Canon, mscorlib]].Contains(System.__Canon)
0000001f8d27d3a0 00007ffd95372933 System.Web.HttpCookieCollection.EnsureKeyValidated(System.String, System.String)
0000001f8d27d3e0 00007ffd9483fa8d System.Web.HttpCookieCollection.Get(System.String)
0000001f8d27d420 00007ffd3e2ab6da xxx.CookieHelper.Read(System.String)
...

仔细琢磨了一下卦象后,发现有两个线程都停在 HashSet 上,而且这个集合还是来自于底层的 System.Web,对一般人来说这个是比较奇葩的现象,但对于我这种有300+分析经验的熟手来说,一眼就看出来了什么问题,对,就是多线程操控 HashSet 导致的死循环,接下来的问题是如何去验证呢?毕竟空口无凭。。。

3. 真的死循环了吗

要想了解有没有真的死循环,需要你对 HashSet 的底层有一个了解,比如说 HashSet 挂链的时候在内部是如何组织的,其实这个我在.NET高级训练营里面也做过讲解,也做过演示,接下来切到 31 号线程观察下它的 HashSet 结构。


0:031> !mdso
Thread 31:
Location          Object            Type
------------------------------------------------------------
RCX:              000000200054ffc0  System.Collections.Generic.HashSet`1+Slot[[System.String, mscorlib]][]
RSI:              000000200054ff58  System.Collections.Generic.HashSet`1[[System.String, mscorlib]]
...
0:031> !mdt 000000200054ff58
000000200054ff58 (System.Collections.Generic.HashSet`1[[System.String, mscorlib]])m_buckets:000000200054ff98 (System.Int32[], Elements: 3)m_slots:000000200054ffc0 (System.Collections.Generic.HashSet`1+Slot[[System.String, mscorlib]][], Elements: 3, ElementMT=00007ffd95555230)m_count:0x0 (System.Int32)m_lastIndex:0x0 (System.Int32)m_freeList:0xffffffff (System.Int32)m_comparer:00000022003d3380 (System.OrdinalComparer)m_version:0x6 (System.Int32)m_siInfo:NULL (System.Runtime.Serialization.SerializationInfo)
...
0:031> !mdt -e:2 000000200054ffc0
000000200054ffc0 (System.Collections.Generic.HashSet`1+Slot[[System.String, mscorlib]][], Elements: 3, ElementMT=00007ffd95555230)
[0] (System.Collections.Generic.HashSet`1+Slot[[System.String, mscorlib]]) VALTYPE (MT=00007ffd95555230, ADDR=000000200054ffd0)hashCode:0xffffffff (System.Int32)next:0x0 (System.Int32)value:NULL (System.__Canon)
[1] (System.Collections.Generic.HashSet`1+Slot[[System.String, mscorlib]]) VALTYPE (MT=00007ffd95555230, ADDR=000000200054ffe0)hashCode:0x3eb5808c (System.Int32)next:0xffffffff (System.Int32)value:000000200054f8f0 (System.String) Length=6, String="xxx"
[2] (System.Collections.Generic.HashSet`1+Slot[[System.String, mscorlib]]) VALTYPE (MT=00007ffd95555230, ADDR=000000200054fff0)hashCode:0x7e225883 (System.Int32)next:0x1 (System.Int32)value:000000200054fba0 (System.String) Length=12, String="xxx"

熟悉 HashSet底层的朋友,从上面的卦信息一眼就能看出问题,对,就是这个 next:0x0,在hashset的挂链中,最后一个节点永远是 -1,如果是 0 的话就相当于指向数组的首元素,最后就是无情死循环了,知道了前因后果之后,接下来就要寻找下到底是什么圣神代码。

4. 到底是什么奇葩代码

这个比较简单,观察下线程栈的托管层代码,然后看源码即可,为了保护客户隐私,我就多注释一点,输出如下:


0:031> !clrstack
OS Thread Id: 0x5cf0 (31)Child SP               IP Call Site
0000001f8d27d330 00007ffd958535b8 System.Collections.Generic.HashSet`1[[System.__Canon, mscorlib]].Contains(System.__Canon)
0000001f8d27d3a0 00007ffd95372933 System.Web.HttpCookieCollection.EnsureKeyValidated(System.String, System.String)
0000001f8d27d3e0 00007ffd9483fa8d System.Web.HttpCookieCollection.Get(System.String)
0000001f8d27d420 00007ffd3e2ab6da xxx.CookieHelper.Read(System.String)
...

虽然信息比较少,但卦还是很明朗的,客户写了一个 CookieHelper 封装了 Request.Cookies 操作,那到底怎么封装的呢?仔细阅读代码之后终于发现了,截图如下:

我去,这代码还是挺奇葩的,居然将 Cookies 给了静态变量,静态变量可是一个进程小缓存呢,水落石出之后改发也比较简单,把 static 去掉即可。

三:总结

这种将Request.Cookies赋给静态变量的奇葩操作其实蕴含着巨大的安全隐患,会导致多个用户之间串cookie,但以服务器自爆的方式来避免客户端串cookie,真的是不幸中的万幸,哈哈,同时用bug去抑制另一个bug的神操作也真的是大自然的鬼斧神工!

这篇关于记一次 .NET某游戏后端API服务 CPU爆高分析的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/834645

相关文章

性能分析之MySQL索引实战案例

文章目录 一、前言二、准备三、MySQL索引优化四、MySQL 索引知识回顾五、总结 一、前言 在上一讲性能工具之 JProfiler 简单登录案例分析实战中已经发现SQL没有建立索引问题,本文将一起从代码层去分析为什么没有建立索引? 开源ERP项目地址:https://gitee.com/jishenghua/JSH_ERP 二、准备 打开IDEA找到登录请求资源路径位置

poj 1258 Agri-Net(最小生成树模板代码)

感觉用这题来当模板更适合。 题意就是给你邻接矩阵求最小生成树啦。~ prim代码:效率很高。172k...0ms。 #include<stdio.h>#include<algorithm>using namespace std;const int MaxN = 101;const int INF = 0x3f3f3f3f;int g[MaxN][MaxN];int n

【区块链 + 人才服务】可信教育区块链治理系统 | FISCO BCOS应用案例

伴随着区块链技术的不断完善,其在教育信息化中的应用也在持续发展。利用区块链数据共识、不可篡改的特性, 将与教育相关的数据要素在区块链上进行存证确权,在确保数据可信的前提下,促进教育的公平、透明、开放,为教育教学质量提升赋能,实现教育数据的安全共享、高等教育体系的智慧治理。 可信教育区块链治理系统的顶层治理架构由教育部、高校、企业、学生等多方角色共同参与建设、维护,支撑教育资源共享、教学质量评估、

如何在Visual Studio中调试.NET源码

今天偶然在看别人代码时,发现在他的代码里使用了Any判断List<T>是否为空。 我一般的做法是先判断是否为null,再判断Count。 看了一下Count的源码如下: 1 [__DynamicallyInvokable]2 public int Count3 {4 [__DynamicallyInvokable]5 get

2、PF-Net点云补全

2、PF-Net 点云补全 PF-Net论文链接:PF-Net PF-Net (Point Fractal Network for 3D Point Cloud Completion)是一种专门为三维点云补全设计的深度学习模型。点云补全实际上和图片补全是一个逻辑,都是采用GAN模型的思想来进行补全,在图片补全中,将部分像素点删除并且标记,然后卷积特征提取预测、判别器判别,来训练模型,生成的像

【区块链 + 人才服务】区块链集成开发平台 | FISCO BCOS应用案例

随着区块链技术的快速发展,越来越多的企业开始将其应用于实际业务中。然而,区块链技术的专业性使得其集成开发成为一项挑战。针对此,广东中创智慧科技有限公司基于国产开源联盟链 FISCO BCOS 推出了区块链集成开发平台。该平台基于区块链技术,提供一套全面的区块链开发工具和开发环境,支持开发者快速开发和部署区块链应用。此外,该平台还可以提供一套全面的区块链开发教程和文档,帮助开发者快速上手区块链开发。

SWAP作物生长模型安装教程、数据制备、敏感性分析、气候变化影响、R模型敏感性分析与贝叶斯优化、Fortran源代码分析、气候数据降尺度与变化影响分析

查看原文>>>全流程SWAP农业模型数据制备、敏感性分析及气候变化影响实践技术应用 SWAP模型是由荷兰瓦赫宁根大学开发的先进农作物模型,它综合考虑了土壤-水分-大气以及植被间的相互作用;是一种描述作物生长过程的一种机理性作物生长模型。它不但运用Richard方程,使其能够精确的模拟土壤中水分的运动,而且耦合了WOFOST作物模型使作物的生长描述更为科学。 本文让更多的科研人员和农业工作者

MOLE 2.5 分析分子通道和孔隙

软件介绍 生物大分子通道和孔隙在生物学中发挥着重要作用,例如在分子识别和酶底物特异性方面。 我们介绍了一种名为 MOLE 2.5 的高级软件工具,该工具旨在分析分子通道和孔隙。 与其他可用软件工具的基准测试表明,MOLE 2.5 相比更快、更强大、功能更丰富。作为一项新功能,MOLE 2.5 可以估算已识别通道的物理化学性质。 软件下载 https://pan.quark.cn/s/57

国产游戏崛起:技术革新与文化自信的双重推动

近年来,国产游戏行业发展迅猛,技术水平和作品质量均得到了显著提升。特别是以《黑神话:悟空》为代表的一系列优秀作品,成功打破了过去中国游戏市场以手游和网游为主的局限,向全球玩家展示了中国在单机游戏领域的实力与潜力。随着中国开发者在画面渲染、物理引擎、AI 技术和服务器架构等方面取得了显著进展,国产游戏正逐步赢得国际市场的认可。然而,面对全球游戏行业的激烈竞争,国产游戏技术依然面临诸多挑战,未来的

衡石分析平台使用手册-单机安装及启动

单机安装及启动​ 本文讲述如何在单机环境下进行 HENGSHI SENSE 安装的操作过程。 在安装前请确认网络环境,如果是隔离环境,无法连接互联网时,请先按照 离线环境安装依赖的指导进行依赖包的安装,然后按照本文的指导继续操作。如果网络环境可以连接互联网,请直接按照本文的指导进行安装。 准备工作​ 请参考安装环境文档准备安装环境。 配置用户与安装目录。 在操作前请检查您是否有 sud