首页 > 其他分享 >记一次并发导致的事故

记一次并发导致的事故

时间:2024-09-25 11:25:54浏览次数:8  
标签:导致 事故 23 18 09 des1 2024 并发 done

记一次并发导致的事故

简化业务逻辑如下:

  1. 创建一批收件人;
  2. 点击发送按钮时发送邮件给这批发件人;

现象是有一批人收到了两封邮件, 还有少部分人收到了 3 封.

原因分析

每次触发发送任务都有一个唯一的 traceid, 记录日志时会带上 traceid, 将日志按 traceid 分组获取第一条和最后一条记录时间, 绘制甘特图如下:

编写脚本绘制甘特图

logfile="logs/watermark_logger.log"
keyword='lock watermark_mail'
ids=$(grep "$keyword" "$logfile" | awk '{print $5}' | sort | uniq)

function format_date() {
    ret=$(echo "$*" | awk '{print $1,$2}' | awk -F ',' '{printf $1}')
    echo $ret
}

for uuid in $ids; do
    first_line=$(grep "$uuid" "$logfile" | head -n 1)
    last_line=$(grep "$uuid" "$logfile" | tail -n 1)
    start=$(format_date $first_line)
    end=$(format_date $last_line)

    name=$(echo ${start} | awk '{print $2}' | tr -d ':')-$(echo ${end} | awk '{print $2}' | tr -d ':')
    # mermaid gant
    echo ${name} :done, des1, ${start},${end}
done

使用 mermeid 将输出渲染为甘特图

gantt
dateFormat  YYYY-MM-DD HH:mm:ss
axisFormat  %Y-%m-%d %H:%M:%S
title       发送开始时间-结束时间
excludes    weekends

