记一次自定义Redis分布式锁导致的生产事件时间

一个走心的RedisUtil工具类 声明: 本文原型参考自https://github.com/whvcse/RedisUtil,并作了进一步进行整理、修正、拓展。 此RedisUtil工具类的功能: 直接使用此RedisUtil工具类的所需条件: 项目基于SpringBoot。 pom.xml中需要引入依赖spring-boot-starter-data-redis。 pom.xml中需要引入依赖lombok。 pom.xml... 阅读详情

背景

企微报警群里连续发出生产环境报错警告,报错核心信息如下:

redis setNX error java.lang.NumberFormatException: For input string: "null"
  at java.lang.NumberFormatException.forInputString(NumberFormatException.java:65)
  at java.lang.Long.parseLong(Long.java:589)
  at java.lang.Long.parseLong(Long.java:631)

经异常信息定位,发现是项目中自定义的Redis分布式锁报错,并且该异常是在最近需求上线后突然出现,并且伴随该异常出现的,还有需求涉及的业务数据出现部分错乱的问题。

问题分析

老规矩,先贴涉及代码

//切面
public class RedisLockAspect{
  public void around(ProceedingJoinPoint pjp) {
    String key = "...";
    try {
      //阻塞,直到获取锁为止
      while (!JedisUtil.lock(key, timeOut)) {
        Thread.sleep(10);
      }
      //执行业务逻辑
      pjp.proceed();
    }finally {
      JedisUtil.unLock(key);
    }
  }
}

以上为自定义Redis分布式锁的切面,不看细节,只看整体逻辑,问题不大,那再看实际加锁方法。

public class JedisUtil{
  public static boolean lock(String key, long timeOut){
        long currentTimeMillis = System.currentTimeMillis();
        long newExpireTime = currentTimeMillis + timeOut;
        RedisConnection connection = null;
        try {
            connection = getRedisTemplate().getConnectionFactory().getConnection();
            Boolean setNxResult = connection.setNX(key.getBytes(StandardCharsets.UTF_8), String.valueOf(newExpireTime).getBytes(StandardCharsets.UTF_8));
          //位置1
            if(setNxResult){
                expire(key,timeOut, TimeUnit.MILLISECONDS);
                return true;
            }
          //位置2
            Object objVal = getRedisTemplate().opsForValue().get(key);
            String currentValue  = String.valueOf(objVal);
          //位置3,异常位置为if判断中Long.parseLong(currentValue),currentValue为null的字符串
            if (currentValue != null && Long.parseLong(currentValue) < currentTimeMillis)  {
                String oldExpireTime = (String) getAndSet(key, String.valueOf(newExpireTime));
                if (oldExpireTime != null && oldExpireTime.equals(currentValue)) {
                    return true;
                }
            }
        }
        return false;
    }
  
  public static void unLock(String key){
    getRedisTemplate().delete(key);
  }
}

有经验的大佬看到这段代码,估计会忍不住爆粗,但咱先不管,先看错误位置。异常信息可以看出,currentValue的值为字符串“null”,即String.valueOf(objVal)中的objVal对象为null,也就是在Redis中,key对应的value不存在,此时思考一下,key对应的value不存在,无非以下两种情况:

  • key被主动删除;

  • key过期了。

继续跟着代码往上走,发现前面执行了setNx命令,并且返回setNxResult表示是否成功。正常来说,当setNxResult为false的时候,加锁失败,此时代码时不应该往下走的,但在本段代码中,却继续往下走!问了下相关同事,说是为了做可重入锁......(弱弱吐槽下,可重入锁也不是这样干的啊...) 其实分析到这,已经可以知道是什么原因导致的异常故障了,即上面说的,key被主动删除、key过期导致,下面假设有两个线程,对同一个key加锁,分别对应以上两种情况:key被主动删除的情况,发生于分布式锁加锁逻辑执行完后,调用unlock方法,见以上RedisLockAspect类中finally部分,如下图:

key过期的情况,主要在线程加锁并设置过期时间后,执行业务代码耗费的时间超过设置的锁过期时间,并且在锁过期前,未对锁进行续期:

解决方案 从上面的代码看来,这已经不是简单的Long.parseLong("null")问题了,这是整个Redis分布式锁实现的问题,并且该分布式锁在整个项目中大量使用,可想而知其实问题非常严重,如果只是解决Long.parseLong("null")的问题,无疑就是隔靴挠痒,没有任何意义的。一般情况下,自定义Redis分布式锁容易出现以下几大问题:

  • setNx锁释放问题;

  • setNx Expire 原子性问题;

  • 锁过期问题;

  • 多线程释放锁问题;

  • 可重入问题;

  • 大量失败时自旋锁问题;

  • 主从架构下锁数据同步问题;

