1. 勘探现场
    既然说 CPU > 90%,那我就来验证一下是否真的如此?

0:359> !syncblk
Index SyncBlock MonitorHeld Recursion Owning Thread Info  SyncBlock Owner53 000000324cafdf68          498         0 0000000000000000     none    0000002e1a2949b0 System.Object
-----------------------------
Total           1025
CCW             3
RCW             4
ComClassFactory 0
Free            620

我去,这卦看起来很奇怪, MonitorHeld=498 是什么鬼??? 教科书上都说: owner + 1 , waiter + 2,所以你肉眼看到的总会是一个奇数,那偶数又是个啥意思? 查了下神奇的 StackOverflow,大概总结成如下两种情况:

内存损坏

这种情况比中彩还难,我也坚信不会走这种天罗运。。。
lock convoy (锁护送)
前段时间我分享了一篇真实案例: 记一次 .NET 某旅行社Web站 CPU爆高分析 ,它就是因为 lock convoy 造成的 CPU 爆高,果然世界真小,又遇到了。。。为了方便大家理解,我还是把那张图贴上吧。

看完这张图你应该就明白了,一个线程在时间片内频繁的争抢锁,所以就很容易的出现一个持有锁的线程刚退出,那些等待锁的线程此时还没有一个真正的持有锁,刚好抓到的dump就是这么一个时间差,换句话说,当前的 498 全部是 waiter 线程的计数,也就是 249 个 waiter 线程,接下来就可以去验证了,把所有线程的线程栈调出来,再检索下 Monitor.Enter 关键词。

从图中可以看出当前有 220 个线程正卡在 Monitor.Enter 处,貌似丢了29个,不管了,反正大量线程卡住就对了,从堆栈上看貌似是在 xxx.Global.PreProcess方法中设置上下文后卡住的,为了满足好奇心,我就把问题代码给导出来。
3. 查看问题代码
还是用老命令 !ip2md + !savemodule 。


0:359> !ip2md 00007ff81ae98854
MethodDesc:   00007ff819649fa0
Method Name:  xxx.Global.PreProcess(xxx.JsonRequest, System.Object)
Class:        00007ff81966bdf8
MethodTable:  00007ff81964a078
mdToken:      0000000006000051
Module:       00007ff819649768
IsJitted:     yes
CodeAddr:     00007ff81ae98430
Transparency: Critical
0:359> !savemodule 00007ff819649768 E:\dumps\PreProcess.dll
3 sections in file
section 0 - VA=2000, VASize=b6dc, FileAddr=200, FileSize=b800
section 1 - VA=e000, VASize=3d0, FileAddr=ba00, FileSize=400
section 2 - VA=10000, VASize=c, FileAddr=be00, FileSize=200

然后用 ILSpy 打开问题代码,截图如下:

尼玛,果然每个 DataContext.SetContextItem() 方法中都有一个 lock 锁,完美命中 lock convoy。
4. 真的就这样结束了吗?
本来准备汇报了,但想着500多个线程栈都调出来了,闲着也是闲着,干脆扫扫看吧,结果我去,意外发现有 134 个线程卡在 ReaderWriterLockSlim.TryEnterReadLockCore 处,如下图所示:

从名字上可以看出,这是一个优化版的读写锁: ReaderWriterLockSlim,为啥有 138 个线程都卡在这里呢? 真的很好奇,再次导出问题。

internal class LocalMemoryCache : ICache
{private string CACHE_LOCKER_PREFIX = "xx_xx_";private static readonly NamedReaderWriterLocker _namedRwlocker = new NamedReaderWriterLocker();public T GetWithCache<T>(string cacheKey, Func<T> getter, int cacheTimeSecond, bool absoluteExpiration = true) where T : class{T val = null;ReaderWriterLockSlim @lock = _namedRwlocker.GetLock(cacheKey);try{@lock.EnterReadLock();val = (MemoryCache.Default.Get(cacheKey) as T);if (val != null){return val;}}finally{@lock.ExitReadLock();}try{@lock.EnterWriteLock();val = (MemoryCache.Default.Get(cacheKey) as T);if (val != null){return val;}val = getter();CacheItemPolicy cacheItemPolicy = new CacheItemPolicy();if (absoluteExpiration){cacheItemPolicy.AbsoluteExpiration = new DateTimeOffset(DateTime.Now.AddSeconds(cacheTimeSecond));}else{cacheItemPolicy.SlidingExpiration = TimeSpan.FromSeconds(cacheTimeSecond);}if (val != null){MemoryCache.Default.Set(cacheKey, val, cacheItemPolicy);}return val;}finally{@lock.ExitWriteLock();}}

看了下上面的代码大概想实现一个对 MemoryCache 的 GetOrAdd 操作,而且貌似为了安全起见,每一个 cachekey 都配了一个 ReaderWriterLockSlim,这逻辑就有点奇葩了,毕竟 MemoryCache 本身就带了实现此逻辑的线程安全方法,比如:


public class MemoryCache : ObjectCache, IEnumerable, IDisposable
{public override object AddOrGetExisting(string key, object value, DateTimeOffset absoluteExpiration, string regionName = null){if (regionName != null){throw new NotSupportedException(R.RegionName_not_supported);}CacheItemPolicy cacheItemPolicy = new CacheItemPolicy();cacheItemPolicy.AbsoluteExpiration = absoluteExpiration;return AddOrGetExistingInternal(key, value, cacheItemPolicy);}
}
  1. 用 ReaderWriterLockSlim 有什么问题吗?
    哈哈,肯定有很多朋友这么问?

