分布式锁其实很简单,6行代码教你实现redis分布式锁

在这里插入图片描述

一、前言

分布式锁是一种用于协调分布式系统中多个节点之间对共享资源进行访问控制的机制。它可以确保在分布式环境下,同一时间只有一个节点能够获取到锁,并且其他节点需要等待释放锁后才能获取。

以下是使用分布式锁的几个常见场景和原因:

  1. 避免资源冲突:当多个节点需要同时对共享资源进行读写操作时,使用分布式锁可以确保同一时间只有一个节点能够执行写操作,避免数据冲突和一致性问题。

  2. 防止重复处理:在某些业务场景中,可能会出现重复处理的问题,例如订单支付、秒杀等。使用分布式锁可以确保同一时间只有一个节点能够处理该任务,避免重复处理和产生脏数据。

  3. 控制资源并发:某些资源的并发操作会导致性能问题,如数据库的并发写操作。使用分布式锁可以限制对资源的并发访问,提高系统的稳定性和性能。

  4. 避免死锁:在分布式环境下,由于网络延迟等原因,可能会发生死锁的情况。使用分布式锁可以避免死锁问题的发生,确保资源的正确释放。

二、使用redisTemplate.opsForValue().setIfAbsent

  1. 获取锁:

    • 客户端通过在Redis中设置一个特定的键,作为锁的标识,并设置过期时间以避免死锁情况。这个操作可以通过Redis的SETNX命令来实现。如果SETNX命令返回1,表示锁获取成功,客户端可以继续执行相应的业务逻辑;如果返回0,表示锁已经被其他客户端持有,客户端需要等待或进行重试操作。
    • 可以通过Redis的SET命令设置锁的过期时间,以防止锁一直被持有而导致死锁。设置过期时间可以保证即使持有锁的客户端发生异常退出,锁也会在过期时间后自动释放。
  2. 释放锁:

    • 客户端完成业务操作后,通过DEL命令删除锁的键,即可释放锁。只有持有锁的客户端才能删除锁,以避免误删其他客户端的锁。

下面是一个示例:

@Component
public class DistributedLock {private static final String LOCK_KEY = "my_lock";private static final long EXPIRE_TIME = 30000; // 锁的过期时间,单位为毫秒private static final long WAIT_TIME = 1000; // 获取锁时的等待时间,单位为毫秒@Autowiredprivate StringRedisTemplate redisTemplate;public boolean acquireLock() throws InterruptedException {long start = System.currentTimeMillis();while (true) {Boolean success = redisTemplate.opsForValue().setIfAbsent(LOCK_KEY, "locked", EXPIRE_TIME, TimeUnit.MILLISECONDS);if (success != null && success) {return true;}long current = System.currentTimeMillis();if (current - start > WAIT_TIME) {return false;}Thread.sleep(100); // 等待一段时间后进行重试}}public void releaseLock() {redisTemplate.delete(LOCK_KEY);}
}

在上述代码中,acquireLock方法尝试获取分布式锁,如果成功获取,则返回true;如果超过等待时间仍未获取到锁,则返回false。releaseLock方法用于释放锁。

使用setIfAbsent的缺点

使用redisTemplate.opsForValue().setIfAbsent()方法实现分布式锁存在以下缺点:

  1. 可靠性问题:使用redisTemplate.opsForValue().setIfAbsent()方法实现分布式锁时,需要手动编写代码来处理锁的获取和释放,容易出现人为的错误,如忘记释放锁、锁的过期时间设置不正确等。而Redisson框架提供了更加可靠的分布式锁实现,内部封装了各种功能的锁,并提供了易于使用的API,能够确保锁的可靠性和正确性。

  2. 功能限制:redisTemplate.opsForValue().setIfAbsent()方法只能实现简单的锁功能,无法支持更复杂的功能,如可重入锁、公平锁、红锁和读写锁等。而Redisson框架提供了丰富的分布式锁实现方式,可以根据实际需求选择适用的锁类型。

  3. 性能问题:redisTemplate.opsForValue().setIfAbsent()方法实现分布式锁时,每次都需要与Redis服务器进行通信,可能会造成较高的网络开销和延迟。而Redisson框架通过内部的优化和封装,能够提供更高效的分布式锁实现,减少与Redis服务器的通信次数和网络开销。

  4. 可拓展性问题:使用redisTemplate.opsForValue().setIfAbsent()方法实现分布式锁时,随着业务的发展和变化,可能需要添加更多的功能和特性,而手动编写的代码可能无法满足新的需求。而Redisson框架提供了丰富的锁实现,同时也支持自定义锁的扩展,能够更好地适应业务的变化和拓展。