232910-233227 :done, des1, 2024-09-18 23:29:10,2024-09-18 23:32:27
232910-233227 :done, des1, 2024-09-18 23:29:10,2024-09-18 23:32:27
233234-233330 :done, des1, 2024-09-18 23:32:34,2024-09-18 23:33:30
233339-233438 :done, des1, 2024-09-18 23:33:39,2024-09-18 23:34:38
233445-233543 :done, des1, 2024-09-18 23:34:45,2024-09-18 23:35:43
233558-233655 :done, des1, 2024-09-18 23:35:58,2024-09-18 23:36:55
233711-233807 :done, des1, 2024-09-18 23:37:11,2024-09-18 23:38:07
233819-233916 :done, des1, 2024-09-18 23:38:19,2024-09-18 23:39:16
234023-234121 :done, des1, 2024-09-18 23:40:23,2024-09-18 23:41:21
234140-234238 :done, des1, 2024-09-18 23:41:40,2024-09-18 23:42:38
234246-234344 :done, des1, 2024-09-18 23:42:46,2024-09-18 23:43:44
234353-234450 :done, des1, 2024-09-18 23:43:53,2024-09-18 23:44:50
234457-234623 :done, des1, 2024-09-18 23:44:57,2024-09-18 23:46:23
234637-234732 :done, des1, 2024-09-18 23:46:37,2024-09-18 23:47:32
234742-234839 :done, des1, 2024-09-18 23:47:42,2024-09-18 23:48:39
234844-234942 :done, des1, 2024-09-18 23:48:44,2024-09-18 23:49:42
234956-235054 :done, des1, 2024-09-18 23:49:56,2024-09-18 23:50:54
235113-235209 :done, des1, 2024-09-18 23:51:13,2024-09-18 23:52:09
235214-235309 :done, des1, 2024-09-18 23:52:14,2024-09-18 23:53:09
235319-235423 :done, des1, 2024-09-18 23:53:19,2024-09-18 23:54:23
235503-235558 :done, des1, 2024-09-18 23:55:03,2024-09-18 23:55:58
235604-235749 :done, des1, 2024-09-18 23:56:04,2024-09-18 23:57:49
235605-235749 :done, des1, 2024-09-18 23:56:05,2024-09-18 23:57:49
235759-235920 :done, des1, 2024-09-18 23:57:59,2024-09-18 23:59:20
235846-000115 :done, des1, 2024-09-18 23:58:46,2024-09-19 00:01:15
235847-000107 :done, des1, 2024-09-18 23:58:47,2024-09-19 00:01:07
235929-000146 :done, des1, 2024-09-18 23:59:29,2024-09-19 00:01:46
000110-000331 :done, des1, 2024-09-19 00:01:10,2024-09-19 00:03:31
000126-000343 :done, des1, 2024-09-19 00:01:26,2024-09-19 00:03:43
000152-000400 :done, des1, 2024-09-19 00:01:52,2024-09-19 00:04:00
000343-000513 :done, des1, 2024-09-19 00:03:43,2024-09-19 00:05:13
000404-000526 :done, des1, 2024-09-19 00:04:04,2024-09-19 00:05:26
000531-000620 :done, des1, 2024-09-19 00:05:31,2024-09-19 00:06:20
000634-000723 :done, des1, 2024-09-19 00:06:34,2024-09-19 00:07:23
001247-001353 :done, des1, 2024-09-19 00:12:47,2024-09-19 00:13:53
gantt dateFormat YYYY-MM-DD HH:mm:ss axisFormat %Y-%m-%d %H:%M:%S title 发送开始时间-结束时间 excludes weekends 232910-233227 :crit, des1, 2024-09-18 23:29:10,2024-09-18 23:32:27 232910-233227 :crit, des1, 2024-09-18 23:29:10,2024-09-18 23:32:27 233234-233330 :done, des1, 2024-09-18 23:32:34,2024-09-18 23:33:30 233339-233438 :done, des1, 2024-09-18 23:33:39,2024-09-18 23:34:38 233445-233543 :done, des1, 2024-09-18 23:34:45,2024-09-18 23:35:43 233558-233655 :done, des1, 2024-09-18 23:35:58,2024-09-18 23:36:55 233711-233807 :done, des1, 2024-09-18 23:37:11,2024-09-18 23:38:07 233819-233916 :done, des1, 2024-09-18 23:38:19,2024-09-18 23:39:16 234023-234121 :done, des1, 2024-09-18 23:40:23,2024-09-18 23:41:21 234140-234238 :done, des1, 2024-09-18 23:41:40,2024-09-18 23:42:38 234246-234344 :done, des1, 2024-09-18 23:42:46,2024-09-18 23:43:44 234353-234450 :done, des1, 2024-09-18 23:43:53,2024-09-18 23:44:50 234457-234623 :done, des1, 2024-09-18 23:44:57,2024-09-18 23:46:23 234637-234732 :done, des1, 2024-09-18 23:46:37,2024-09-18 23:47:32 234742-234839 :done, des1, 2024-09-18 23:47:42,2024-09-18 23:48:39 234844-234942 :done, des1, 2024-09-18 23:48:44,2024-09-18 23:49:42 234956-235054 :done, des1, 2024-09-18 23:49:56,2024-09-18 23:50:54 235113-235209 :done, des1, 2024-09-18 23:51:13,2024-09-18 23:52:09 235214-235309 :done, des1, 2024-09-18 23:52:14,2024-09-18 23:53:09 235319-235423 :done, des1, 2024-09-18 23:53:19,2024-09-18 23:54:23 235503-235558 :done, des1, 2024-09-18 23:55:03,2024-09-18 23:55:58 235604-235749 :crit, des1, 2024-09-18 23:56:04,2024-09-18 23:57:49 235605-235749 :crit, des1, 2024-09-18 23:56:05,2024-09-18 23:57:49 235759-235920 :crit, des1, 2024-09-18 23:57:59,2024-09-18 23:59:20 235846-000115 :crit, des1, 2024-09-18 23:58:46,2024-09-19 00:01:15 235847-000107 :crit, des1, 2024-09-18 23:58:47,2024-09-19 00:01:07 235929-000146 :crit, des1, 2024-09-18 23:59:29,2024-09-19 00:01:46 000110-000331 :crit, des1, 2024-09-19 00:01:10,2024-09-19 00:03:31 000126-000343 :crit, des1, 2024-09-19 00:01:26,2024-09-19 00:03:43 000152-000400 :crit, des1, 2024-09-19 00:01:52,2024-09-19 00:04:00 000343-000513 :crit, des1, 2024-09-19 00:03:43,2024-09-19 00:05:13 000404-000526 :crit, des1, 2024-09-19 00:04:04,2024-09-19 00:05:26 000531-000620 :done, des1, 2024-09-19 00:05:31,2024-09-19 00:06:20 000634-000723 :done, des1, 2024-09-19 00:06:34,2024-09-19 00:07:23 001247-001353 :done, des1, 2024-09-19 00:12:47,2024-09-19 00:13:53

从图中可以看到两处异常(标红处).

第一个异常点, 上下两个 task 在时间上重合了, 说明次处发生了并发操作.

并发原因如下:

  • 查询状态和更改状态不在一个原子操作中;

修复方案:

  • 更改任务发送状态(加锁)时采用原子操作: 具体操作为, 使用update task set status=1 where status!=1 and id=***执行加锁动作, 根据 affected rows 做进一步操作;

第二个异常点, 下面的任务在上个任务结束之前就开始了.

原因如下:

