合集:.NET Core多线程温故知新

去年换工作时系统复习了一下.NET Core多线程相关专题,学习了一线码农老哥的《.NET 5多线程编程实战》课程,我将复习的知识进行了总结形成本专题。

本篇,我们来继续复习一下多线程性能问题的相关知识点,预计阅读时间10分钟。

首先,我们可以明确一下,多线程场景下的常见问题一般为:高CPU占用

一、CPU暴高问题

基本认知

CPU暴高大部分情况下都是线程打暴的!

暴高案例

(1)错误地使用List导致的CPU暴高

常见于偶发性CPU暴高案例中,比如使用了List.Insert(0, item) 时在大数据量下(比如20w+)时间复杂度很大 + 扩容机制,性能很差!一般可能是由模糊查询导致的查了大量DB数据出来组装,因此只会在大数据量时才会偶发。

(2)错误地使用String的拼接导致的CPU暴高

大量错误的大字符串(>85K的都会进LOH)拼接导致LOH频繁触发GC导致CPU暴高。建议使用StringBuilder来重构,但要设置一个合适的初始容量Capacity从而避免频繁对象申请和内存复制。

(3)非线程安全的Dictionary导致的CPU暴高

在多线程环境下使用非线程安全的Dictionary.Contains(key)时导致了在内部实现方法FindEntry(key)时出现了死循环(Entry结构体的next指针指向了自己,由于其他线程也正在Insert、Remove、Update等操作),然后多线程环境下可能有多个死循环一起把CPU打暴了!建议使用线程安全的ConcurrentDictionary结构

(4)lock convoy(锁护送)导致的CPU暴高

在多线程环境下频繁的上下文切换导致,比如每个线程被分配了30ms时间片,但只执行了5ms就被卡主了,即每个请求都有一个lock锁。之前Edison所在的Y公司项目中的JSON-RPC的PreRequest就是这种情况。建议使用批量操作,降低串行化的 lock 个数,不要去玩锁内卷。

(5)应用服务器错误地配置32位导致的CPU暴高

多线程环境下某个方法读取了大量数据(50w+)导致了内存不够用进而引发GC频繁回收进而导致CPU暴高。这常常发生部署在IIS上的.NET Framework Web应用程序:

  • 32bit最高只能吃4G内存;
  • 32bit的临时代(Gen0+Gen1)大概只有不到100M的内存空间;
  • 在IIS服务器模式下,GC会临时征用托管线程充当GC回收线程。

快速解决:将IIS的应用程序域 配置中的 “启用32bit应用程序” 改成False

二、一些实际案例

案例背景

在Edison的前任Y公司,我们做了一些性能优化的措施,提高了系统的稳定性。这里假设之前的系统(大单体)域名为 cj.wzy.cn,每天平均UV(独立用户数) 10000~15000个,平均每天PV(页面浏览数)大概20000~25000个,实时用户数UV(高峰期)800~1000个。虽然这个数值并不高,但是对于这个已经运行了7年多的大单体老系统(.NET 4.5的大Shi山)而言,已经是线上很不稳定了,经常可以看到客服发来的客户抱怨的ticket。

优化内容

(1)优化了一堆年久失修的基础组件

未优化之前存在的问题:

  • jsonrpc的全局PreRequest方法中存在大量 lock convoy (锁护送) 导致线程频繁的上下文切换

    • 比如:每个线程被分配了30ms时间片,但只执行了5ms就被卡主了,即每个请求都有一个lock锁

  • 封装的LocalMemoryCache类基于ReaderWriterLocakSlim对本身就是线程安全的MemoryCache类做线程安全控制

    • 用户态自旋 => 用户态 转 内核态 => 造成CPU压力升高

  • 团队以前自己封装的一个 KafkaHelper 的 Send 方法中加锁范围过大导致等待时间较长

  • ......

(2)优化了一堆慢SQL

未优化之前存在的问题:随着数据量的不断增加,老业务的SQL脚本包含了很多聚合函数、临时表操作 以及 未命中索引的查询条件,解决办法就是SQL优化,对比执行计划 + DBA Review后上线。

(3)优化了IIS的基本配置

未优化之前的问题:部分应用服务器特别是自建的文件服务,经常发生由于配置了“启用32位应用程序”导致的内存不够(因为32位应用最大可用4G内存)用进而引发GC频繁回收进而导致CPU暴高。

解决办法就是将启用32位应用设为False,然后参考一些IIS配置的最佳实践去做了一遍。

