目录
目录
Redis
1.安装
略 自行百度。
2.基础知识
redis默认有16个数据库,默认使用的是第0个,可以使用select 2来切换数据库 。
-
keys *查看数据库所有key
-
DBSIZE查看容量
-
select +数字0-16来切换数据库
-
flushdb 清空当前库
-
flushall清空所有库
Redis是单线程的,基于内存操作,CPU不是Redis性能瓶颈,他是根据机器内存和服务器带宽。
他是C语言写的,官方数据说明每秒解决10W+QPS,不必Memecache差。
Redis速度快的原因:redis将数据都放在内存中,使用单线程操作效率最高,多线程的话线程上下文切换导致不必要的损耗。
Redis-key
-
keys *查看数据库所有key
-
exists key 判断当前key是否存在
-
move key 移除当前的key
-
expire key 10 设置过期时间
-
ttl key 查看当前key的过期时间
-
type key 查看当前key的类型
Redis类型
1.String 类型
#设置、获取
set key value 设置值
get key 获得值
#自操作
append key "hello" 在key后追加字符串,如果key不存在 则创建。
incr key 自增1
decr 自减1
#步长
incrby key 步长 可以设置步长,指定增量
decrby key 步长 可以设置步长,指定减量
getrange key 0 3 截取字符串【0,3】
setrange key 1 xx 替换从1开始的字符串
setex(set with expire) 设置过期时间
setnx mykey "redis" (set if not exit ) 如果mykey不存在则设置(分布式锁常用)
#批量操作
msetnx k1 v1 k2 v2批量设置 (mset是原子性的操作,要么一起成功,要么一起失败。)
mget k1 k2 批量获取
#对象
set user:1{name:zhangsan,age:3} #设置user1对象 值为json字符串来保存一个对象!
mset user:1:name zhangsan user:1:age 18
mget user:1:name user:1:age
1)"zhangsan"
2)"18"
getset #先get后set
getset db redis #如果不存在,则返回nil,并设置新的值;如果存在,则返回原来的值,并设置新的值。
String使用场景:value除了是字符串还可以是数字
-
计数器
-
统计多单位的数量
-
粉丝数
-
对象缓冲存储
2.List类型
在redis里面list可以玩成栈、队列、阻塞队列,List的命令都是以l开头
LPUSH #将一个值或多个值插入到列表的头部 (左)
RPUSH #将一个值或多个值插入到列表的头部 (右)
LRANGE list 0 -1 #获取list中值
LPOP #移除第一个元素
RPOO #移除最后一个元素
LINDEX X #通过下标获取list中指定索引的值
Llen list #获取list长度
Lrem list 2 value # 移除list中指定个数的value值,精确匹配。
Ltrim list 1 2 #截取的操作,执行后list剩下1-2的元素。
rpoplpush #移除列表的最后一个元素并且添加到另一个列表
lset list 0 item #将列表中指定索引值更改为item
Linsert list before a b #在a后插入b
Linsert list after a b #在a前插入b
实际上是一个链表,before node after,left ,right都可以插入值
如果key不存在,创建新的链表
如果key存在,新增内容
如果移除了所有值,空链表也代表不存在
消息排队!消息队列(Lpush Rpop) 、栈(Lpush、Lpop)
3.Set类型
sadd myset "hello" #添加值
SMEMBER myset #查看所有值
SISMEMBER myset hello #判断一个值是不是在set中
srem myset hello #移除set中的指定元素
scard myset #获取元素个数
SRANDMEMBER myset 2 #随机抽出指定个数的元素
spop myset #随机删除set中的元素
smove myset1 myset2 hello #将myset1的hello移到myset2
数字集合类:
-差集 SDIFF KEY1 KEY2
-交集 SINTER KEY1 KEY2
-并集 SUNION KEY1 KEY2
4.Hash
key-map 只是这个值 变成了map集合,本质和string类型没有太大区别,还是个简单的key-value
hset myhash field zouqi
5.Zset(有序集合)
在set的基础上增加了一个值
zadd myset 1 one #添加一个值
zadd myset 2 two 3 three #添加多个值
Redis高级
Redis事务
redis事务本质:一组命令的集合!一个事务的所有命令都会被序列化,在事务执行的过程中,按照顺序执行。
一次性、顺序性、排他性
Redis单条命令保存原子性,但是事务不保证原子性。
MySQL:ACID。要么同时成功,要么同时失败。
Redis事务的本质:一组命令的集合!一个事务中的所有命令都会被序列化,在事务执行的过程中,会按照顺序执行。
一次性、顺序性、排他性。执行一系列的命令。
Redis事务没有隔离级别的概念!Redis单条命令是保证原子性的,但是事务不保证原子性。
所有的命令在事务中,并没有直接执行!只有发起命令的时候才会执行!Exec
Redis的事务:
正常执行事务:
-
开启事务 multi
-
命令入队 ... (写自己的命令)
-
执行事务 exec
放弃事务:DISCARD (取消事务)
事务中:
-
命令有错,所有的命令都不会被执行。
-
运行时错误:其他命令可以正常执行。
监控!Watch
使用watch可以当作redis的乐观锁操作。(使用watch监视后,使用事务提交,如果有别的线程修改,那么会提交失败)
如果提交失败,先unwatch释放监视,重新用watch监视值,继续操作,提交事务。
简言之,如果修改失败,获取最新值即可。
Jedis
导入对应的依赖
<dependency>
<groupId>redis.clients</groupId>
<artifactId>jedis</artifactId>
<version>2.9.0</version>
</dependency>
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>fastjson</artifactId>
<version>1.2.67</version>
</dependency>
//1.new Jedis对象即可
Jedis jedis = new Jedis("127.0.0.1",6379);
//2.所有指令,就是方法。
System.out.println(jedis.ping());
控制台PONG 连接成功
SpringBoot整合
SpringBoot操作数据库:spring-data、jpa jdbc mongodb redis
SpringData也是和springBoot齐名的项目
说明:在springBoot2.x后 jedis被替换成lettuce!
jedis:底层采用直连,多个线程操作是不安全的。想要安全用jedis pool
lettuce:采用nettty,实例可以在多个线程共享,不存在线程不安全的情况。可以减少线程数量,更像nio模式。
1.依赖导入
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
2.自定义redisTempltes,然后自定义redisUtils
Redis配置文件
网络
bind 127.0.0.1 #绑定的地址
protected-mode yes #是否保护模式
port 6379 #端口配置
通用general
daemonize yes #后台方式运行,默认为no
pidfile /var/run/redis_6379pid #如果以后台方式运行,必须指定一个pid文件
logfile "" #日志的文件名
databast 16 #数据库数量,默认16
always-show-logo yes #是否总是显示logo
快照
在规定的时间内,执行了多少次操作,则会持久化到文件.rdb .rof
redis是内存数据库,如果没有持久化,数据断电则无
save 900 1 #900s内如果至少有一个key进行了修改,就进行持久化操作
save 300 10 #300s内如果至少有十个key进行了修改,就进行持久化操作
save 60 10000 #60s内如果至少有10000key进行了修改,就进行持久化操作
#持久化一般自己定义
stop-writes-on-bgsave-error yes #持久化出错后,是否需要继续工作。
rdbcompression yes #是否压缩rdb文件,会消耗一些cpu资源。
rdbchecksum yes #保存rdb时是否进行错误校验。
dir ./ #rdb保存的文件目录
repliction 后续主从复制在补充。
security
可以设置redis密码 requirepass 123456 命令行设置 config set requirepass "123456"
限制客户端
maxclients 10000 #能链接上的最大客户端数量
maxmemory <bytes> #配置最大内存
maxmemory-po+-*licy noeviction #内存到达上限后的处理策略
#移除一些过期的key
#报错
# 。。。
当Redis所使用的内存达到 maxmemory 之后会触发相应的溢出控制策略,Redis支持 6 种策略:
- noeviction:当内存使用达到阈值的时候,所有引起申请内存的命令会报错。
- allkeys-lru:在所有键中采用lru算法删除键,直到腾出足够内存为止。
- volatile-lru:在设置了过期时间的键中采用lru算法删除键,直到腾出足够内存为止。
- allkeys-random:在所有键中采用随机删除键,直到腾出足够内存为止。
- volatile-random:在设置了过期时间的键中随机删除键,直到腾出足够内存为止。
- volatile-ttl:在设置了过期时间的键空间中,具有更早过期时间的key优先移除。
APPEND ONLY 模式 AOF模式
appendonly no #默认不开启aof模式,默认使用rdb模式,大部分情况下,rdb完全够用。
appendfilename "appendonly.aof" #持久化文件名
appendsync eyerysec #每秒进行一次持久化,但是可能会丢失1s的数据 默认!
#appendsync alwyas #每次修改都会进行一次持久化,消耗性能。
#appendsync no #不执行同步。操作系统会自动同步,速度最快!
RDB持久化 redis data base
触发条件
1.save规则满足,自动触发。
2.执行flushall命令。也会触发。
3.退出redis,也会产生rdb文件。
如何恢复rdb文件
-
只需要将rdb文件放到redis启动目录就可以,redis启动时会自动检测。
-
查看需要存在的位置。 /user/local/bin
优点:
-
适合大规模的数据恢复!
-
如果你对数据完整性要求不高!
缺点:
-
需要一定的时间间隔进行操作,如果意外宕机,最后一次修改数据就没了。
-
fork进程会占用一定的内存空间。
AOF持久化 append only file
将我们的所有命令(写)都记录下来,恢复的时候就把所有的命令都执行一遍。
aof文件内部有错误是无法启动redis 。这时需要redis-check-aof去修复。
redis-check-aof --fix appendonly.aof
如果aof文件大于64m,fork一个新进程将文件进行重写。
Redis发布/订阅
通过subscribe订阅某一个频道,redis-server里维护了一个字典,字典的key是订阅的频道名,字典的value则是一个链表,链表里保存了所有订阅这个频道的客户端。 通过publish发布消息后,redis-server会根据给定的频道作为key,找到value的链表,遍历链表给每个客户端发送消息。
场景
-
实时消息系统
-
实时聊天(频道当成聊天室)
-
订阅关注系统。
Redis主从复制
主从复制,是指将一台redis(master/leader)上的数据复制到另一台redis(slave/fllower)。数据的复制是单向的,只能由主节点到从节点。master以写为主,slave以读为主。
默认情况下,每台redis都是主节点。一个主节点可以用多个从节点也可以没有,但一个从节点只能有一个主节点。
主从复制的作用
-
数据备份:主从复制实现了数据的热备份,是持久化之外的另一种数据备份方式。
-
故障恢复:当主节点出现问题时,可以由从节点提供服务,实现快速的故障恢复。
-
读写分离:可以用于实现读写分离,主库写、从库读,读写分离不仅可以提高服务器的负载能力,同时可根据需求的变化,改变从库的数量;
-
负载均衡:在主从复制的基础上,配合读写分离,可以由主节点提供写服务,由从节点提供读服务(即写Redis数据时应用连接主节点,读Redis数据时应用连接从节点),分担服务器负载;尤其是在写少读多的场景下,通过多个从节点分担读负载,可以大大提高Redis服务器的并发量。
-
高可用基石:除了上述作用以外,主从复制还是哨兵和集群能够实施的基础,因此说主从复制是Redis高可用的基础。
环境配置
只需要配置从库,不需要配置主库。单机多集群测试的话,复制三份配置文件,开三个端口。
-
复制三个配置文件, cp redis-config redis-config1 cp redis-config redis-config2 cp redis-config redis-config3
-
然后修改对应的信息
端口
pid名字
log文件名字
dump.rdb文件名字
-
开启三个服务
redis-server kconfig/redis-config1
redis-server kconfig/redis-config2
redis-server kconfig/redis-config3
默认情况下,每个redis都是主节点。
-
slaveof 127.0.0.1 6379 #在从库中执行,设置主机为127.0.0.1 6379 (找老大)
-
info replication 在主机查看信息 会看到多了从机的配置;在从机查看信息会看到role变为slave
真实的主从配置,应从配置文件中配置,才会永久,命令行配置只是暂时的。
-
主机才能写入,从机只能读取!主机中的数据和信息都会被从机自动保存。
-
主机断开连接,从机依旧是连着主机。如果主机重新连接,从机一样能读取主机数据。
复制原理
slave 启动成功master会发送一个sync命令
master接受到命令后,启动后台的存盘进程,同时收集所有接收到的用于修改数据集命令,在后台进程执行完毕之后,master将传送整个数据文件到slave,并完成一次完全同步。
全量复制:slave接受到数据库文件数据后,将其存盘加入到内存中。
增量复制:master继续将所有收集到的修改命令依次传给slave,完成同步
但是只要重新链接master,将会执行一次全量复制。
哨兵模式
1.配置哨兵配置文件 sentinel.conf
#sentinel monitor 被监控的名称 127.0.0.1 6379 1
sentinel monitor myredis 127.0.0.1 6379
后面的数字1 代表主机挂了slave投票看让谁成为主机,票数最多的就会编程主机。
2.启动哨兵
优点:
-
哨兵集群,基于主从复制,所有主从复制优点都有。
-
主从可以切换,故障可以转移,系统可用性好。
-
就是主从模式的升级,更加自动化。
缺点:
-
redis在线扩容很麻烦,一旦达到上限。
-
配置复杂
缓存穿透
从名字上来看,缓存击穿和缓存穿透很像,实际上页比较像,但是既然区分了出来,自然有一些不同的地方
缓存穿透的概念很简单,用户想要查询一个数据,发现redis内存数据库没有,也就是缓存没有命中,于是向持久层数据库查询。发现也没有,于是本次查询失败。当用户很多的时候,缓存都没有命中,于是都去请求了持久层数据库。这会给持久层数据库造成很大的压力,这时候就相当于出现了缓存穿透。
但是,缓存穿透真正要防止的是黑客。
如果一个黑客每次故意查询一个在缓存内必然不存在的数据,导致每次请求都要去存储层去查询,这样缓存就失去了意义。如果在大流量下数据库可能挂掉,这也是缓存击穿。
解决办法:
- 1、增加参数校验
- 2、从网关层Nginx增加配置项,对单个IP每秒访问次数超出阈值的拉黑处理
- 3、Bloom Filter 能很好地防止缓存穿透、他的原理也很简单的就是利用高效的数据结构和算法快速判断出你这个Key是否在数据库,不存在直接return、存在就直接去DB刷新KV再return
利用布隆过滤器来防止缓存击穿,主要是通过将已存在的缓存放到布隆过滤器中,当黑客访问不存在的缓存时迅速返回避免缓存及DB挂掉。
什么是布隆过滤器?后续补充
缓存击穿
短时间内同时请求同一个数据
解决办法:
- 1.设置热点数据不过期
- 2.加互斥锁
缓存雪崩
简单点说就是Redis宕机,或者缓存集体失效。
解决办法:
- 1、批量网Redis存数据的时候,把每个KEY失效时间都增加随机值,保证不会同时失效
- 2、设置热点数据永不过期,有更新操作就更新缓存(但是这个方法不好,永不过期导致缓存大量堆积,很多缓存不一定有用)
- 3、Redis集群部署,将热点数据均匀分布在不同Redis库中也能避免全部失效,避免了Redis出现问题导致缓存雪崩
Redis高可用
有空补充细节。。。
Redis使用场景建议
计数器
可以对 String 进行自增自减运算,从而实现计数器功能。
Redis 这种内存型数据库的读写性能非常高,很适合存储频繁读写的计数量。
缓存
将热点数据放到内存中,设置内存的最大使用量以及淘汰策略来保证缓存的命中率。
会话缓存
可以使用 Redis 来统一存储多台应用服务器的会话信息。
当应用服务器不再存储用户的会话信息,也就不再具有状态,一个用户可以请求任意一个应用服务器,从而更容易实现高可用性以及可伸缩性。
全页缓存(FPC)
除基本的会话token之外,Redis还提供很简便的FPC平台。
以Magento为例,Magento提供一个插件来使用Redis作为全页缓存后端。此外,对WordPress的用户来说,Pantheon有一个非常好的插件 wp-redis,这个插件能帮助你以最快速度加载你曾浏览过的页面。
查找表
例如 DNS 记录就很适合使用 Redis 进行存储。
查找表和缓存类似,也是利用了 Redis 快速的查找特性。但是查找表的内容不能失效,而缓存的内容可以失效,因为缓存不作为可靠的数据来源。
消息队列(发布/订阅功能)
List 是一个双向链表,可以通过 lpush 和 rpop 写入和读取消息
不过最好使用 Kafka、RabbitMQ 等消息中间件。
分布式锁实现
在分布式场景下,无法使用单机环境下的锁来对多个节点上的进程进行同步。
可以使用 Redis 自带的 SETNX 命令实现分布式锁,除此之外,还可以使用官方提供的 RedLock 分布式锁实现。
其它
Set 可以实现交集、并集等操作,从而实现共同好友等功能。
ZSet 可以实现有序性操作,从而实现排行榜等功能。