三、使用redisson实现分布式锁

通过Redisson框架可以方便地实现分布式锁。Redisson是一个基于Redis的分布式Java对象和服务框架,提供了丰富的分布式锁的实现方式。

要使用Redisson实现分布式锁,需要完成以下步骤:

  1. 引入Redisson依赖:在项目的pom.xml文件中添加Redisson的依赖。
<dependency><groupId>org.redisson</groupId><artifactId>redisson</artifactId><version>3.14.0</version>
</dependency>
  1. 创建RedissonClient对象:在Spring Boot中,可以通过Redisson的Spring支持来创建RedissonClient对象。
@Configuration
public class RedissonConfig {@Beanpublic RedissonClient redissonClient() {Config config = new Config();config.useSingleServer().setAddress("redis://localhost:6379");return Redisson.create(config);}
}

在上述代码中,创建了一个RedissonClient对象,并配置了连接Redis的地址。

  1. 实现分布式锁:
    • 使用RedissonClient对象获取RLock对象,RLock是Redisson提供的分布式锁接口。
    • 通过RLock对象的lock方法来获取锁,并在获取锁成功后执行业务逻辑。
    • 通过RLock对象的unlock方法来释放锁。

下面是一个示例:

@Service
public class DistributedLockService {@Autowiredprivate RedissonClient redissonClient;public void executeWithLock() {RLock lock = redissonClient.getLock("my_lock");try {lock.lock();// 执行业务逻辑...} finally {lock.unlock();}}
}

在上述代码中,executeWithLock方法通过redissonClient获取了一个名为"my_lock"的锁,并通过lock方法获取锁。在获取锁成功后,可以执行业务逻辑。最后,通过unlock方法释放锁。

Redisson还提供了其他一些功能强大的分布式锁实现方式,如可重入锁、公平锁、红锁、读写锁等。这些锁的实现方式更加灵活和强大,可以根据实际需求进行选择和使用。

使用Redisson实现分布式锁时,需要确保Redis服务器的可用性和稳定性,以避免单点故障导致的锁失效或锁的不稳定情况。此外,还需要根据具体的应用场景和需求,合理设置锁的过期时间,避免锁的长时间占用。

1. 可重入锁(Reentrant Lock):

可重入锁是指同一个线程可以多次获得同一个锁,而不会发生死锁。Redisson的可重入锁实现是基于Redis的分布式锁的一种特例。

@Service
public class ReentrantLockService {@Autowiredprivate RedissonClient redissonClient;public void executeWithReentrantLock() {RLock lock = redissonClient.getLock("my_lock");try {lock.lock();// 执行业务逻辑...executeWithReentrantLock();} finally {lock.unlock();}}
}

在上述代码中,使用redissonClient获取了一个名为"my_lock"的可重入锁,并通过lock方法获取锁。在获取锁成功后,可以执行业务逻辑,包括递归调用executeWithReentrantLock方法。最后,通过unlock方法释放锁。

2. 公平锁(Fair Lock):

公平锁是指按照线程请求锁的顺序来分配锁。Redisson的公平锁实现可以保证多个线程按照先后顺序获取锁。

@Service
public class FairLockService {@Autowiredprivate RedissonClient redissonClient;public void executeWithFairLock() {RLock lock = redissonClient.getFairLock("my_lock");try {lock.lock();// 执行业务逻辑...} finally {lock.unlock();}}
}

在上述代码中,使用redissonClient获取了一个名为"my_lock"的公平锁,并通过lock方法获取锁。在获取锁成功后,可以执行业务逻辑。最后,通过unlock方法释放锁。

3. 红锁(Red Lock):

红锁是指在多个Redis节点上获取锁,以提高分布式系统的可靠性和容错性。Redisson的红锁实现是基于Redis的分布式锁的一种优化方式。

@Service
public class RedLockService {@Autowiredprivate RedissonClient redissonClient;public void executeWithRedLock() {RLock lock1 = redissonClient.getLock("lock1");RLock lock2 = redissonClient.getLock("lock2");RLock lock3 = redissonClient.getLock("lock3");RedissonRedLock redLock = new RedissonRedLock(lock1, lock2, lock3);try {redLock.lock();// 执行业务逻辑...} finally {redLock.unlock();}}
}

在上述代码中,使用redissonClient分别获取了名为"lock1"、"lock2"和"lock3"的锁,并通过RedissonRedLock将这些锁组合成红锁。在获取红锁成功后,可以执行业务逻辑。最后,通过unlock方法释放红锁。

4. 读写锁(ReadWrite Lock):

读写锁是指在多线程环境下,对于读操作可以并行进行,对于写操作必须互斥进行。Redisson的读写锁实现提供了读锁和写锁两种操作。

@Service
public class ReadWriteLockService {@Autowiredprivate RedissonClient redissonClient;public void readWithReadWriteLock() {RReadWriteLock rwLock = redissonClient.getReadWriteLock("my_lock");RLock readLock = rwLock.readLock();try {readLock.lock();// 执行读操作...} finally {readLock.unlock();}}public void writeWithReadWriteLock() {RReadWriteLock rwLock = redissonClient.getReadWriteLock("my_lock");RLock writeLock = rwLock.writeLock();try {writeLock.lock();// 执行写操作...} finally {writeLock.unlock();}}
}

在上述代码中,使用redissonClient获取了一个名为"my_lock"的读写锁,并通过readLock方法获取读锁,通过writeLock方法获取写锁。在获取锁成功后,可以执行相应的读操作或写操作。最后,通过unlock方法释放锁。

四、遇到redis单点故障怎么办

当使用Redisson实现分布式锁时,如果遇到Redis服务器的单点故障,可以采取以下解决方案:

