Redis 2023面试5题(六)

news/2024/10/25 12:27:07/

一、Redis集群为什么至少需要三个master节点

Redis集群至少需要三个master节点,这是因为新master的选举需要大于半数的集群master节点同意才能选举成功,如果只有两个master节点,当其中一个挂了,是达不到选举新master的条件的。此外,Redis Cluster推荐节点数为奇数,因为这样可以避免出现脑裂现象。

二、Redis集群为什么推荐奇数个节点

因为新master的选举需要大于半数的集群master节点同意才能选举成功,奇数个master节点可以在满足选举该条件的基础上节省一个节点,比如三个master节点和四个master节点的集群相比,大家如果都挂了一个master节点都能洗举新master节点,如果都挂了两个master节点都没法选举新master节点了,所以奇数的master节点更多的是从节省机器资源角度出发说的。

三、Redis集群支持批量操作命令吗

Redis集群支持批量操作命令,但是需要注意的是,不同的命令在不同的节点上执行可能会有不同的结果。

例如,使用mget命令时,如果一个key在多个节点上都有数据,那么这些节点都会返回该key对应的值;

而使用pipeline命令时,如果一个key在多个节点上都有数据,那么这些节点会将该key对应的值打包成一个批次发送给客户端。

对于类似mset,mget这样的多个key的原生批量操作命令,redis集群只支持所有key落在同一slot的情况,如果有多个key一定要用mset命令在redis集群上操作,则可以在key的前面加上XXX1,这样参数数据分片hash计算的只会是大括号里的值,这样能确保不同的key能落到同一slot里去,示例如下:

mset (user11:1:name zhuge fuser1}:1:age 18
  • pipeline使用方法
private Jedis jedis;public void initJedis() {jedis = new Jedis("192.168.16.10", 6379);jedis.select(3);
}@Testpublic void testPipeline() {initJedis();Pipeline pipelined = jedis.pipelined();long start = System.currentTimeMillis();String[] arr = new String[2000];for (int i = 1; i <= 100000; i++) {pipelined.set("test:key_" +i, "value_" +i);if (i % 1000 == 0){pipelined.sync();}}long end = System.currentTimeMillis();System.out.println("时间==" + (end - start));}

四、Lua脚本能在Redis集群里执行吗

是的。可以使用Lua脚本在Redis集群中执行。Redis集群支持在多个节点上执行Lua脚本,这可以通过将脚本推送到多个节点并使用Redis的EVAL命令来执行来实现。使用Lua脚本可以方便地执行一些复杂的操作,例如条件判断、循环和数据转换等。

需要注意的是,在Redis集群中执行Lua脚本时,需要确保所有节点都可以访问到脚本文件,并且脚本文件应该位于所有节点上。此外,在执行Lua脚本之前,需要使用Jedis客户端将脚本推送到Redis集群中的一个节点,然后使用EVAL命令在集群中执行脚本。为了提高性能和可靠性,建议使用pipeline技术一次性发送多个命令到Redis集群,并使用sync()方法获取所有结果。

执行示例:

下面是一个使用Lua脚本在Redis集群中执行的条件交易示例:
保存为test.lua文件

-- 定义Lua脚本  
local buy_key = KEYS[1]   -- 交易买入信号的key  
local sell_key = KEYS[2]  -- 交易卖出信号的key  
local price = tonumber(ARGV[1])   -- 交易价格  
local amount = tonumber(ARGV[2])  -- 交易数量  -- 获取当前股票价格  
local current_price = tonumber(redis.call('get', buy_key))  
if not current_price then  return 'Invalid'  
end  -- 判断是否满足买入条件  
if price > current_price then  -- 记录买入信号  redis.call('set', buy_key, price)  redis.call('set', sell_key, amount)  return 'Buy'  
else  return 'Sell'  
end

在Redis集群中执行该脚本,可以使用以下Jedis代码:

Jedis jedis = new Jedis("localhost");  
jedis.set("stock_price", "100");  
jedis.set("stock_amount", "1000");  Pipeline pipeline = jedis.pipelined();  
pipeline.eval(Scripting.scriptText("test.lua"), 2, "stock_price", "120", "stock_amount", "50");  
pipeline.sync();

在以上示例中,

  • 首先使用Jedis客户端将股票价格和数量存储到Redis集群中。
  • 然后,使用Pipeline技术执行Lua脚本,将脚本文件名和参数传递给eval()方法。
  • 在Lua脚本中,使用GET命令获取当前股票价格,判断是否满足买入条件,如果满足,则使用SET命令记录买入信号,并返回"Buy",否则返回"Sell"。
  • 最后,使用sync()方法获取所有结果。

需要注意的是,在执行Lua脚本之前,需要将脚本文件保存在所有Redis节点上,并确保所有节点都可以访问到该文件。

五、Redis主从切换导致分布式锁丢失问题是怎么回事

当使用Redis实现分布式锁时,主从切换可能导致分布式锁丢失的问题。这是因为当主Redis实例挂掉后,Redis集群会进行主从切换,从Redis实例会成为新的主Redis实例。在这个过程中,如果主Redis实例上还有未同步到从Redis实例的写操作,就会导致写操作丢失。

具体来说,当一个线程获取了分布式锁并执行业务逻辑时,如果主Redis实例挂掉了,那么在主从切换过程中,从Redis实例上就不会有该线程持有的锁。当该线程再次尝试获取锁时,由于从Redis实例上没有该线程持有的锁,该线程就会再次获取到锁,导致并发安全问题。

