特点 :1、是一个高性能的key/value内存型数据库
2、支持丰富的数据类型(string,List,Set,ZSet,Hash)
3、支持持久化 内存数据, 可以持久化到硬盘中
4、单进程,单线程 效率高 redis实现分布式锁
1、flushDB 清空当前库
2、flushAll 清空所有库
3、查看redis服务进程是否已经启动(redis服务状态)
1.ps -ef | grep redis
2.ps -aux | grep redis
3.netstat -tunple | grep 6379
4.lsof -i :6379
1、删除: del key(名字) ……
2、exists : 检查指定key是否存在 EXISTS key(名字)
3、expire: 给key设置生存时间,当key过期时(生存时间为0),它会被自动删除 EXPIRE key 时间
4、keys * 查询所有key
命令 | 说明 |
---|---|
set | 设置一个key/value |
get | 根据key获得对应的value |
mset | 一次设置多个key value |
mget | 一次获得多个key的value |
getset | 获得原始key的值,同时设置新值 |
strlen | 获得对应key存储value的长度 |
append | 为对应key的value追加内容 |
getrange 索引0开始 | 截取value的内容 |
setex | 设置一个key存活的有效期(秒) |
psetex | 设置一个key存活的有效期(毫秒) |
setnx | 存在不做任何操作,不存在添加 |
msetnx原子操作(只要有一个存在不做任何操作) | 可以同时设置多个key,只有有一个存在都不保存 |
decr | 进行数值类型的-1操作 |
decrby | 根据提供的数据进行减法操作 |
Incr | 进行数值类型的+1操作 |
incrby | 根据提供的数据进行加法操作 |
Incrbyfloat | 根据提供的数据加入浮点数 |
list 列表 相当于java中list 集合 特点 元素有序 且 可以重复
命令 | 说明 |
---|---|
lpush | 将某个值加入到一个key列表头部 |
lpushx | 同lpush,但是必须要保证这个key存在 |
rpush | 将某个值加入到一个key列表末尾 |
rpushx | 同rpush,但是必须要保证这个key存在 |
lpop | 返回和移除列表左边的第一个元素 |
rpop | 返回和移除列表右边的第一个元素 |
lrange | 获取某一个下标区间内的元素 |
llen | 获取列表元素个数 |
lset | 设置某一个指定索引的值(索引必须存在) |
lindex | 获取某一个指定索引位置的元素 |
lrem | 删除重复元素 |
ltrim | 保留列表中特定区间内的元素 |
linsert | 在某一个元素之前,之后插入新元素 |
特点: Set类型 Set集合 元素无序 不可以重复
命令 | 说明 |
---|---|
sadd | 为集合添加元素 |
smembers | 显示集合中所有元素 无序 |
scard | 返回集合中元素的个数 |
spop | 随机返回一个元素 并将元素在集合中删除 |
smove | 从一个集合中向另一个集合移动元素 必须是同一种类型 |
srem | 从集合中删除一个元素 |
sismember | 判断一个集合中是否含有这个元素 |
srandmember | 随机返回元素 |
sdiff | 去掉第一个集合中其它集合含有的相同元素 |
sinter | 求交集 |
sunion | 求和集 |
特点: 可排序的set集合 排序 不可重复
ZSET 官方 可排序SET sortSet
命令 | 说明 |
---|---|
zadd | 添加一个有序集合元素 |
zcard | 返回集合的元素个数 |
zrange 升序 zrevrange 降序 | 返回一个范围内的元素 |
zrangebyscore | 按照分数查找一个范围内的元素 |
zrank | 返回排名 |
zrevrank | 倒序排名 |
zscore | 显示某一个元素的分数 |
zrem | 移除某一个元素 |
zincrby | 给某个特定元素加分 |
特点: value 是一个map结构 存在key value key 无序的
命令 | 说明 |
---|---|
hset | 设置一个key/value对 |
hget | 获得一个key对应的value |
hgetall | 获得所有的key/value对 |
hdel | 删除某一个key/value对 |
hexists | 判断一个key是否存在 |
hkeys | 获得所有的key |
hvals | 获得所有的value |
hmset | 设置多个key/value |
hmget | 获得多个key的value |
hsetnx | 设置一个不存在的key的值 |
hincrby | 为value进行加法运算 |
hincrbyfloat | 为value加入浮点值 |
原因:
目前Redis官网下载的版本为 6.0版本 make安装
会报错是因为gcc版本过低,yum安装的gcc是4.8.5的。因此需要升级gcc,升级过程如下:
当2种持久化同时开启的时候以AOF为主。
redis官方提供了两种不同的持久化方法来将数据存储待硬盘里面分别是:
1、快照(Snapshot)
(1)、特点:这种方式可以将某一时刻的数据都写入到磁盘中,当然这也是redis的默认开启持久化方式,保存文件形式是以rdb结尾的文件因此这方式也称之为rdb方式
(2)、生成方式:
●客户端方式:BGSAVE 和 SAVE指令
BGSAVE:当接受到客户端的BGSAVE命令时,redis会调用frok来创建一个子进程,然后子进程负责将快照写入磁盘中,儿父进程继续处理命令请求。
●服务器配置自动触发
2、AOF(Append Only File)只追加日志文件
开启AOF持久化
1、在redis 配置文件里redis.conf 修改appendonly yes 开启持久化
2、修改 appendonlyname “appendonlyname.aof” 指定生成文件名
3、日志追加频率
1、always 谨慎使用 每个redis写命令都要同步写入磁盘,严重降低redis的速度
2、everysec 推荐 redis默认使用的方式。 每秒执行一次同步显示的将多个写命令同步到磁盘
3、no 不推荐 由操作系统决定何时同步,有可能会导致数据丢失
4、修改日志同步频率
修改appendfsync everysec | always |no 指定
1、AOF带来的问题
AOF的方式也同时带来了另一个问题。持久化文件会变的越来越大。例如我们调用incr test命令100次,文件中必须保存全部的100条命令,其实有99条都是多余的。因为要恢复数据库的状态其实文件中保存一条set test 100就够了。为了压缩aof的持久化文件Redis提供了AOF重写(ReWriter)机制。
2、AOF重写
用来在一定程度上减小AOF文件的体积
# 1.客户端方式触发重写
- 执行BGREWRITEAOF命令 不会阻塞redis的服务
# 2.服务器配置方式自动触发
- 配置redis.conf中的auto-aof-rewrite-percentage选项 参加下图↓↓↓
- 如果设置auto-aof-rewrite-percentage值为100和auto-aof-rewrite-min-size 64mb,并且启用的AOF持久化时,那么当AOF文件体积大于64M,并且AOF文件的体积比上一次重写之后体积大了至少一倍(100%)时,会自动触发,如果重写过于频繁,用户可以考虑将auto-aof-rewrite-percentage设置为更大
注意:重写aof文件的操作,并没有读取旧的aof文件,而是将整个内存中的数据库内容用命令的方式重写了一个新的aof文件,替换原有的文件这点和快照有点类似。 进行文件的替换
4.现在父进程可以使用临时文件替换老的aof文件,并重命名,后面收到的写命令也开始往新的aof文件中追加。
两种持久化方案既可以同时使用(aof),又可以单独使用,在某种情况下也可以都不使用,具体使用那种持久化方案取决于用户的数据和应用决定。
无论使用AOF还是快照机制持久化,将数据持久化到硬盘都是有必要的,除了持久化外,用户还应该对持久化的文件进行备份(最好备份在多个不同地方)。
RDB:将redis内存的中数据存库记录定时写入磁盘上的RDB持久化
AOF:将redis的操作日志以追加的方式写入文件
RDB持久化是指在指定的时间间隔内将内存中的数据集快照写入磁盘,实际操作过程是fork一个子进程,先将数据集写入临时文件,写入成功后,再替换之前的文件,用二进制压缩存储。
AOF持久化以日志的形式记录服务器所处理的每一个写、删除操作,查询操作不会记录,以文本的方式记录,可以打开文件看到详细的操作记录。
Redis会将数据集的快照dump到dump.rdb文件中。此外,我们也可以通过配置文件来修改Redis服务器dump快照的频率,在打开6379.conf文件之后,我们搜索save,可以看到下面的配置信息:
在Redis的配置文件中存在三种同步方式,它们分别是:
<dependency>
<groupId>redis.clientsgroupId>
<artifactId>jedisartifactId>
<version>2.9.0version>
dependency>
public static void main(String[] args) {
//1.创建jedis对象
Jedis jedis = new Jedis("192.168.40.4", 6379);//1.redis服务必须关闭防火墙 2.redis服务必须开启远程连接
jedis.select(0);//选择操作的库默认0号库
//2.执行相关操作
//....
//3.释放资源
jedis.close();
}
public class TestKey {
private Jedis jedis;
@Before
public void before(){
jedis = new Jedis("192.168.3.176",7000);
}
@After
public void after(){
jedis.close();
}
//测试key相关
@Test
public void testKey(){
//删除一个key
jedis.del("name");
//删除多个key
// jedis.del("name","age");
//判断一个key是否存在
System.out.println(jedis.exists("name"));
//设置一个key的超时时间
//Long age = jedis.expire("age", 100);
//System.out.println(age);
//查看一个key的超时时间
/* Long age1 = jedis.ttl("newAge");
System.out.println(age1);*/
//随机获取一个key
System.out.println(jedis.randomKey());
//修改key的名称
//System.out.println(jedis.rename("age","newAge"));
//查看key对应值的类型
System.out.println(jedis.type("zsts"));
}
}
public class TestString {
private Jedis jedis;
@Before
public void before(){
jedis = new Jedis("192.168.3.176",7000);
}
@After
public void after(){
jedis.close();
}
//测试String相关
@Test
public void testString(){
//set
jedis.set("name", "小陈");
//get
System.out.println(jedis.get("name"));
//设置多个 mset
jedis.mset("sex","20","bir","2020-12-23");
//获取多个 mget
jedis.mget("name","sex","bir").forEach(mget-> System.out.println("mget="+mget));
//getset
System.out.println(jedis.getSet("name","小红"));
// System.out.println(jedis.get("name"));
}
}
public class TestList {
private Jedis jedis;
@Before
public void before(){
jedis = new Jedis("192.168.3.176",7000);
}
@After
public void after(){
jedis.close();
}
//测试List相关
@Test
public void testString(){
//lpush 将某个值加入到一个key列表头部
/* jedis.lpush("names1","张三","王五","赵六","win7");
//rpush 将某个值加入到一个key列表末尾
jedis.rpush("names1","xiaomingming");
//遍历
//jedis.lrange("names1",0,-1).forEach(list-> System.out.println("list="+list));
//lpop 从左边移除 rpop 从右边移除
//System.out.println(jedis.lpop("names1"));
System.out.println(jedis.rpop("names1"));*/
//linsert 在某一个元素之前,之后插入新元素
jedis.linsert("lists", BinaryClient.LIST_POSITION.BEFORE,"xiaohei","xiaobai");
//linsert 在某一个元素之后插入新元素
jedis.linsert("lists", BinaryClient.LIST_POSITION.AFTER,"xiaohei","xiaolang");
}
}
//测试SET相关
@Test
public void testSet(){
//sadd
jedis.sadd("names","zhangsan","lisi");
//smembers
jedis.smembers("names");
//sismember
jedis.sismember("names","xiaochen");
//...
}
//测试ZSET相关
@Test
public void testZset(){
//zadd
jedis.zadd("names",10,"张三");
//zrange
jedis.zrange("names",0,-1);
//zcard
jedis.zcard("names");
//zrangeByScore
jedis.zrangeByScore("names","0","100",0,5);
//..
}
//测试HASH相关
@Test
public void testHash(){
//hset
jedis.hset("maps","name","zhangsan");
//hget
jedis.hget("maps","name");
//hgetall
jedis.hgetAll("mps");
//hkeys
jedis.hkeys("maps");
//hvals
jedis.hvals("maps");
//....
}
Spring Boot Data(数据) Redis 中提供了RedisTemplate和StringRedisTemplate,其中StringRedisTemplate是RedisTemplate的子类,两个方法基本一致,不同之处主要体现在操作的数据类型不同,RedisTemplate中的两个泛型都是Object,意味着存储的key和value都可以是一个对象,而StringRedisTemplate的两个泛型都是String,意味着StringRedisTemplate的key和value都只能是字符串。
注意: 使用RedisTemplate默认是将对象序列化到Redis中,所以放入的对象必须实现对象序列化接口
<dependency>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-starter-data-redisartifactId>
dependency>
spring.redis.host=localhost
spring.redis.port=6379
spring.redis.database=0
@Autowired
private StringRedisTemplate stringRedisTemplate; //对字符串支持比较友好,不能存储对象
@Autowired
private RedisTemplate redisTemplate; //存储对象
@Test
public void testRedisTemplate(){
System.out.println(redisTemplate);
//设置redistemplate值使用对象序列化策略
redisTemplate.setValueSerializer(new JdkSerializationRedisSerializer());//指定值使用对象序列化
//redisTemplate.opsForValue().set("user",new User("21","小黑",23,new Date()));
User user = (User) redisTemplate.opsForValue().get("user");
System.out.println(user);
// Set keys = redisTemplate.keys("*");
// keys.forEach(key -> System.out.println(key));
/*Object name = redisTemplate.opsForValue().get("name");
System.out.println(name);*/
//Object xiaohei = redisTemplate.opsForValue().get("xiaohei");
//System.out.println(xiaohei);
/*redisTemplate.opsForValue().set("name","xxxx");
Object name = redisTemplate.opsForValue().get("name");
System.out.println(name);*/
/*redisTemplate.opsForList().leftPushAll("lists","xxxx","1111");
List lists = redisTemplate.opsForList().range("lists", 0, -1);
lists.forEach(list-> System.out.println(list));*/
}
//key的绑定操作 如果日后对某一个key的操作及其频繁,可以将这个key绑定到对应redistemplate中,日后基于绑定操作都是操作这个key
//boundValueOps 用来对String值绑定key
//boundListOps 用来对List值绑定key
//boundSetOps 用来对Set值绑定key
//boundZsetOps 用来对Zset值绑定key
//boundHashOps 用来对Hash值绑定key
@Test
public void testBoundKey(){
BoundValueOperations<String, String> nameValueOperations = stringRedisTemplate.boundValueOps("name");
nameValueOperations.set("1");
//yuew
nameValueOperations.set("2");
String s = nameValueOperations.get();
System.out.println(s);
}
//hash相关操作 opsForHash
@Test
public void testHash(){
stringRedisTemplate.opsForHash().put("maps","name","小黑");
Object o = stringRedisTemplate.opsForHash().get("maps", "name");
System.out.println(o);
}
//zset相关操作 opsForZSet
@Test
public void testZSet(){
stringRedisTemplate.opsForZSet().add("zsets","小黑",10);
Set<String> zsets = stringRedisTemplate.opsForZSet().range("zsets", 0, -1);
zsets.forEach(value-> System.out.println(value));
}
//set相关操作 opsForSet
@Test
public void testSet(){
stringRedisTemplate.opsForSet().add("sets","xiaosan","xiaosi","xiaowu");
Set<String> sets = stringRedisTemplate.opsForSet().members("sets");
sets.forEach(value-> System.out.println(value));
}
//list相关的操作opsForList
@Test
public void testList(){
// stringRedisTemplate.opsForList().leftPushAll("lists","张三","李四","王五");
List<String> lists = stringRedisTemplate.opsForList().range("lists", 0, -1);
lists.forEach(key -> System.out.println(key));
}
//String相关的操作 opsForValue
@Test
public void testString(){
//stringRedisTemplate.opsForValue().set("166","好同学");
String s = stringRedisTemplate.opsForValue().get("166");
System.out.println(s);
Long size = stringRedisTemplate.opsForValue().size("166");
System.out.println(size);
}
//key相关的操作
@Test
public void test(){
Set<String> keys = stringRedisTemplate.keys("*");//查看所有key
Boolean name = stringRedisTemplate.hasKey("name");//判断某个key是否存在
stringRedisTemplate.delete("age");//根据指定key删除
stringRedisTemplate.rename("","");//修改key的名称
stringRedisTemplate.expire("key",10, TimeUnit.HOURS);
//设置key超时时间 参数1:设置key名 参数2:时间 参数3:时间的单位
stringRedisTemplate.move("",1);//移动key
}
主从复制架构仅仅用来解决数据的冗余备份,从节点仅仅用来同步数据
无法解决: 1.master节点出现故障的自动故障转移
# 1.准备3台机器并修改配置
- master
port 6379
bind 0.0.0.0
- slave1
port 6380
bind 0.0.0.0
slaveof masterip masterport
- slave2
port 6381
bind 0.0.0.0
slaveof masterip masterport
# 2.启动3台机器进行测试
- cd /usr/redis/bin
- ./redis-server /root/master/redis.conf
- ./redis-server /root/slave1/redis.conf
- ./redis-server /root/slave2/redis.conf
Sentinel(哨兵)是Redis 的高可用性解决方案:由一个或多个Sentinel 实例 组成的Sentinel 系统可以监视任意多个主服务器,以及这些主服务器属下的所有从服务器,并在被监视的主服务器进入下线状态时,自动将下线主服务器属下的某个从服务器升级为新的主服务器。简单的说哨兵就是带有自动故障转移功能的主从架构。
无法解决: 1.单节点并发压力问题 2.单节点内存和磁盘物理上限
# 1.在主节点上创建哨兵配置
- 在Master对应redis.conf同目录下新建sentinel.conf文件,名字绝对不能错;
# 2.配置哨兵,在sentinel.conf文件中填入内容:
- sentinel monitor 被监控数据库名字(自己起名字) ip port 1
# 3.启动哨兵模式进行测试
- redis-sentinel /root/sentinel/sentinel.conf
说明:这个后面的数字2,是指当有两个及以上的sentinel服务检测到master宕机,才会去执行主从切换的功能。
# redis sentinel 配置
# master书写是使用哨兵监听的那个名称
spring.redis.sentinel.master=mymaster
# 连接的不再是一个具体redis主机,书写的是多个哨兵节点
spring.redis.sentinel.nodes=192.168.202.206:26379
Redis在3.0后开始支持Cluster(模式)模式,目前redis的集群支持节点的自动发现,支持slave-master选举和容错,支持在线分片(sharding shard )等特性。reshard
- 所有的redis节点彼此互联(PING-PONG机制),内部使用二进制协议优化传输速度和带宽.
- 节点的fail是通过集群中超过半数的节点检测失效时才生效.
- 客户端与redis节点直连,不需要中间proxy层.客户端不需要连接集群所有节点,连接集群中任何一个可用节点即可
- redis-cluster把所有的物理节点映射到[0-16383]slot上,cluster 负责维护node<->slot<->value
判断一个是集群中的节点是否可用,是集群中的所用主节点选举过程,如果半数以上的节点认为当前节点挂掉,那么当前节点就是挂掉了,所以搭建redis集群时建议节点数最好为奇数,搭建集群至少需要三个主节点,三个从节点,至少需要6个节点。
# 1.准备环境安装ruby以及redis集群依赖
- yum install -y ruby rubygems
- gem install redis-xxx.gem
# 2.在一台机器创建7个目录
# 3.每个目录复制一份配置文件
[root@localhost ~]# cp redis-4.0.10/redis.conf 7000/
[root@localhost ~]# cp redis-4.0.10/redis.conf 7001/
[root@localhost ~]# cp redis-4.0.10/redis.conf 7002/
[root@localhost ~]# cp redis-4.0.10/redis.conf 7003/
[root@localhost ~]# cp redis-4.0.10/redis.conf 7004/
[root@localhost ~]# cp redis-4.0.10/redis.conf 7005/
[root@localhost ~]# cp redis-4.0.10/redis.conf 7006/
# 4.修改不同目录配置文件
- port 6379 ..... //修改端口
- bind 0.0.0.0 //开启远程连接
- cluster-enabled yes //开启集群模式
- cluster-config-file nodes-port.conf //集群节点配置文件
- cluster-node-timeout 5000 //集群节点超时时间
- appendonly yes //开启AOF持久化
# 5.指定不同目录配置文件启动七个节点
- [root@localhost bin]# ./redis-server /root/7000/redis.conf
- [root@localhost bin]# ./redis-server /root/7001/redis.conf
- [root@localhost bin]# ./redis-server /root/7002/redis.conf
- [root@localhost bin]# ./redis-server /root/7003/redis.conf
- [root@localhost bin]# ./redis-server /root/7004/redis.conf
- [root@localhost bin]# ./redis-server /root/7005/redis.conf
- [root@localhost bin]# ./redis-server /root/7006/redis.conf
# 6.查看进程
- [root@localhost bin]# ps aux|grep redis
# 1.复制集群操作脚本到bin目录中
- [root@localhost bin]# cp /root/redis-4.0.10/src/redis-trib.rb .
# 2.创建集群
- ./redis-trib.rb create --replicas 1 192.168.202.205:7000 192.168.202.205:7001 192.168.202.205:7002 192.168.202.205:7003 192.168.202.205:7004 192.168.202.205:7005
# 3.集群创建成功出现如下提示
# 1.查看集群状态 check [原始集群中任意节点] [无]
- ./redis-trib.rb check 192.168.202.205:7000
# 2.集群节点状态说明
- 主节点
主节点存在hash slots,且主节点的hash slots 没有交叉
主节点不能删除
一个主节点可以有多个从节点
主节点宕机时多个副本之间自动选举主节点
- 从节点
从节点没有hash slots
从节点可以删除
从节点不负责数据的写,只负责数据的同步
# 1.添加主节点 add-node [新加入节点] [原始集群中任意节点]
- ./redis-trib.rb add-node 192.168.1.158:7006 192.168.1.158:7005
- 注意:
1.该节点必须以集群模式启动
2.默认情况下该节点就是以master节点形式添加
# 1.添加从节点 add-node --slave [新加入节点] [集群中任意节点]
- ./redis-trib.rb add-node --slave 192.168.1.158:7006 192.168.1.158:7000
- 注意:
当添加副本节点时没有指定主节点,redis会随机给副本节点较少的主节点添加当前副本节点
# 2.为确定的master节点添加主节点 add-node --slave --master-id master节点id [新加入节点] [集群任意节点]
- ./redis-trib.rb add-node --slave --master-id 3c3a0c74aae0b56170ccb03a76b60cfe7dc1912e 127.0.0.1:7006 127.0.0.1:7000
# 1.删除节点 del-node [集群中任意节点] [删除节点id]
- ./redis-trib.rb del-node 127.0.0.1:7002 0ca3f102ecf0c888fc7a7ce43a13e9be9f6d3dd1
- 注意:
1.被删除的节点必须是从节点或没有被分配hash slots的节点
# 1.在线分片 reshard [集群中任意节点] [无]
- ./redis-trib.rb reshard 192.168.1.158:7000
redis的session管理是利用spring提供的session管理解决方案,将一个应用session交给Redis存储,整个应用中所有session的请求都会去redis中获取对应的session数据。
<dependency>
<groupId>org.springframework.sessiongroupId>
<artifactId>spring-session-data-redisartifactId>
dependency>
@Configuration
@EnableRedisHttpSession
public class RedisSessionManager {
}