  1. Redis Sentinel(哨兵模式):Redis Sentinel是Redis官方提供的高可用性解决方案,它通过监控Redis主节点和从节点的状态,实现自动故障转移和故障恢复。在使用Redisson时,可以配置Redis Sentinel来实现高可用性的Redis集群,在主节点故障时,Redis Sentinel会自动将从节点切换为主节点,从而保证分布式锁的可用性。

  2. Redis Cluster(集群模式):Redis Cluster是Redis官方提供的分布式解决方案,通过将数据分散到多个节点上进行存储和访问,实现高可用性和横向扩展。使用Redisson时,可以配置Redis Cluster来搭建分布式锁的集群,当某个节点出现故障时,其他节点仍然可以正常工作,确保分布式锁的可用性。

  3. 使用RedLock算法:RedLock算法是由Redis官方提出的一种多实例锁机制,通过在多个独立的Redis实例之间获取锁,确保锁的可靠性。在使用Redisson时,可以使用RedLock算法来实现分布式锁,通过协调多个Redis实例之间的锁获取和释放,即使部分实例发生故障,仍然可以保证锁的可用性。

  4. 引入其他高可用的中间件:除了Redis本身的高可用性解决方案,也可以考虑引入其他高可用的中间件,如ZooKeeper、etcd等。在使用Redisson时,可以将这些中间件作为分布式锁的协调中心,用于进行锁的获取和释放操作,以保证分布式锁的可用性。

以上解决方案都需要在配置和部署时做相应的工作,如正确配置Redis Sentinel或Redis Cluster、合理设计Redis实例的数量和分布、选择合适的RedLock算法实现等。同时,还需要在代码实现中考虑异常处理和重试机制,以应对可能出现的故障和异常情况。

1、如何实现哨兵模式

哨兵模式是一种用于提供Redis高可用性的解决方案。在哨兵模式下,多个Redis Sentinel进程监控着一个Redis主节点和其对应的从节点,当主节点发生故障时,哨兵会自动进行故障转移,将一个从节点升级为新的主节点,并将其他从节点重新配置为新的主节点的从节点。

下面是哨兵模式的实现步骤:

  1. 配置Redis Sentinel:在Redis Sentinel的配置文件中,需要指定监控的主节点和从节点,并配置哨兵的运行参数。可以通过配置文件或命令行参数来指定。示例配置文件如下:
sentinel monitor mymaster 127.0.0.1 6379 2
sentinel down-after-milliseconds mymaster 30000
sentinel failover-timeout mymaster 180000
  1. 启动Redis Sentinel:按照配置启动Redis Sentinel进程,可以运行多个哨兵进程以提高可用性。每个哨兵进程会周期性地监控主节点和从节点的状态,并进行故障检测和故障转移。

