redis学习

redis学习

五大数据类型

string(字符串类型)

Set key 设置key

Get key 获得key

Keys * 查看所有的key

incr key key值+一

decr key key值-1

incrby key 10。 key值+10

decrby key 10 key值-10

================================================
#获取字符串范围
127.0.0.1:6379> set key "hello world"   #设置key
OK
127.0.0.1:6379> getrange key1 0 2
""
127.0.0.1:6379> getrange key 0 2			#截取key
"hel"
===============================================
#替换
127.0.0.1:6379> set key adsfsd
OK
127.0.0.1:6379> setrange key 1 xxx			#替换指定位置开始的字符串
(integer) 6
127.0.0.1:6379> get key
"axxxsd"
===============================================
# setex(set with expire)      #设置过期时间
# setnx (set if not exist)    #不存在再设置(在分布式锁中会常常使用)

127.0.0.1:6379> setex key3 30 "hello"						#设置过期时间
OK
127.0.0.1:6379> ttl key3												#查看还有多长时间过期
(integer) 24
127.0.0.1:6379> ttl key3
(integer) 23
127.0.0.1:6379> setnx mykey redis								#不存在mykey则设置mykey
(integer) 1
127.0.0.1:6379> get mykey
"redis"
127.0.0.1:6379> keys *
1) "mykey"
2) "key"
127.0.0.1:6379>  setnx key3 mongodb							
(integer) 1
127.0.0.1:6379>  setnx mykey mongodb						#如果mykey存在就创建失败了
(integer) 0
127.0.0.1:6379> keys *
1) "mykey"
2) "key"
3) "key3"
127.0.0.1:6379> get mykey
"redis"
==============================================================================================
#mset  			批量设置健值对
#mget 			批量获取健值对

127.0.0.1:6379> mset k1 v1 k2 v2 k3 v3			#同时设置多个值
OK
127.0.0.1:6379> mget				
(error) ERR wrong number of arguments for 'mget' command
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   				#msetnx是原子性操作,要么一起成功,要么一起失败
(integer) 0
127.0.0.1:6379> keys *
1) "k3"
2) "k2"
3) "k1"
127.0.0.1:6379> get k4
(nil)
==============================================================================================
#set user:1 {name:zhangsan,age:3}  

#mset user:1:name zhangsan user:1:age 3;用user:{id}:{filed}来设计key值
==============================================================================================
#getset   先get再set
127.0.0.1:6379> getset db redis				#如果不存在值则返回null
(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"

value除了是字符串还可以是数字

  • 计数器
  • 统计多单位的数量
  • 粉丝数
  • 对象缓存存储

List

​ 在redis里面,可以把list当成栈/队列/阻塞队列

所有的list命令都是以l开头的

==============================================================================================
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
(error) ERR wrong number of arguments for 'lrange' command
127.0.0.1:6379> lrange list   0 -1
1) "three"
2) "two"
3) "one"
127.0.0.1:6379> lrange list   0 1
1) "three"
2) "two"
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> lrange list 0 -1
1) "two"
2) "one"
3) "right"
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> lrange list 0 -1			
1) "two"
2) "one"
127.0.0.1:6379> lindex list 1						#通过下标获得list中的值
"one"
127.0.0.1:6379> lindex list 0
"two"
==============================================================================================
127.0.0.1:6379> llen list						#获取list 长度
(integer) 2
==============================================================================================
127.0.0.1:6379> lpush list two
(integer) 3
127.0.0.1:6379> lrange list 0 -1
1) "two"
2) "two"
3) "one"
127.0.0.1:6379> lrem list 1 two							#移除list集合中指定个数的value
(integer) 1
========================================================================================
ltrim

127.0.0.1:6379> lpush mylist hello hello2 hello3
(integer) 3
127.0.0.1:6379> lrange mylist 0 -1
1) "hello3"
2) "hello2"
3) "hello"
127.0.0.1:6379> ltrim mylist 1 2						#通过下标截取指定的长度,hello下标是0
OK
127.0.0.1:6379>  lrange 0 -1
(error) ERR wrong number of arguments for 'lrange' command
127.0.0.1:6379>  lrange mylist  0 -1
1) "hello2"
2) "hello"
========================================================================================
rpoplpush  				#移除列表的最后一个元素,将它移动到新的列表中去
127.0.0.1:6379> lpush mylist hello hello2 hello3
(integer) 3	
127.0.0.1:6379> rpoplpush mylist myotherlist						#移除列表的最后一个元素,将它移动到新的列表中去
"hello"
127.0.0.1:6379> lrange mylist 0 -1
1) "hello3"
2) "hello2"
127.0.0.1:6379> lrange myotherlist 0 -1
1) "hello"
========================================================================================
127.0.0.1:6379> exists list							#首先要确定列表是否存在
(integer) 0
127.0.0.1:6379> lset list 0 item						
(error) ERR no such key
127.0.0.1:6379> lpush list  value
(integer) 1
127.0.0.1:6379> lrange list 0 0
1) "value"
127.0.0.1:6379> lset list 0 item						#将列表中指定下标的值替换到另外一个值
OK
127.0.0.1:6379> lrange list 0 0
1) "item"
========================================================================================
linsert   #将某个具体的值插入到列表中的某个元素的前面或后面
127.0.0.1:6379> rpush list hello world
(integer) 2
127.0.0.1:6379> lrange list 0 -1
1) "hello"
2) "world"
127.0.0.1:6379> linsert list before world
(error) ERR wrong number of arguments for 'linsert' command
127.0.0.1:6379> linsert list before 'world' 'value' 
(integer) 3
127.0.0.1:6379> lrange list 0 -1
1) "hello"
2) "value"
3) "world"
127.0.0.1:6379> linsert list after world hehe
(integer) 4
127.0.0.1:6379> lrange list 0 -1
1) "hello"
2) "value"
3) "world"
4) "hehe"

小结:

  • list实际上是个链,before node after ,left,right都可以插入值

  • 如果key不存在,则创建新的列表

  • 如果key存在 ,新增内容

  • 如果移除了所有值,则是空链表,也代表不存在

  • 在两边插入或改动值效率会高,如果链表特别长,在中间元素效率会低一点

    消息排队,消息队列(lpush rpop),栈(lpush lpop)