为了解决这个问题,可以使用Redlock算法,它是一种Redis分布式锁的解决方案。Redlock算法使用多个Redis实例来保证分布式锁的可靠性,当一个线程需要获取分布式锁时,它需要获得多个Redis实例上的锁。当主Redis实例挂掉后,从Redis实例可以继续服务客户端的请求,从而保证分布式锁不会丢失。

  • 以下是一个使用Redlock算法解决Redis主从切换导致分布式锁丢失的示例:
import redis.clients.jedis.Jedis;  
import redis.clients.jedis.JedisPool;  
import redis.clients.jedis.JedisPoolConfig;  
import redis.clients.jedis.Redlock;  public class DistributedLock {  private static final int LOCK_EXPIRE_TIME = 3000; // 锁过期时间,单位为毫秒  private static final int LOCK_ACQUIRE_TIMEOUT = 3000; // 获取锁的超时时间,单位为毫秒  private static final int NUM_REDIS_INSTANCES = 5; // Redis实例数量  private JedisPool jedisPool;  public DistributedLock(String[] redisNodes) {  JedisPoolConfig config = new JedisPoolConfig();  jedisPool = new JedisPool(config, "localhost", 6379);  // 创建Redlock实例,需要传入Redis实例的数量和节点列表  Redlock redlock = new Redlock(jedisPool, NUM_REDIS_INSTANCES, redisNodes);  // 获取锁,需要传入锁的名称、锁的过期时间和获取锁的超时时间  boolean locked = redlock.lock("my_lock", LOCK_EXPIRE_TIME, LOCK_ACQUIRE_TIMEOUT);  if (locked) {  try {  // 执行业务逻辑  // ...  } finally {  // 释放锁  redlock.unlock("my_lock");  }  } else {  // 获取锁失败,处理并发访问的情况  // ...  }  }  public void close() {  jedisPool.close();  }  
}

在以上示例中,使用Jedis客户端创建了一个包含5个Redis实例的连接池,并使用Redlock算法实现了分布式锁。

  • 在创建Redlock实例时,需要传入Redis实例的数量和节点列表。
  • 在获取锁时,需要传入锁的名称、锁的过期时间和获取锁的超时时间。如果获取锁成功,就执行业务逻辑,并在finally块中释放锁。如果获取锁失败,就处理并发访问的情况。
  • 最后,在程序结束时,需要调用close()方法关闭连接池。

http://www.ppmy.cn/news/546550.html

相关文章

【C++】泛型编程——模板进阶

文章目录 前言1. 模板参数的分类2. 非类型模板参数2.1 非类型模板参数的概念2.2 铺垫2.2 非类型模板参数的使用2.4 注意2.5 array的了解 3. 模板的特化3.1 概念3.2 函数模板特化3.3 类模板特化3.3.1 全特化3.3.2 偏特化部分特化参数更进一步的限制 4. 模板分离编译4.1 什么是分…

计算机病毒是指______.,计算机病毒是指

语音内容&#xff1a; 大家好&#xff0c;我是时间财富网智能客服时间君&#xff0c;上述问题将由我为大家进行解答。 计算机病毒是编制者在计算机程序中插入的破坏计算机功能或者数据的代码&#xff0c;能影响计算机使用&#xff0c;能自我复制的一组计算机指令或者程序代码。…

关于计算机病毒

1.计算机病毒 编制或在计算机中插入的可破坏计算机功能&#xff0c;数据&#xff0c;并能够自我复制的计算机指令或程序代码。 2.蠕虫 蠕虫病毒是以计算机为载体&#xff0c;以网络为攻击对象的病毒。它在互联网环境下复制自身进行传播&#xff0c;通过共享文件夹&#xff0c;…

计算机病毒计算机中的程序是吗,计算机病毒是一种程序吗?

计算机病毒是一种程序&#xff0c;是一种工资编制的特别程序。计算机病毒是编制者在计算机程序中插进去的损坏计算机功用或许数据的代码&#xff0c;能影响计算机运用&#xff0c;能自我复制的一组计算机指令或许程序代码。 计算机病毒是工资制作的&#xff0c;有损坏性&#x…

最近有什么厉害的计算机病毒?

和同事朋友们吃饭聚会&#xff0c;一说起来我是做计算机安全的&#xff0c;一个常常被问到的问题是&#xff1a;最近有什么厉害的计算机病毒没有&#xff1f; 要回答这个问题&#xff0c;我们先说说&#xff0c;你觉得什么才是“厉害”的病毒&#xff1f; 是指病毒发作的时候造…

计算机病毒的六大特征

计算机病毒的六大特征 1、繁殖性&#xff1a;计算机病毒可以像生物病毒一样进行繁殖&#xff0c;当正常程序运行时&#xff0c;它也进行运行自身复制&#xff0c;是否具有繁殖、感染的特征是判断某段程序为计算机病毒的首要条件。 2、破坏性&#xff1a;计算机中毒后&#xff…

计算机病毒与防范技术

一 、计算机病毒概述 1. 计算机病毒的概念&#xff1a; 从多个角度对"计算机病毒"进行定义&#xff1a; 1. 计算机病毒实际上是一段程序代码。类似自然界中的生物病毒,计算机病毒具有强大的复制能力,能够迅速地蔓延到网络&#xff0c;上的每一台计算机。病毒能够将…

计算机病毒基本知识

今天了解了计算机病毒的一些基本知识 &#xff0c;如下六点&#xff1a; 一、计算机病毒 定义 计算机病毒是指编制或者在计算机程序中插入的破坏计算机功能或者破坏数据&#xff0c;影响计算机使用并且能够自我复制的一组计算机指令或者程序代码 二、产生原因 1、编制人员出于…