当然,根本解法还是去分析自建文件服务中耗内存的地方去优化代码。不过由于当时的物理服务器都是128G的内存且业务场景中也确实存在上传大文件的需求,因此耗内存的地方也暂时搁置去解决了。

(4)优化了滥用Parallel并行库的接口

未优化之前存在的问题:部分耗时较长的Job不加限制的使用 Parallel.ForEach 等方法造成所有CPU Core都被占用并持续数秒,造成CPU>=90%优化后增加了统一的设置的MaxParallelOptions,修复所有滥用的地方传递进去,默认只会用到CPU内核数量的一半。

(5)新增了一台DB服务器分摊压力

有一次因为XXXXXReadDB少了一台,本来是1台写库,2台读库,突然少了一台,导致XXXXXReadDB CPU暴高,应用程序段的DB连接超时严重进而造成延时较多,请求对接,应用程序频繁挂掉。因此后续DBA新增了一台读库,组成1主3从的配置,应用程序段通过切分 合同查询 的业务查询 到 XXXXXReadDB04,所有Job的查询都走XXXXXReadDB03,将流量分摊到不同的读库,保证核心用户的查询流量的可用性。

(6)新增了两台应用服务器分流压力

2021年开始研发中心内部各团队应用开始疯狂调用该系统接口,每分钟请求量达到了1500+左右,造成了原本只是对外部客户服务的应用服务器压力增大,因此新增了两台应用服务器将所有其他团队的内部应用的service请求流量切分到独立的三台服务器上,内外部客户的流量分开,优先保证外部客户的可用性。

未完成的事情

这一切的根因都是因为这七年来这个系统所在的团队单纯拼命的干业务迭代,往原本设计就不佳的大单体系统中堆了太多的屎山,造成了太多的技术债并未及时地去偿还。我们也原本想极力推荐将其拆分后升级到.NET Core或最新的.NET技术,基于.NET Core + 容器化技术 + 开源项目去做较低成本的升级改造,可是计划赶不上变化,当公司从阿什么味的公司找来一高P来做技术总监之后,研发中心所有的Team Leader基本都换成了阿什么味背景的或者靠近阿什么味领导的。此后,所有的计划都是围绕着Java从0到1花费大量成本重构整个大系统来进行,用他们的话来说就是降本增效只能靠Java而不是.NET。公司里整个Java圈子的高级开发者对.NET的认识也还是停留在10年前,我们的发声已变得微不足道,政治正确才是明哲保身的唯一出路。

在这里,Edison还是祝愿Y公司能够越走越好。

参考资料

一线码农,腾讯课堂《.NET 5多线程编程实战

不明作者,《Task调度与await》

作者:周旭龙

出处:https://edisonchou.cnblogs.com

本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文链接。