set(集合)

set中的值不能重复

========================================================================================
127.0.0.1:6379> sadd myset hello							#set集合中 添加元素
(integer) 1
127.0.0.1:6379> sadd myset hello in
(integer) 1
127.0.0.1:6379> sadd myset hellomo
(integer) 1
127.0.0.1:6379> smembers myset				#查看set值
1) "in"
2) "hellomo"
3) "hello"
127.0.0.1:6379> sismember myset in			#判断元素是否在set集合中
(integer) 1
127.0.0.1:6379> scard myset							#获取set集合中的个数
(integer) 3
========================================================================================

127.0.0.1:6379> srem myset hello							#移除set中的一个元素
(integer) 1
127.0.0.1:6379> scard myset
(integer) 2
127.0.0.1:6379> smembers myset
1) "in"
2) "hellomo"
127.0.0.1:6379> SRANDMEMBER myset						#随机抽出指定个数的元素,默认是一个
"hellomo"
========================================================================================
随机删除指定的元素

127.0.0.1:6379> spop myset 					#随机删除set集合中的元素
"in"

127.0.0.1:6379> sadd myset hello
(integer) 1
127.0.0.1:6379> sadd myset hello1
(integer) 1
127.0.0.1:6379> sadd myset hello2
(integer) 1
127.0.0.1:6379> sadd myset2 world
(integer) 1
127.0.0.1:6379> smove myset myset2 hello			#将myset中的hello移动到myset2中
(integer) 1
127.0.0.1:6379> SMEMBERS myset
1) "hello2"
2) "hello1"
127.0.0.1:6379> smembers myset2
1) "world"
2) "hello"
========================================================================================
微博,b站 共同关注(并集)
差集 交集 并集 
127.0.0.1:6379> sadd key1 a
(integer) 1
127.0.0.1:6379> sadd key1 b
(integer) 1
127.0.0.1:6379> sadd key1 c
(integer) 1
127.0.0.1:6379> sadd key2 d
(integer) 1
127.0.0.1:6379> sadd key2 c
(integer) 1
127.0.0.1:6379> sadd key2 e
(integer) 1
127.0.0.1:6379> sdiff key1 key2			#差集
1) "a"
2) "b"
127.0.0.1:6379> sinter key1 key2		#交集
1) "c"
127.0.0.1:6379> sunion key1 key2		#并集
1) "a"
2) "b"
3) "d"
4) "c"
5) "e"

微博:A用户将所有关注的人放在一个集合中,将粉丝也放在集合中

共同关注:共同爱好,二度好友,推荐好友

hash

map集合 key-

127.0.0.1:6379> hset myhash field1 xiaochao
(integer) 1
127.0.0.1:6379> hget myhash field1
"xiaochao"
127.0.0.1:6379> hmset myhash field1 hello  field2 world	
(integer) 1
127.0.0.1:6379> hmget myhash field1 field2
1) "hello"
2) "world"
127.0.0.1:6379> hget myhash  field1 
"hello"
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> HGETALL myhash
1) "field2"
2) "world"
127.0.0.1:6379> hlen myhash				#获取hash的字段数量
(integer) 1

========================================================================================
127.0.0.1:6379> HEXISTS myhash  field
(integer) 0
127.0.0.1:6379> HEXISTS myhash  field2
(integer) 1
========================================================================================
127.0.0.1:6379> hkeys myhash				#获取hash的所有key值
1) "field2"
127.0.0.1:6379> HVALS myhash				#获取hash所有的value值
1) "world"	
========================================================================================
127.0.0.1:6379> HINCRBY myhash field4  1			#hash值加1
(integer) 2
127.0.0.1:6379> hsetnx myhash field4 hah			#如果存在不能设置
(integer) 0
127.0.0.1:6379> hsetnx myhash field5 heh			#如果不存在则可以设置
(integer) 1

小结

hash存一些变更数据, 尤其是用户的信息,经常变动的信息,hash更适合对象的存储,string更适合字符串存储

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"
3) "three"
========================================================================================
排序 
127.0.0.1:6379> zadd salary 2500 xiaohong 5000 zhangsan		#添加用户的薪水
(integer) 2
127.0.0.1:6379> zadd salary 200 xiaochao
(integer) 1
127.0.0.1:6379> ZRANGEBYSCORE salary -inf +inf 						#按照从小到大的排序
1) "xiaochao"
2) "xiaohong"
3) "zhangsan"
127.0.0.1:6379> ZRANGEBYSCORE salary -inf +inf  withscores    #附带有序集合的值
1) "xiaochao"
2) "200"
3) "xiaohong"
4) "2500"
5) "zhangsan"
6) "5000"
127.0.0.1:6379> ZRANGEBYSCORE salary -inf 2500			#判断2500以下的值,升序排列
1) "xiaochao"
2) "xiaohong"
127.0.0.1:6379> ZREVRANGEBYSCORE salary +inf -inf			#降序排列
1) "zhangsan"
2) "xiaochao"
127.0.0.1:6379> ZREVRANGE salary 0 -1										#也是降序排列(到时候查查有什么不一样)
1) "zhangsan"
2) "xiaochao"
========================================================================================
#移除元素
127.0.0.1:6379> ZRANGE salary 0 -1			#查询集合
1) "xiaochao"
2) "xiaohong"
3) "zhangsan"
127.0.0.1:6379> zrem salary xiaohong		#移除有序集合中的具体元素
(integer) 1
127.0.0.1:6379> ZRANGE salary 0 -1
1) "xiaochao"
2) "zhangsan"
127.0.0.1:6379>  zcard salary					#获取集合数量
(integer) 2
========================================================================================
zcount
127.0.0.1:6379> zadd myset  1 hello
(integer) 1
127.0.0.1:6379> zadd myset  2 world
(integer) 1
127.0.0.1:6379> zadd myset  3 xiaochao
(integer) 1
127.0.0.1:6379> ZCOUNT myset 1 2						#获取指定区间的成员数量
(integer) 2
127.0.0.1:6379> ZCOUNT myset 1 3
(integer) 3