结合以上故障代码,可以发现项目中的Redis分布式锁实现几乎未对Redis分布式锁问题进行考虑,以下为主要问题以及对应解决方案:

setNx 和 expire 原子操作:使用Lua脚本,在一次Lua脚本命令中,执行setNx 与 expire命令,保证原子性;锁过期问题:为防止锁自动过期,可在锁过期前,定时对锁过期时间进行续期。可重入问题:可重入设计粒度需到线程级别,可在锁上加上线程唯一id。锁自旋问题:参考JDK中AQS设计,实现获取锁时最大等待时长。

对于项目中的问题以及每个问题的解决方案实现,baidu一下就有大量参考,此处不再介绍。目前比较成熟的综合解决方案为使用Redisson客户端,以下为简单伪代码demo:

public class RedisLockAspect{
  @Autowired
  private Redisson redisson;
  
  public void around(ProceedingJoinPoint pjp) {
    String key = "...";
    Long waitTime = 3000L;
    //获取锁
    RLock lock = redisson.getLock(key);
    boolean lockSuccess = false;
    try {
      //加锁设置超时时间,防止无限自旋。默认启用看门狗功能(自动对锁进行续期)
      lockSuccess = lock.tryLock(waitTime);
      //执行业务逻辑
      pjp.proceed();
    }finally {
      //解锁,防止释放其他线程锁
      if (lock.isLocked() && lock.isHeldByCurrentThread() && lockSuccess){
          lock.unlock();
      }
    }
  }
}

使用Redisson可以快速解决目前项目中Redis分布式锁存在的问题。除此之外,对于Redis主从架构下数据同步导致的锁问题,对应的解决方案RedLock,也提供了相应的实现。更多使用文档详见官方文档github.com/liulongbiao…

总结

对于分布式锁来说,可实现方案其实远远不止Redis这个实现途径,比如基于Zookeeper、基于Etcd等方案,但其实对于目的来说,都是殊途同归,重点在于,如何安全、正确的使用这些方案,保证业务正常。对于研发团队来说,针对类似的问题,需要对技术小伙伴进行培训,不断提升技术,更需要重视codereview工作,及时识别风险,避免发生故障造成严重损失(本次故障造成脏数据修复耗时一个多星期)。 敬畏技术,忠于业务。

作者: 十年培训经验的菜包

文章来源: https://c1n.cn/OZvGN

最近在准备面试BAT,特地整理了一份面试资料,覆盖Java核心技术分支、JVM、Java并发、SSM、微服务、数据库、数据结构等等。在这里,我为大家准备了一份2021年最新最全的互联网大厂Java面试经验总结。

Redis分布式锁核心原理与生产实践:从SET NX到高并发场景应用 分布式锁是解决分布式系统并发控制问题的关键技术,其核心原理是通过一个所有节点可见的协调者来确保资源的互斥访问。在众多实现方案中,基于Redis的分布式锁因其高性能和原子操作特性被广泛应用,其中SET NX命令是实现锁语义的基础。该方案利用Redis单线程执行命令的特性,通过原子性操作实现锁的获取与释放,有效解决了电商秒杀、库存扣减等高并发场景下的数据一致性问题。在实际工程实践中,需要重点关注锁的键值设计、过期时间设置以及释放锁时的安全校验,避免出现死锁和锁误删等问题。通过合理的锁续期机制和主从架构下的容错处 阅读详情

相关推荐

Beyond the Spec: Decoding Samsung‘s LPDDR6 Sub-Channel and Wide-NRZ Innovations

本文深入解析了三星LPDDR6内存的两大核心技术:Sub-Channel架构与Wide-NRZ信号技术。Sub-Channel架构通过将物理通道划分为多个独立子通道,实现了内存访问的细粒度控制,大幅提升了能效,尤其适用于AI与边缘计算场景。Wide-NRZ则通过增加并行数据线而非采用PAM4,在提升带宽的同时保持了优异的信号完整性与低功耗特性。

weixin_29209801的博客 136

redisTemplate+redis+lua解决redis分布式锁集群报错问题

单机环境redis+lua实现分布式锁没有问题。

我的博客 380

微纳加工技术中的自对准硅化物(Silicide)工艺:关键步骤与应用场景解析

本文深入解析了微纳加工技术中的自对准硅化物(Silicide)工艺,详细介绍了其关键步骤与应用场景。从表面清洁、金属沉积到两步退火法,全面拆解工艺全流程,并探讨了不同技术节点下的工艺演进。文章还提供了实际应用中的问题排查方法和新兴技术对Silicide工艺的挑战,为芯片制造领域的工程师提供了实用参考。

