记一次 .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的神操作也真的是大自然的鬼斧神工!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/761620.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

CDH中重装Kafka

##事情缘由 之前测试集群kafka安装在01、02、04节点&#xff0c;但是01节点经常宕机&#xff0c;于是直接在CM页面上把01节点上的kafka broker手动删除了。。。 然后重新再03节点安装了新的kafka broker 于是kafka集群不能使用了&#xff01;&#xff01;&#xff01; ##初始化…

Springboot中Tomcat配置及切换Undertow

一、Tomcat配置 1. 通过application.yml配置 以下展示常用配置 server:port: 8182 # 配置端口tomcat:threads:max: 10 # 最大工作线程&#xff0c;默认是200min-spare: 5 # 最小工作线程&#xff0c;默认是10accept-count: 200 # tomcat启动线程达到最大值后&#xff0c;接受…

JSP基础进阶(案例代码)

JDBC技术 通过JDBC连接MySQL数据库 <% page language"java" contentType"text/html; charsetUTF-8"pageEncoding"UTF-8" import "java.sql.*"%> <!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN&quo…

大数据开发(Spark面试真题)

大数据开发&#xff08;Spark面试真题&#xff09; 一、Spark基础和核心概念1、什么是Spark Streaming&#xff1f;简要描述其工作原理。2、什么是Spark内存管理机制&#xff1f;请解释其中的主要概念&#xff0c;并说明其作用。3、请解释一下Spark中的shuffle是什么&#xff0…

AnythingLLM

AnythingLLM是一款私人ChatGPT&#xff0c;它与传统的ChatGPT相比&#xff0c;具有更高的灵活性和可定制性。AnythingLLM是一个全栈应用程序&#xff0c;它能够将任何文档、资源或内容片段转化为上下文&#xff0c;供任何LLM&#xff08;大语言模型&#xff09;在聊天时作为参考…

大型语言模型(LLM)全解读

大型语言模型&#xff08;Large Language Model&#xff0c;LLM&#xff09;是指使用大规模数据集进行预训练的神经网络模型&#xff0c;用于生成人类类似的自然语言文本。LLM在自然语言处理&#xff08;Natural Language Processing&#xff0c;NLP&#xff09;领域有着广泛的…

idea快捷鍵

在IntelliJ IDEA中&#xff0c;如果你无法通过鼠标点击打开spring-boot-starter-web的依赖&#xff0c;你可以尝试以下几种方法&#xff1a; 快捷键方式&#xff1a;选中spring-boot-starter-web依赖&#xff0c;然后按下Ctrl B&#xff08;Windows和Linux&#xff09;或者Com…

两个基本功不足导致的bug

作为程序员&#xff0c;基本功不好&#xff0c;可能会在工作中经常碰到一些看起来很隐蔽的 bug&#xff0c;乍看没毛病&#xff0c;自己半天还找不到问题所在。 但是&#xff0c;如果基本功扎实的同学可能一眼就能看出来。 一、HashMap 取不到值 Map<Integer, Integer>…

Scikit-Learn逻辑回归(二)

Scikit-Learn逻辑回归二&#xff1a;多项式与正则化 1、多项式回归回顾1.1、逻辑回归为什么要使用多项式1.2、多项式回归及原理 2、逻辑回归与多项式 1、多项式回归回顾 本文接上篇&#xff1a;Scikit-Learn逻辑回归(一) 上篇中&#xff0c;我们详细介绍了逻辑回归的概念、原理…

哪种造型更适合铸铁焊接平台——河北北重厂家专业设计制造

哪种造型更适合焊接平台取决于具体的需求和条件。以下是一些常见的焊接平台造型供参考&#xff1a; 平面平台&#xff1a;这是最简单的造型&#xff0c;适合进行标准的焊接工作。平面平台提供了稳定的工作表面&#xff0c;便于操作和移动。 运输平台&#xff1a;如果需要频繁移…

spring boot 如何升级 Tomcat 版本