127.0.0.1:6379> ZRANGEBYSCORE myset -inf +inf  withscores
1) "hello"
2) "1"
3) "world"
4) "2"
5) "xiaochao"
6) "3"
127.0.0.1:6379> ZINCRBY myset 10  xiaochao					#增量分数 
"13"
127.0.0.1:6379> ZRANGEBYSCORE myset -inf +inf  withscores
1) "hello"
2) "1"
3) "world"
4) "2"
5) "xiaochao"
6) "13"

集合存储,跟排序有关的东西,排行榜啥的,带权重判断

三种特殊数据类型

geospatial(地理位置)

朋友的定位,附近的人,打车距离计算

redis的geo,在redis3.2以后的版本推出的,这个功能可以推算地理位置信息,比如两地之间的距离,方圆几里的人

可以查询经纬度的网站:http://www.jsons.cn/lngcode/

只有6个命令

getadd,geopos

========================================================================================
#规则:地球两极无法添加
#key (经度,纬度,名称)
127.0.0.1:6379> GEOADD china:city 116.40 39.90 beijng
(integer) 1
127.0.0.1:6379> GEOADD china:city 121.47 31.23 shanghai
(integer) 1
127.0.0.1:6379> GEOADD china:city 106.50 29.53 chongqing
(integer) 1
127.0.0.1:6379> GEOADD china:city 114.05 22.52 shenzhen
(integer) 1
127.0.0.1:6379> GEOADD china:city 120.16 30.24 hangzhou 108.96 34.26 xian		#添加地理位置
(integer) 2
========================================================================================
#geopos
#获取指定的经纬度
127.0.0.1:6379> geopos china:city hangzhou
1) 1) "120.1600000262260437"
   2) "30.2400003229490224"
127.0.0.1:6379> geopos china:city beijng
1) 1) "116.39999896287918091"
   2) "39.90000009167092543"

Geodesy 返回两个给定位置之间的距离。

两人之间的距离

127.0.0.1:6379> geodist china:city beijng shanghai				#查看距离
"1067378.7564"
127.0.0.1:6379> geodist china:city beijng shanghai km			#设置距离
"1067.3788"
127.0.0.1:6379> GEODIST china:city beijng chongqing
"1464070.8051"
127.0.0.1:6379> GEODIST china:city beijng chongqing km
"1464.0708"

Georadius. 以给定的经纬度为中心, 返回键包含的位置元素当中, 与中心的距离不超过给定最大距离的所有位置元素。

获取附近的人,获取所有人的定位,然后半径查询

127.0.0.1:6379> GEORADIUS china:city 110 30 1000 km     #110是经度,30是纬度, 半径1000km范围内
1) "chongqing"
2) "xian"
3) "shenzhen"
4) "hangzhou"
127.0.0.1:6379> GEORADIUS china:city 110 30 500 km
1) "chongqing"
2) "xian"
127.0.0.1:6379> GEORADIUS china:city 110 30 500 km withdist				#加上直线距离
1) 1) "chongqing"
   2) "341.9374"	
2) 1) "xian"
   2) "483.8340"
127.0.0.1:6379> GEORADIUS china:city 110 30 500 km withdist withcoord				#加上直线距离和经纬度
1) 1) "chongqing"
   2) "341.9374"
   3) 1) "106.49999767541885376"
      2) "29.52999957900659211"
2) 1) "xian"
   2) "483.8340"
   3) 1) "108.96000176668167114"
      2) "34.25999964418929977"

127.0.0.1:6379> GEORADIUS china:city 110 30 500 km count 1			#查询数量
1) "chongqing"

GEORADIUSBYMEMBER

这个命令和 GEORADIUS 命令一样, 都可以找出位于指定范围内的元素, 但是 GEORADIUSBYMEMBER 的中心点是由给定的位置元素决定的, 而不是像 GEORADIUS 那样, 使用输入的经度和纬度来决定中心点

指定成员的位置被用作查询的中心

127.0.0.1:6379> GEORADIUSBYMEMBER china:city beijng 1000 km  withdist				#查询指定元素周围的其他元素
1) 1) "beijng"
   2) "0.0000"
2) 1) "xian"
   2) "910.0565"

GEOHASH key member [member …]

该命令将返回11个字符的Geohash字符串,

127.0.0.1:6379> GEOHASH china:city beijng chongqing			#将经纬度转换为11位的字符串,如果两个字符串越接近则距离越近
1) "wx4fbxxfke0"
2) "wm5xzrybty0"

GEO 底层的实现原理就是zset,可以使用zset来操作geo

127.0.0.1:6379> ZRANGE china:city 0 -1					#可以用zset命令来查看
1) "chongqing"
2) "xian"
3) "shenzhen"
4) "hangzhou"
5) "shanghai"
6) "beijng"
127.0.0.1:6379> zrem china:city beijng				#可以用zset命令来移除
(integer) 1
127.0.0.1:6379> ZRANGE china:city 0 -1
1) "chongqing"
2) "xian"
3) "shenzhen"
4) "hangzhou"
5) "shanghai"

HyperLogLog

什么是基数。

A{1,3,5,7,9}.B{1,3,5,7,8}. 两个合集中不重复的元素

简介:

redis hyperloglog 是用来做基数统计的算法(优点:占的内存固定,2^64不同元素的基数,只会占用12KB的内存),0.81%的错误率

比如网页的UV (一个人访问网站多次算一个人)

传统方式 set保存用户的id,然后就可以统计元素的数量作为标准判断 ,如果没登录就不能记录了

127.0.0.1:6379> PFADD mykey  a b c d e f g h i j k 			#创建第一组元素
(integer) 1
127.0.0.1:6379> PFCOUNT  mykey													#统计元素数量 
(integer) 11
127.0.0.1:6379> PFADD mykey2 j k l m n c v b 						
(integer) 1	
127.0.0.1:6379> PFMERGE mykey3 mykey mykey2							#把mykey和mykey2合并到mykey3中
OK
127.0.0.1:6379> PFCOUNT mykey3
(integer) 15