weixin_30613727的博客 431

使用redis实现防止重复提交,成功解决方案

1、业务场景 业务开发中,常常涉及对前端操作进行重复校验,避免重复提交造成数据重复操作。比如转账操作,因为网络卡顿,客户连续点击转账按钮,造成多次转成;又比如,连点"核保"操作,如果不做限制,核保通过,如有积分下发功能,有可能会重复下发积分。 2、基础解决方案 通常,我们在数据库层面进行数据校验,但是并发操作下,并不理想。 3、解决方案 本文,使用redis,实现对重复提交进行判断和阻止...

春风化雨 2万+

SAP接口错误查询日志

随着数字经济的迅速发展,企业数字化转型不在只追求“业财一体化”,而是在业务端也想要进行更为精细化的管理,所以很多企业在SAP ERP的基础上,集成更多垂直领域更精细的外围系统,比如销售CRM系统,采购SRM系统,生产MES系统等等,琳琅满目的产品,那对SAP实施来说,系统集成过程中,接口的一些报错查询能力必不可少,今天我们就介绍一下,SAP和CRM系统集成中接口常见的报错。

weixin_43657667的博客 2050

从RadixTree到哈希表:深入对比SGLang和vLLM的Prefix Cache实现差异

本文深入对比了SGLang与vLLM在大语言模型推理服务中实现Prefix Cache(前缀缓存)的两种核心方案。SGLang采用基于Radix Tree的RadixAttention,支持任意长度前缀的精确匹配与灵活复用;vLLM则采用基于哈希表的方案,深度集成于PagedAttention,实现简洁但要求块级精确对齐。文章剖析了二者在设计哲学、内存管理、适用场景及集群级优化(如Prefix Cache Aware Routing)上的关键差异,为高性能LLM服务的技术选型提供决策依据。

blockchain9miner的博客 957

Redis的setNX分布式锁超时时间失效 -1

Redis的setNX分布式锁超时时间失效 -1

woaiwojialanxi的专栏 2982

【Python基础】FastAPI 从入门到项目实战操作详解

【Python基础】FastAPI从入门到使用实战操作详解

congge_study的博客 456

Redis分布式锁故障,我忍不住想爆粗...

文章来源:https://c1n.cn/OZvGN目录背景问题分析解决方案总结背景企微报警群里连续发出生产环境报错警告,报错核心信息如下:redissetNXerrorjava.lang.NumberFormatException:Forinputstring:"null" atjava.lang.NumberFormatException.forIn...

weixin_43167418的博客 296

【制作100个unity实战之2】实现一款简单的FPS游戏

你将学到: fps武器脚本 基础瞄准功能 僵尸敌人AI 巡逻范围 攻击间 搜寻半径 追击 枪声吸引周围的僵尸 击中僵直效果

向宇的博客,专注php/web全栈 unity游戏开发,欢迎大家评论纠错 3553

全面解读 SAP Business Data Cloud

SAP 在 2025 年初正式推出(简称BDC),它把、以及全新的统一封装为一项完全托管的 SaaS 服务,配套交付“语义层 + 数据产品 + 智能应用”三层能力,为企业构建真正贴近业务语境的 “Business Data Fabric”。这一方案不仅解决了跨系统数据碎片化、治理难及 AI 训练数据可信度低的问题,还为现有 BW 客户、S/4HANA以及第三方工作负载提供云上现代化路径和零拷贝数据共享机制。本文将围绕技术架构、核心组件、业务场景、迁移路线及未来展望展开,以 Henkel 等真实案例佐证。

2007 年 ~ 2025 年,深耕 SAP 技术 18 年 911

记一次自定义Redis分布式锁导致的生产事件

对于分布式锁来说,可实现方案其实远远不止Redis这个实现途径,比如基于Zookeeper、基于Etcd等方案,但其实对于目的来说,都是殊途同归,重点在于,如何安全、正确的使用这些方案,保证业务正常。对于研发团队来说,针对类似的问题,需要对技术小伙伴进行培训,不断提升技术,更需要重视codereview工作,及时识别风险,避免发生故障造成严重损失(本次故障造成脏数据修复耗时一个多星期)。敬畏技术,忠于业务。

Cr1556648487的博客 220

【S32K3 MCAL配置】-1.1-GPIO配置及其应用-DIO之高低电平输出-点亮LED灯(基于MCAL)

【S32K3 MCAL配置】-1.1-GPIO配置及其应用-点亮LED灯(基于MCAL)

「汽车电子助手」的博客 1937

redis分布式锁

