一,引言
在学一门技术之前,还是需要先看他的官方,接下来给一篇中文文档:https://www.redis.net.cn/tutorial/3501.html
二,什么是redis
Remote Dictionary Server,远程字典服务
是一个开源的使用AnSI C语言编写,支持网络,可基于内存亦可持久化的日志型,key-value数据库,并提供多种语言的api
免费和开源,是当下最热门的NoSQL技术之一,也被人们称为结构化数据库
三,安装redis
由于基本上操作都是在服务器下或者虚拟机下的,所以安装linux的版本
链接:https://github.com/redis/redis/tags 下载解压后,上传到服务器即可,我这边使用的是xftp进行连接,然后将服务器上的redis移到/usr/local/software即可,software为自己新建的目录
我这边redis下载的版本是4.0.6的版本
然后解压,直接解压在当前目录即可
tar -zxvf redis-4.0.6.tar.gz
解压完成之后,接下来进行安装的步骤
安装c++环境,有就可以不用装
yum -y install gcc-c++
编译
make
安装到指定的目录,所以这个redis4new需要新建在/usr/local下面
make install PREFIX=/usr/local/redis4new
不得不说,在这里可能会遇到大坑,make一直失败。之前使用vm虚拟机的时候就遇到过,最后还是看了一篇大佬的文章才发现这个问题的,接下来可以大家可以去参考一下
正式安装之后,看下图,会有一个bin目录
接下来就是查看这个bin目录
启动 ./redis.server
redis-cli -p 6379,测试一下能否ping通
那么这个redis就安装成功了
四,redis基础知识
一共有16个数据库,默认使用的是第0个数据库
使用select 切换数据库
dbsize:查看数据库大小
keys *:查看数据库所有的key
flushdb:清空数据库
flushall:清空全部的数据库的内容
redis是单线程的,基于内存操作,cpu不是redis的瓶颈,redis的瓶颈是根据机器的内存和网络带宽
redis是由c语言写的,官方提供的数据是100000+ 的qps,完全不比同样使用的key-value的Memecaahe差
redis为什么单线程还这么快
误区1:高性能的服务器一定是多线程的
误区2:多线程一定比单线程快
cpu速度 > 内存 > 硬盘
核心:redis是将所有的数据全部存放在内存中的,所以说使用单线程是
效率最高的,如果使用的是多线程,
在cpu进行资源切换的时候回浪费大量的时间, 所以这就是使用单线程
的优势,多次读写在一个cpu上的
在内存情况下,这就是最佳的方案
五,五大数据类型
先说key,首先key基本都是使用string类型
exists:判断是否存在
move name:将name的键值移除
expire name 10 等价于setex:设置key的过期时间,单位是s,
可以使用ttl查看:如ttl name查看剩余时间
type name:查看name的类型
value,一共有五种数据类型,不过我们大部分还是使用的string类型比较多
String(字符串类型)
append命令:追加字符串,如果当前key不存在,相当于新set一个key
strlen:获取字符串的长度
incr:自动增加
decr:自动减少
incrby key 10:可以加任意的数字
decrby:
getrange key 0 3:字符串截取
setrange key 2 xx:字符串替换
setex(set with expire):设置过期时间
setnx():不存在设置(一般在分布式锁中会设置),如果不存在则进行保存
如果存在则报错
mset:可以进行多个值的存储设置
mget:可以获取多个值
如果在设置多个值时,具有原子性:要么同时成功,要么同时失败
getset:先get然后set
getset a b:如果不存在值,则返回nil,如果存在值,
获取原来的值,并设置新的值
get a
String类型的使用场景:value除了字符串还可以是数字
计数器
统计多单位的数量 uid:
应用场景:基本上应用场景都可以使用String,如用户登录时存取用户的用户名和密码;在登录时手机验证码的校验,即将需要发送的验证码存入到string类型中,并通过expire设置有效期时间,这样就完成了现实中的我们的验证码登录了;还有一个就是一定要利用好自增这个属性,经常在开发场景中就是有要统计人数的,比如访问人数,那么就要使用这个自增属性了,还挺好用的。
hash(哈希类型)
map集合,key-map:即value为一个map集合
所有的hash是以h开头的
hset hash field1 zhenghuisheng:filed zhenghuisheng为一个map键值对
hget hash field1:获取这个hash值
hmset:可以用于设置多个值
hgetall:获取多个值
hdel:删除值
hlen:获取hash表的字段数量
hexists:判断某个hash值是否存在
hkeys:获取所有的字段
hvalues:
hincrby:指定增量
hsetnx:如果存在则可以设置,如果不存在则不行
hash可以用于存变更的数据 user name age,尤其是用户信息之类的保存
hash更适合对象的存储,string更适合字符串的存储
应用场景:比如登录时的用户名和密码,最适合用hash存储了
List(list集合)
在redis中,可以将list变成队列和栈
所有的list命令都是用l开头的
lpush:将一个或多个值插入到列表的左边
lrange:查看list中的所有值 lrange list 0 -1
rpush:将一个或多个值插入到列表的右边
range:获取值
lpop:从左边将值取出,移除列表的第一个元素
rpop:从右边将至取出
lindex:获取某个值的下标 lindex list 1
Llen:获取list的长度
lrem:移除list中指定的value。lrem list value
ltrim:通过下标截取指定长度,这个list只剩下截取的部分
ltrim list 1 2
rpoplpush:移除列表的最后一个元素,将这个值移到新列表的最左边
rpoiplpush list1 list2
lset:将列表中下标的值进行替换,如果下标不存在,则会报错
linsert:将某个具体的值插入到列表中某个元素的前面后者后面
linsert mylist before|after "hello3" "other"
应用场景:比如在一个秒杀系统中,我们一般就是将所有的商品都存储在这个list集合中,允许商品重复
Set(set集合)
所有的set命令时以s开头的
sadd:将数据加入到集合中
smembers:查看集合中所有的值
sismember:判断某个值是不是在set集合中
scard:获取set集合中的内容元素个数
srem:移除set中的某个元素
srandmember:随机抽选一个元素
spop:出栈,随机删除一些set集合中的一些元素
smove:移动指定的元素,将set1移动到set2中
sdidd:判断两个集合之间的差集
sinter:判断两个集合之间的交集
sunion:判断两个集合之间的并集
应用场景:同上在一个秒杀系统中,要保证每个人只能抢到一个东西,如果已经抢到就不能再抢了;也可以在幸运用户抽奖的时候,用来存幸运用户
Zset(有序的set集合)
在set的基础上增加了一个值,以z开头
zrange myzset 0 -1:获取所有值
zrangebyscore myzset -inf +inf withscores:排序,显示所有用户并进行排序
zrevrangescore myzset 0 -1:从大到小排序,并显示用户
zrem:移除某个元素
zcard:获取有序集合中的个数
zcount myzset 1 3:获取指定区间的成员数量
应用场景:set排序,用于存储班级成绩,工资表排序。还有一个就是用来存储购物车时根据添加到购物车的时间进行购物车的排序。
六,redis事务原子性:要么同时成功,要么同时失败
redis单条命令式保存原子性的,但是整个事务不保证原子性(参照运行时异常)
redis事务的本质:
一组命令的集合
一个事务中所有的命令都会被序列化,在事务执行过程中,会按照顺序执行。redis事务中没有事务隔离级别的概念,所有的命令在事务中,并没有直接被执行,只有发起执行的命令才会执行:exec
redis的事务:
开启事务(multi)
命令入队:正常代码,如set,get
执行事务(exec):在执行完事务后即结束
放弃(取消)事务:discard
编译时异常:代码有问题,命令有错,事务中所有的命令都不会被执行
运行时异常:如果事务队列存在语法性,那么执行命令的时候,
其他命令是可以正常执行的,错误命令抛出异常
七,redis整合springboot
可以参考我之前写的一篇博客:
八,Redis配置文件
通过配置文件redis.config启动服务
配置文件unit单位对大小写不敏感
包含,可以将多个配置文件包含进来, include /.conf
1,网络
bind 127.0.0.1:绑定的ip
port:端口6379
protected-mode:保护模式
2,通用general
daemon yes:以守护进程的方式运行,默认为no,可以修改为yes
如果以后台的方式运行,我们就需要指定一个pid文件
logfile "":日志的文件位置名
databases 16:数据库数量,默认是16个数据库
always-show-log yes:是否总是显示logo
3,快照
持久化,在规定的时间,执行了多少次参数,则会持久化到文件.rdb.aof
redis是内存数据库,如果没有持久化,那么数据在断电即失
save进行持久化操作
stop-writes-on-bgsave-error yes:持久化出错,是否需要继续工作
rdbcompression yes:是否压缩rdb文件,需要消耗一些cpu的资源
rdbchecksum yes:在保存rdb文件的时候,进行错误的检查校验
dir ./:文件保存的目录
4,security
requirepass xxx:设置密码,默认是没有密码的。
使用命令为config set requirepass "xxx"
auth xxx:加上密码才能登陆
5,限制clients
maxclients xxx:设置能连上redis最大客户端的数量
maxmemory <bytes>:redis设置最大的内存容量
maxmemory-policy noeviction:内存到达上限之后的处理策略
6种方式:百度
6,append only模式aof配置
appendonly no:默认是不开启aof模式的,默认是使用rdb方式持久化的,在大部分情况下,rdb够用
appendfilename "appendonly.aof":持久化文件的名字
appendfsync everysec:每秒执行一次,可能会丢失这一秒的数据
appendfsync always:每次都修改,消耗性能
appendfsync no:不执行sync,这个时候操作系统自己腿部数据,速度最快
九,持久化(重点-面试必问)
在指定的时间间隔内将数据集的快照写入到磁盘中,也就是快照,他恢复是将快照文件直接读到内存中
机制:
redis会单独的创建一个子进程来进行持久化,会将数据先写到一个
临时的文件中,待持久化过程都结束了,再用这个临时文件替换上一次
持久化好的文件,整个过程中,主进程是不进行任何io操作的,这就确保了
极高的性能。如果需要进行大规模的数据恢复,且对于数据恢复的完整性并不敏感,
那rdb就比aof的方式更加高效,rdb的缺点就是
最后一次持久化数据可能丢失,我们默认的就是rdb,一般不会去修改这个配置
rdb(redis database)
1,触发rdb机制
save的规则满足的情况下会自动触发rdb规则
执行flushall命令,也会触发rdb规则
退出redis也会产生rdb规则
2,恢复rdb文件
只需要将rdb文件放在我们的redis启动目录即可,redis启动的
时候会自动检查dump.rdb恢复其中的数据查看需要存在的位置
config get dir
3,优点
适合大规模的数据恢复
对数据的完整性要求不高,
4,缺点
需要一定的时间间隔进程操作,如果redis宕机了,这个最后一次修改
数据的机会就没有了fork进程(单独创建一个子进程)的时候,
会占用一定的内存空间
aof(append only filed)
以日志的形式来保存每一个操作,将所有redis执行过指令的记录记下来(读操作不记录),只许追加文件不许修改文件,redis启动会读取该文件重新构建数据库。换言之,redis重启的话根据日志文件的内容将写指令从前到后执行一次以完成数据的恢复工作,默认是不开启的,将appendonly改为yes就开启了aof,重启redis就可以生效。如果这个aof文件存在错误,或者是启动不起来,可以使用redis-check-aof --fix appendonly.aof进行排错,如果文件正常,重启就可以恢复了,sof默认的就是文件的追加
优点
每一次修改都同步,文件的完整性会更加好
每秒同步一次,可能丢失一秒的数据
缺点
相对于数据文件来看,aof的数据远远多于rdb,修复的·速度也比rdb慢
aof运行效率也要比rdb慢,所以我们的redis默认的配置为rdb持久化
十,redis发布订阅
redis发布订阅(pub/sub)是一种消息通信模式,发送者发送信息,订阅者接收消息
模型:消息发送者,频道,消息订阅者
subscribe xxx:订阅一个频道
publish xxx message:向频道中发送消息
使用场景
1,实时的消息系统
2,实时聊天
3,订阅,关注系统
稍微复杂的场景就可能用mq
十一,redis主从复制
指将一台redis服务器复制到其他redis服务器上,前者称为主节点,后者称为从节点,数据的复制时是单向的,只能从主节点到从节点,master为主节点,slave为从节点
1,主从复制作用
数据冗余
故障恢复
负载均衡
高可用基石
2,一般来说,只使用一台redis是不可能的,因为有可能宕机
从结构上:多个redis会发生单点故障,并且一台服务需要处理器
需要处理所有的请求负载,压力较大
从容量上:多个redis的内存容量有限,一般来说,单台的redis
最大使用的内存不应该超过20个G
主从复制可以实现读写分离
3,主从复制原理
slaveof host port:找谁当主机
真实的配置时在配置文件中进行配置,这样才能永久的配置,
如果用命令的话则使暂时性的
细节
主机可以写,从机只能读,主机中的所有的信息和数据,都会自动被保存
如果从机进行写的话会报错
如果是使用命令行配置的主从,如果重启了就会变回主机
复制原理
slave从机启动成功连接到master主机后会发送一个sycn同步命令
主机在接到命令后,启动后台的存盘进程,提示收集所有的用于修改数据集的命令,
在后台执行完毕后,主机将整个文件发送给从机,并完成一次同步
全量复制:slave服务在接收到数据库文件数据后,将其存盘并加载到内存中
增量复制:master继续将所有的收集到的修改命令依次传给slave,完成同步,
但是只要是重新连接master,一次完全同步将被自动执行我们的数据就一定
可以在从机中看到
十二,哨兵模式(Sentinel)
主从切换技术的方法是:当主服务器宕机之后,需要手动把一台服务器切换为主服务器,这就需要人工干预,费时费力,还会造成一段时间内服务不可用,这不是一种推荐的方式
1,什么是哨兵模式
哨兵模式是一种特殊的模式,提供了哨兵的命令,哨兵是一个独立的进程,
作为进程,他会独立的运行,其原理是:
哨兵通过发送命令,等待redis服务器响应,从而运行多个redis实例
2,哨兵的作用
通过发送命令,让redis服务器返回监控其运行状态,包括主服务器和从服务器
当哨兵检测到master宕机,会自动将·slave切换为master,然后通过
发布订阅模式通知其他的服务器,
3,哨兵模式原理
假设主服务器宕机,哨兵1先检测到这个结果,系统并不会马上进行failover过程,
仅仅是哨兵1主观的认为主服务器不可用,这个现象称为主观下线,当后面的哨兵也
检测到主服务器不可用,并且达到一定的值时,那么哨兵之间就会进行一次投票,
投票的结果由一个哨兵发起,进行failover的故障转移,切换成功之后,就会通过
发布订阅模式,让各个哨兵把自己监控的从服务器实现切换主机,
这个过程称为客观下线
4,哨兵配置文件sentinel.conf
sentinel monitor 被监控的名称 host port 1 //1代表投票的票数
如果主机断开了,就会从从机中随机选择一个服务器
哨兵日志:
failover:故障转移
sdown slave:
如果在原来的主机中再重新连接,也不可恢复原来的主机,只能当做从机
十三,缓存穿透和雪崩(重点-面试必问)
1,缓存穿透(查不到导致的)
概念:
用户想要查询一个数据,发现redis内存数据库中没有,也就是缓存没有命中,于是
向持久层数据库查询,发现也没有,于是本次查询命令失败,当用户很多的时候,缓
存中都没有命中(如秒杀),于是都去请求了持久层数据库,这回给持久层数据库造成
很大的压力,这时候相当于出现了缓存穿透
解决方案
添加布隆过滤器
2,缓存击穿(量太大导致的)
3,缓存雪崩
指服务器某个节点宕机或断网,因为自然形成的缓存雪崩,一定是在某个时间段集中
创建缓存,这个时候,数据库是可以顶住压力的,无非是对数据库产生周期性的压力
而已。而缓存服务节点的宕机,对数据库服务器造成的压力是不可预知的,很有可能
瞬间把数据库压垮
解决方案
异地多活:多增加几台redis服务器设备,这样一台挂掉之后其他的还可以继续工作
限流降级:在缓存失效后,通过加锁或者队列来控制数据库读写缓存的线程数量,
比如只允许一个线程查询数据和写缓存,其他线程等待
数据预热:在正是部署前,先把可能的数据尽可能的欲先访问一遍,这样大部分可能
访问的数据就会加载到缓存中,在即将发生大并发前手动触发加载缓存不同的key,
设置不同的过期时间,让缓存过期的时间尽量均匀
十四,保证redis数据库的安全性
为了redis的安全性,可以在redis配置文件中添加白名单,在这个名单上的人才能访问!