bitmap

位存储

统计疫情感染人数 没感染的用0,感染的 用1 ,统计用户信息 ,活跃不活跃。登陆没登陆,打卡没打卡,两个状态的都可以使用bitmaps

都是操作二进制进行记录

测试

使用setbit来记录周一到周日的打卡

周一: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> setbit sign 3 1
(integer) 0
127.0.0.1:6379> setbit sign 4 0
(integer) 0
127.0.0.1:6379> setbit sign 5 1
(integer) 0
127.0.0.1:6379> setbit sign 6 0 
(integer) 0
127.0.0.1:6379> setbit sign 7 0
(integer) 0

查看某一天是否有打卡

127.0.0.1:6379> getbit sign 3      #查看某天的状态
(integer) 1

统计的操作

127.0.0.1:6379> BITCOUNT sign     #统计打卡的天数
(integer) 4

事务

要么同时成功,要么同时失败,具有原子性。redis单条命令是保证原子性的,但是事是不保证原子性的,redis事务是一组命令一起执行,一个事务中的所有命令都会被序列化,在事务执行的过程中会按照顺序执行

一次性,顺序性, 排他性,没有隔离级别的概念,执行一系列的命令,所有命令在入队的 时候并没有被执行 ,只有在发起执行的命令的时候才会去执行。Exec 执行事务

redis事务阶段

  • 开启事务(multi)
  • 命令入队(set 。。。)
  • 执行事务(exec)

锁:可以实现乐观锁

127.0.0.1:6379> MULTI										#开启事务
OK
127.0.0.1:6379(TX)> set k1 v1						#命令入队
QUEUED
127.0.0.1:6379(TX)> set k2 v2
QUEUED
127.0.0.1:6379(TX)> get k2
QUEUED
127.0.0.1:6379(TX)> set k3 v3
QUEUED
127.0.0.1:6379(TX)> exec						#执行事务
1) OK
2) OK
3) "v2"
4) OK


127.0.0.1:6379> MULTI
OK
127.0.0.1:6379(TX)> set  k1 v1 
QUEUED
127.0.0.1:6379(TX)> set k2 v2
QUEUED
127.0.0.1:6379(TX)> set k4 v4
QUEUED
127.0.0.1:6379(TX)> DISCARD					#取消事务,队列中命令不会被执行
OK
127.0.0.1:6379> get  k4
(nil)

编译性异常,代码有误,事务队列中所有命令都 不会被执行

127.0.0.1:6379> MULTI
OK
127.0.0.1:6379(TX)> set k1 v1
QUEUED
127.0.0.1:6379(TX)> set k2 v2
QUEUED
127.0.0.1:6379(TX)> set k3 v3 
QUEUED
127.0.0.1:6379(TX)> getset k4												#错误的命令
(error) ERR wrong number of arguments for 'getset' command
127.0.0.1:6379(TX)> set k5 v5
QUEUED
127.0.0.1:6379(TX)> exec					#执行命令报错,所有命令都没有执行
(error) EXECABORT Transaction discarded because of previous errors.

运行时异常(1/0这种错误),队列中存在语法错误,执行命令的时候 其他命令会被执行,错误命令会抛出异常

127.0.0.1:6379> set k1 v1
OK
127.0.0.1:6379> MULTI
OK
127.0.0.1:6379(TX)> INCR k1
QUEUED
127.0.0.1:6379(TX)> set k2 v2 
QUEUED
127.0.0.1:6379(TX)> set k3 v3
QUEUED
127.0.0.1:6379(TX)> get k3
QUEUED
127.0.0.1:6379(TX)> exec
1) (error) ERR value is not an integer or out of range    #虽然第一条命令报错了,但是依然执行成功了
2) OK
3) OK
4) "v3"

监控 watch(面试常问的)

悲观锁:很悲观,什么时候都会出问题 ,无论做什么都加锁。

乐观锁:很乐观,什么时候都不会出现问题,所以不会上锁,在更新数据的时候判断一下在此期间是否有人修改过这个数据。

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					#监视money 
OK
127.0.0.1:6379> MULTI  
OK
127.0.0.1:6379(TX)> DECRBY money 20
QUEUED
127.0.0.1:6379(TX)> INCRBY out 20
QUEUED 
127.0.0.1:6379(TX)> EXEC  						#事务正常结束,数据期间没有发生变动,这个时候就正常执行成功
1) (integer) 80
2) (integer) 20

测试多线程修改值,使用watch可以当redis的乐观锁

#线程1	
127.0.0.1:6379> watch money						#监视money
OK
127.0.0.1:6379> MULTI
OK
127.0.0.1:6379(TX)> DECRBY money 10
QUEUED
127.0.0.1:6379(TX)> INCRBY out 10
QUEUED
127.0.0.1:6379(TX)> exec								#执行之前另一个线程修改了值,这个时候事务就失败了
(nil)
127.0.0.1:6379> unwatch									#如果事务执行失败了,就先解锁,然后再去加锁重新做
OK

#线程2
127.0.0.1:6379> get money
"80"
127.0.0.1:6379> set money 1000
OK 

redis.conf 详解

1、单位:单位unit对大小写不敏感,

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-lpe5rXTJ-1629631546661)(/Users/wanghaichao/Library/Application Support/typora-user-images/截屏2021-08-18 21.48.20.png)]

2、包含:可以包含其他配置文件

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-JZb5W40r-1629631546663)(/Users/wanghaichao/Library/Application Support/typora-user-images/image-20210818215506190.png)]

网络

bind 127.0.0.1 ::1   #绑定ip
protected-mode yes
port 6379						#端口设置

通用配置

daemonize no    #守护进程启动,默认关闭
pidfile /var/run/redis_6379.pid    #如果后台运行,就需要制定一个pid文件

# 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       #数据库的数量,默认16个 
always-show-logo no   #是否显示logo,默认不显示

快照 SNAPSHOTTING

持久化:在规定时间内,执行了多少次操作,则会持久化到文件 .rdb文件 和 .aof文件

redis是内存数据库,没有持久化 数据断电即失去

