NoSQL的四大分类:
KV键值对 文档型数据库: MongoDB(要掌握)是一个介于关系型数据库和非关系型数据库中间的产品,是非关系型数据库中功能最丰富,最像关系型数据库的 ConthDB 列存储数据库: 图关系数据库:
Redis:
Remote Dictionary Server 远程字典服务 Redis是单线程的 6.0之后有多线程,将所有的数据全部放在内存中,所以使用单线程去操作效率最高 是一个开源的使用ANSI C语言编写、支持网络、可基于内存亦可持久化的日志型、Key-value数据库,并提供多种语言的API 是热门的NoSQL技术之一,也被称为结构化数据库,可以用作数据库、缓存和消息中间件MQ 一共有17个数据库默认使用第0个
Redis作用:
1.内存存储、持久化 什么是持久化(rdb、aof) 2.效率高,可以用于高速缓存 3.发布订阅系统 4.地图信息分析 5.计时器、计数器
Redis和Mysql的区别:
mysql是关系型数据库,redis是缓存数据库 mysql用于持久化的存储数据到硬盘,功能强大,速度较慢,基于磁盘,读写速度没有Redis快,但是不受空间容量限制,性价比高 redis用于存储使用较为频繁的数据到缓存中,读取速度快,基于内存,读写速度快,也可做持久化,但是内存空间有限,当数据量超过内存空间时,需扩充内存,但内存价格贵
windows用命令启动:redis-server redis.windows.conf
打开cli.exe
127.0.0.1:6379> ping
PONG
127.0.0.1:6379> set name lv
OK
127.0.0.1:6379> get name
"lv"
127.0.0.1:6379> keys *
1) "name"
127.0.0.1:6379> FLUSHDB
OK
127.0.0.1:6379> FLUSHALL
OK
127.0.0.1:6379> select 3
OK
127.0.0.1:6379[3]> DBSIZE
(integer) 0
127.0.0.1:6379> EXISTS name
(integer) 1
127.0.0.1:6379> move name 1
(integer) 1
127.0.0.1:6379> EXPIRE name 10
(integer) 1
127.0.0.1:6379> ttl name
(integer) -2
127.0.0.1:6379> get name
(nil)
127.0.0.1:6379> type age
string
String(字符串): String类似的使用场景:value除了是字符串还可以是数字
127.0.0.1:6379> APPEND KEY1 HELLO
(integer) 7
127.0.0.1:6379> GET KEY1
"V1HELLO"
127.0.0.1:6379> STRLEN KEY1
(integer) 7
127.0.0.1:6379> incr views
(integer) 1
127.0.0.1:6379> decr views
(integer) 0
127.0.0.1:6379> INCRBY views 10
(integer) 10
127.0.0.1:6379> DECRBY views 5
(integer) 5
127.0.0.1:6379> get name
"zhangsan"
127.0.0.1:6379> GETRANGE name 0 3
"zhan"
127.0.0.1:6379> GETRANGE name 0 -1
"zhangsan"
127.0.0.1:6379> SETRANGE name 1 xx
(integer) 8
127.0.0.1:6379> get name
"zxxngsan"
127.0.0.1:6379> setex age 10 22
OK
127.0.0.1:6379> ttl age
(integer) -2
127.0.0.1:6379> get age
(nil)
127.0.0.1:6379> setnx mykey redis
(integer) 1
127.0.0.1:6379> setnx mykey mongoDB
(integer) 0
127.0.0.1:6379> mset k1 v1 k2 v2 k3 v3
OK
127.0.0.1:6379> keys *
1) "views"
2) "k2"
3) "name"
4) "k1"
5) "mykey"
6) "k3"
127.0.0.1:6379> mget k1 k2 k3
1) "v1"
2) "v2"
3) "v3"
127.0.0.1:6379> msetnx k1 v1 k4 v4
(integer) 0
127.0.0.1:6379> mset user:1:name zhangsan user:1:age 22
OK
127.0.0.1:6379> mget user:1:name user:1:age
1) "zhangsan"
2) "22"
127.0.0.1:6379> getset db redis
(nil)
127.0.0.1:6379> get db
"redis"
127.0.0.1:6379> getset db mongodb
"redis"
127.0.0.1:6379> get db
"mongodb"
List(列表): 实际上是一个链表,可以作用栈、队列、阻塞队列,在两边插入或改动值,效率最高
127.0.0.1:6379> LPUSH list one
(integer) 1
127.0.0.1:6379> LPUSH list two
(integer) 2
127.0.0.1:6379> LPUSH list three
(integer) 3
127.0.0.1:6379> LRANGE list 0 -1
1) "three"
2) "two"
3) "one"
127.0.0.1:6379> RPUSH list right
(integer) 4
127.0.0.1:6379> LRANGE list 0 -1
1) "three"
2) "two"
3) "one"
4) "right"
127.0.0.1:6379> Lpop list
"three"
127.0.0.1:6379> Rpop list
"right"
127.0.0.1:6379> LRANGE list 0 -1
1) "two"
2) "one"
127.0.0.1:6379> Lindex list 1
"one"
127.0.0.1:6379> Llen list
(integer) 2
127.0.0.1:6379> LREM list 1 one
(integer) 1
127.0.0.1:6379> LRANGE list 0 -1
1) "two"
127.0.0.1:6379> lrange list 0 -1
1) "four"
2) "three"
3) "one"
4) "two"
127.0.0.1:6379> ltrim list 1 2
OK
127.0.0.1:6379> lrange list 0 -1
1) "three"
2) "one"
127.0.0.1:6379> lrange list 0 -1
1) "two"
2) "four"
3) "three"
4) "one"
127.0.0.1:6379> rpoplpush list list2
"one"
127.0.0.1:6379> lrange list 0 -1
1) "two"
2) "four"
3) "three"
127.0.0.1:6379> lrange list2 0 -1
1) "one"
127.0.0.1:6379> exists list
(integer) 1
127.0.0.1:6379> lrange list 0 0
1) "two"
127.0.0.1:6379> lset list 0 five
OK
127.0.0.1:6379> lrange list 0 0
1) "five"
127.0.0.1:6379> lrange list 0 -1
1) "two"
127.0.0.1:6379> linsert list before two three
(integer) 2
127.0.0.1:6379> lrange list 0 -1
1) "three"
2) "two"
127.0.0.1:6379> linsert list after two one
(integer) 3
127.0.0.1:6379> lrange list 0 -1
1) "three"
2) "two"
3) "one"
Set(集合): set中的值是不能重复的,并且是无序的
127.0.0.1:6379> sadd myset hello
(integer) 1
127.0.0.1:6379> sadd myset lv
(integer) 1
127.0.0.1:6379> sadd myset redis
(integer) 1
127.0.0.1:6379> SMEMBERS myset
1) "hello"
2) "redis"
3) "lv"
127.0.0.1:6379> SISMEMBER myset hello
(integer) 1
127.0.0.1:6379> SISMEMBER myset world
(integer) 0
127.0.0.1:6379> scard myset
(integer) 3
127.0.0.1:6379> srem myset hello
(integer) 1
127.0.0.1:6379> SMEMBERS myset
1) "redis"
2) "lv"
127.0.0.1:6379> SRANDMEMBER myset
"lv"
127.0.0.1:6379> SRANDMEMBER myset
"redis"
127.0.0.1:6379> spop myset
"mongodb"
127.0.0.1:6379> sadd myset2 set2
(integer) 1
127.0.0.1:6379> smove myset myset2 lv
(integer) 1
127.0.0.1:6379> SMEMBERS myset
1) "world"
2) "hello"
127.0.0.1:6379> SMEMBERS myset2
1) "set2"
2) "lv"
数字集合类:差集、交集、并集:共同关注可以这样实现
127.0.0.1:6379> SDIFF myset myset2
1) "hello"
2) "world"
127.0.0.1:6379> SINTER myset myset2
1) "lv"
127.0.0.1:6379> SUNION myset myset2
1) "set2"
2) "hello"
3) "world"
4) "lv"
Hash(哈希): 可以看做Map集合 key-value,当key-map的时候,这个值是个map集合,本质和String类型没有太大区别,还是一个简单的key-value 使用场景:hash可以存变更的数据,比如用户信息,经常变动的信息,比较适合对象的存储
127.0.0.1:6379> hset myhash field1 lv
(integer) 1
127.0.0.1:6379> hget myhash field1
"lv"
127.0.0.1:6379> hmset myhash field1 hello field2 world
OK
127.0.0.1:6379> hmget myhash field1 field2
1) "hello"
2) "world"
127.0.0.1:6379> hgetall myhash
1) "field1"
2) "hello"
3) "field2"
4) "world"
127.0.0.1:6379> hdel myhash field1
(integer) 1
127.0.0.1:6379> hgetall myhash
1) "field2"
2) "world"
127.0.0.1:6379> hlen myhash
(integer) 1
127.0.0.1:6379> hexists myhash field1
(integer) 0
127.0.0.1:6379> hkeys myhash
1) "field2"
127.0.0.1:6379> hvals myhash
1) "world"
127.0.0.1:6379> hset myhash field1 5
(integer) 1
127.0.0.1:6379> hincrby myhash field1 1
(integer) 6
127.0.0.1:6379> hincrby myhash field1 -1
(integer) 5
127.0.0.1:6379> hsetnx myhash field4 hello
(integer) 1
127.0.0.1:6379> hsetnx myhash field4 hello
(integer) 0
Zset(有序集合): 在set的基础上,增加一个值。 普通消息,重要消息,带权重进行判断,应用场景:排行榜排序
127.0.0.1:6379> zadd myset 1 one
(integer) 1
127.0.0.1:6379> zadd myset 2 two
(integer) 1
127.0.0.1:6379> zadd myset 3 three
(integer) 1
127.0.0.1:6379> zrange myset 0 -1
1) "one"
2) "two"
127.0.0.1:6379> zadd gz 2500 xiaohong
(integer) 1
127.0.0.1:6379> zadd gz 5000 zhangsan
(integer) 1
127.0.0.1:6379> zadd gz 8000 lv
(integer) 1
127.0.0.1:6379> ZRANGEBYSCORE gz -inf +inf
1) "xiaohong"
2) "zhangsan"
3) "lv"
127.0.0.1:6379> ZREVRANGE gz 0 -1
1) "lv"
2) "zhangsan"
127.0.0.1:6379> ZRANGEBYSCORE gz -1 0
(empty list or set)
127.0.0.1:6379> ZRANGEBYSCORE gz -inf +inf withscores
1) "xiaohong"
2) "2500"
3) "zhangsan"
4) "5000"
5) "lv"
6) "8000"
127.0.0.1:6379> ZRANGEBYSCORE gz -inf 2500 withscores
1) "xiaohong"
2) "2500"
127.0.0.1:6379> zrem gz xiaohong
(integer) 1
127.0.0.1:6379> zrange gz 0 -1
1) "zhangsan"
2) "lv"
127.0.0.1:6379> zcard gz
(integer) 2
127.0.0.1:6379> zcount gz 2500 5000
(integer) 2
127.0.0.1:6379> zcount gz 2500 8000
(integer) 3
geospatial地理位置: 场景:定位,附近的人,打车距离计算,底层命令就是Zset 可以用Zset命令来操作Geo
127.0.0.1:6379> GEOADD china:city 118.11022 24.490474 xiamen
(integer) 1
127.0.0.1:6379> GEOADD china:city 121.472644 31.231706 shanghai
(integer) 1
127.0.0.1:6379> geoadd china:city 116.405285 39.904989 beijing
(integer) 1
127.0.0.1:6379> geoadd china:city 106.50 29.53 chongqing 114.05 22.52 shenzhen
(integer) 2
127.0.0.1:6379> GEOPOS china:city beijing chongqing
1) 1) "116.40528291463852"
2) "39.904988422912503"
2) 1) "106.49999767541885"
2) "29.529999579006592"
127.0.0.1:6379> GEODIST china:city beijing shanghai
"1067597.9668"
127.0.0.1:6379> GEODIST china:city beijing shanghai km
"1067.5980"
127.0.0.1:6379> GEORADIUS china:city 110 30 1000 km
1) "chongqing"
2) "shenzhen"
127.0.0.1:6379> GEORADIUS china:city 110 30 500 km
1) "chongqing"
127.0.0.1:6379> GEORADIUS china:city 110 30 500 km withdist
1) 1) "chongqing"
2) "341.9374"
127.0.0.1:6379> GEORADIUS china:city 110 30 500 km withcoord
1) 1) "chongqing"
2) 1) "106.49999767541885"
2) "29.529999579006592"
127.0.0.1:6379> GEORADIUS china:city 110 30 500 km withdist withcoord count 1
1) 1) "chongqing"
2) "341.9374"
3) 1) "106.49999767541885"
2) "29.529999579006592"
127.0.0.1:6379> GEORADIUSBYMEMBER china:city xiamen 1000 km
1) "shenzhen"
2) "xiamen"
3) "shanghai"
127.0.0.1:6379> geohash china:city beijing xiamen
1) "wx4g0b7xrt0"
2) "ws7grdm5re0"
hyperloglog 基数统计的算法 场景:网页的uv 传统的方式,set保存用户的id,然后可以统计set中元素数量作为标准判断
127.0.0.1:6379> PFadd mykey a b c d e f g h i j k l
(integer) 1
127.0.0.1:6379> PFcount mykey
(integer) 12
127.0.0.1:6379> PFadd mykey2 j k l m n o p q r s t
(integer) 1
127.0.0.1:6379> PFMERGE mykey3 mykey mykey2
OK
127.0.0.1:6379> pfcount mykey3
(integer) 19
Bitmaps 位存储,场景:统计用户信息,登陆和未登陆的用户,只有两个状态的都可以使用 数据结构,操作二进制位来进行记录,只有0和1两个状态
127.0.0.1:6379> setbit sign 0 1
(integer) 0
127.0.0.1:6379> setbit sign 1 1
(integer) 0
127.0.0.1:6379> setbit sign 2 0
(integer) 0
127.0.0.1:6379> getbit sign 1
(integer) 1
127.0.0.1:6379> bitcount sign
(integer) 2
Redis的事务 事务本质:一组命令的集合 一个事务中的所有命令都会被序列化,执行过程中会按顺序执行,一次性、顺序性、排他性 单条命令有原子性,但是事务没有原子性,没有隔离级别的概念 1.开启事务(multi) 2.命令入队(…) 3.执行事务(exec)
127.0.0.1:6379> multi
OK
127.0.0.1:6379> set k1 v1
QUEUED
127.0.0.1:6379> exec
1) OK
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> discard
OK
127.0.0.1:6379> get k1
"v1"
127.0.0.1:6379> get k2
(nil)
编译型异常(代码有问题,执行的命令有错误)事务中所有的命令都不会被执行
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> getset k3
(error) ERR wrong number of arguments for 'getset' command
127.0.0.1:6379> set k4 v4
QUEUED
127.0.0.1:6379> exec
(error) EXECABORT Transaction discarded because of previous errors.
127.0.0.1:6379> get k1
(nil)
运行时异常(1/0)如果事务队列中存在语法性,那么执行命令的时候其他命令是可以正常执行的,错误命令抛出异常
127.0.0.1:6379> set k1 v1
OK
127.0.0.1:6379> multi
OK
127.0.0.1:6379> incr k1
QUEUED
127.0.0.1:6379> get k1
QUEUED
127.0.0.1:6379> exec
1) (error) ERR value is not an integer or out of range
2) "v1"
乐观锁 多线程修改值,使用watch可以当做redis的乐观锁操作
127.0.0.1:6379> set money 100
OK
127.0.0.1:6379> set out 0
OK
127.0.0.1:6379> watch money
OK
127.0.0.1:6379> multi
OK
127.0.0.1:6379> DECRBY money 20
QUEUED
127.0.0.1:6379> INCRBY out 20
QUEUED
127.0.0.1:6379> exec
1) (integer) 80
2) (integer) 20
Jedis 是redis官方推荐的java连接开发工具,使用java操作redis中间件 导入对应的依赖
<dependency>
<groupId>redis.clients</groupId>
<artifactId>jedis</artifactId>
<version>4.2.3</version>
</dependency>
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>fastjson</artifactId>
<version>1.2.62</version>
</dependency>
用IDEA模拟开启事务:
public class Test {
public static void main(String[] args) {
Jedis jedis = new Jedis("127.0.0.1",6379);
jedis.flushDB();
JSONObject jsonObject = new JSONObject();
jsonObject.put("hello","world");
jsonObject.put("name","zhangsan");
Transaction multi = jedis.multi();
String result = jsonObject.toString();
try {
multi.set("user1",result);
multi.set("user2",result);
multi.exec();
}catch (Exception e){
multi.discard();
e.printStackTrace();
}finally {
System.out.println(jedis.get("user1"));
System.out.println(jedis.get("user2"));
jedis.close();
}
}
}
SpringBoot整合: 在SpringBoot2.x之后Jedis被替换成lettuce Jedis:采用的直连,多个线程操作是不安全的,如果想避免不安全要使用jedis pool连接池 BIO模式 lettuce:采用的netty,实例可以在多个线程中共享,不存在线程不安全,可以减少线程数据 NIO模式
pom.xml加入依赖
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
配置文件
spring.redis.host=127.0.0.1
spring.redis.port=6379
Redis持久化
Redis是内存数据库,如果不将内存中的数据库状态保存到磁盘,那么一旦服务器进程退出,服务器中的数据库状态也会消失,所以Redis提供了持久化功能
RDB持久化操作:
配置文件中修改save 60 5,只要60秒内修改5次key,执行flushall命令和退出redis的时候就会触发rdb操作,自动生成的文件为dump.rdb 127.0.0.1:6379> config get dir 1) “dir” 2) “D:\Redis\Redis-x64-3.0.504” ---->dump.rdb文件目录 优点: 1.适合大规模的数据恢复 2.对数据的完整性要求不高 缺点: 1.需要一定的时间间隔进程操作,如果redis意外宕机了,最后一次修改的数据就没了 2.fork进程的时候,会占用一定的内容空间
AOF持久化操作:
将我们所有的命令都记录下来,history,恢复的时候就把这个文件全部执行一遍 配置文件中默认不开启appendonly no 改为yes就是开启 如果aof文件有错误,redis是启动不起来的,我们需要用redis-check-aof修复aof文件 优点: 1.每一次修改都同步,文件的完整性会更好 2.每秒同步一次,可能会丢失一秒的数据 3.从不同步,效率最高 缺点: 1.相对于数据文件来说,aof远远大于rdb,修复的速度比rdb慢 2.aof运行效率也比rdb慢,所以我们redis默认就是rdb持久化
总结:
RDB持久化方式就是能在指定的时间间隔内对你的数据进行快照存储 AOF持久化方式就是记录每次对服务器写的操作命令,服务器重启就会重新执行这些命令来恢复数据 只做缓存,如果希望数据在服务器运行的时候存在,可以不使用任何持久化
Redis发布订阅
是一种消息通信模式:发送者发送消息,订阅者接收消息
Redis主从复制
主从复制是指将一台Redis服务器的数据复制到其他的Redis服务器,数据的复制是单向的,只能从主节点到从节点,读写分离。 主机能写入数据,从机只能读取数据 主从复制的作用: 1.数据冗余:主从复制实现了数据的热备份,是持久化之外的一种数据冗余方式 2.故障恢复:当主节点出现问题时,可以由从节点提供服务,实现快速的故障恢复,实际是一种服务的冗余 3.负载均衡:在主从复制的基础上,配合读写分离,可以由主节点提供写服务,由从节点提供读服务 4.高可用(集群)基石:主从复制还是哨兵和集群能够实施基础
127.0.0.1:6379> info 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
默认情况下每台Redis服务器都是主节点,一般只用配置从机
SLAVEOF 127.0.0.1 6379
全量复制:slave服务在接收到数据库文件数据后,将其存盘并加载到内存中
增量复制:Master继续将新的所有收集到的修改命令依次传给slave,完成同步
只要重新链接master,一次全量复制将被自动执行
Redis哨兵模式
1.配置哨兵配置文件sentinel.conf sentinel monitor myredis 127.0.0.1 6379 1 ---->后面的数字1代表主机宕机后slave投票票数最多的成为主机 2.启动哨兵 redis-sentinel kconfig/sentinel.conf 如果从机选举完了,主机连接回来了,主机会被哨兵模式切换成从机 优点: 1.哨兵集群,基于主从复制模式,所有的主从配置优点都有 2.主从可以切换,故障可以转移,系统的可用性好 3.哨兵模式就是主从模式的升级,手动到自动 缺点: 1.Redis不好在线扩容,集群容量一旦到达上限,在线扩容就十分麻烦 2.实现哨兵模式的配置是很麻烦的
哨兵模式的全部配置:
# Example sentinel.conf
# 哨兵sentinel实例运行的端口 默认26379
port 26379
# 哨兵sentinel的工作目录
dir /tmp
# 哨兵sentinel监控的redis主节点的 ip port
# master-name 可以自己命名的主节点名字 只能由字母A-z、数字0-9 、这三个字符".-_"组成。
# quorum 配置多少个sentinel哨兵统一认为master主节点失联 那么这时客观上认为主节点失联了
# sentinel monitor <master-name> <ip> <redis-port> <quorum>
sentinel monitor mymaster 127.0.0.1 6379 2
# 当在Redis实例中开启了requirepass foobared 授权密码 这样所有连接Redis实例的客户端都要提供密码
# 设置哨兵sentinel 连接主从的密码 注意必须为主从设置一样的验证密码
# sentinel auth-pass <master-name> <password>
sentinel auth-pass mymaster MySUPER--secret-0123passw0rd
# 指定多少毫秒之后 主节点没有应答哨兵sentinel 此时 哨兵主观上认为主节点下线 默认30秒
# sentinel down-after-milliseconds <master-name> <milliseconds>
sentinel down-after-milliseconds mymaster 30000
# 这个配置项指定了在发生failover主备切换时最多可以有多少个slave同时对新的master进行 同步,这个数字越小,完成failover所需的时间就越长,但是如果这个数字越大,就意味着越 多的slave因为replication而不可用。可以通过将这个值设为 1 来保证每次只有一个slave 处于不能处理命令请求的状态。
# sentinel parallel-syncs <master-name> <numslaves>
sentinel parallel-syncs mymaster 1
# 故障转移的超时时间 failover-timeout 可以用在以下这些方面:
#1. 同一个sentinel对同一个master两次failover之间的间隔时间。
#2. 当一个slave从一个错误的master那里同步数据开始计算时间。直到slave被纠正为向正确的master那里同步数据时。
#3.当想要取消一个正在进行的failover所需要的时间。
#4.当进行failover时,配置所有slaves指向新的master所需的最大时间。不过,即使过了这个超时,slaves依然会被正确配置为指向master,但是就不按parallel-syncs所配置的规则来了
# 默认三分钟
# sentinel failover-timeout <master-name> <milliseconds>
sentinel failover-timeout mymaster 180000
# SCRIPTS EXECUTION
#配置当某一事件发生时所需要执行的脚本,可以通过脚本来通知管理员,例如当系统运行不正常时发邮件通知相关人员。
#对于脚本的运行结果有以下规则:
#若脚本执行后返回1,那么该脚本稍后将会被再次执行,重复次数目前默认为10
#若脚本执行后返回2,或者比2更高的一个返回值,脚本将不会重复执行。
#如果脚本在执行过程中由于收到系统中断信号被终止了,则同返回值为1时的行为相同。
#一个脚本的最大执行时间为60s,如果超过这个时间,脚本将会被一个SIGKILL信号终止,之后重新执行。
#通知型脚本:当sentinel有任何警告级别的事件发生时(比如说redis实例的主观失效和客观失效等等),将会去调用这个脚本,这时这个脚本应该通过邮件,SMS等方式去通知系统管理员关于系统不正常运行的信息。调用该脚本时,将传给脚本两个参数,一个是事件的类型,一个是事件的描述。如果sentinel.conf配置文件中配置了这个脚本路径,那么必须保证这个脚本存在于这个路径,并且是可执行的,否则sentinel无法正常启动成功。
#通知脚本
# shell编程
# sentinel notification-script <master-name> <script-path>
sentinel notification-script mymaster /var/redis/notify.sh
# 客户端重新配置主节点参数脚本
# 当一个master由于failover而发生改变时,这个脚本将会被调用,通知相关的客户端关于master地址已经发生改变的信息。
# 以下参数将会在调用脚本时传给脚本:
# <master-name> <role> <state> <from-ip> <from-port> <to-ip> <to-port>
# 目前<state>总是“failover”,
# <role>是“leader”或者“observer”中的一个。
# 参数 from-ip, from-port, to-ip, to-port是用来和旧的master和新的master(即旧的slave)通信的
# 这个脚本应该是通用的,能被多次调用,不是针对性的。
# sentinel client-reconfig-script <master-name> <script-path>
sentinel client-reconfig-script mymaster /var/redis/reconfig.sh # 一般都是由运维来配置!
Redis缓存穿透和雪崩(重点)
缓存穿透概念:用户想查一个数据,发现redis内存数据库没有,也就是缓存没有命中,于是向持久层数据库查询,发现也没有 于是本次查询失败,当用户很多的时候,缓存都没有命中,就都会去请求持久层数据库,这就给持久层数据库造成很大压力(一直查不到某个数据) 解决方案: 1.布隆过滤器:布隆过滤器是一种数据结构,对所有可能查询的参数以hash形式存储,在控制层先进行校验,不符合则丢弃,从而避免了对底层存储系统的查询压力
缓存击穿概念:是指一个key非常热点,在不停的抗着大并发,大并发集中对这一点进行访问,当这个key在失效的瞬间,大并发就 穿破缓存,直接请求数据库,导致数据库瞬间压力过大(比如微博热搜某条热搜一直被搜索) 解决方案: 1.设置热点数据永不过期 2.分布式锁
缓存雪崩概念:是指在某一个时间段,缓存集体过期失效 解决方案: 1.redis高可用 2.限流降级 3.数据预热
内存淘汰和过期key删除策略
Redis 4.0前具体回收策略有以下6种: ● volatile-lru: 在所有带有过期时间的 key 中使用 LRU 算法淘汰数据; ● alkeys-lru: 在所有的 key 中使用最近最少被使用 LRU 算法淘汰数据,保证新加入的数据正常; ● volatile-random: 在所有带有过期时间的 key 中随机淘汰数据; ● allkeys-random: 在所有的 key 中随机淘汰数据; ● volatile-ttl: 在所有带有过期时间的 key 中,淘汰最早会过期的数据; ● noeviction: 不回收,当达到最大内存的时候,在增加新数据的时候会返回 error,不会清除旧数据,这是 Redis 的默认策略;
Ps: volatile-lru, volatile-random, volatile-ttl 这几种情况在 Redis 中没有带有过期 Key 的时候跟 noeviction 策略是一样的。淘汰策略是可以动态调整的,调整的时候是不需要重启的
Redis 4.0后增加以下两种: ● volatile-lfu:从已设置过期时间的数据集(server.db[i].expires)中挑选最不经常使用的数据淘汰(LFU(Least Frequently Used)算法,也就是最频繁被访问的数据将来最有可能被访问到) ● allkeys-lfu:当内存不足以容纳新写入数据时,在键空间中,移除最不经常使用的key。
常见的过期删除策略是惰性删除、定期删除、定时删除。Redis中同时使用了惰性删除和定期删除两种。
(1)惰性删除:只有访问这个键时才会检查它是否过期,如果过期则清除。 ● 优点:最大化地节约CPU资源。 ● 缺点:如果大量过期键没有被访问,会一直占用大量内存。
(2)定时删除:为每个设置过期时间的key都创造一个定时器,到了过期时间就清除。 ● 优点:该策略可以立即清除过期的键。 ● 缺点:会占用大量的CPU资源去处理过期的数据。
(3)定期删除:每隔一段时间就对一些键进行检查,删除其中过期的键。该策略是惰性删除和定时删除的一个折中,既避免了占用大量CPU资源又避免了出现大量过期键不被清除占用内存的情况。
|