1.事故背景

在APP访问服务器接口时需要从redis中获取token进行校验,服务器上线后发现一开始可以正常访问,但只要短时间内请求量增长服务则无法响应

2.排查流程

(1)使用top指令查看CPU资源占用还远远达不到瓶颈,排查因为CPU资源不足导致服务不可用的可能

(2)查看tomcat线程池配置,默认最大线程数为200,理论上可以支持目前服务器的访问量

(3)使用jmap指令保存堆栈信息,jmap -dump:format=b,file=dump.log pid,pid为进程号

(4)使用Java visualVM打开保存的堆栈日志dump.log,发现绝大部分的线程都阻塞在从redis连接池中获取连接的代码,如下图所示

 3.原理分析

根据堆栈日志所显示得知线程访问redis前需要从连接池队列中推出一个连接,当连接池没有连接时,则会阻塞等待,阻塞等待的时间可以自行设置MAA_WAIT参数,默认是-1表示不限时等待,目前项目使用默认配置,所以所有的线程都会一直阻塞在获取连接的步骤,如果设置了最大等待时间,当超过最大等待时间会报出Could not get a resource from the pool的异常

(1)在spring配置文件中的stringRedisTemplate对象配置参数中打开了事务支持,而redis的事务支持是用MUTI和EXEC指令来支持,以下事务实例截图来自菜鸟教程 https://www.runoob.com/redis/redis-transactions.html

(2)如果要保证在事务能正常执行,那么在一个方法中多次操作redis必须是同一条连接,这样才能保证事务能正常执行,所以在stringRedisTemplate会将连接绑定在当前线程,当第二次访问redis时直接从当前线程中获取连接,绑定连接源码如下:

(3)按照流程,先绑定连接,最后在finally代码块中释放连接,看起来并没有问题,但跳进去releaseConnection方法的代码发现连接需要在事务提交后才能释放,也就是说service方法上必须使用@Transation注解修饰,但因为业务方法上少写了@Transation注解导致连接将一直绑定第一次获取他的线程上,当线程池的线程被获取完之后,其他线程就会就如阻塞等待状态,导致服务不可用

(4)如果加上@Transation注解,那么方法执行完之后将会执行TransactionSynchronizationUtils.invokeAfterCompletion这个方法,mysql事务也是在这个方法执行commit操作,如下图所示方法的第一个参数是List<TransactionSynchronization> synchronizations,代表可以有多个事务,redis,mysql等,都会此进行事务提交操作,这里使用多态,根据对象的具体类型执行不同的方法,redis则执行redis的事务提交操作,mysql则执行mysql的事务提交操作

(5)以下为redis事务提交的代码,也跟我们上面提到的一样,发送exec指令提交事务

 4.如何修改代码

(1)确认实际需求是否需要事务支持,如果需要则在对应方法上加上@Transaction注解

(2)如果不需要事务支持则将enableTransactionSupport设置为false

Spring Redis开启事务支持错误用法导致服务不可用的更多相关文章

  1. $Django python中使用redis, django中使用(封装了),redis开启事务(管道)

    一 Python操作Redis之普通连接 #先安装 pip3 install redis import redis r = redis.Redis(host='127.0.0.1', port=637 ...

  2. 修改ip导致服务不可用

    修改ip导致服务不可用 1.修改hostsvi /etc/hosts 修改ip地址 2.lsnrctl start 后会发现The listener supports no services,解决方案 ...

  3. springboot开启事务支持时报代理错误

    问题:The bean 'xxx' could not be injected as a 'com.github.service.xx' because it is a JDK dynamic pro ...

  4. 对Spring 容器管理事务支持的总结

    1.问题 Connection conn = DataSourceUtils.getConnection(); //开启事务 conn.setAutoCommit(false); try { Obje ...

  5. spring boot开启事务管理,使用事务的回滚机制,使两条插入语句一致

    spring boot 事务管理,使用事务的回滚机制 1:配置事务管理 在springboot 启动类中添加 @EnableTransactionManagement //开启事务管理 @Enable ...

  6. 如何在Spring Boot开启事务

    说到事务,那什么是事务呢? 事务(Transaction),一般是指要做的或所做的事情. 原子性(Atomicity):事务作为一个整体被执行,包含在其中的对数据库的操作要么全部被执行,要么都不执行. ...

  7. 集群FULL GC导致服务不可用

    FULL GC会导致stop-the-world,频繁的FULL GC会影响系统的可用性.stackoverflow上有个提问是这么描述这个问题的:当服务器集群批量启动后,执行FULL GC的频率和时 ...

  8. Spring Boot—13事务支持

    pom.xml <dependency> <groupId>org.springframework.boot</groupId> <artifactId> ...

  9. IIS应用程序池"启用32位"导致服务不可用的503错误

    原来运行正常的站点,突然不正常了,出现503错误.查看操作系统的日志查看器显示: 由于配置问题,无法加载模块 DLL“C:\Program Files (x86)\IIS\Asp.Net Core M ...