#save 3600 1            #如果3600s内至少有一个key进行了修改,我们就进行持久化操作
# save 300 100					#如果300s内至少 有 100key
# save 60 10000					#如果60s内至少有10000key就
stop-writes-on-bgsave-error yes  				#持久化出现错误时是否继续进行工作
rdbcompression yes  								#是否压缩rdb文件,需要消耗cpu资源
rdbchecksum yes											#保存rdb文件时候进行错误 校验
dir /usr/local/var/db/redis/        #rdb文件保存目录
   REPLICATION   复制 ,后面 讲解主从复制的  
# replicaof <masterip> <masterport>			#在从机配置中开启,replicaof 127.0.0.1 6379

# If the master is password protected (using the "requirepass" configuration
# directive below) it is possible to tell the replica to authenticate before
# starting the replication synchronization process, otherwise the master will
# refuse the replica request.
#
# masterauth <master-password>						#这里配置主机的密码
#
# However this is not enough if you are using Redis ACLs (for Redis version
# 6 or greater), and the default user is not capable of running the PSYNC
# command and/or other commands needed for replication. In this case it's
# better to configure a special user to use with replication, and specify the
# masteruser configuration as such:
#
# masteruser <username>									#这里配置主机的用户名

SECURITY 安全

127.0.0.1:6379> config set requirepass 123456					#设置密码
OK
127.0.0.1:6379> config get requirepass							#获取密码
1) "requirepass"
2) "123456"
127.0.0.1:6379> config set requirepass "123456"      # 退出后要重新输入密码
(error) NOAUTH Authentication required.

CLIENTS 客户端

maxclients 10000     #最大客户端数,默认是10000
maxmemory <bytes>    #设置最大内存量
maxmemory-policy noeviction  #内存达到上限的处理策略
                            1、volatile-lru:只对设置了过期时间的key进行LRU(默认值) 
                            2、allkeys-lru : 删除lru算法的key   
                            3、volatile-random:随机删除即将过期key   
                            4、allkeys-random:随机删除   
                            5、volatile-ttl : 删除即将过期的   
                            6、noeviction : 永不过期,返回错误

APPEND ONLY MODE aof

appendonly no   												#默认不开启,默认是rdb,大部分情况跟rdb就够了
appendfilename "appendonly.aof"					#持久化的文件的名字

# appendfsync always										#每次修改就同步
appendfsync everysec											#每秒同步一次,但是可能丢失这一秒的数据
# appendfsync no													#不执行sync,这个时候操作系统自己同步数据,速度最快

redis持久化

面试和工作持久化都是重点

RDB

在指定的时间间隔内,将内存中的数据集快照写入磁盘,也就是Snapshot快照,它恢复时是将快照文件直接读到内存里

Redis是内存数据库,如果不把内存中的数据保存到磁盘中,那么一旦服务器的进程退出,服务器中的数据库状态也会消失,所以Redis提供了持久化功能

Redis会单独创建(fork)一个子进程来进行持久化,会先将数据写入到一个临时文件中,待持久化过程都结束了,再用这个临时文件替换上次持久化好的文件。整个持久化过程中,主进程是不进行任何IO操作的。非常的高效。如果需要进行大规模数据的恢复,且对数据恢复的完整性不是非常的敏感,那么RDB方式要比AOF方式高效的多。注意:RDB最后一次持久化的数据很可能丢失。

rdb保存的文件是dump.rdb,都是在配置文件的SNAPSHOTTING中配置的

触发机制

1、save的规则满足会自动触发rdb,2、flushall 也会触发 3、redis关机也会触发

备份自动生产dump.rdb

生产环境会备份dump.rdb

恢复rdb

1、只需要将rdb文件放在redis启动目录中,Redis启动会自动监测rdb文件,恢复其中的数据

2、查看需要存放的位置

127.0.0.1:6379> config get dir     #查看启动文件夹,rdb放在这个目录中
1) "dir"
2) "/usr/local/var/db/redis"

优点:

1、适合大规模的数据恢复,dump.rdb

2、对数据的完整性不高,

缺点:

1、需要一定的时间间隔进行操作,如果redis意外宕机,最后一次修改的数据可能就没了

2、 fork进程 的时候会占用内存空间

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-j5S6wmxX-1629631546665)(/Users/wanghaichao/Library/Application Support/typora-user-images/image-20210818224809757.png)]

AOF(Apend Only File)

将我们的所有命令都记录下来,history,恢复的时候就把这个文件全部再执行一遍

在这里插入图片描述

以日志的形式记录每个写操作,将redis所有执行的命令全部记录下来(读命令不记录),只许追加到文件但不可以改文件,redis启动之初会读取该文件重新构建数据,换言之,redis重启的话就根据日志文件的内容将写指令从前到后执行一次以完成数据的恢复工作。

Aof保存的是appendonly.aof文件

配置文件位置

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-NTLIpccm-1629631546667)(/Users/wanghaichao/Library/Application Support/typora-user-images/image-20210819211210223.png)]

默认是不开启的,appendonly yes是开启,只需要开启就行,其他默认就好,重启就会生效了

假如aof文件出问题了,是不能启动redis的,可以用redis-check-aof进行修复,修复命令:./redis-check-aof --fix /usr/local/var/db/redis/appendonly.aof

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-HXXFPDtC-1629631546668)(/Users/wanghaichao/Library/Application Support/typora-user-images/image-20210819223020251.png)]

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-wsV6PsiB-1629631546669)(/Users/wanghaichao/Library/Application Support/typora-user-images/image-20210819223130641.png)]

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-MEUwhwwy-1629631546670)(/Users/wanghaichao/Library/Application Support/typora-user-images/image-20210819223643246.png)]

重写规则

如果aof文件大于64m,这时候会fork一个新的进程,来将文件重写,

优缺点

优点:

1、每次的修改都同步,文件的完整更好

2、每秒同步一次,可能会丢失一秒的数据

3、不开启的话从不同步,效率最高

缺点:

1、对于数据文件来说,aof远远大于rdb,修复的速度也比rdb慢

2、运行效率也要比rdb慢,所以默认 的就是rdb,不是aof

发布订阅

