并发场景下的幂等问题——分布式锁详解-附录

简介: 并发场景下的幂等问题——分布式锁详解

附录

分布式锁

public class MdbDistributeLock implements DistributeLock {
    /**
     * 锁的命名空间
     */
    private final int namespace;
    /**
     * 锁对应的缓存key
     */
    private final String lockName;
    /**
     * 锁的唯一标识,保证可重入,以应对put成功,但是返回超时的情况
     */
    private final String lockId;
    /**
     * 是否持有锁。true:是
     */
    private boolean locked;
    /**
     * 缓存实例
     */
    private final TairManager tairManager;
    public MdbDistributeLock(TairManager tairManager, int namespace, String lockCacheKey) {
        this.tairManager = tairManager;
        this.namespace = namespace;
        this.lockName = lockCacheKey;
        this.lockId = UUID.randomUUID().toString();
    }
    @Override
    public boolean tryLock() {
        try {
            //获取锁状态
            Result<DataEntry> getResult = null;
            ResultCode getResultCode = null;
            for (int cnt = 0; cnt < DEFAULT_RETRY_TIMES; cnt++) {
                getResult = tairManager.get(namespace, lockName);
                getResultCode = getResult == null ? null : getResult.getRc();
                if (noNeedRetry(getResultCode)) {
                    break;
                }
            }
            //重入,已持有锁,返回成功
            if (ResultCode.SUCCESS.equals(getResultCode)
                && getResult.getValue() != null && lockId.equals(getResult.getValue().getValue())) {
                locked = true;
                return true;
            }
            //不可获取锁,返回失败
            if (!ResultCode.DATANOTEXSITS.equals(getResultCode)) {
                log.error("tryLock fail code={} lock={} traceId={}", getResultCode, this, EagleEye.getTraceId());
                return false;
            }
            //尝试获取锁
            ResultCode putResultCode = null;
            for (int cnt = 0; cnt < DEFAULT_RETRY_TIMES; cnt++) {
                putResultCode = tairManager.put(namespace, lockName, lockId, MDB_CACHE_VERSION,
                    DEFAULT_EXPIRE_TIME_SEC);
                if (noNeedRetry(putResultCode)) {
                    break;
                }
            }
            if (!ResultCode.SUCCESS.equals(putResultCode)) {
                log.error("tryLock fail code={} lock={} traceId={}", getResultCode, this, EagleEye.getTraceId());
                return false;
            }
            locked = true;
            return true;
        } catch (Exception e) {
            log.error("DistributedLock.tryLock fail lock={}", this, e);
        }
        return false;
    }
    @Override
    public void unlock() {
        if (!locked) {
            return;
        }
        ResultCode resultCode = tairManager.invalid(namespace, lockName);
        if (!resultCode.isSuccess()) {
            log.error("DistributedLock.unlock fail lock={} resultCode={} traceId={}", this, resultCode,
                EagleEye.getTraceId());
        }
        locked = false;
    }
    /**
     * 判断是否需要重试
     *
     * @param resultCode 缓存的返回码
     * @return true:不用重试
     */
    private boolean noNeedRetry(ResultCode resultCode) {
        return resultCode != null && !ResultCode.CONNERROR.equals(resultCode) && !ResultCode.TIMEOUT.equals(
            resultCode) && !ResultCode.UNKNOW.equals(resultCode);
    }
}

分布式锁工厂

