问题:redis如何持久化数据?
redis持久化数据的方式有两种:
第一种方式:Rdb
- 这种方式是定时存储数据
- 修改了1条数据900秒(15分钟)保存
- 修改了10条数据300秒(5分钟)保存
- 修改了10000条数据60秒(1分钟)保存
这种方式存在的问题:如果数据保存时间还没有到,程序意外终止,就会导致还没有保存的数据会丢失
为了解决该问题redis提供了另一种持久化的机制: aof
第二种方式: AOF
- 特点:这种方式修改任何数据,都会马上将数据持久化到文件
问题2:如何防止redis中的单点故障?
- 单点故障是指,redis主机损坏或者无法访问,导致数据数据无法正常读取
redis通过主从复制的方式,可以防止单点故障
主从复制:给一台主机配置一台或者是多台从机,主机上有任何数据变化,数据将会自动保存到从机上,当主机无法访问时,从机依然可以提供数据
问题3:如何配置redis的主从复制?
实际开发中,一台主机或者从机都是一台独立的电脑
在学习环境中,我们在linux中,配置多个redis目录,它就相当于多个redis服务器
步骤:
1、将/usr/local/d91/redis/bin目录复制一份,取名bin2
- bin,bin2就相于当两台redis主机
2、主机:无需要进行任何配置
3、配置从机:
A、删除 bin2目录下的 *.rdb 和 *.aof
- rm -rf *.rdb *.aof
B、修改redis.conf文件
- 将port端口号,从6379更改为6380
- 指定当前是哪一台主机的从机
- slaveof 主机的ip地址 主机的端口
- slaveof 192.168.112.137 6379
4、分别启动主机、从机
启动主机
进入bin目录,执行
./redis-server redis.conf --启动服务器
./redis-cli ---启动客户端
启动从机
进入bin2目录,执行
./redis-server redis.conf --启动服务器
./redis-cli -p 6380 ---启动客户端
- 在redis中,主机可读可写,从机只可读,不可写
-------------------------------------------------------------------------------
Redis集群:通过网络把多台redis主机连接在一起,共同处理用户请求
redis集群的要求:
- redis集群中主机的数量必须是单数 (至少要有3台)
- redis集群中的主机一般都需要配置从机(当主机挂了,从机就会升级成主机) 配置redis集群,一般至少需要6台服务器
- redis中的主机相互之间可以通信,只要连接上集群中的任意一台主机,其他主机上的数据都可以访问
配置redis集群以后,数据如何存储(数据到底存储在哪一台主机?)
答:当配置redis集群以后,集群中,会产生16384个哈希槽(哈希槽用于存储具体的数据),这16384个哈希槽会均分到每1台redis主机 (哈希槽的编号是从: 0 ----16383),当通过键,值对存储数据时,redis将会键产生crc16算法,将键转换成一个数值,然后再用该数值取模16384,它的结果一定介于0-16383之间,然后系统会判断,该数值对应的哈希槽在哪一台redis主机上,然后就会自动切换到当前主机存储数据
判断redis集群失败的标准:
- 当集群中的某一台主机挂掉了,而它没有配置从机(集群失败)
- 当集群中有一半以上的主机挂掉了,即使它们都配置有从机(集群也算失败)
- redis集群的管理工具,是用ruby这种语言编写的,所以,要管理redis集群,要先配置ruby的环境
准备工作:
1、安装ruby环境
- yum install ruby
- yum install rubygems
2、将redis集群管理工具 发布到linux系统中的d91目录下
- redis-3.0.0.gem
3、安装集群管理工具(进入d91目录)
- gem install redis-3.0.0.gem
4、在usr/local/d91/目录下,新建 redis-cluster目录,用于存放redis集群中的多台服务器
- mkdir /usr/local/d91/redis-cluster
5、将usr/local/d91/redis.3.0.0/src/redis-trib.rb复制一份,放到usr/local/d91/redis-cluster目录下
- cp /usr/local/d91/redis-3.0.0/src/redis-trib.rb /usr/local/d91/redis-cluster/
配置集群:
1、将 /usr/local/d91/redis/目录的bin复制一份到/usr/local/d91/redis-cluster目录中,取名7001
- cp -r /usr/local/d91/redis/bin /usr/local/d91/redis-cluster/7001
2、进入 7001目录,修改redis.conf文件
- 更改端口为7001
- 启用集群
cluster-enable yes
3、删除目录中 aof,rdb文件
- rm -rf *.aof *.rdb
4、将7001复制5份,分别命令为:7002----7006 (相当于6台redis服务器)
- cp -r 7001 7002
- cp -r 7001 7003
- cp -r 7001 7004
- cp -r 7001 7005
- cp -r 7001 7006
5、分别进入7002-7006目录,将端口号更改为:7002---7006
6、分别启动 7001--7006这六台服务器
- 进入对应的目录,执行 ./redis-server redis.conf
7、创建redis集群
进入/usr/local/d91/redis-cluster,执行下列命令
./redis-trib.rb create --replicas 1 虚拟机ip地址:7001 虚拟机ip地址:7002 虚拟机ip地址:7003 192.168.112.137:7004 虚拟机ip地址:7005 虚拟机ip地址:7006
- 安装过程中,有选择的地方,输入yes
8、连接客户端(任意一台主机的客户端都可以连接)
以7001为例:
- 先进入7001目录
- 连接客户端
./redis-cli -h 虚拟机ip地址 -p 7001 -c
9、查看集群的信息
- cluster info
10、查看集群中的主机信息,以及哈希槽的分布
- cluster nodes
11、测试
- set msg jack
12、在防火墙注册 7001----7006
- firewall-cmd --zone=public --add-port=7001/tcp --permanent
- firewall-cmd --reload
@@@@@@@:集群中的某一台主机挂掉了,它的从机就会自动升级为主机
@@@@@@@:此时,将挂掉的主机,再次启动,它就是变为其他主机的从机
redis中的缓存穿透
package org.java.service.impl;
import org.java.dao.PrdMapper;
import org.java.entity.Prd;
import org.java.redis.RedisClient;
import org.java.service.PrdService;
import org.java.util.JsonUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.stereotype.Component;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;
import java.util.List;
@Service
public class PrdServiceImpl implements PrdService {
@Autowired
private PrdMapper mapper;
@Autowired//注入redis接口
@Qualifier("singleton")
private RedisClient redisClient;
@Override
public List<Prd> getList() {
//首先判断,redis中有没有需析数据
String json = redisClient.hget("redis_j54_singleton", "getList");
if (StringUtils.isEmpty(json)) {
//缓存中没有
//此时,第1次的100个线会同时运行到此处
synchronized (this){
//再一次判断,是否已经有线程从数据库加载了数据放入缓存中
json = redisClient.hget("redis_j54_singleton", "getList");
if(StringUtils.isEmpty(json)){
//目前还没有线程查询数据库,当前线程可以从数据库加载
System.out.println("==================数据来自至于database============");
//redis没有缓存,准备查询关系型数据库
List<Prd> list = mapper.getList();
//将集合序列化成json格式的字符串
json = JsonUtils.objectToJson(list);
//将查询到的结果,存放到缓存中
redisClient.hset("redis_j54_singleton", "getList", json);
return list;
}else{
//已经有线程从数据库加载了数据
System.out.println("==================数据来自至于redis============");
//有缓存数据,可以将json数据,转换成集合
List<Prd> list = JsonUtils.jsonToList(json, Prd.class);
return list;
}
}
} else {
//缓存中存在
System.out.println("==================数据来自至于redis============");
//有缓存数据,可以将json数据,转换成集合
List<Prd> list = JsonUtils.jsonToList(json, Prd.class);
return list;
}
}
}