redis发布订阅(pub/sub)是一种消息通信模式,发送者发送消息,订阅者接收消息。(微信、微博等关注系统)

redis客户端可以订阅任意数量的频道

img

下图展示了频道 channel1 , 以及订阅这个频道的三个客户端 —— client2 、 client5 和 client1 之间的关系:

img

当有新消息通过 PUBLISH 命令发送给频道 channel1 时, 这个消息就会被发送给订阅它的三个客户端:

img

命令

这些命令被广泛用户构建即时通讯应用,比如网络聊天室,实时广播,实时提醒等

序号命令及描述
1[PSUBSCRIBE pattern pattern …] 订阅一个或多个符合给定模式的频道。
2[PUBSUB subcommand argument [argument …]] 查看订阅与发布系统状态。
3PUBLISH channel message 将信息发送到指定的频道。(重要)
4[PUNSUBSCRIBE pattern [pattern …]] 退订所有给定模式的频道。
5[SUBSCRIBE channel channel …] 订阅给定的一个或多个频道的信息。(重要)
6[UNSUBSCRIBE channel [channel …]] 指退订给定的频道。

测试

订阅

127.0.0.1:6379> SUBSCRIBE  xiaochao      (订阅一个频道)
Reading messages... (press Ctrl-C to quit)
1) "subscribe"
2) "xiaochao"
3) (integer) 1
1) "message"							#接收的消息
2) "xiaochao"							#接收的频道
3) "hello"								#消息的内容
1) "message"
2) "xiaochao"
3) "hello  heheh "

发送端

127.0.0.1:6379> PUBLISH xiaochao hello									#给频道发送消息
(integer) 1
127.0.0.1:6379> PUBLISH xiaochao "hello  heheh "
(integer) 1

使用场景:

实时消息系统,实时聊天,订阅关注系统

稍微复杂的场景用消息中间件MQ

主从复制

概念

主从复制,是指将一台Redis服务器的数据,复制到其他的Redis服务器。前者称为主节点(master),后者称为从节点(slave);数据的复制是单向的,只能由主节点到从节点。主机以写为主,从机以读为主

默认情况下,每台Redis服务器都是主节点;且一个主节点可以有多个从节点(或没有从节点),但一个从节点只能有一个主节点。

主从复制的作用

主从复制的作用主要包括:

  1. 数据冗余:主从复制实现了数据的热备份,是持久化之外的一种数据冗余方式。

  2. 故障恢复:当主节点出现问题时,可以由从节点提供服务,实现快速的故障恢复;实际上是一种服务的冗余。

  3. 负载均衡:在主从复制的基础上,配合读写分离,可以由主节点提供写服务,由从节点提供读服务(即写Redis数据时应用连接主节点,读Redis数据时应用连接从节点),分担服务器负载;尤其是在写少读多的场景下,通过多个从节点分担读负载,可以大大提高Redis服务器的并发量。

  4. 高可用(集群 )基石:除了上述作用以外,主从复制还是哨兵和集群能够实施的基础,因此说主从复制是Redis高可用的基础。

点击查看源网页

主从复制,读写分离,80%都是读的操作,减缓服务器的压力,最小是一主二从

127.0.0.1:6379> info replication      #查看当前库的信息
# Replication	
role:master														#角色
connected_slaves:0										#没有从机
master_failover_state:no-failover
master_replid:b474fcfdb8d4c2b7007305cd6da0d26cccb4b757
master_replid2:0000000000000000000000000000000000000000
master_repl_offset:0
second_repl_offset:-1
repl_backlog_active:0
repl_backlog_size:1048576
repl_backlog_first_byte_offset:0
repl_backlog_histlen:0

伪主从(在单机上搭建多个redis服务器)

1、修改主服务的配置文件,

	logfile "6379.log"

​ dbfilename dump6379.rdb

​ pidfile /var/run/redis_6379.pid

2、从服务的配置

  1. 端口

  2. pid名字

  3. log文件名字

  4. dump.rdb名字

    修改以上配置文件即可

    例如:

​ port 6380

​ logfile “6380.log”

​ pidfile /var/run/redis_6380.pid

​ dbfilename dump6380.rdb

​ port 6381

​ pidfile /var/run/redis_6381.pid

​ logfile “6381.log”

​ dbfilename dump6381.rdb

一主二从

默认情况下,每台Redis服务器都是主节点;一般情况下只 配置从机就可以了。

一主(79)二从(80、81)

主要配置就是从机认主机,所以只要在从机里面配置就可以了

127.0.0.1:6380> SLAVEOF 127.0.0.1 6379        #在从机中确认主机,主机的ip和端口为127.0.0.1和6379
OK
127.0.0.1:6380> info replication
# Replication
role:slave																			#当前角色,从机
master_host:127.0.0.1														#主机的信息
master_port:6379
master_link_status:up
master_last_io_seconds_ago:0
master_sync_in_progress:0
slave_repl_offset:14
slave_priority:100
slave_read_only:1
replica_announced:1
connected_slaves:0
master_failover_state:no-failover
master_replid:30040017403749cc8cc08788decaec1a9f36ecc4
master_replid2:0000000000000000000000000000000000000000
master_repl_offset:14
second_repl_offset:-1
repl_backlog_active:1
repl_backlog_size:1048576
repl_backlog_first_byte_offset:1
repl_backlog_histlen:14
#在主机中查看
127.0.0.1:6379> info replication
# Replication
role:master
connected_slaves:1														#多了从机的配置
slave0:ip=127.0.0.1,port=6380,state=online,offset=434,lag=1				#从机的信息
master_failover_state:no-failover
master_replid:30040017403749cc8cc08788decaec1a9f36ecc4
master_replid2:0000000000000000000000000000000000000000
master_repl_offset:434
second_repl_offset:-1
repl_backlog_active:1
repl_backlog_size:1048576
repl_backlog_first_byte_offset:1
repl_backlog_histlen:434

如果两个都配置完了,就是有两个从机了

