一台主机上打开了6个redis节点
其中123是主节点,456分别是它们的从节点
每一个主节点都只有一个从节点
在1节点中写入数据那么在不是1节点的从节点的5节点为什么可以get到该数据
从节点会从主节点同步数据,当主节点故障时,从节点可以切换为主节点,整个redis集群仍可用,达到高可用的目的。另外,集群模式下,在任何一个节点get(不属于该节点的)数据,集群会自动跳到该数据所在的节点获取到数据
如果在1节点中写入数据,那么它的从节点4也会收到并执行这个写命令,将数据保存在自己的数据库中。同时,如果4节点和5节点之间也存在主从复制关系,那么4节点会将收到的写命令再同步给5节点,使得5节点也能够获取到这个数据
不知道你这个问题是否已经解决, 如果还没有解决的话: redis作为一种非关系型数据库,它有很多用法,这次就简单说下spring boot集成redis时简单的配置并简单介绍防止订单重复提交的做法和缓存的用法.
首先要安装redis对于如何安装redis可以参考链接:
当然也可以自己参考其他网站的安装方法
安装完成之后一定要设置自己的密码:检查步骤
(1).找到redis的安装路径找到redis.conf ----redis的配置文件
(2).在与redis.conf同级的目录下输入命令:
grep requirepass redis.conf
(3).在输入上命令后假如看到
requirepass 你的密码
说明你的redis已经设置了密码,那么就可以进行java集成;
假如看到
requirepass 前面带#那么说明设置的密码不生效,需要进入到配置文件中将requirepass前面的#去掉 后面是你想要设置的密码:
vim redis.conf
那么接下来开始集成到java中.
1.首先引入坐标
<!-- kaptcha -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
2.配置yml文件设置连接redis的ip和端口以及密码的设置
spring:
redis:
database: 1
host: 192.168.159.23 #这里填写redis所在虚拟机的ip
port: 6379 #这里填写redis服务的端口
password: 12345 #这里填写redis的密码
jedis:
pool:
max-active: 8 #连接池的最大数据库连接数。设为0表示无限制。
max-wait: 5000ms #最大等待毫秒数, 单位为 ms, 超过时间会出错误信息
max-idle: 8 #最大空闲数,数据库连接的最大空闲时间。超过空闲时间,数据库连接将被标记为不可用,然后被释放。设为0表示无限制。
min-idle: 0 #连接池中的最小空闲连接数
timeout: 5000 #超时时间单位ms
3.配置RedisTemplate:
package com.person.config;
import com.fasterxml.jackson.annotation.JsonAutoDetect;
import com.fasterxml.jackson.annotation.PropertyAccessor;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.redis.connection.RedisConnectionFactory;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.serializer.Jackson2JsonRedisSerializer;
import org.springframework.data.redis.serializer.StringRedisSerializer;
@Configuration
public class RedisTemplateConfig {
@Bean("redis")
@SuppressWarnings("all")
public RedisTemplate<String, Object> redisTemplate(RedisConnectionFactory factory) {
RedisTemplate<String, Object> template = new RedisTemplate<>();
template.setConnectionFactory(factory);
Jackson2JsonRedisSerializer jackson2JsonRedisSerializer = new Jackson2JsonRedisSerializer(Object.class);
ObjectMapper mapper = new ObjectMapper();
mapper.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);
mapper.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL);
jackson2JsonRedisSerializer.setObjectMapper(mapper);
StringRedisSerializer stringRedisSerializer = new StringRedisSerializer();
// key采用String的序列化方式
template.setKeySerializer(stringRedisSerializer);
// hash的key也采用String的序列化方式
template.setHashKeySerializer(stringRedisSerializer);
// value序列化方式采用jackson
template.setValueSerializer(jackson2JsonRedisSerializer);
// hash的value序列化方式采用jackson
template.setHashValueSerializer(jackson2JsonRedisSerializer);
template.afterPropertiesSet();
return template;
}
}
4.配置一个获取Bean的类:
package com.person.util;
import org.springframework.beans.BeansException;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.stereotype.Component;
@Component
public class AppCtxtUtil implements ApplicationContextAware {
private static ApplicationContext ctx;
@Override
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
ctx = applicationContext;
}
public static ApplicationContext getCtx() {
return ctx;
}
/**
* 根据name获取Bean
*
* @param beanName bean名称
* @return Bean
* @throws BeansException
*/
public static Object getBean(String beanName) throws BeansException {
return ctx.getBean(beanName);
}
/**
* 根据Class获取Bean
*
* @param <T> 类型
* @param requiredType bean类型
* @return Bean
* @throws BeansException
*/
public static <T> T getBean(Class<T> requiredType) throws BeansException {
return ctx.getBean(requiredType);
}
}
5.编写redis工具类:
package com.person.util;
import org.springframework.data.redis.core.RedisTemplate;
import java.util.concurrent.TimeUnit;
public class RedisUtil {
private static RedisTemplate redis = (RedisTemplate)AppCtxtUtil.getBean("redis");
/**
* 存入缓存数据
* @param key 要缓存的key
* @param value 要缓存的value
* @param time 缓存的时间
* @param timeout 缓存的时间单位秒,毫秒,小时等等
*/
public static void setKey(String key,String value,long time,TimeUnit timeout) {
try {
redis.opsForValue().set(key,value,time, timeout);
} catch (Exception e) {
e.printStackTrace();
}
}
/**
* redis中是否存在缓存数据
* @param key 想要检查的key
* @return
*/
public static boolean hasKey(String key){
try {
Boolean aBoolean = redis.hasKey(key);
return aBoolean;
} catch (Exception e) {
e.printStackTrace();
}
return false;
}
}
6.开始使用RedisUtil工具进行缓存和校验
防止订单提交重复:
在controller层测试:
@PostMapping("/order")
public String saveGoods(@RequestBody Goods goods) throws Exception {
//防止订单短时间内重复提交
try {
if (!RedisUtil.hasKey(goods.getId())) {
throw new Exception("订单提交重复");
} else {
//保存订单信息
save(goods);
//缓存订单信息时间为5s
RedisUtil.setKey(goods.getId(), null, 5, TimeUnit.SECONDS);
return "订单保存成功";
}
} catch (Exception e) {
return e.getMessage();
}
}
除此之外还有很多用,比如验证码校验,查询缓存只要redis配置好,没有什么能难倒!!!
问题:在同一IP下的Redis节点在逻辑上的数据共享吗?
回答:Redis节点在逻辑上是不共享数据的。每个Redis节点都拥有独立的存储空间和数据集。当你在其中一个节点中写入数据时,该数据只会保存在该节点自己的存储空间中,并不会被自动复制到其他节点。
如果你希望在多个Redis节点之间实现数据共享,你可以利用Redis的主从复制功能。主从复制是一种通过复制主节点上的数据到从节点来实现数据共享的机制。
下面是一种使用Redis主从复制的方式来实现数据共享的步骤:
replicaof <masterip> <masterport>
其中,<masterip>
和<masterport>
是主节点的IP地址和端口。
启动所有Redis节点,包括主节点和从节点。你可以使用redis-server
命令来启动Redis节点。
在主节点中写入数据。可以使用set
命令来向主节点写入数据,例如:
set key value
get
命令来从从节点中获取数据,例如:get key
如果从节点能够获取到数据,说明主从复制已成功实现,数据在逻辑上进行了共享。
需要注意的是,Redis主从复制是异步进行的,有一定的延迟。主节点上的数据变动不会立即在从节点上可见,需要等待一段时间。此外,从节点只能读取数据,无法在从节点上进行写入操作。
如果在以上步骤中遇到了问题,例如数据未能正确同步或数据延迟过高,可能是由于网络延迟、配置错误或其他原因造成的。在排查问题时,可以参考参考资料中的段落编号9中关于主从数据不一致和网络延时的解决办法。
如果你对Redis主从复制的配置和操作还不熟悉,建议先查阅Redis官方文档或其他专业资料,以便更加全面地理解和使用这个功能。