两个任务同时执行, 第一个任务结束时进行解锁, 此时第二个任务仍在运行, 第二个任务结束时又进行了解锁操作, 由此形成了恶性循环.

修复方案:

  • 加锁时同时记录拥有者信息, 解锁时做判断

总结

此时事故遇到的是锁方案中常见的问题:

  1. 原子加锁;
  2. 解锁操作者必须和加锁操作者相同;
    关键操作需严格按照锁理论进行实现.
    另外, 甘特图在分析并发问题时是一个不错的选择.

标签:导致,事故,23,18,09,des1,2024,并发,done
From: https://www.cnblogs.com/aloe-n/p/18430950

相关文章

  • # 高可用的并发解决方案nginx+keepalived(三)
    高可用的并发解决方案nginx+keepalived(三)一、Nginx搭建图片服务器针对任何站点,几乎都要访问图片,而一个网页里面几乎有好些张图片,这时候会占据大量tomcat连接,造成大量并发,我们可以通过Nginx配置直接访问硬盘里的图片,绕开tomcat。1、在CentOS7服务器上,创建/usr/local/im......
  • 并发处理的利器:深入探讨锁分离设计+6大分离场景(高并发篇)
    锁分离设计的本质在于将对共享资源的访问操作根据其类型或性质区分开来,并为每种操作提供独立的锁。这种设计背景通常源于对高并发系统的需求,其中多个线程或进程需要频繁地对共享资源进行读写或其他操作。在传统的锁机制中,所有操作都可能使用同一把锁,这在高并发环境下会导致严重的......
  • 有问题的达梦客户端导致应用crash
    【问题描述】userapp03su-smbsuserbak安装包有问题的,不带bak包是正确的573Mdamengbak.tgz376Mdameng.tgz /var/log/messages一直报错$DM_HOME/bin/libdmdpc.soerror导致/var/log/messages不断写信息,直到/var文件系统写满Aug2503:40:03userapp03systemd-......
  • 【Vue】【uni-app】【小程序】多层嵌套方法导致this指向出错:解析 JSON 失败: TypeErro
    项目场景:在使用vue+uni-app开发微信小程序的时候,调试报错:解析JSON失败:TypeError:Cannotreadproperty‘push’ofundefined问题描述报错如下:以下是出问题的代码:data(){return{fileLists:[],}}//上传文......
  • 【Java】并发编程的艺术:悲观锁、乐观锁与死锁管理
    目录一、乐观锁和悲观锁二、ReadWriteLock三、StampedLock四、Semaphore五、死锁的条件六、如何发现死锁七、如何避免死锁一、乐观锁和悲观锁        悲观锁(PessimisticLocking)具有强烈的独占和排他特性。它指的是对数据被外界修改持保守态度。因此,在整......
  • 并发编程工具集——Fork/Join-上(三十六)
    简述前面提到的线程池、Future、CompletableFuture和CompletionService,这些工具类都是在帮助我们站在任务的视角来解决并发问题,而不是让我们纠缠在线程之间如何协作的细节上(比如线程之间如何实现等待、通知等)。精髓:对于简单的并行任务,你可以通过“线程池+Future”的方案......
  • Java——图片文件位于 bin 目录下,下载新图片会导致应用程序重启
    当应用程序在运行时需要加载图片文件时,如果图片文件位于bin目录下,下载新图片会导致应用程序重启,这是因为Java应用程序在加载资源时通常会遵循以下机制:类加载器:Java应用程序使用类加载器来加载类文件和资源。资源加载:类加载器会根据类路径(classpath)来查找资源,而bin目录......
  • 一文夯实并发编程的理论基础
    JMM内存模型定义java内存模型(即javaMemoryModel,简称JMM),不存在的东西,是一个概念,约定主要分成两部分来看,一部分叫做主内存,另一部分叫做工作内存。java当中的共享变量;都放在主内存当中,如类的成员变量(实例变量),还有静态的成员变量(类变量),都是存储在主内存中的。每一个线程都可以......
  • 一文夯实并发编程的理论基础
    JMM内存模型定义java内存模型(即javaMemoryModel,简称JMM),不存在的东西,是一个概念,约定主要分成两部分来看,一部分叫做主内存,另一部分叫做工作内存。java当中的共享变量;都放在主内存当中,如类的成员变量(实例变量),还有静态的成员变量(类变量),都是存储在主内存中的。每一个线程都可......
  • 线程同步:锁,条件变量,并发
    1)锁mutex2)条件变量头文件<condiction_variable>condition_variablecv;cv.wait(_lock,谓语)//使用谓语检查是否满足唤醒条件,防止假唤醒usingnamespacestd; mutex_mutex; condition_variablecv; //condition_variablecv2; intnum=1; threadth1([&](){ int......