127.0.0.1:6379> info replication
# Replication
role:master
connected_slaves:2
slave0:ip=127.0.0.1,port=6380,state=online,offset=602,lag=0
slave1:ip=127.0.0.1,port=6381,state=online,offset=602,lag=0
master_failover_state:no-failover
master_replid:30040017403749cc8cc08788decaec1a9f36ecc4
master_replid2:0000000000000000000000000000000000000000
master_repl_offset:602
second_repl_offset:-1
repl_backlog_active:1
repl_backlog_size:1048576
repl_backlog_first_byte_offset:1
repl_backlog_histlen:602

细节

主机可以写,从机不能写只能读。主机中的所有的信息和数据都会被从机自动保存

=====================
#主机可以写
127.0.0.1:6379> keys * 
(empty array)
127.0.0.1:6379> set k1 v1
OK
========================
#从机可以读出来
127.0.0.1:6380> keys *
(empty array)
127.0.0.1:6380> keys *
1) "k1"
#第二台从机
127.0.0.1:6381> keys *
1) "k1"
127.0.0.1:6381> set ke ve								#但是从机不能写
(error) READONLY You can't write against a read only replica.

测试:主机断开连接,从机依然是连接主机的,但是没有写操作了,这个时候主机如果重新连接,从机依然可以直接获取主机写的信息

如果是使用命令行配置的主从,如果从机重启了,那么就会变成主机。但是只要变回从机,立马就可以在主机中获取值

复制原理

这个系统的运行依靠三个主要的机制:

  • 当一个 master 实例和一个 slave 实例连接正常时, master 会发送一连串的命令流来保持对 slave 的更新,以便于将自身数据集的改变复制给 slave , :包括客户端的写入、key 的过期或被逐出等等。
  • 当 master 和 slave 之间的连接断开之后,因为网络问题、或者是主从意识到连接超时, slave 重新连接上 master 并会尝试进行部分重同步:这意味着它会尝试只获取在断开连接期间内丢失的命令流。
  • 当无法进行部分重同步时, slave 会请求进行全量重同步。这会涉及到一个更复杂的过程,例如 master 需要创建所有数据的快照,将之发送给 slave ,之后在数据集更改时持续发送命令流到 slave 。

只要连接主机,一定会执行一次全量复制

层层链路

上一个master,链接下一个从机

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-PbTxJqrj-1629631546674)(/Users/wanghaichao/Library/Application Support/typora-user-images/image-20210822165019637.png)]

这时候也可以完成主从复制

如果没有主机(比如主机宕机)了,可不可以自己选出一个主机来呢?

如果主机断开连接,可以使用 SLAVEOF no one 将从机变为主机,其他从机就可以连接到这个主机中,如果这个时候断开的主机连接回来了,那就只能重新配置了。

哨兵模式

概述

主从切换技术的方法是:当主服务器宕机后,需要手动把一台从服务器切换为主服务器,这就需要人工干预,费事费力,还会造成一段时间内服务不可用。这不是一种推荐的方式,更多时候,我们优先考虑哨兵模式

哨兵模式是一种特殊的模式,首先Redis提供了哨兵的命令,哨兵是一个独立的进程,作为进程,它会独立运行。其原理是哨兵通过发送命令,等待Redis服务器响应,从而监控运行的多个Redis实例。

img

这里的哨兵有两个作用

  • 通过发送命令,让Redis服务器返回监控其运行状态,包括主服务器和从服务器。
  • 当哨兵监测到master宕机,会自动将slave切换成master,然后通过发布订阅模式通知其他的从服务器,修改配置文件,让它们切换主机。

然而一个哨兵进程对Redis服务器进行监控,可能会出现问题,为此,我们可以使用多个哨兵进行监控。各个哨兵之间还会进行监控,这样就形成了多哨兵模式。

img

用文字描述一下故障切换(failover)的过程。假设主服务器宕机,哨兵1先检测到这个结果,系统并不会马上进行failover过程,仅仅是哨兵1主观的认为主服务器不可用,这个现象成为主观下线。当后面的哨兵也检测到主服务器不可用,并且数量达到一定值时,那么哨兵之间就会进行一次投票,投票的结果由一个哨兵发起,进行failover操作。切换成功后,就会通过发布订阅模式,让各个哨兵把自己监控的从服务器实现切换主机,这个过程称为客观下线。这样对于客户端而言,一切都是透明的。

https://www.jianshu.com/p/06ab9daf921d

测试

目前状态是一主二从,先来配置哨兵

1、哨兵配置文件,

#sentinel monitor 名称 host port 1				
sentinel monitor myredis 127.0.0.1 6379 1

后面的1代表,主机挂了,slave投票看让谁接替成为主机,票数最多的就会成为主机

2、启动哨兵