    .NET 某电商交易平台Web站 CPU爆高分析相关推荐

    1. 记一次 .NET 某电商交易平台Web站 CPU爆高分析

      一:背景 1. 讲故事 已经连续写了几篇关于内存暴涨的真实案例,有点麻木了,这篇换个口味,分享一个 CPU爆高 的案例,前段时间有位朋友在 wx 上找到我,说他的一个老项目经常收到 CPU > ...

    2. 买卖汽车电商交易平台、选车社区论坛、买新车、二手车交易平台、移动端汽车电商平台、web端汽车运营管理平台、供应商管理、营销商管理、新车交易管理、调车管理、汽车顾问、车库管理、出入库管理、Axure原型

      买卖汽车电商交易平台.选车社区论坛.买新车.二手车交易平台.移动端汽车电商平台.web端汽车运营管理平台.供应商管理.营销商管理.新车交易管理.调车管理.汽车顾问.车库管理.出入库管理.Axure原型 ...

    3. 跨境电商自建站后台系统原型rp_Shoptago---跨境电商平台又一个新选择

      在去年邀请2000卖家参与内测的跨境电商自建站平台Shoptago,现在用户数已经达到了3850+,成绩可谓,我们也能在各大媒体看到Shoptago相关的新功能上线公告,那么在这段时间里,Shopta ...

    4. web电商系统、电商平台WEB端交互原型模板、用户中心、会员中心、优惠券、积分、互动社区、运营推广、内容推荐、商品展示、订单流程、订单管理、售后及服务、Axure原型、rp原型、电商原型、商城系统原型

      作品介绍:web电商系统.电商平台WEB端交互原型模板.用户中心.会员中心.优惠券.积分.互动社区.运营推广.内容推荐.商品展示.订单流程.订单管理.售后及服务等完整的电商体系功能架构和业务流程 Ax ...

    5. 构建船舶航海用品B2B电商交易平台,健壮产业生态

      电子商务正以一种巨大的力量影响着传统企业,海运业也不例外.根据ShipParts.com大数据显示在过去的一年中,来自国外的订单及售后配件需求呈现出爆发式的增长,电子商务正以不可阻挡的势头改变着行业生 ...

    6. 跨境电商商城独立站_是什么?

      跨境电商商城独立站是一种在线零售平台,它专门为跨境电商出口企业搭建的独立网站,独立站通常而言是源码商城.这些网站提供的服务包括商品展示.在线交易.物流跟踪和支付等功能.在跨境电商行业中,这种独立站的重 ...

    7. 电商网站Web自动化测试实战( 编写京东搜索脚本python+selenium框架)

      电商网站Web自动化测试实战( 编写京东搜索脚本) 1,打开京东页 京东首页地址:https://www.jd.com/,故进入京东首页如下: 2,打开浏览器开发者模式 定位元素前需先打开浏览器开发者 ...

    8. 简要讨论python对于1688的关键字搜索、商品详情在电商运营大数据分析、电商选品、竞品分析上的帮助

      目录 1688商品详情简要描述 1688商品详情请求URL 请求方式 参数 关键信息 淘宝天猫以及1688.京东.拼多多平台不断地在改变人们的消费习惯,人们从传统购物模式不断走向线上模式,作为电商行业 ...

    9. 利用python分析电商_基于Word2Vec+SVM对电商的评论数据进行情感分析

      Word2Vec-sentiment 基于Word2Vec+SVM对电商的评论数据进行情感分析 首先是利用word2vec对正负评论数据进行词向量训练,然后利用SVM分类器对语料进行分类,具体的过程如 ...

    最新文章

    1. linux上安装mysql,tomcat,jdk
    2. 真正厉害的 AI,从来不走「捷径」
    3. Exchange Server 2013 规划系列之日志容量规划、数据库容量规划
    4. 异常详细信息: System.Web.HttpException: 请求在此上下文中不可用
    5. Pytyon3中实现十进制转不同进制
    6. eclipse / 绑定 OpenJDK 1.8 Java 源码的方法
    7. Go知识点:slice、map、func、struct、method、interface、channel、goroutine
    8. Android.text.TextUtils类
    9. chart.js 饼图显示百分比_Excel制作华夫饼图,其实很简单
    10. 【NLPCC 2020】Call for Participation: Shared Tasks in NLPCC 2020
    11. Windows下vim方式操作软件+Gvim使用
    12. 程序员必备的25个好网站汇总
    13. goap git上的v sploreg/goap
    14. 程序员凌晨3点不回家
    15. UFO-ViT:没有Softmax的高性能线性视觉Transformer
    16. matplotlib之pyplot教程
    17. 大数据面试必问点与模拟笔试题
    18. ubuntu ufw 防火墙使用
    19. Android JNI调用概要
    20. 光纤激光器原理与特性详解

    热门文章

    1. java memorystream 包_存储在MemoryStream中的裁剪图像中心
    2. sqlyog如何设置.时提示字段名_Spring boot 中使用 Tomcat时 用户名 密码如何设置呢?...
    3. Ajax(三)——XMLHttpRequst定义连接发送及其他操作
    4. 计算机应用基础文章 茶的功效,茶文化下的计算机应用基础课程改革-计算机应用论文-计算机论文.docx...
    5. linux 打zip gz tar,linux把文件压缩成.tar.gz的命令 | PT Ubuntu Blog
    6. 通过系统进程查找sql语句
    7. Backblaze发布2016年2季度硬盘可靠性报告
    8. OSGi 的核心配置、动态化及问题
    9. 题目7 街区最短路径问题
    10. java.lang.IncompatibleClassChangeError: