惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

博客园 - 司徒正美
大猫的无限游戏
大猫的无限游戏
腾讯CDC
J
Java Code Geeks
博客园 - 【当耐特】
Microsoft Azure Blog
Microsoft Azure Blog
V
Visual Studio Blog
人人都是产品经理
人人都是产品经理
博客园 - Franky
博客园 - 聂微东
阮一峰的网络日志
阮一峰的网络日志
美团技术团队
云风的 BLOG
云风的 BLOG
freeCodeCamp Programming Tutorials: Python, JavaScript, Git & More
U
Unit 42
雷峰网
雷峰网
B
Blog RSS Feed
博客园_首页
量子位
F
Fortinet All Blogs
罗磊的独立博客
H
Hackread – Cybersecurity News, Data Breaches, AI and More
酷 壳 – CoolShell
酷 壳 – CoolShell
C
Check Point Blog

Hsu Yeung 的博客

三圣花市 | Hsu Yeung 的博客 网站支持 Live Photo 图片展示 | Hsu Yeung 的博客 梦 | Hsu Yeung 的博客 周末午餐 | Hsu Yeung 的博客 张家界 | Hsu Yeung 的博客 话剧《寻她芳踪·张爱玲》 | Hsu Yeung 的博客 博客自动生成文章目录 | Hsu Yeung 的博客 灭螂行动! | Hsu Yeung 的博客 张靓颖成都演唱会 | Hsu Yeung 的博客 最近对博客做的一些微调总结 | Hsu Yeung 的博客 Windows 上安装 Lua | Hsu Yeung 的博客 网站支持展示 B 站 iframe 视频 SpringBoot 中使用 RedisTemplate 存取整数值的坑 | Hsu Yeung 的博客 SQL JOIN 中 ON 与 WHERE 的区别 值得记录的一些工作近况 | Hsu Yeung 的博客 周传雄成都演唱会 | Hsu Yeung 的博客 风信子 | Hsu Yeung 的博客 Linux 安装并配置 Nginx | Hsu Yeung 的博客 使用 logrotate 切割 nginx 日志 郁金香土培结果 | Hsu Yeung 的博客 MySQL LEFT JOIN 右表有多条数据但只取最新的一条 | Hsu Yeung 的博客 获取数据库锁等待超时问题 | Hsu Yeung 的博客 从零开始挑选相机 | Hsu Yeung 的博客 郁金香 | Hsu Yeung 的博客 我的第一束花 | Hsu Yeung 的博客 快乐的一周 | Hsu Yeung 的博客 重庆,来了 | Hsu Yeung 的博客 散步 | Hsu Yeung 的博客 Git 工作区、暂存区、版本库之间的关系 | Hsu Yeung 的博客 Collectors.toMap() 操作 value 为 null 的情况
并行操作导致获取数据库连接超时 | Hsu Yeung 的博客
2024-08-04 · via Hsu Yeung 的博客

前段时间晚上突然收到 1300+ 的线上监控告警,点开一看,全是虚拟号码解绑的异常,看异常信息全是获取数据库连接超时,定位了一下代码,是系统里一个解绑虚拟号码的定时任务(UnbindJob)里面抛出的异常,最开始以为是 SQL 有问题,把里面涉及到数据库的 SQL 复制出来拿到控制台去执行,也正常,由于代码是 18 年的时候的老代码了,这个系统也是今年才重新开始启用的,最后一行一行看代码,找可能出现问题的地方。最后发现这个定时任务进行批量解绑是先将所有需要解绑的隐私号数据查询出来,然后再直接用 Paralle.ForEach 来并行执行单个的解绑逻辑(Unbind),而这个 Unbind 方法里面每次都会去读写一次数据库。

由于是公司项目,不方便直接贴源代码,问题代码差不多就是下面这个样子:

public void ExecuteUnbindJob()
{
    var unbindList = GetSecretPhoneNosToUnbind();

    Parallel.ForEach(unbindList, secretPhoneNo =>
    {
        Unbind(secretPhoneNo);
    });
}

private void Unbind(string secretPhoneNo)
{
    // 获取数据库连接
    using (var connection = new SqlConnection(connectionString))
    {
        connection.Open();
        // 执行解绑逻辑
    }
}

想了想,最近暑假也开始了,系统业务量也起来了,每天需要解绑的隐私号码自然也多起来了,之前业务量没这么高,因此直接这样并发操作数据库也没把数据库的连接打满,也就没出现过这个问题,现在数据多起来了(每天需要解绑的隐私号大概 1500 个左右)自然就很容易将数据库连接打满。解决办法的话要么就是修改一下线程池配置的最大线程数,或者是在调用 Paralle.ForEach 时显式设置一下并行度更推荐在使用的时候显式设置并行度,因为修改线程池的话会影响到所有的地方,设置小了影响效率,设置大了依旧会存在数据库连接被打满的可能。

修改的代码也很简单:

public void ExecuteUnbindJob()
{
    var unbindList = GetSecretPhoneNosToUnbind();
    // 设置并行度限制
    var options = new ParallelOptions { MaxDegreeOfParallelism = 10 }; 

    Parallel.ForEach(unbindList, options, secretPhoneNo =>
    {
        Unbind(secretPhoneNo);
    });
}

private void Unbind(string secretPhoneNo)
{
    // 获取数据库连接
    using (var connection = new SqlConnection(connectionString))
    {
        connection.Open();
        // 执行解绑逻辑
    }
}