随机推荐

  1. Java实现 LeetCode 717 1比特与2比特字符(暴力)

    717. 1比特与2比特字符 有两种特殊字符.第一种字符可以用一比特0来表示.第二种字符可以用两比特(10 或 11)来表示. 现给一个由若干比特组成的字符串.问最后一个字符是否必定为一个一比特字符. ...

  2. Java实现 LeetCode 268 缺失数字

    268. 缺失数字 给定一个包含 0, 1, 2, -, n 中 n 个数的序列,找出 0 - n 中没有出现在序列中的那个数. 示例 1: 输入: [3,0,1] 输出: 2 示例 2: 输入: [ ...

  3. Java实现 蓝桥杯VIP 算法提高 棋盘多项式

      算法提高 棋盘多项式   时间限制:1.0s   内存限制:256.0MB 棋盘多项式 问题描述 八皇后问题是在棋盘上放皇后,互相不攻击,求方案.变换一下棋子,还可以有八车问题,八马问题,八兵问题 ...

  4. Java实现 蓝桥杯 历届试题 连号区间数

    问题描述 小明这些天一直在思考这样一个奇怪而有趣的问题: 在1~N的某个全排列中有多少个连号区间呢?这里所说的连号区间的定义是: 如果区间[L, R] 里的所有元素(即此排列的第L个到第R个元素)递增 ...

  5. java实现第三届蓝桥杯源码变换

    源码变换 这道题因为有一些html语言在编写的时候不会显示出来,所以就用代码格式把题目写出来 [编程题](满分22分) 超文本标记语言(即HTML),是用于描述网页文档的一种标记语言. HTML通过文 ...

  6. java代码(15) ---java8 Function 、Consumer 、Supplier

    Java8 Function.Consumer.Supplier 有关JDK8新特性之前还有三篇博客: 1,java代码(1)---Java8 Lambda 2,java代码(2)---Java8 S ...

  7. Pycharm添加Python文件模板

    #!/usr/bin/env python# -*- encoding: UTF-8 -*-'''=================================================@P ...

  8. tab-switch 样式的添加 与 tab元素样式的切换

    要点: 1.多个div类名相同情况下添加class样式 2.siblings() 方法返回被选元素的所有同级元素.DOM 树:该方法沿着 DOM 元素的同级元素向前和向后遍历. 3.利用索引,只添加当 ...

  9. JAVA第三次blog总结

    JAVA第三次blog总结 0.前言 这是我们在博客园上第三次写博客,也是本学期最后一次的JAVA学习大总结.现在我们的JAVA已经接近尾声了,对于编程思想和方法的改变依旧是难点,但是经过这一段时间的 ...

  10. mysql导入超大sql文件

    mysql导入超大sql文件 在网上找了个2017年行政区划的sql文件,需要导入到本地mysql库中,同事使用navicat导入的时候直接卡死了,该SQL文件差不多112MB大小.通过百度.goog ...