public class MdbDistributeLockFactory implements DistributeLockFactory {
    /**
     * 缓存的命名空间
     */
    @Setter
    private int namespace;
    @Setter
    private MultiClusterTairManager mtairManager;
    @Override
    public DistributeLock getLock(String lockName) {
        return new MdbDistributeLock(mtairManager, namespace, lockName);
    }
}
相关文章
|
2月前
|
NoSQL Java Redis
秒杀抢购场景下实战JVM级别锁与分布式锁
在电商系统中,秒杀抢购活动是一种常见的营销手段。它通过设定极低的价格和有限的商品数量,吸引大量用户在特定时间点抢购,从而迅速增加销量、提升品牌曝光度和用户活跃度。然而,这种活动也对系统的性能和稳定性提出了极高的要求。特别是在秒杀开始的瞬间,系统需要处理海量的并发请求,同时确保数据的准确性和一致性。 为了解决这些问题,系统开发者们引入了锁机制。锁机制是一种用于控制对共享资源的并发访问的技术,它能够确保在同一时间只有一个进程或线程能够操作某个资源,从而避免数据不一致或冲突。在秒杀抢购场景下,锁机制显得尤为重要,它能够保证商品库存的扣减操作是原子性的,避免出现超卖或数据不一致的情况。
82 10
|
2月前
|
调度 数据库
什么场景下要使用分布式锁
分布式锁用于确保多节点环境下的资源互斥访问、避免重复操作、控制并发流量、防止竞态条件及任务调度协调,常见于防止超卖等问题。
55 4
|
3月前
|
NoSQL Java 数据处理
基于Redis海量数据场景分布式ID架构实践
【11月更文挑战第30天】在现代分布式系统中,生成全局唯一的ID是一个常见且重要的需求。在微服务架构中,各个服务可能需要生成唯一标识符,如用户ID、订单ID等。传统的自增ID已经无法满足在集群环境下保持唯一性的要求,而分布式ID解决方案能够确保即使在多个实例间也能生成全局唯一的标识符。本文将深入探讨如何利用Redis实现分布式ID生成,并通过Java语言展示多个示例,同时分析每个实践方案的优缺点。
101 8
|
4月前
|
NoSQL Java Redis
京东双十一高并发场景下的分布式锁性能优化
【10月更文挑战第20天】在电商领域,尤其是像京东双十一这样的大促活动,系统需要处理极高的并发请求。这些请求往往涉及库存的查询和更新,如果处理不当,很容易出现库存超卖、数据不一致等问题。
95 1
|
4月前
|
存储 缓存 NoSQL
大数据-38 Redis 高并发下的分布式缓存 Redis简介 缓存场景 读写模式 旁路模式 穿透模式 缓存模式 基本概念等
大数据-38 Redis 高并发下的分布式缓存 Redis简介 缓存场景 读写模式 旁路模式 穿透模式 缓存模式 基本概念等
119 4
|
6月前
|
人工智能 监控 虚拟化
操作系统的演变:从单任务到多任务,再到并发和分布式
随着计算技术的发展,操作系统经历了从简单的单任务处理到复杂的多任务、并发处理,再到现代的分布式系统的转变。本文将探索这一演变过程中的关键里程碑,以及它们如何塑造我们今天使用的计算机系统的架构和性能。
|
6月前
|
SQL 索引
分布式之接口幂等性
分布式之接口幂等性
57 2
|
7月前
|
人工智能 分布式计算 物联网
操作系统的演变:从单任务到多任务再到并发和分布式
在数字时代的浪潮中,操作系统作为计算机硬件与应用程序之间的桥梁,其发展史是一部技术革新与需求演进的史诗。本文将带领读者穿梭于操作系统的时空隧道,从早期简单而原始的单任务系统出发,一路见证它如何逐步进化为支持多任务、并发执行乃至分布式计算的复杂系统。我们将一探究竟,是什么推动了这些转变,它们又是如何影响我们日常的技术实践与生活的。
79 1
|
7月前
|
负载均衡 NoSQL Java
|
7月前
|
Web App开发 物联网 Unix
操作系统的演变:从单任务到多任务再到并发与分布式
本文旨在探讨操作系统的发展历程,着重分析其从处理单一任务的原始阶段,经历多任务处理能力的增强,直至支持并发计算和分布式架构的现代转型。我们将追溯关键时间节点,审视技术创新如何塑造了今日操作系统的复杂性与多样性,并预测未来可能的发展趋势。