.NET Core多线 (5) 常见性能问题的更多相关文章

  1. 常见性能优化策略的总结 good

    阅读目录 代码 数据库 缓存 异步 NoSQL JVM调优 多线程与分布式 度量系统(监控.报警.服务依赖管理) 案例一:商家与控制区关系的刷新job 案例二:POI缓存设计与实现 案例三:业务运营后 ...

  2. ASP.NET Core之跨平台的实时性能监控(2.健康检查)

    前言 上篇我们讲了如何使用App Metrics 做一个简单的APM监控,最后提到过健康检查这个东西. 这篇主要就是讲解健康检查的内容. 没看过上篇的,请移步:ASP.NET Core之跨平台的实时性 ...

  3. 健康检查NET Core之跨平台的实时性能监控

    ASP.NET Core之跨平台的实时性能监控(2.健康检查)   前言 上篇我们讲了如何使用App Metrics 做一个简单的APM监控,最后提到过健康检查这个东西. 这篇主要就是讲解健康检查的内 ...

  4. 使用Django.core.cache操作Memcached导致性能不稳定的分析过程

    使用Django.core.cache操作Memcached导致性能不稳定的分析过程 最近测试一项目,用到了Nginx缓存服务,那可真是快啊!2Gb带宽都轻易耗尽. 不过Api接口无法简单使用Ngin ...

  5. Unity游戏项目常见性能问题

    Unity技术支持团队经常会对有需求的客户公司项目进行游戏项目性能审查与优化,在我们碰到过的各种项目相关的问题中也有很多比较共同的方面,这里我们罗列了一些常见的问题并进行了归类,开发者朋友们可以参考下 ...

  6. ASP.NET Core 之跨平台的实时性能监控

    前言 前面我们聊了一下一个应用程序 应该监控的8个关键位置. . 嗯..地址如下: 应用程序的8个关键性能指标以及测量方法 最后卖了个小关子,是关于如何监控ASP.NET Core的. 今天我们就来讲 ...

  7. ios 常见性能优化

    1. 用ARC管理内存 2. 在正确的地方使用reuseIdentifier 3. 尽可能使Views透明 4. 避免庞大的XIB 5. 不要block主线程 6. 在Image Views中调整图片 ...

  8. .NET Core 成都线下面基会拉开序幕

    2017年07月29日下午,由 .NET China Foundation 成都小组组织的 .NET Core 成都地区线下技术交流会在成都成华区某茶楼成功举行,这也是成都地区 .NET Core 非 ...

  9. EF Core 使用编译查询提高性能

    今天,我将向您展示这些EF Core中一个很酷的功能,通过使用显式编译的查询,提高查询性能. 不过在介绍具体内容之前,需要说明一点,EF Core已经对表达式的编译使用了缓存:当您的代码需要重用以前执 ...

  10. async/await 的基本实现和 .NET Core 2.1 中相关性能提升

    前言 这篇文章的开头,笔者想多说两句,不过也是为了以后再也不多嘴这样的话. 在日常工作中,笔者接触得最多的开发工作仍然是在 .NET Core 平台上,当然因为团队领导的开放性和团队风格的多样性(这和 ...

随机推荐

  1. 2021-11-27:给定一个数组arr,长度为N,做出一个结构,可以高效的做如下的查询: 1) int querySum(L,R) : 查询arr[L...R]上的累加和; 2) int query

    2021-11-27:给定一个数组arr,长度为N,做出一个结构,可以高效的做如下的查询: int querySum(L,R) : 查询arr[L-R]上的累加和; int queryAim(L,R) ...

  2. 新出的Alist云盘视频助手,真的香还是假的香?

    作为某云盘的重度使用者和长期受虐者,前段时间无意中看到一款新出的网盘工具,叫Alist云盘视频助手,不同于一般的网盘工具,它不是面向网盘数据下载的,它面向的是网盘视频文件隐私保护,大白话就是:加密网盘 ...

  3. CogSci 2017-Learning to reinforcement learn

    Key 元学习系统(监督+从属)扩展于RL设置 LSTM用强化学习算法进行训练,可以使agent获得一定的学习适应能力 解决的主要问题 DRL受限于特定的领域 DRL训练需要大量的数据 作者参考了Ho ...

  4. hadoop 2.7.7 ERROR datanode.DataNode: BlockSender.sendChunks() exception: java.io.IOException: 你的主机中的软件中止了一个已建立的连接。

    最近在测试Hbase在windows上的单机版的功能. 版本:hadoop 2.7.7  hbase 2.0.0 错误: ERROR datanode.DataNode: BlockSender.se ...

  5. Python日期带时区转换工具类总结

    目录 1.背景 2. 遇到的坑 3. 一些小案例 3.1 当前日期.日期时间.UTC日期时间 3.2 昨天.昨天UTC日期.昨天现在这个时间点的时间戳 3.3 日期转时间戳 3.4 时间戳转日期 3. ...

  6. Galaxy Release 20.05 发布,新增多项可视化体验

    Galaxy Project(https://galaxyproject.org/)是在云计算背景下诞生的一个生物信息学可视化分析开源项目. 该项目由美国国家科学基金会(NSF).美国国家人类基因组研 ...

  7. python利用subprocess执行shell命令

    subprocess以及常用的封装函数 运行python的时候,我们都是在创建并运行一个进程.像Linux进程那样,一个进程可以fork一个子进程,并让这个子进程exec另外一个程序.在Python中 ...

  8. Rust的语句与表达式

    Rust 语句与表达式 Rust 中的语法分为两大类: 语句 (statement) 和表达式 (Expression). 语句:指的是要执行的一些操作和产生副作用的表达式. 表达式:主要用于计算求值 ...

  9. youtobe深度学习推荐系统-学习笔记

    简介 前言 本文是Deep Neural Networks for YouTube Recommendations 论文的学习笔记.淘宝的召回模型曾经使用过这篇论文里面的方案,后续淘宝召回模型升级到了 ...

  10. SpringBoot之MVC配置(WebMvcConfigurer详解)

    一:基本介绍 Spring MVC是一种常用的Java Web框架,它提供了一种基于MVC模式的开发方式,可以方便地实现Web应用程序.在Spring MVC中,WebMvcConfigurer是一种 ...