  2. 配置Redis客户端:在Redis客户端中,需要配置哨兵模式下的连接参数。通常,需要指定哨兵的地址和端口,以及要连接的Redis实例的名称。示例代码如下(使用Java Redisson框架):

RedisSentinelConfiguration sentinelConfig = new RedisSentinelConfiguration().master("mymaster").sentinel("127.0.0.1", 26379).sentinel("127.0.0.1", 26380).sentinel("127.0.0.1", 26381);RedissonClient redisson = Redisson.create(sentinelConfig);
  1. 处理故障转移:当主节点发生故障时,Redis Sentinel会自动进行故障转移。它会选取一个从节点升级为新的主节点,并将其他从节点重新配置为该新主节点的从节点。在故障转移期间,客户端可能会遇到一段时间的不可用,需要处理相关异常或者等待故障转移完成。

哨兵模式下的高可用性是通过监控和自动故障转移来实现的,但在故障转移期间,可能会存在一段时间的不可用,因此需要在应用程序中进行适当的异常处理和重试机制。另外,哨兵模式适用于小规模的Redis集群,对于大规模集群和高并发场景,可以考虑使用Redis Cluster或其他方案来提供更高可用性和性能。

2、如何实现集群模式

Redis Cluster是Redis官方提供的一种分布式解决方案,用于实现Redis的高可用性和横向扩展。Redis Cluster将数据分散存储在多个节点上,并通过使用Gossip协议进行节点之间的通信和数据同步,从而实现了分布式的数据存储和访问。

下面是Redis Cluster的实现步骤:

  1. 配置Redis Cluster:创建一个Redis Cluster所需的Redis实例数量,并按照一定规则将槽位(slot)分配给这些实例。Redis Cluster将数据分为16384个槽位,每个实例负责一部分槽位。可以使用redis-trib.rb工具来进行槽位分配和配置。示例命令如下:
redis-trib.rb create --replicas 1 127.0.0.1:7000 127.0.0.1:7001 127.0.0.1:7002
  1. 启动Redis Cluster节点:按照配置启动Redis Cluster各个节点,每个节点需指定一个端口号,以及相应的槽位分配信息。示例配置文件如下:
port 7000
cluster-enabled yes
cluster-config-file nodes.conf
cluster-node-timeout 5000
cluster-announce-ip 127.0.0.1
cluster-announce-port 7000
cluster-announce-bus-port 7000
appendonly yes
  1. 配置Redis客户端:在Redis客户端中,需要配置Redis Cluster的连接参数。通常,需要指定多个节点的地址和端口,以便客户端可以与集群中的任何一个节点进行通信。示例代码如下(使用Java Redisson框架):
RedisClusterNodes clusterNodes = new RedisClusterNodes.Builder().addNodeAddress("127.0.0.1:7000").addNodeAddress("127.0.0.1:7001").addNodeAddress("127.0.0.1:7002").build();RedissonClusterClient redisson = Redisson.createCluster(clusterNodes);
  1. 数据分片和故障转移:当客户端向Redis Cluster发送命令时,Redis Cluster会根据槽位的分配规则将命令路由到相应的节点进行处理。同时,Redis Cluster会自动进行故障检测和故障转移。当一个节点故障或离线时,Redis Cluster会将该节点的槽位重新分配给其他节点,以保证数据的可用性。

Redis Cluster要求至少有3个主节点,并且每个主节点都有至少一个从节点进行数据备份。这样可以保证在单个节点故障时,数据仍然可用,并且Redis Cluster可以自动进行故障转移。同时,为了保证Redis Cluster的高可用性和性能,还需要合理配置集群中的节点数量、网络拓扑等参数。

总之,Redis Cluster通过将数据分布存储和自动故障转移,实现了Redis的高可用性和横向扩展。在使用Redis Cluster时,需要正确配置和启动节点,以及合理设计和管理集群的数据分片和故障转移机制,以提供稳定和可靠的分布式数据存储服务。

3、如何使用RedLock算法
RedLock算法是一种用于在分布式系统中实现分布式锁的算法,它由Redis官方提出。RedLock算法通过在多个独立Redis实例上加锁,以保证分布式环境下的互斥性。

以下是使用RedLock算法的详细步骤:

  1. 配置Redis实例:在多个独立的Redis实例上,需要配置相同的密码,并确保这些实例之间可以相互通信。

  2. 获取锁:当需要获取锁时,客户端应该在多个Redis实例上分别执行以下步骤:

    a. 生成一个唯一的锁标识符(lock identifier)。

    b. 尝试在每个Redis实例上使用SET命令来设置一个锁键(lock key),并设置过期时间。

    c. 统计成功设置锁键的实例数量。