在Spring Boot应用程序中升级内嵌的Tomcat版本通常涉及以下几个步骤&#xff1a; 1. 确定当前使用的Tomcat版本 首先&#xff0c;你需要确定你的Spring Boot应用程序当前使用的Tomcat版本。这可以通过查看项目的pom.xml或build.gradle文件来完成&#xff0c;其中会列出所有的…

计算机网络2 TCP/IP协议

目录 1 前言2 传输层2.1 端口号2.2 UDP2.3 TCP 3 网络层3.1 IP 4 数据链路层4.1 以太网4.2 ARP 5 DNS6 NAT 1 前言 2 传输层 2.1 端口号 端口号又分为&#xff1a; 知名端口&#xff1a;知名程序在启动之后占用的端口号&#xff0c;0-1023。 HTTP, FTP, SSH等这些广为使用的…

Netty(2)-编写简单的Netty应用程序

本篇将讲述如何书写简单的Netty服务端和客户端。 1. 编写服务端 所有的Netty服务器都需要以下两部分&#xff1a; 至少一个ChannelHandler&#xff0c;该组件实现了服务器对从客户端接收的数据的处理&#xff0c;即它的业务逻辑。引导&#xff0c;配置服务器的启动代码。至少…

【CKA模拟题】查找集群中使用内存最高的node节点

题干 For this question, please set this context (In exam, diff cluster name) kubectl config use-context kubernetes-adminkubernetesFind the Node that consumes the most MEMORY in all cluster(currently we have single cluster). Then, store the result in the …

Linux实战笔记(四) 后台运行

大家好&#xff0c;我是半虹&#xff0c;这篇文章来讲 Linux 系统怎么在后台运行命令 0、序言 很多时候&#xff0c;特别是在连接服务器进行开发时&#xff0c;通常会遇到以下问题&#xff1a; 运行一些命令时&#xff0c;终端被阻塞&#xff0c;无法执行其他操作运行一些命令…

云效 AppStack + 阿里云 MSE 实现应用服务全链路灰度

作者&#xff1a;周静、吴宇奇、泮圣伟 在应用开发测试验证通过后、进行生产发布前&#xff0c;为了降低新版本发布带来的风险&#xff0c;期望能够先部署到灰度环境&#xff0c;用小部分业务流量进行全链路灰度验证&#xff0c;验证通过后再全量发布生产。本文主要介绍如何通…

大数据安全分析相关与安全分析的场景

数据采集与预处理 数据源是大数据分析的基础和前提&#xff0c;进行安全分析需要收集的数据源&#xff1a; 日志数据&#xff1a;设备与系统的日志和安全告警信息流量数据&#xff1a;网络流量数据、包括netflow数据和全流量镜像数据支持数据&#xff1a;资产信息、账号信息、漏…

springboot网站开发如何配置log4j日志插件

springboot网站开发如何配置log4j日志插件&#xff01;为了便于服务器等环境下的错误情况的排查根源&#xff0c;还是很有必要使用日志插件的&#xff0c;它可以记录下我们提前埋下的锚点信息。 在遇到故障&#xff0c;查看这些锚点记录的日志信息&#xff0c;可以快速高效的解…

低压MOS在无人机上的应用-REASUNOS瑞森半导体

一、前言 无人机的结构由机身、动力系统、飞行控制系统、链路系统、任务载荷等几个方面组成的。 无人机动力系统中的电机&#xff0c;俗称“马达”&#xff0c;是无人机的动力来源&#xff0c;无人机通过改变电机的转速来改变无人机的飞行状态。即改变每个电机的速度&#xf…

Uni App中遇到的跨域问题

通过与多年开发经验的h5前端沟通后&#xff0c;可以对某些事情更加明确&#xff0c;才此期间&#xff0c;会和后端、运维同学产生密不可分的交集&#xff0c;成了谁来改的问题。 明确&#xff1a;跨域99%由后台来配置&#xff0c;如果在本地开发&#xff0c;可以手动配置&…