1、五大基本数据类型
String、List、Set、Hash、Zset
2、三种特殊数据类型
geo、hyperloglog、bitmap
3、redis持久化
RDB、AOF
4、redis事务操作
5、redis实现订阅发布(消息队列)
6、redis主从复制
7、redis哨兵模式(现在公司中所有的集群都用哨兵模式)
8、缓存穿透以及解决方案
9、缓存击穿及解决方案
10、缓存雪崩以及解决方案
11、基础api之jedis
12、springboot集成redis操作
13、redis的实践分析
大数据
mysql集群可以通过中间件连接多个数据库,某个数据库用来写入数据,其他数据库来负载均衡的读取数据。
Myisam使用表锁,innodb使用行锁
大数据年代mysql等关系型数据库不够用,数据量多,变化快。
mysql存放比较大的文件的时候,效率会很低。
not only sql 泛指非关系型数据库。比如redis
nosql特点:
1、方便扩展
2、大数据高性能,一秒写8w,读取11w,NoSql的缓存记录级,是一种细粒度的缓存,性能回比较高!
3、数据类型是多样型的,不需要事先设计数据库,随取随用。
4、文本比较多的可以存放在文档型数据库、MongoDB中
图片等可以存在分布式文件系统FastDFS、Hdaoop的HDFS等
商品的关键字 --搜索引擎: elasticsearch Isearch:多隆
商品热门的波段信息:存在redis、Tair、Memache等
大型互联网应用的问题:
数据类型多、数据源繁多、数据要大面积改造
KV键值对:
文档型数据库(bson格式和json一样)
列存储数据库
图关系型数据库(不是存储图形的)
比如社交网络、广告推荐
remote dictionary server 远程字典服务
redis能干啥?
1、内存存储、持久化、内存中是断电即失、所以持久化很重要(rdb和aof)
2、效率高,可以用于高速缓存
3、发布订阅系统
4、地图信息分析
5、计时器、浏览量
特性:
多样的数据类型、持久化、集群、事务
http://www.redis.cn/
下载并解压redis压缩包
进入到压缩包目录
下载c++环境、然后执行make命令
yum install gcc-c++
make
make install #确认一下
redis的默认安装路径 /usr/local/bin/
将redis配置文件copy到redis的安装目录下
需要修改redis.conf中的daemonize 为yes,即开启为后台启动的方式
redis-server conf/redis.conf #指定配置文件启动redis服务
redis-cli -p 6379 #客户端连接
shutdown #在redis客户端中直接执行该语句可以直接关闭redis服务
# 进入redis客户端后可以进行简单的操作
set name chw
get name
redis-benchmark
#测试100个并发 100000个请求
reids-benchmark -h localhost 6379 -c 100 -n 100000
redis 的 配置文件中默认配置了16个数据库
# 切换到第三个数据库
select 3
# 查看db的大小
DBSIZE
# 查看数据库所有的key
keys *
#清楚当前数据库
flushdb
#清空所有的数据库
FLUSHALL
Redis是单线程的
redis是很快的,是基于内存操作的,CPU不是redis的性能瓶颈,redis的瓶颈是根据机器的内存和网络的带框,既然可以使用单线程来实现,就是用单线程了。
为什么redis单线程还这么快?
redis是c语言写的,100000+的QPS,不比同样使用key-value 的 Memecache差!
1、误区1:高性能的服务器一定是多线程的?
2、误区2:多线程(CPU上下文会切换消耗资源)一定比单线程效率高!
CPU>内存>硬盘速度
核心:redis是将所有的数据全部放在内存中的,所以说使用单线程去操作效率就是最高的,多线程(CPU上下文切换:耗时的操作!)对于内存系统来说,如果没有上下文切换,效率就是最高的!多次读写都是在一个cpu上的,在存在情况下,这就是最佳方案。
redis是一个内存中的数据结构存储系统,它可以用作数据库、缓存和消息中间件MQ。
#判断name 这个key是否存在
EXISTS name
#移除这个key
move name
#设置name这个key 10s过期
EXPIRE name 10
#查看name这个key值还有多久过期
ttl name
# 查看存放的key类型
type name
#string
#往字符串后面拼接字符串
APPEND key1 hellp
#输出长度
STRLEN key1
#让views加1
set views 0
incr views
# 减1
decr views
#加10
INCRBY views 10
# 减10
DECRBY views 10
#跟subString一样,截取字符串
GETRANGE key1 0 3
# 查看整个字符串
GETRANGE key1 0 -1
# 将下标1开始的位置替换为xx
SETRANGE key1 1 xx
# 设置key1 过期时间为30s set with expire
setex key1 30 value
#查看剩余过期时间
ttl key1
#set if not exist 如果存在这个key值不存在就设置,重复设置不生效
setnx mykey "Redis"
setnx mykey "mongoDB"
# 多次设置key-value
mset k1 v1 k1 v2 k3 v3
mget k1 k2 k3
# 多次设置,由于k1存在导致整个命令设置失败,k4的值也没有,保持原子性操作
msetnx k1 v1 k4 v4
# 设置一个user:1对象,值为json字符串保存一个对象。
set user:1 {name:chw,age:3}
mset user:1:name chw user:1:age 2
mget user:1:name user:1:age
#先get 再set,先获取db对应的value再将值设置为新的值
getset db redis
String类似的使用场景:
计数器、统计多单位的数量、粉丝数、对象缓存存储
基本的数据类型,列表
在redis中,,可以把list设置成堆栈、队列、阻塞队列
#从左边将是value push进列表头部
LPUSH list one
LPUSH list two
# 取出所有的值
LRANGE list 0 -1
# 从右边放value push进列表尾部
RPUSH list thrid
#爱出下标为1的
lindex list 1
#输出列表的长度
Llen list
# 移除1个one
Lrem list 1 one
# 移除两个one
Lrem list 2 one
#截取list的下标1到下标2 赋值给list
ltrim list 1 2
LRANGE list 0 -1 #查看下整list
#移除最后一个元素并移动到新的列表otherlist中
rpush mylist "hell"
rpush mylist "hell1"
rpoplpush mylist otherlist
lrange mylist 0 -1
lrange otherlist 0 -1
# 设置列表的下标为0的值为item,如果存在则更新下标值,不存在则报错
lset list 0 item
#在item前面插入other
linsert list before item other
linser list after item other
#实际上是一个类似链表的东西,在前后都可以插入值,如果key不存在,创建新的链表,如果key存在,新增内容,如果移除恶所有值,空链表,也代表不存在,在两遍插入或者改动值,效率最高,中间元素,相对效率低一点。
消息队列! Lpush Rpop
#往set中添加值
sadd myset "hellp"
#查看set对应的所有的值
SMEMBERS myset
#获取set集合中的内容元素个数
scard myset
#移除对应的元素
srem myset hellp
#随机抽选出指定个数的元素
SRANDMEMBER myset 2
#随机移除元素
spop myset
#指定一个值移除到另一个集合中
smove myset myset2 "hellp"
微博|B站 的共同关注。通过集合的交集做到。
# set1 - set2的差集
ADIFF set1 set2
# 交集
SINTER set1 set2
#并集
SUNION set1 set2
Map集合,key-集合
#存放一个hash
hset myhash field1 chw
#取一个hash map 中对应的一个key对应的值
hget myhash field1
# 多次设置map字典对应的key-value
hmset myhash field1 hcw1 field chw3
hmget field1 field2
#取出整个字典
hgetall myhash
#删除map中指定的key
hdel myhash field1
#查看hash map的长度
hlen myhash
#判断hash中指定字段是否存在
HEXISTS myhash field1
#只获得所有的field
hkeys myhash
#只获取所有的value
hvals myhash
#对某个field +1
hincrby myhash filed 1
#对某个field 减
hdecrby myhash field 1
#判断hash中对应的key-value是否存在,如果不存在则设置field4的值为hello,如果已经存在则返回0,不能进行设置
hsetnx myhash field4 hello
hash变更的数据user name age尤其是用户信息之类的,经常变动。hash更适合用于对象的存储,String 更适合字符串存储。
在set的基础上,增加了一个值,set k1 v1 zset k1 score1 v1
zset 会根据score1来进行排序
zadd myset 1 one
#添加多个值
zadd myset 2 two 3 three
#编辑整个set
zrange myset 0 -1
#按照无限小到无限大排序
zrangebyscore myset -inf +inf
#打印出这个区间的数据。最小值写在前
zrangebyscore myset -inf 250 withscores
#移除对应的元素
zrem myset chw
#查看对应的zset的大小
zcard myset
# 从大到小排序遍历
zrevrange chw 0 -1
#判断对应区间有多少元素
zcount myset 1 1000
zset存放带权重的数据进行排序,实现排行版的排序
redis的Geo 在redis3.2 版本就推出了。这个功能可以推算地理位置的信息,两地之间的距离,方圆几里的人。
六个命令
GEOADD
GEODIST
GEOHASH
GEOPOS
GEORADIUS
GEORADIUSBYMEMBER
#geoadd添加地理位置,两级无法直接添加,一般通过下载经纬度文件通过java导入
geoadd china:city 116.40 39.90 beijing
geoadd chain:city 121.47 31.23 shanghai
# 一次添加多个
geoadd china:city 106.50 29.53 chongqing 114.05 22.52 shenzhen
geoadd china:city 120.16 30.24 hangzhou 108.96 34.26 xian
#获取指定城市的经度和纬度
geopos china:city beijing chongqing
#获取两个城市之间的距离,直线距离
geodist china:city beijing chongqing km
附近的人的功能实现,通过程序定位获取人为定位
m米 km 千米 mi 英里 ft英尺
# 查找经纬度为110 30 为中心(一般是当前用户的点),查看半径在1000km内的城市点
georedius china:city 110 30 1000km
#count限制查出多少人,withdist顺便查找出直线距离,withcoord顺便查找具体的点的经纬度
georedius china:city 110 30 1000km withdist withcoord count 1
# 以定位成员beijing为中心寻找1000km范围内的城市,找出指定元素周围的其他元素
georadiusbtmember china:city beijing 1000 km
# 返回一个或者多个位置元素的geohash表示
# 返回11字符串的geohash字符串
geohash china:citybeijing chongqing
#GEO底层实现原理其实就是ZSET,可以使用ZSET命令操作geo
#查看China:city中的所有元素
zrange china:city 0 -1
# 移除北京
zrem china:city beijing
基数统计的算法
网页的User View(一个人访问一个网站多次,但是还是算作一个人)
传统是set保存用户id,统计set数据进行计算,但是保存大量的用户id,比较麻烦,目的是计数,不菲保存用户id。
hyperloglog有点:占用的内存是固定的,2^64不同元素的技术,只需要用12kb内存。如果要从内存角度比较,这个是首选,但是有0.81%的错误率。
PFadd mykey a b c d e f
PFCOUNT mykey
PFadd mykey2 i j x k m n a
# 合并mykey和mykey2
PFMEGER mykey3 mykey mykey2
PFCOUNT mykey3
允许容错的情况下才可以用
位存储
统计疫情感染人数、打卡365。两个状态的可以使用bitmaps
bitmaps位图,数据结构,都是操作二进制位来进行记录,就只有0和1两个状态。
365天=365bit 1字节=8bit 这样可以更加节省存储。
#打卡五天使用bitmap记录
setbit sign 0 0
setbit sign 1 0
setbit sign 2 1
setbit sign 3 0
setbit sign 4 1
#查看具体的某一天是否打卡
getbit sign 3
#统计打卡天数,默认计算全部,可以加参数指定区间计算
bitcount sign
redis单条命令是保证原子性的,但是事务不保存原子性。
redis事务本质:一组命令的集合,一个事务中的所有命令都会被序列化,在事务执行过程中,会按顺序执行。一次性、顺序性、排他性,执行一些列的命令。
-------队列 set set set 执行------
redis事务没有隔离级别的概念。
所有的命令在事务中,并没有直接被执行,只有发起执行命令的时候才会执行。Exec
redis的事务:
# 开启事务
multi
set k1 v1
set k2 v2
get k2
set k3 v3
#真正执行获取输出
exec
DISCARD 取消事务
# 开启事务
multi
set k1 v1
set k2 v2
get k2
set k3 v3
discard
取消事务后队列中的所有的命令都不会被执行
# 开启事务
multi
set k1 v1
set k2 v2
# 制造错误,编译型错误
getset k3
#执行事务会报错,此时所有的命令都不会被执行
exec
# 开启事务
multi
set k1 "b1"
#制造运行时错误,字符串不能incr
incr k1
set k2 "v2"
set k3 "v3"
#执行事务会会报错,但是后面的命令可以正常执行
exec
# 可以正常拿到值
get k3
监控
锁:redis可以实现乐观锁
悲观锁:
认为什么时候都会出现问题,无论什么情况都加锁
乐观锁:
认为什么都不会出现问题,更新数据的时候判断一下是否有人修改过数据,校验version,性能会好点
set money 100
set out 0
#监视money
watch money
multi
decrby money 20
incrby out 20
exec
#事务正常结束,数据没有发生变动,事务执行成功后监视会自动消失
开启两个客户端,模拟多线程并发,在客户端1事务还未执行之前,在客户端2中修改money的值
#客户端1
set money 100
set out 0
#监视money
watch money
multi
decrby money 20
incrby out 20
#客户端1的事务还未执行的时候,money就被修改了。watch是redis的乐观锁,
#unwatch可以解锁,如果导致执行失败了的话先解锁
#客户端2
set money 1000
# 在客户端2执行修改money后再返回到客户端1执行exec 事务,会出现执行失败。
#客户端1
exec
如果使用乐观锁,在事务执行的时候会监视money值是否发生变化,变化则执行失败。那么久的解锁再重新操作。
java操作redis
springboot操作数据:spring-data jpa jdbc mongodb redis
jedis采用直连,多线程的话,是不安全的,可以使用jedis pool连接池使用。BIO模式。
lettuce:采用netty,实例可以在多线程中进行共享,不存在线程不安全的情况,可以减少线程数量。NIO模式。
org.springframework.boot
spring-boot-starter-data-redis
#启动时,通过配置文件来启动
#配置文件对大小写不敏感,单位的配置
# 1k => 1000 bytes
# 1kb => 1024 bytes
# 1m => 1000000 bytes
# 1mb => 1024*1024 bytes
# 1g => 1000000000 bytes
# 1gb => 1024*1024*1024 bytes
#可以包含多个其他的配置文件
################################## INCLUDES ###################################
# Include one or more other config files here. This is useful if you
# have a standard template that goes to all Redis servers but also need
# to customize a few per-server settings. Include files can include
# other files, so use this wisely.
#
# Notice option "include" won't be rewritten by command "CONFIG REWRITE"
# from admin or Redis Sentinel. Since Redis always uses the last processed
# line as value of a configuration directive, you'd better put includes
# at the beginning of this file to avoid overwriting config change at runtime.
#
# If instead you are interested in using includes to override configuration
# options, it is better to use include as the last line.
#
# include .\path\to\local.conf
# include c:\path\to\other.conf
#网络,默认127.0.0.1 可以设置为对应的网络ip,提供他人连接
################################## NETWORK #####################################
# By default, if no "bind" configuration directive is specified, Redis listens
# for connections from all the network interfaces available on the server.
# It is possible to listen to just one or multiple selected interfaces using
# the "bind" configuration directive, followed by one or more IP addresses.
#
# Examples:
#
# bind 192.168.1.100 10.0.0.1
# bind 127.0.0.1 ::1
#
# ~~~ WARNING ~~~ If the computer running Redis is directly exposed to the
# internet, binding to all the interfaces is dangerous and will expose the
# instance to everybody on the internet. So by default we uncomment the
# following bind directive, that will force Redis to listen only into
# the IPv4 lookback interface address (this means Redis will be able to
# accept connections only from clients running into the same computer it
# is running).
#
# IF YOU ARE SURE YOU WANT YOUR INSTANCE TO LISTEN TO ALL THE INTERFACES
# JUST COMMENT THE FOLLOWING LINE.
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
bind 127.0.0.1 #绑定ip
protected-mode yes # 保护模式
port 6379 #端口设置
GENERAL 通用配置
daemonize yes #默认no,守护进程方式运行,yes则后台运行
pidfile /var/run/redis.pid # 如果后台运行,需要指定,windows不支持
loglevel notice #日志
logfile "" #日志文件位置
databases 16 #默认的数据库数量
always-show-logo yes #是否总是显示LOGO
快照
持久化,在规定时间内,执行了多少次啊哦做,则会持久化到文件.rdb.aof中
redis是内存数据库,如果没有持久化,那么数据断电即失去。
#如果900s内,至少有一个key进行了修改,就进行持久化操作
save 900 1
# 300s内,至少10个操作,持久化。
save 300 10
save 60 10000
stop-writes-on-bgsave-error yes #持久化出错,是否还继续工作
rbbcompression yes #是否压缩rdb文件需要消耗cpu资源
rdbchecksum yes # 保存rdb文件的时候进行错误的检查校验
dir ./ #持久化rdb文件的保存路径
REPLICATION 主从复制
SECURITY 安全
# 设置密码,默认没有密码
requirepass test123
命令设置密码 config set requirepass 123456
密码登录 auto 123456
限制 CLIENTS
# 连接redis的最大客户端数量
maxclients 10000
# reids的最大内存配置
maxmemory
# 内存满了的时候,redis对应的处理策略,移除过期的key还是啥的等等
maxmemory-policy noeviction
APPEND ONLY 模式 aof配置
.appendonly no # 默认不开启aof,默认使用rdb模式持久化,大部分情况,rdb够用
appendfilename “appendonly.aof” # 持久化文件的位置
#appendfsync always # 每次都会sync,同步数据,消耗性能
appendfsync everysec # 每秒执行一次 sync,可能丢失者1s的数据。
#appendfsync no #不执行sync,操作系统自己同步数据,效率较快
redis是内存数据库,如果不将内存中的数据保存到磁盘,那么服务挂了,那么就会存在数据丢失。
在指定时间内将内存中的数据集快照写入磁盘,也就是Snapshot快照,它回复时是将快照文件直接读到内存里的。
redis会单独创建(fork)一个子进程来进行持久化,会先将数据写入到一个临时文件中,待持久化过程结束了,再用这个临时文件替换上次持久化好的文件,整个过程中,主进程是不进行任何IO操作的,确保了极高的性能,如果需要进行大规模的数据恢复,且对数据恢复的完整性不是非常敏感,那么RDB要比AOF更加高效,RDB的缺点是最后一次持久化后的数据可能丢失,我们默认使用RDB,一般情况下不需要配置。
但是RDB如果在最后一次持久化的时候服务挂掉了,那么就会丢失最后一次的数据。
rdb保存的文件是dump.rdb
# 每900修改1个key就会进行rdb持久化
save 900 1
触发机制:
save的规则满足的情况下,会触发rdb规则
flushall命令也会触发我们rdb规则
退出redis,热会产生rdb文件。
如何恢复rdb文件
1、只需要将rdb文件在我们redis启动目录下就可以,redis启动的时候回自动检查dump.rdb文件进行数据恢复。
2、查看需要存放的位置
# 获取rdb文件存放的位置
config get dir
优点:
1、适合大规模的数据恢复 dump.rdb
2、如果对数据完整性要求不高的情况可使用
缺点:
1、需要一定是时间间隔的操作,如果redis意外挂了,会丢失最后一次数据
2、fork进程的时候,会占用一定的内存空间
appendonly.aof
将所有的命令都记录下来,类似history,恢复的时候把文件全部再执行一遍
以日志的形式来记录没个操作,将redis执行过的指令记录下来,(读操作不记录),只允许追加文件,但不可以改写文件,redis启动之初会读取该文件重新构建数据,redis重启的话就根据日志文件的内容将指令全部执行一遍完成数据恢复工作。
appendonly yes #开启
appendsync always #每次修改都会同步,消耗性能
appendfsync everysec #每秒中记录一次
appendsync no #不执行sync,操作系统自己同步,速度最快
auto-aof-rewrite-min-size 64mb #重写机制,文件超出64mb就再写一个文件
redis-check-aof可以对损坏的appendonly.aof文件进行修复。
redis-check-aof --fix appendonly.aof
优点:
1、每一次修改都同步,文件的完整性更加好
2、每秒同步一次,可能会丢失1s的数据
3、从不同步,效率最高
缺点:
1、相对于数据文件来说,aof远远大于rdb,修复速度也比rdb慢。
2、aof运行效率也要比rdb慢,所以默认的redis配置就是rdb持久化。
扩展:
1、rdb持久化方式能够在指定的时间间隔内对数据进行快照存储。
2、aof持久化方式记录每次对服务器的写操作,当服务器重启的时候会重新执行这些命令来恢复数据,aof命令以redis协议追加保存每次的写操作到文件末尾,redis还能对aof文件进行后台重写,使得aof文件的体积不至于过大。
3、只做缓存,如果希望数据在服务器运行的时候存在,可以不适用个任何持久化。
4、同时开启两种持久化方式
5、性能建议
redis发布订阅是一种消息同喜模式,发送者(pub)发送消息,订阅者sub接受消息
redis客户端可以订阅任意数量的频道。
第一个:消息发送者
第二个:频道(redis)
第三个:消息订阅者
# cliet1 chw为频道,订阅一个频道
subscribe chw
#clinet2 发布信息
publish chw hello
可以做一些网络聊天室,实时传播消息等。简单的订阅和关注系统都可以。
复杂的场景一般会用消息中间MQ来做
主从复制,读写分离,80%的情况读操作,减缓服务器的压力。一主二从。
主从复制,是指将一台redis服务器的数据,复制到其他的redis服务器,前者称为主节点(master/leader),后者称为从节点(skave/fllower);数据的复制是单向的,只能从主节点到从节点,master以写为主,slave以读为主。
主从复制的作用主要包括:
1、数据冗余:处从复制实现了数据的热备份,是持久化之外的一种数据冗余方式。
2、故障恢复:当主节点出现问题的时候,可以由从节点提供服务,实现快速的故障恢复,实际上是一种冗余服务。
3、负载均衡,在主从复制的基础上,配置读写分离,可以由主节点提供服务,由从节点提供读取(即redis数据写入时应用连接组节点,读redis时连接从节点),分担服务器复杂;尤其是在写少,读多的场景下,通过多个从节点分担负载,可以大大提高redsi 服务器的并法量。
4、高可用基石:除了上述作用外,主从复制还是哨兵和集群能够实施的基础,因此说主从复制是redis高可用的基础。‘
复制四个配置文件后修改
#修改一下四个配置可以构建一个虚拟集群,6379 6380 6381
port
pidfile
logfile
dbfilename
#开启多个不同端口的redis服务
redis-server redis6379.conf
# 查看当前节点信息,默认每个独立的redis都是一个主节点
info replication
#配置一主二从,一般情况下配置丛机
在6380端口的服务中执行下面命令,认领6379端口的redis服务为主节点
SLAVEOF 127.0.0.1 6379
info replication #查看节点信息
真实的主从配置应该在配置文件中高配置,才能永久有效,这里使用命令是暂时的。
#在配置文件中可以进行主从复制的配置。
replicaof
masterauth
主机可以写,从机只能读,主机中的所有信息和数据,都会自动被从机保存
shutdown关闭主节点机后,主从复制的配置还是在的。
主机断开连接了,从机依旧是连接到主机的额,但是没有写操作的,如果主机回来了,从机依旧可以获取到主机的写的信息。
通过命令行的方式配置的主从复制,如果从机重启了,主从复制的配置是会失效的,变为从机,就能再次获取数据。
复制原理
slave启动成功连接到master后会发送一个sync同步命令。
master接到命令,启动后台的存盘进程,同时收集接受到的用于修改数据集的命令,在后台进程执行完毕之后,master将传送整个数据文件到slave,并完成一次完全同步。
全量复制,而slave服务在接受到数据库文件数据后,将其存盘并加载到内存中;
增量复制,master继续将新的所有手机到的修改命令一次传给slave,完成同步;
但是只要重新连接master,一次完全同步(全量复制)将被执行。
宕机后手动配置主机
配置6380节点机为6379的从节点,将6381配置为6380的从节点,配置为一个链式的集群
6380在这里依然是从机。
(之前配置的是6380、6381都是6379的从节点)
如果6379 shutdown了,主节点没了,可以在从节点上执行 slaveof no one 使用自己变成主机,其他的节点可以手动连接到最新的主节点。这时候就算6379重新启动了,也没有用了,info replication 查看发现已经没有节点机了。
主从切换技术的方式是:当主服务宕机后,需要手动把一台从服务器切换为主服务器,这就需要人工干预,不太推荐。
哨兵模式是一种特殊的模式,首先redis提供了哨兵的命令,哨兵是一个独立的进程,作为进程,它会独立进程,其原理是哨兵通过发送命令,等待redsi服务器响应,从而监控运行多个redis实例。
哨兵模式也有集群,哨兵可以发布多个,形成多哨兵监控模式。
哨兵的作用:
然而一个哨兵进程对redis服务器进行监控,可能会出现问题,为此,可以设置多个哨兵进行监控,各个哨兵之间还会进行监控,这样就行成了多哨兵模式。
主观下线和客观下线
主观下线可能只是每一个哨兵进程发现某一台主机挂了,多个哨兵共同发现服务挂了之后就会进行可观下线。然后投票重新选出主节点。
客户下线是真正的哨兵发现并认为主节点挂了。
配置哨兵
1、在一主二从的情况下,配置哨兵
#配置哨兵 后面配置的1是发现有主机挂了之后会投票重新产生主机。
# myredis 是被监控名称
vim sentinel.conf
sentinel monitor myredis 127.0.0.1 6379 1
2、启动哨兵
#按照配置文件启动一个哨兵
redis-sentinel sentinel.conf
3、将6379主节点机关闭。稍微等待一会哨兵进程会重新选举出新的节点机。 failover …
4、info replication 查看从机的状态,其中会有一台从机会变为master节点。
5、此时再启动6379端口的服务,发现当前的服务不会再是master了,过了一会哨兵进程会将6379的服务设置为集群中的从节点。主机宕机后重启只能当从机了。
优点:
缺点:
哨兵模式的全部配置有很多。。。。
#哨兵实例运行的端口,默认这个
port 26379
#哨兵sentinel的工作目录
dir /tmp
#配置哨兵
sentinel monitor mymaster 127.0.0.1 6379 2
#设置哨兵sentinel连接主从的密码,必须和主从设置一样的密码
sentinel auth-pass mymaster paswword
#指定多少毫秒后,主节点没有应答,哨兵主观上认为节点下限,默认30s
sentinel down-after-millisecond's mymaster 30000
#设置1保证每次只有一个slave处于不能处理命令请求的状态。
sentinel parallel-syncs mysater 1
#故障转移时间
sentinel failover-timeout mymaster 180000
#当主机宕机了,调用脚本,可以在脚本中写通知命令等
sentinel notification-script mymaster /vat/redis/notify.sh
#客户端重新配置主节点参数脚本
sentinel client-reconfig-script mymaster /vat/redis/reconfig.sh
**缓存穿透:**用户想要查询一个数据,发现redis内存数据库没有,也就是缓存没有命中,于是向持久层数据库汇中查询,发现也没有,于是本次查询是啊比,当用户很多的时候,缓存都没有命中(秒杀活动),于是都去请求了持久层数据库,这会给持久层数据库造成巨大压力,这就出现了缓存穿透。
**布隆过滤器:**解决缓存穿透
布隆过滤器是一种数据结构,对所有可能查询的参数以hash形式存储,在控制层进行校验,不符合则丢弃,从而避免对底层存储系统的查询压力。拦截请求。
缓存空对象:解决缓存穿透
当存储层不命中后,返回空对象也将会缓存起来,同时会设置一个国企时间,之后再访问这个数据会从缓存中去,保护了后端数据源。
问题:
1、如果空值被缓存起来,以为这需要更多的空间存储而更多的键,可能有很多空值的键。
2、及时设置了过期时间,还是会存在缓存层和存储层的数据会有一段时间窗口不一致,这对于需要保持一直性的业务会有影响。
缓存击穿
是指一个key非常热点,在不停的扛着大并发,大并发集中对这个点进行访问,当这个key在失效的瞬间,持续的大并发就穿透缓存,就像一个屏障上凿开一个洞。
在某个key过期瞬间,会有大量并发请求,会同时访问数据库来查询最新数据(这一瞬间会导致数据库宕机),并且回写缓存,会导致数据库瞬间压力过大。
解决方案:
设置热点数据永不过期:
从缓存层面看,没有设置过期时间,所有不会出现热点key过期后产生的问题。
加互斥锁
**分布式锁:**使用分布式锁,保证对每个key同时只有一个线程器查询后端服务,其他线程服务没有获得分布式锁的权限,因此只需要等待即可,这种方式高并发的压缩转移到分布式锁,因此对分布式锁考验很大。
缓存雪崩:
只在某一时间段,缓存集中过期失效,或者redis宕机。
雪崩的原因之一:如在在双十二零点,这波商户比较集中时间的将一些数据上传,到缓存中,假设缓存是一小时有效时间,到了凌晨一点,这些商品缓存都过期了,而对这批商品的查询,都落到数据库上,这就会产生周期性的压力波峰,于是所有的请求都会达到存储层,就可能挂掉宕机。
redis宕机是比较可怕的,一部分数据过期还不是最可怕的。
解决方案:
redis 高可用
这个方法的思想是,多设置几台redis服务器。搭建集群
限流降级
在缓存失效后,通过加锁或者队列来读取数据库写缓存的线程数量,比如对某个key只允许一个线程查询数据和写缓存,其他等待。
数据预热
数据加热的含义是在正式部署之前,先把可能的数据预先访问一遍,这样部分可能大量访问的数据就会加载到缓存汇总,在即将发生大并发访问手动触发加载缓存不同的key,设置不同的过期时间,让缓存失效的时间尽量均匀。