redis-sentinel /usr/local/etc/sentinel.conf    #启动命令 
16888:X 22 Aug 2021 17:29:39.677 # oO0OoO0OoO0Oo Redis is starting oO0OoO0OoO0Oo
16888:X 22 Aug 2021 17:29:39.677 # Redis version=6.2.5, bits=64, commit=00000000, modified=0, pid=16888, just started
16888:X 22 Aug 2021 17:29:39.677 # Configuration loaded
16888:X 22 Aug 2021 17:29:39.678 * Increased maximum number of open files to 10032 (it was originally set to 2560).
16888:X 22 Aug 2021 17:29:39.678 * monotonic clock: POSIX clock_gettime
                _._                                                  
           _.-``__ ''-._                                             
      _.-``    `.  `_.  ''-._           Redis 6.2.5 (00000000/0) 64 bit
  .-`` .-```.  ```\/    _.,_ ''-._                                  
 (    '      ,       .-`  | `,    )     Running in sentinel mode				#哨兵模式
 |`-._`-...-` __...-.``-._|'` _.-'|     Port: 26379        							#监听端口
 |    `-._   `._    /     _.-'    |     PID: 16888
  `-._    `-._  `-./  _.-'    _.-'                                   
 |`-._`-._    `-.__.-'    _.-'_.-'|                                  
 |    `-._`-._        _.-'_.-'    |           https://redis.io       
  `-._    `-._`-.__.-'_.-'    _.-'                                   
 |`-._`-._    `-.__.-'    _.-'_.-'|                                  
 |    `-._`-._        _.-'_.-'    |                                  
  `-._    `-._`-.__.-'_.-'    _.-'                                   
      `-._    `-.__.-'    _.-'                                       
          `-._        _.-'                                           
              `-.__.-'                                               

16888:X 22 Aug 2021 17:29:39.681 # Sentinel ID is 8cdf0f7a7c555ff6d27a07616b920f1a5655a1e4
16888:X 22 Aug 2021 17:29:39.681 # +monitor master myredis 127.0.0.1 6379 quorum 1
16888:X 22 Aug 2021 17:29:39.683 * +slave slave 127.0.0.1:6380 127.0.0.1 6380 @ myredis 127.0.0.1 6379
16888:X 22 Aug 2021 17:29:39.684 * +slave slave 127.0.0.1:6381 127.0.0.1 6381 @ myredis 127.0.0.1 6379

如果master断开了,这个时候就会从机中随机选择一个服务器,

16888:X 22 Aug 2021 17:33:04.130 * +failover-state-send-slaveof-noone slave 127.0.0.1:6380 127.0.0.1 6380 @ myredis 127.0.0.1 6379
16888:X 22 Aug 2021 17:33:04.195 * +failover-state-wait-promotion slave 127.0.0.1:6380 127.0.0.1 6380 @ myredis 127.0.0.1 6379
16888:X 22 Aug 2021 17:33:04.393 # +promoted-slave slave 127.0.0.1:6380 127.0.0.1 6380 @ myredis 127.0.0.1 6379
16888:X 22 Aug 2021 17:33:04.394 # +failover-state-reconf-slaves master myredis 127.0.0.1 6379    故障转移 
16888:X 22 Aug 2021 17:33:04.454 * +slave-reconf-sent slave 127.0.0.1:6381 127.0.0.1 6381 @ myredis 127.0.0.1 6379
16888:X 22 Aug 2021 17:33:05.432 * +slave-reconf-inprog slave 127.0.0.1:6381 127.0.0.1 6381 @ myredis 127.0.0.1 6379
16888:X 22 Aug 2021 17:33:05.432 * +slave-reconf-done slave 127.0.0.1:6381 127.0.0.1 6381 @ myredis 127.0.0.1 6379
16888:X 22 Aug 2021 17:33:05.509 # +failover-end master myredis 127.0.0.1 6379
16888:X 22 Aug 2021 17:33:05.509 # +switch-master myredis 127.0.0.1 6379 127.0.0.1 6380	#此时转换为6380主节点
16888:X 22 Aug 2021 17:33:05.509 * +slave slave 127.0.0.1:6381 127.0.0.1 6381 @ myredis 127.0.0.1 6380
16888:X 22 Aug 2021 17:33:05.509 * +slave slave 127.0.0.1:6379 127.0.0.1 6379 @ myredis 127.0.0.1 6380
16888:X 22 Aug 2021 17:33:35.536 # +sdown slave 127.0.0.1:6379 127.0.0.1 6379 @ myredis 127.0.0.1 6380
																		#6379挂了,到了6380 
																	

如果原主机此时回来了,只能归属到现在主机当从机

优点

1、哨兵集群一般急于主从复制,所有的主从配置优点,它全都有

2、主从可以切换,故障可以转移,系统的可用性就会更好

3、哨兵模式就是主从模式的升级,手动到自动,更加健壮

缺点:

1、redis不好在线扩容,如果集群容量一旦到达上限,在线扩容就十分麻烦(特别是在配置文件中写死了,要改很多配置)

2、实现哨兵模式的配置很麻烦,里面有很多选择

哨兵模式的全部配置

a

redis 缓存穿透和雪崩

缓存穿透(查不到)

概念

缓存穿透是指缓存和数据库中都没有的数据,而用户不断发起请求,如发起为id为“-1”的数据或id为特别大不存在的数据。这时的用户很可能是攻击者,攻击会导致数据库压力过大。

解决方案

1、布隆过滤器

布隆过滤器是一种数据结构,对所有可能查询的参数以hash形式存储,在控制层先进行校验,不符合则丢弃,从而避免了对底层存储系统的查询压力

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-dxkwEnW6-1629631546676)(https://pics6.baidu.com/feed/d788d43f8794a4c2773846a5251e13d3ac6e3910.jpeg?token=029a90d30125df6852018a7e4e7294ff&s=1AA27423D99E44C80E5CE5DE000080B1)]

2、缓存空对象

当存储层不命中后,即使返回的空对象也将其缓存起来,同时会设置一个过期时间,之后再访问这个数据将会从缓存中获取,保护了后端数据源;

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-C6wcaQRX-1629631546677)(https://pics6.baidu.com/feed/203fb80e7bec54e7a4ba970397d293564ec26a4d.jpeg?token=0068420533f90cb97750b10ce30053b8&s=9A027C239B9E4DC848DDC4D6000080B2)]

但是这种方法会存在两个问题:

1、如果空值能够被缓存起来,这就意味着缓存需要更多的空间存储更多的键,因为这当中可能会有很多的空值的键;

2、即使对空值设置了过期时间,还是会存在缓存层和存储层的数据会有一段时间窗口的不一致,这对于需要保持一致性的业务会有影响

缓存击穿(量太大,缓存击穿)

概述

缓存击穿是指缓存中没有但数据库中有的数据(一般是缓存时间到期),这时由于并发用户特别多,同时读缓存没读到数据,又同时去数据库去取数据,引起数据库压力瞬间增大,造成过大压力

解决方法

1、设置热点数据永不过期

从缓存层面来看,没有设置过期时间,所以不会出现热点key过期后产生的问题

2、加互斥锁

使用分布式锁,保证对于每个key同时只有一个线程去查询后端服务,其他线程没有获得分布式锁的权限,因此只要等待即可。这种方式将高并发的压力转移到了分布式锁上

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-q6aBFLUD-1629631546678)(/Users/wanghaichao/Library/Application Support/typora-user-images/image-20210822190812181.png)]

缓存雪崩

概念

缓存雪崩是指在某一个时间段缓存集体失效或者集群宕机

img

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值