Redis分布式锁是一种基于Redis实现的跨进程互斥机制,用于在分布式系统中控制多个服务/节点对共享资源的并发访问,确保同一时刻只有一个客户端能执行关键操作(如修改共享数据、执行任务等)。在单机系统中,我们可以用线程锁(如Java的synchronized或ReentrantLock)保证并发安全。但在分布式系统中【项目集群部署】,服务部署在多台机器上,跨进程的共享资源无法通过本地锁保护。如下图1所示:此时就需要分布式锁。

qq_24574189的博客 1090

jre9下载 jdk9

(Java SE Runtime Environment 9.0) 9.0u175 官方最新版 【x86|x64】

NTscan扫描工具

ntscan是一个扫描器,可以扫描没有密码和弱密码的共享,先到配置文件中填写猜测的用户名和密码,扫描过程中右侧出现的是扫描日志。

java如何保证redis设置过期时间的原子性_构建基于Redis的分布式锁

架构师(JiaGouX)我们都是架构师!架构未来,你来不来?作者: 云枭zd出处:https://www.cnblogs.com/fixzd/一、介绍这篇博文讲介绍如何一步步构建一个基于Redis的分布式锁。会从最原始的版本开始,然后根据问题进行调整,最后完成一个较为合理的分布式锁。本篇文章会将分布式锁的实现分为两部分,一个是单机环境,另一个是集群环境下的Redis锁实现。在介绍分布式...

weixin_39637571的博客 425

Devexpress16.2.6破解工具

Devexpress16.2.6破解工具Devexpress16.2.6破解工具Devexpress16.2.6破解工具Devexpress16.2.6破解工具

基于Redis(setnx)实现分布式锁

什么是分布式锁? 分布式锁是控制分布式系统或不同系统之间共同访问共享资源的一种锁实现,如果不同的系统或同一个系统的不同主机之间共享了某个资源时,往往需要互斥来防止彼此干扰来保证一致性。 分布式锁需要具备哪些条件? 互斥性:在任意一个时刻,只有一个客户端持有锁。 无死锁:即便持有锁的客户端崩溃或者其他意外事件,锁仍然可以被获取。 容错:只要大部分Redis节点都活着,客户端就可以获取和...

猪猪 4万+

迈瑞BS系列全自动生化分析仪LIS协议接口手册(内含HL7和ASTM)

迈瑞BS系列全自动生化分析仪LIS协议接口手册,内含HL7和ASTM)

Redis下篇--分布式锁

Redis分布式锁简介 Redis分布式锁是一种基于Redis实现的跨进程互斥机制,用于控制分布式系统中多个节点对共享资源的并发访问。相比本地线程锁,它解决了集群环境下无法保护跨进程共享资源的问题。 核心实现要点: 使用SET命令结合NX(不存在才设置)和EX(过期时间)参数实现原子性加锁 通过唯一value值避免误删其他线程的锁 设置合理过期时间防止死锁 典型应用场景包括: 防止重复操作(如订单提交) 高并发库存扣减 分布式任务调度 相比数据库锁和Zookeeper实现,Redis分布式锁具有更好的性能和

okok__TXF的博客 821

Redis分布式锁深度解析:从SETNX到Redisson,彻底搞懂分布式锁!

本文从秒杀超卖故障引入分布式锁。详解单机锁失效原因和分布式锁必要性。深入Redis锁演进:SETNX死锁、SETNX加EXPIRE非原子、SET EX NX原子操作、Lua脚本防误删、Redisson生产级方案。剖析Watch Dog自动续期机制防止锁过期。讲解可重入锁、公平锁、读写锁、联锁特性。完整秒杀实战代码防超卖。对比Redis、Zookeeper、数据库三种方案。提供最佳实践:锁粒度、超时时间、异常处理、监控。

比较是偷走幸福的小偷 6189

Asyncio + Redis 实现分布式锁:5分钟解决任务重复执行的生产级方案

5分钟解决任务重复执行问题,基于Asyncio + Redis实现分布式锁,适用于Python分布式任务Asyncio应用。通过真实场景示例展示高并发下任务唯一性保障方案,具备高性能、低延迟优势,稳定可靠值得收藏。

CompiGap的博客 907

一次分布式锁死锁引发的全集群服务不可用:从故障定位到 Redis Redlock 方案迁移全记录

1. 单节点Redis锁在高并发生产环境中存在结构性缺陷。GC暂停、网络抖动、时钟漂移等常见异常,都可能在特定条件下导致锁的状态不一致,进而引发幻锁或死锁。仅依赖看门狗续租并不能解决根因——当看门狗线程与业务线程共享同一进程时,GC暂停会同时冻结两者。2. Redlock算法通过多节点quorum机制,从根本上消除了单点故障风险。在5节点部署下,即使2个节点同时异常,锁的安全性仍由剩余3个节点保障。迁移后的实测数据显示:锁异常失效率从0.8%/月降至0.02%/月,降幅达97.5%。