    d. 如果成功设置锁键的实例数量超过半数(majority),则表示锁获取成功;否则,表示锁获取失败。

  3. 释放锁:当不再需要锁时,客户端应该在每个Redis实例上执行以下步骤:

    a. 检查当前锁键是否和之前生成的锁标识符匹配。

    b. 如果匹配,则通过执行DEL命令来删除锁键。

  4. 容错处理:在使用RedLock算法时,需要处理网络延迟、节点故障以及竞争条件等可能引发的问题。可以通过设置合理的锁超时时间、重试机制和容错策略来提高算法的可靠性。

需要注意的是,RedLock算法并不是绝对可靠的,它无法解决网络分区(split-brain)等特殊情况下的一致性问题。因此,在使用RedLock算法时,需要根据具体应用场景和需求来评估其可用性和适用性。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/123272.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

「常识」浮点数和定点数

浮点数和定点数 本篇文章旨在简短的介绍浮点数、定点数的定义&#xff0c;以及一些常见的数制、补码。 一、常识 如果缺少以下常识的话&#xff0c;将很难理解浮点数和定点数的概念。 1、数 自然数整数/分数小数&#xff1a;有限小数、无限循环小数、无限不循环小数实数&a…

2.2 消元法的概念

一、消元法介绍 消元法&#xff08;elimination&#xff09;是一个求解线性方程组的系统性方法。下面是使用消元法求解一个 2 2 2\times2 22 线性方程组的例子。消元之前&#xff0c;两个方程都有 x x x 和 y y y&#xff0c;消元后&#xff0c;第一个未知数 x x x 将从第…

APC学习记录

文章目录 APC概念APC插入、执行过程逆向分析插入过程执行过程总结 代码演示参考资料 APC概念 APC全称叫做异步过程调用&#xff0c;英文名是 Asynchronous Procedure Call&#xff0c;在进行系统调用、线程切换、中断、异常时会进行触发执行的一段代码&#xff0c;其中主要分为…

机器学习 | 决策树算法

一、决策树算法概述 1、树模型 决策树&#xff1a;从根节点开始一步步走到叶子节点(决策)。所有的数据最终都会落到叶子节点&#xff0c;既可以做分类也可以做回归。 在分类问题中&#xff0c;表示基于特征对实例进行分类的过程&#xff0c;可以认为是if-then的集合&#xff0…

推理还是背诵?通过反事实任务探索语言模型的能力和局限性

推理还是背诵&#xff1f;通过反事实任务探索语言模型的能力和局限性 摘要1 引言2 反事实任务2.1 反事实理解检测 3 任务3.1 算术3.2 编程3.3 基本的句法推理3.4 带有一阶逻辑的自然语言推理3.5 空间推理3.6 绘图3.7 音乐3.8 国际象棋 4 结果5 分析5.1 反事实条件的“普遍性”5…

基于Qt 文本读写(QFile/QTextStream/QDataStream)实现

​ 在很多时候我们需要读写文本文件进行读写,比如写个 Mp3 音乐播放器需要读 Mp3 歌词里的文本,比如修改了一个 txt 文件后保存,就需要对这个文件进行读写操作。本章介绍简单的文本文件读写,内容精简,让大家了解文本读写的基本操作。 ## QFile 读写文本 QFile 类提供了读…

AIGC应用公司开始赚钱了,创始人来自中国,7个月实现100万美元ARR

图片来源&#xff1a;由无界AI生成 自 2022 年中以来&#xff0c;AIGC 赛道持续 1 年有余。然而&#xff0c;热闹归热闹&#xff0c;赚钱的公司一只手都能数得过来。奇葩如 Midjourney&#xff0c;硬是不靠 VC 输血凭着 11 人年做到 1 亿美元 ARR&#xff1b;幸运如 Jasper&…

ideaSSM在线商务管理系统VS开发mysql数据库web结构java编程计算机网页源码maven项目

一、源码特点 SSM 在线商务管理系统是一套完善的信息管理系统&#xff0c;结合SSM框架和bootstrap完成本系统&#xff0c;对理解JSP java编程开发语言有帮助系统采用SSM框架&#xff08;MVC模式开发&#xff09;&#xff0c;系统具有完整的源代码 和数据库&#xff0c;系统主…

No175.精选前端面试题,享受每天的挑战和学习

🤍 前端开发工程师(主业)、技术博主(副业)、已过CET6 🍨 阿珊和她的猫_CSDN个人主页 🕠 牛客高级专题作者、在牛客打造高质量专栏《前端面试必备》 🍚 蓝桥云课签约作者、已在蓝桥云课上架的前后端实战课程《Vue.js 和 Egg.js 开发企业级健康管理项目》、《带你从入…

WIN11新版画图问题解决

1 白色背景被连同删除的问题 解决方法&#xff1a;加层 将层调整为新建的层&#xff0c;在这个层下画图就行。 2 QQ截图无法直接放在画图上的问题 使用QQ截图的时候&#xff1a; 解决方法&#xff1a;使用windows自带的截图工具或者微信截图 步骤&#xff1a; 1. windows自带…

网络安全—小白自学

1.网络安全是什么 网络安全可以基于攻击和防御视角来分类&#xff0c;我们经常听到的 “红队”、“渗透测试” 等就是研究攻击技术&#xff0c;而“蓝队”、“安全运营”、“安全运维”则研究防御技术。 2.网络安全市场 一、是市场需求量高&#xff1b; 二、则是发展相对成熟…

docker-compose安装

1.安装docker-compose&#xff1a; yum install -y docker-compose 出现如下错误&#xff1a; 可以先执行&#xff1a; 添加docker-compose的yum仓库 yum install -y epel-release 附&#xff1a;

【Bug—eNSP】华为eNsp路由器设备启动一直是0解决方案!

问题描述 在上机实验时&#xff0c;打开ensp软件&#xff0c;添加AR设备时启动异常&#xff0c;最开始错误代码是40&#xff0c;最后通过重新安装&#xff0c;又出现了新的问题&#xff0c;启动AR设备一直是0&#xff0c;而且界面卡住。 解决方法 打开VirtualBox&#xff0c;将…

Redis文件事件模型

Redis是事件驱动的程序&#xff0c;并基于Reactor模式开发了自己的网络事件处理器&#xff0c;被称之为文件处理器(File Event Handler)。 文件处理器通过I/O多路复用程序来同时监听多个Socket&#xff0c;并根据Socket目前执行的任务来关联不同的事件处理器。当被监听的Socket…

剪辑中遮罩可分几种 剪辑遮罩视频怎么做

当你觉得剪辑特效很难制作的时候&#xff0c;不妨阅读一下本文&#xff0c;来了解遮罩的原理和用法。它是一种超级剪辑工具&#xff0c;可以制作出各种神奇的画面效果。在了解遮罩的基本原理后&#xff0c;就连初学者也能轻松地制作出令人惊艳的剪辑遮罩。有关剪辑中遮罩可分几…

vue3 code format bug

vue code format bug vue客户端代码格式化缺陷&#xff0c;为了方便阅读和维护&#xff0c;对代码格式化发现这个缺陷 vue.global.min.3.2.26.js var Vuefunction(r){"use strict";function e(e,t){const nObject.create(null);var re.split(",");for(le…

Spark新特性与核心概念

一、Sparkshuffle &#xff08;1&#xff09;Map和Reduce 在shuffle过程中&#xff0c;提供数据的称之为Map端&#xff08;Shuffle Write&#xff09;&#xff0c;接受数据的称之为Redeuce端&#xff08;Shuffle Read&#xff09;&#xff0c;在Spark的两个阶段中&#xff0c;总…

基于springboot,vue校园社团管理系统

开发工具&#xff1a;IDEA 服务器&#xff1a;Tomcat9.0&#xff0c; jdk1.8 项目构建&#xff1a;maven 数据库&#xff1a;mysql5.7 系统分前后台&#xff0c;项目采用前后端分离 前端技术&#xff1a;vueelementUI 服务端技术&#xff1a;springbootmybatis-plus 本系…

Linux之系统编程

1.yum 1.yum list可以出现所有可下载的程序 辅助grep进行查找 2.yum install可以下载并安装 3.yum remove可以卸载程序 不同的商业操作系统内核都是一样的&#xff0c;主要是配套社区不一样。 开源组织&#xff0c;各大公司&#xff0c;既得利益者。 同上 基础软件源可以保证…

李沐——论文阅读——VIT(VIsionTransformer)

一、终极结论&#xff1a; 如果在足够多的数据上面去做预训练&#xff0c;那么&#xff0c;我们也可以不用 卷积神经网络&#xff0c;而是直接用 自然语言处理那边搬过来的 Transformer&#xff0c;也能够把视觉问题解决的很好 &#xff08;tips&#xff1a;paperswithcode.co…