Redis笔记
文章目录
https://blog.csdn.net/weixin_43246215/article/details/107947562
redis基本命令
dbsize 查看数据库大小
flushdb 清空当前数据库
flushall 清空所有数据库
select index 选择数据库
exists key 判断key是否存在
redis中文官网 http://www.redis.cn/
redis是单线程的
原因: 一个程序是否采用多线程或者单线程是与CPU有关的, 而Redis的性能瓶颈并不是CPU, 而是内存和网络带宽, 并且Redis是很快的, 能用单线程就使用单线程
redis-benchmark性能测试工具
redis-benchmark -h IP地址 -p 端口 -c 并发连接数 -n 指定请求数
redis-benchmark -h localhost -p 3306 -c 100 -n 100000
redis为什么这么快
首先CPU>内存>硬盘, redis的所有数据都是放在内存中的, 如果使用多线程去操作Redis, CPU会引起一个上下文的切换, 这是一个很耗时的操作!
所以对于内存系统来说, 没有上下文的切换, 效率就是最高的!
五大数据类型
String list set zset hash
String
set key value # 设置键值
get key # 获取对应键的值
append key value # 如果原来有key,则旧value+新value; 如果原来没key, 则设置
strlen key # 获取键对应值的长度
# 实现键自增1
set age 1
incr age
get age # 2
# 实现键自减1
decr age
键自增步长 incrby key integer
键自减步长 decrby key integer
# 获取字符串的范围
getrange key start end # 从0开始, 截取会包括end, 最后一个是-1
# 替换字符串
setrange key offset value # 在偏移量offset的位置, 替换等长的value
setex (set with expire) 设置值的同时设置过期时间
setex key seconds value
setnx (set if not exists) 将key设置值为value,如果key不存在,这种情况下等同SET命令。 当key存在时,什么也不做
分布式锁中常用
返回值
Integer reply, 特定值:
1 如果key被设置了
0 如果key没有被设置
mset k1 v1 k2 v2 同时设置多个值
mget k1 k2 同时获取多个值
msetnx k1 v1 k2 v2
对应给定的keys到他们相应的values上。只要有一个key已经存在,MSETNX一个操作都不会执行。 由于这种特性,MSETNX可以实现要么所有的操作都成功,要么一个都不执行,这样可以用来设置不同的key,来表示一个唯一的对象的不同字段。
MSETNX是原子的,所以所有给定的keys是一次性set的。客户端不可能看到这种一部分keys被更新而另外的没有改变的情况。
返回值
integer-reply,只有以下两种值:
1 如果所有的key被set
0 如果没有key被set(至少其中有一个key是存在的)
getset 自动将key对应到value并且返回原来key对应的value。如果key存在但是对应的value不是字符串,就返回错误。
设计模式
GETSET可以和INCR一起使用实现支持重置的计数功能。举个例子:每当有事件发生的时候,一段程序都会调用INCR给key mycounter加1,但是有时我们需要获取计数器的值,并且自动将其重置为0。这可以通过GETSET mycounter “0”来实现:
INCR mycounter
GETSET mycounter "0"
GET mycounter
返回值
bulk-string-reply: 返回之前的旧值,如果之前Key不存在将返回nil。
rpoplpush source destination
原子性地返回并移除存储在 source 的列表的最后一个元素(列表尾部元素), 并把该元素放入存储在 destination 的列表的第一个元素位置(列表头部)。
例如:假设 source 存储着列表 a,b,c, destination存储着列表 x,y,z。 执行 RPOPLPUSH 得到的结果是 source 保存着列表 a,b ,而 destination 保存着列表 c,x,y,z。
如果 source 不存在,那么会返回 nil 值,并且不会执行任何操作。 如果 source 和 destination 是同样的,那么这个操作等同于移除列表最后一个元素并且把该元素放在列表头部, 所以这个命令也可以当作是一个旋转列表的命令。
返回值
bulk-string-reply: 被移除和放入的元素
文章目录
三种特殊类型
geospatial hyperloglog bitmaps
geospatial 地理位置, 可以推算地理位置信息, 两地之间的距离, 方圆几里的人
geoadd key longitude经度 latitude纬度 member成员 [longitude latitude member ...]
将指定的地理空间位置(纬度、经度、名称)添加到指定的key中。这些数据将会存储到sorted set
例如
GEOADD city 13.361389 38.115556 "Palermo" 15.087269 37.502669 "Catania"
GEOPOS key member [member ...]
从key里返回所有给定位置元素的位置(经度和纬度)。
GEODIST key member1 member2 [unit]
返回两个给定位置之间的距离。
如果两个位置之间的其中一个不存在, 那么命令返回空值。
GEORADIUS key longitude latitude radius m|km|ft|mi [WITHCOORD] [WITHDIST] [WITHHASH] [COUNT count]
以给定的经纬度为中心, 返回键包含的位置元素当中, 与中心的距离不超过给定最大距离的所有位置元素。
GEORADIUSBYMEMBER key member radius m|km|ft|mi [WITHCOORD] [WITHDIST] [WITHHASH] [COUNT count]
指定成员的位置被用作查询的中心。
geo是使用zset实现的, 所以可以使用zset的相关命令, 例如在geo中没有删除命令, 可以使用zrem删除一个地理位置
bitmap 位存储
只有两个状态的, 都可以使用bitmap存储
SETBIT key offset value
设置或者清空key的value(字符串)在offset处的bit值。
GETBIT key offset
返回key对应的string在offset处的bit值
bitcount key
统计为1的数量
HyperLogLog
HyperLogLog 是用来做基数统计的算法,HyperLogLog 的优点是,在输入元素的数量或者体积非常非常大时,计算基数所需的空间总是固定 的、并且是很小的。
什么是基数?
一个集合(注意:这里集合的含义是 Object 的聚合,可以包含重复元素)中不重复元素的个数。例如集合 {1,2,3,1,2},它有5个元素,但它的基数/Distinct 数为3。
Redis 为 HyperLogLog提供了三个命令:PFADD、PFCOUNT、PFMERGE。
###事务
redis单条命令是保持原子性的, 但是其事务并不保持原子性
事务是一组命令的集合
redis事务没有隔离性
redis事务本质: 一组命令的集合, 一个事务中的所有命令都会被序列化, 在事务的执行过程中, 会按照顺序执行
具有一次性, 顺序性,排他性
队列------ set… set… set… 执行------
redis事务:
- 开启事务 (multi) # multi 多元
- 命令入队
- 执行事务 (exec)
127.0.0.1:6379> multi
OK
127.0.0.1:6379> set k1 v1
QUEUED
127.0.0.1:6379> set k2 v2
QUEUED
127.0.0.1:6379> set k3 v3
QUEUED
127.0.0.1:6379> exec
- 放弃事务 (discard)
事务当中编译时异常 - 命令都敲错了, 即使提交了事务, 整个事务中的命令都不会执行
multi 开启事务
set k1 v1
getset k1 报错
set k2 v2
exec 报错
运行时异常 - 在Java中类似除零,提交事务后, 除了报错的命令不执行, 其它的都会执行
multi
set k1 v1
incr k1 # 对一个字符串自增1, 此时还没报错
set k2 v2
exec # 3) (error) ERR value is not an integer or out of range
即: redis的事务不保证原子性
文章目录
监控
悲观锁:默认什么时候都会出现问题, 无论做什么都加锁, 这是很影响性能的。负重前行总是要走的很慢。
######乐观锁
-
乐观锁:认为什么时候都不会出现问题, 所以什么时候都不会加锁, 更新的时候去判读一下,在此期间是否有人修改过这个数据;在mysql中是通过version字段实现的,只有判断version是正确的才会去提交。
-
在redis中使用的是监视器watch
redis监视测试
# 正常情况下
set money 100
set out 0 # 花出去的钱
watch money # 监控money
multi # 开启事务
decrby money 20 # 钱减少了20
incrby out 20 # 花出去了20
exec
事务执行成功后, 监控watch会自动取消
测试多线程-失败的事务
线程1 | 线程2 |
set money 100 | |
set out 0 | |
watch money | |
multi | |
decrby money 20 | |
incrby out 20 | |
set money 10000 | |
exec |
提交事务前,修改监控器监视的对象, 整个事务失败!
所以,监控器watch可以当作redis的乐观锁操作。
此时如果想重新开启事务,先放弃监视unwatch, 再重新watch对象开启事务。
文章目录
##Jedis
使用Java操作redis
jedis是Redis官方推荐的redis连接工具,使用Java操作redis中间件
使用idea创建一个空项目
-
导入对应的依赖
<!-- 导入jedis的包--> <dependencies> <!-- https://mvnrepository.com/artifact/redis.clients/jedis --> <dependency> <groupId>redis.clients</groupId> <artifactId>jedis</artifactId> <version>3.2.0</version> </dependency> <!--fastjson--> <dependency> <groupId>com.alibaba</groupId> <artifactId>fastjson</artifactId> <version>1.2.62</version> </dependency> </dependencies>
-
编码测试
-
连接数据库
-
操作命令
-
断开连接
public static void main(String[] args) { Jedis jedis = new Jedis("127.0.0.1", 6379); System.out.println(jedis.ping()); // 连接成功输出 PONG }
-
可能出现的错误
java: 错误: 不支持发行版本 xx
解决方法
1.设置->搜索 Javac Java编译器 ->将目标字节码版本修改为jdk对应的版本
2.项目结构->模块->语言级别 修改为jdk对应的版本
->项目 修改项目SDK
慢慢地学习, 速度最快!
常用API
setnx : set if Not Exists 设置一个键值, 如果存在则无动作, 否则就进行设置
package com.kuang;
import redis.clients.jedis.Jedis;
import java.util.Set;
public class TestPing {
public static void main(String[] args) {
Jedis jedis = new Jedis("127.0.0.1", 6379);
String ping = jedis.ping();
if ("PONG".equals(ping)) {
System.out.println("连接redis成功");
} else {
System.out.println("连接redis失败!");
return;
}
System.out.println("清空数据: "+ jedis.flushDB());
System.out.println("判断某个键是否存在: " + jedis.exists("username"));
System.out.println("新增<'username', 'kuang'>键值对: " + jedis.setnx("username", "kuang"));
System.out.println("新增<'password', 'password'>键值对: "+jedis.setnx("password", "password"));
System.out.println("系统的所有key如下: ");
Set<String> keys = jedis.keys("*");
System.out.println(keys);
System.out.println("删除password:"+jedis.del("password"));
System.out.println("查看password是否存在: " + jedis.exists("password"));
System.out.println("查看键username所存储的值对应的类型: " + jedis.type("username"));
System.out.println("随机返回key空间的一个: "+ jedis.randomKey());
System.out.println("重命名key: "+jedis.rename("username", "name"));
System.out.println("取出改后的name的值: "+jedis.get("name"));
System.out.println("按索引查询: "+jedis.select(0));
System.out.println("删除当前数据库中的所有key: "+jedis.flushDB());
System.out.println("返回当前数据库中的键数目: "+jedis.dbSize());
System.out.println("删除所有数据库中的所有键: "+ jedis.flushAll());
}
}
命令基本一致
package com.kuang;
import com.alibaba.fastjson.JSONObject;
import redis.clients.jedis.Jedis;
import redis.clients.jedis.Transaction;
// redis 事务
public class TestTX {
public static void main(String[] args) {
Jedis jedis = new Jedis("127.0.0.1", 6379);
jedis.flushDB();
JSONObject jsonObject = new JSONObject(); // 阿里fastjson
jsonObject.put("hello", "world");
jsonObject.put("name", "kuang");
String s = jsonObject.toJSONString();
jedis.watch(s); // 监控
// 开启事务
Transaction multi = jedis.multi();
System.out.println("fastjson to json string: " + s);
try {
multi.set("user1", s);
multi.set("user2", s);
// int i = 1 / 0;
multi.exec();
} catch (Exception e) {
multi.discard(); // 放弃事务
e.printStackTrace();
} finally {
System.out.println("user1: " + jedis.get("user1"));
System.out.println("user2: " + jedis.get("user2"));
jedis.close(); // 关闭连接
}
}
}
redis配置文件
包含其它的配置
# include /path/to/local.conf
# include /path/to/other.conf
网络
bind 127.0.0.1 # 指定哪个IP能访问该redis-server, 远程访问使用 *
protected-mode yes # 保护模式
port 6379 # 指定端口
通用 GENERAL
daemonize yes # 以守护进程运行, 默认为no, 要修改
pidfile /var/run/redis_6379.pid # 如果以后台的方式运行, 我们就需要指定一个pid文件
# 日志记录
# Specify the server verbosity level.
# This can be one of:
# debug (a lot of information, useful for development/testing) # 最详细, 生产环境使用
# verbose (many rarely useful info, but not a mess like the debug level)
# notice (moderately verbose, what you want in production probably)
# warning (only very important / critical messages are logged) # 仅重要信息
loglevel notice
logfile "" # 日志文件的位置名, 如果为空就是直接打印输出
databases 16 # 数据库的数量
快照 持久化
在规定的时间内, 执行了多少次操作, 符合条件就会持久化到文件中 (rdb/aof)
# save 时间 操作
save 900 1 # 如果在900秒内操作了1个key, 则保存
save 300 10 # 如果在300秒内操作了10个key
save 60 10000 # 如果在60秒内操作了10000个key
stop-writes-on-bgsave-error yes # 如果持久化出错了, 是否让redis继续工作
rdbcompression yes # 是否要压缩rdb文件, 需要消耗cpu资源
rdbchecksum yes # 保存rdb文件的时候, 是否进行错误校验
dir ./ # rdb文件保存的目录, 默认当前目录
主从复制 replication
安全 security
redis默认没有密码, 使用客户端可以直接连接
127.0.0.1:6379> config get requirepass # 获取密码
1) "requirepass"
2) ""
127.0.0.1:6379> config set requirepass "123" # 设置密码
OK
127.0.0.1:6379> ping # 此时ping不通了
(error) NOAUTH Authentication required.
127.0.0.1:6379> auth 123 # 认证密码登陆
OK
127.0.0.1:6379> ping
PONG
限制 clients
maxclients 10000 # 最大客户端连接数
maxmemory <bytes> # redis最大内存
maxmemory-policy noeviction # 达到最大内存时, 应对的策略
Append Only File (持久化aof)
appendonly no # 默认不开启
appendfilename "appendonly.aof" # 持久化的文件名
# appendfsync always # 每次修改都会同步sync, 消耗性能
appendfsync everysec # 每秒同步
# appendfsync no # 不同步, 这个时候操作系统自己同步数据, 速度快
auto-aof-rewrite-percentage 100 # percentage比例
auto-aof-rewrite-min-size 64mb # 如果aof文件大于64M, 将重写aof文件
##redis持久化
redis持久化只要分为两种 1. rdb (redis DataBase 默认)
2. aof (append only file 在两种方式都开启的情况下, 将优先使用这种)
rdb
可以通过配置文件中的save参数进行配置 # save 时间 操作, 在该时间内执行完这些操作将save一次, 所以如果它中途宕机丢失的数据会比aof方式的多, 但是它的持久化文件dump.rdb要比aof的持久化文件append.aof要小, 数据的恢复速度也更加快。 rdb的性能较高,它是fork一个子进程来进行写操作,让主进程继续工作,所以是IO最大化。
aof
将每一次的写命令追加到文件中, 如果中途发生宕机数据丢失较少, 但是aof方式的资源消耗要比rdb方式多, 当数据出现某些错误的时候可以通过redis-check-aof工具进行修复
订阅发布
Redis发布订阅(pub/sub)是一种消息通信模式: 发送者(pub)发送消息,订阅者(sub)接收消息。
Redis客户端可以订阅任意数量的频道。
订阅端
127.0.0.1:6379> SUBSCRIBE kuang # subscribe 订阅
Reading messages... (press Ctrl-C to quit)
1) "subscribe"
2) "kuang"
3) (integer) 1
# 等待信息推送过来
1) "message"
2) "kuang"
3) "helloooooo"
1) "message"
2) "kuang"
3) "worlddddddd"
发送端
127.0.0.1:6379> PUBLISH kuang helloooooo
(integer) 1
127.0.0.1:6379> publish kuang worlddddddd
(integer) 1
Redis主从复制
只用配置从库, 不用配置主库, redis默认就是主库
127.0.0.1:6379> info replication # 查看复制信息
# Replication
role:master # 主
connected_slaves:0 # 现在没有从机
master_repl_offset:0
repl_backlog_active:0
repl_backlog_size:1048576
repl_backlog_first_byte_offset:0
repl_backlog_histlen:0
相关配置, 复制3个配置文件, 后缀名为3个端口号
# 主机 端口6379 需要修改log和dump的文件命令
logfile "6379.log"
dbfilename dump6379.rdb
# 从机 端口6380 需要修改端口、pidfile、logfile、dbfilename
port 6380
pidfile /var/run/redis_6380.pid
logfile "6380.log"
dbfilename "dump6380.rdb"
# 从机 端口6381 ....
修改完后启动3个redis
redis-ser configs(配置文件目录)/redis6379.conf
一主二从
默认情况下三台都是主机
127.0.0.1:6381> info replication
# Replication
role:master
connected_slaves:0
master_repl_offset:0
repl_backlog_active:0
repl_backlog_size:1048576
repl_backlog_first_byte_offset:0
repl_backlog_histlen:0
配置从机, 认老大
127.0.0.1:6381> SLAVEOF 127.0.0.1 6379
OK
127.0.0.1:6381> info replication
# Replication
role:slave # 从机角色
master_host:127.0.0.1 # 主机IP
master_port:6379 # 主机PORT
master_link_status:up
master_last_io_seconds_ago:2
master_sync_in_progress:0
slave_repl_offset:85
slave_priority:100
slave_read_only:1
connected_slaves:0
master_repl_offset:0
repl_backlog_active:0
repl_backlog_size:1048576
repl_backlog_first_byte_offset:0
repl_backlog_histlen:0
127.0.0.1:6379> info replication # 当前主机信息
# Replication
role:master
connected_slaves:2
slave0:ip=127.0.0.1,port=6381,state=online,offset=239,lag=0
slave1:ip=127.0.0.1,port=6380,state=online,offset=225,lag=0
master_repl_offset:239
repl_backlog_active:1
repl_backlog_size:1048576
repl_backlog_first_byte_offset:2
repl_backlog_histlen:238
目前使用的是命令配置主从, 使用配置文件进行配置的话就是永久配置
配置文件中的 REPLICATION
# slaveof <masterip> <masterport>
# masterauth <master-password>
主机可以写读, 从机不能写只能读, 主机中的所有数据都会被从机保存
127.0.0.1:6380> set k2 vv22 # 从机写 - 报错
(error) READONLY You can't write against a read only slave.
如果此时主机宕机, 从机仍然可以读取信息
主机恢复后, 还可以读取到原来的数据, 并且写操作之后, 其它从机仍然可以获取到数据
slaveof no one # 如果主机宕机, 可以使用该命令让自己变成主机, 其它节点再手动连接到该节点
哨兵模式
sentinel monitor 名称 IP地址 Port端口 投票(当监控的主机宕机后,投票该从机为主机,有一个投票算法)
sentinel monitor myredis 127.0.0.1 6379 1
- 启动哨兵
redis-sentinel sentinel.conf
如果宕掉的主机回来了, 只能当从机了
哨兵配置文件sentinel.conf
# Example sentinel.conf
# 哨兵sentinel实例运行的端口 默认是26379
port 26379 # 如果有哨兵集群,我们还需要配置每个哨兵端口
#哨兵sentinel的工作目录
dir /tmp
#哨兵 sentine1 监控的redis主节点的 ip port
# master-name ,可以自己命名的主节点名字 只能由字母A-Z、数字0-9、这三个字符" . - _ "组成。
# quorum配置多少个sentine1哨兵统- -认为master主节点失联那么这时客观上认为主节点失联了
# sentine1 monitor <master-name> <ip> <redis-port> <quorum>
sentinel monitor mymaster 127.0.0.1 6379 2
#当在Redis实例中开启了requirepass foobared 授权密码这样所有连接kedis实例的客户端都要提供密码
#设置哨兵sentinel连接主从的密码注意必须为主从设置- - 样的验证密码
# sentine1 auth-pass <master-name> <password>
sentine1 auth-pass mymaster MySUPER--secret-0123passwOrd
#指定多少毫秒之后主节点没有应答哨兵sentine1 此时哨兵主观上认为主节点下线默认30秒
# sentinel down-after-mi 11i seconds <master-name> <mi 11iseconds>
sentine1 down-after-mi 11iseconds mymaster 30000
#这个配置项指定了在发生failover主备切换时最多可以有多少个slave同时对新的master进行同步,这个数字越小,完成fai lover所需的时间就越长,但是如果这个数字越大,就意味着越多的slave因为replication而 不可用。可以通过将这个值设为1来保证每次只有一个slave处于不能处理命令请求的状态。
# sentine1 paralle1-syncs <master-name> <numslaves>
sentine1 paralle1-syncs mymaster 1
#故障转移的超时时间failover-timeout 可以用在以下这些方面:
#1.同一个sentine1对同一 个master两次fai lover之间的间隔时间。
#2.当一个slave从一 个错误的master那里同步数据开始计算时间。直到s1ave被纠正为向正确的master那里同步数据时。
#3.当想要取消一个正在进行的failover所需要的时间。
#4.当进行failover时,配置所有s1aves指向新的master所需的最大时间。不过,即使过了这个超时,slaves 依然会被正确配置为指向master,但是就不按parallel-syncs所配置的规则来了
#默认三分钟
# sentine1 failover-timeout <master-name> <milliseconds>
sentine1 fai lover-ti meout mymaster 180000
# SCRIPTS EXECUTION
#配置当某一事件发生时所需要执行的脚本,可以通过脚本来通知管理员,例如当系统运行不正常时发邮件通知相关人员。
#对于脚本的运行结果有以下规则:
#若脚本执行后返回1,那么该脚本稍后将会被再次执行,重复次数目前默认为10
#若脚本执行后返回2,或者比2更高的一个返回值,脚本将不会重复执行。
#如果脚本在执行过程中由于收到系统中断信号被终止了,则同返回值为1时的行为相同。
#一个脚本的最大执行时间为60s,如果超过这个时间,脚本将会被-一个SIGKILL信号终止,之后重新执行。
#通知型脚本:当sentine1有任何警告级别的事件发生时(比如说redis实例的主观失效和客观失效等等),将会去调用这个脚本,
#这时这个脚本应该通过邮件,SMS等 方式去通知系统管理员关于系统不正常运行的信息。
#调用该脚本时,将传给脚本两个参数,一 个是事件的类型,一个是事件的描述。如果sentine1. conf配置文件中配置了
#这个脚本路径,那么必须保证这个脚本存在于这个路径,并且是可执行的,否则sentine1无法正常启动成功。
#通知脚本
# she11编程
# sentine1 notification-script <master-name> <script-path>
sentine1 notificati on-script mymaster /var/redis/notify. sh
#客户端重新配置主节点参数脚本
#当一个master由于failover而发生改变时,这个脚本将会被调用,通知相关的客户端关于master地址已经发生改变的信息。
#以下参数将会在调用脚本时传给脚本:
# <master-name> <role> <state> <from-ip> <from-port> <to-ip> <to-port>
#目前<state>总是“failover",
# <role>是“Teader"或者"observer"中的-一个。
#参数from-ip, from-port, to-ip,to-port是用来和旧的master和新的master(即旧的s lave)通信的
#这个脚本应该是通用的,能被多次调用,不是针对性的。
# sentine1 client-reconfig-script <master-name> <script-path>
缓存穿透和雪崩
redis缓存的应用, 极大地提高了应用程序的性能和效率, 尤其是查询方面, 但同时它也存在数据的一致性问题, 从严格意义上讲, 这个问题是无解的, 如果对数据的一致性要求很高, 那么就不能使用缓存
另外的一些问题就是
- 缓存穿透
- 缓存雪崩
- 缓存击穿
缓存穿透
读的请求先去缓存中查询, 如果没有就去数据库中查询
如果缓存和数据库都没有这个数据, 会导致所有的请求都会落在数据库上, 如果此时有大量的该请求就会给数据库造成一个巨大的压力而崩掉
解决方案
- 布隆过滤器
- 缓存空对象
缓存击穿
缓存中没有, 但是数据库中有的情况
实验笔记
-
在不同的机器上搭建主从时, 连不上
原因: 对配置中的bind IP理解错误, bind IP的意思是允许该IP连接到本机, 而不是本机IP; IP可以改为0.0.0.0
-
搭建集群时,报错 Either the node already knows other nodes (check with CLUSTER NODES) or contains some key in database 0.
导致异常的主要原因是该节点中默认生成的配置或历史存储数据不一致导致的,清除对应节点的dump.rdb、nodes.conf文件,重启之后即可。
dump.rdb是由Redis服务器自动生成的 默认情况下 每隔一段时间redis服务器程序会自动对数据库做一次遍历,把内存快照写在一个叫做“dump.rdb”的文件里,这个持久化机制叫做SNAPSHOT。有了SNAPSHOT后,如果服务器宕机,重新启动redis服务器程序时redis会自动加载dump.rdb,将数据库状态恢复到上一次做SNAPSHOT时的状态。
解决步骤:
1、停止服务,删除aof/rdb文件;
2、删除nodes.conf
3、必要的情况下执行flushdb。
我的做法: 停止所有机器上的redis
pkill redis
, 删除aof/rdb文件和所有的node.conf文件, 然后启动所有redis-server,最后启动集群redis-cli --cluster create IP:port IP:port ...
-
集群获取到所有key
redis-cli -c --cluster call IP:PORT keys \*
数据库中有的情况
实验笔记
-
在不同的机器上搭建主从时, 连不上
原因: 对配置中的bind IP理解错误, bind IP的意思是允许该IP连接到本机, 而不是本机IP; IP可以改为0.0.0.0
-
搭建集群时,报错 Either the node already knows other nodes (check with CLUSTER NODES) or contains some key in database 0.
导致异常的主要原因是该节点中默认生成的配置或历史存储数据不一致导致的,清除对应节点的dump.rdb、nodes.conf文件,重启之后即可。
dump.rdb是由Redis服务器自动生成的 默认情况下 每隔一段时间redis服务器程序会自动对数据库做一次遍历,把内存快照写在一个叫做“dump.rdb”的文件里,这个持久化机制叫做SNAPSHOT。有了SNAPSHOT后,如果服务器宕机,重新启动redis服务器程序时redis会自动加载dump.rdb,将数据库状态恢复到上一次做SNAPSHOT时的状态。
解决步骤:
1、停止服务,删除aof/rdb文件;
2、删除nodes.conf
3、必要的情况下执行flushdb。
我的做法: 停止所有机器上的redis
pkill redis
, 删除aof/rdb文件和所有的node.conf文件, 然后启动所有redis-server,最后启动集群redis-cli --cluster create IP:port IP:port ...
-
集群获取到所有key
redis-cli -c --cluster call IP:PORT keys \*