qwe0iop0的博客 4636

生产事故复盘:你写的Redis分布式锁真的安全吗?万字图解Redisson锁底层原理

│ 分布式锁最佳实践清单 ││ ││ 【必须做】 ││ 1. 使用Redisson提供的分布式锁(不要自己实现) ││ 2. 始终在finally块中释放锁 ││ 3. 释放锁前检查是否是当前线程持有 ││ 4. 设置合理的等待时间和持有时间 ││ 5. 使用看门狗机制处理业务执行时间不确定的场景 ││ ││ 【不要做】 ││ 1. 不要使用简单的SETNX命令 ││ 2. 不要在业务代码中直接使用Thread.sleep测试 │。

2401_83440791的博客 1211

java redis 原子操作_基于redis的各种分布式锁实现对比分析

一、介绍这篇博文讲介绍如何一步步构建一个基于Redis的分布式锁。会从最原始的版本开始,然后根据问题进行调整,最后完成一个较为合理的分布式锁。本篇文章会将分布式锁的实现分为两部分,一个是单机环境,另一个是集群环境下的Redis锁实现。在介绍分布式锁的实现之前,先来了解下分布式锁的一些信息。二、分布式锁2.1 什么是分布式锁?分布式锁是控制分布式系统或不同系统之间共同访问共享资源的一种锁实现,如果不...

weixin_39953100的博客 661

分布式锁,分布式锁应该具备哪些条件,分布式锁的实现方式有:基于Zookeeper实现、Redis实现、数据库实现

随着互联网技术的不断发展,用户量的不断增加,越来越多的业务场景需要用到分布式系统。分布式系统有一个著名的理论CAP,指在一个分布式系统中,最多只能同时满足下面三项中的两项一致性):在分布式系统中的所有数据备份,在同一时刻是否同样的值(等同于所有节点访问同一份最新的数据副本)可用性):保证每个请求不管成功或者失败都有响应分区容错性Partitiontolerance):系统中任意信息的丢失或失败不会影响系统的继续运作所以在设计系统时,往往需要权衡,在CAP中作选择,要么AP,要么CP、要么AC。

weixin_44797327的博客 1579

Java分布式锁的实现方案

锁超时时间 > 业务最大执行时间 + 时钟漂移补偿 + 网络延迟缓冲。TTL = (业务最大执行时间 × 2) + 网络延迟缓冲。使用临时顺序节点实现先来先服务的公平锁,避免"惊群效应"会话超时 > 业务最大执行时间 + 网络恢复时间。看门狗线程(Redisson)Session断开自动释放。高(需处理临时节点和监听)CP系统(优先保证一致性)强一致性(ZAB协议)金融交易、强一致性要求。中等(需要磁盘写入)中等(需处理多节点)较高(需要维持会话)高并发、允许偶尔失效。PEXPIRE 命令。

wuqjwuqj2013的博客 1850

Redis 缓存架构与分布式锁:从设计到生产级实践全解析

Redis作为高性能内存数据库,核心用途包括缓存、数据存储和消息队列。本文重点探讨其缓存架构设计:通过Redis缓存层减轻MySQL压力,提升系统性能。详细分析了缓存更新策略(定时/实时更新)、内存淘汰机制(LRU/LFU等)及常见问题解决方案(缓存穿透/击穿/雪崩)。同时介绍了Redis实现分布式锁的原理与进阶问题处理,包括原子性操作、锁续期和Redlock算法。最后强调了生产环境中监控缓存命中率、内存使用等关键指标的重要性。合理运用Redis能显著提升系统并发能力,保障数据一致性。

2302_79737429的博客 1254

基于redis的分布式锁

基于redis的分布式锁 1 介绍 这篇博文讲介绍如何一步步构建一个基于Redis的分布式锁。会从最原始的版本开始,然后根据问题进行调整,最后完成一个较为合理的分布式锁。 本篇文章会将分布式锁的实现分为两部分,一个是单机环境,另一个是集群环境下的Redis锁实现。在介绍分布式锁的实现之前,先来了解下分布式锁的一些信息。 2 分布式锁 2.1 什么是分布式锁? 分布式锁是控制分布式...

C18298182575的博客 234
上一篇: JVM堆外内存导致的FGC问题排查
下一篇: 异常架构与关键
程序员职业指南
博客等级 码龄4年 2138粉丝 960原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值