Redis从入门到开发
NoSQL数据库,不支持SQL,没有事务处理
支持分布式,理论可以无限扩展
去usr/local/redis-6.2.6/src目录下
使用命令./redis-server,打开客户端
看port默认端口号6379,pid是1568
目前来说,直接打开server就是前端。我们要让它后台运行
通过docker的方式安装redis
限制redis读取速度的是内存操作io接口,与cpu无关
因此是单线程程序
redis采用网络io多路复用技术保证多连接的时候,系统的吞吐量
redis默认有16个库,也就是一个MySQL有16个数据库,下标从0开始
往redis里面添加数据,使用set key value的方式,比如set k1 20
获取数据的值,get 键名,比如get k1,得到20
切换数据库,从默认的0库,到1库,就是select 1,后面的就是数据库的下标
数据库的数据不是通用的。
我们直接创建的键值对,存放在0库里面,当我们使用select切换到1库之后,就无法get了
清空数据库,flushdb,清空当前数据库的所有键
清空所有数据库,flushall
最多放512m的数据,是一个二进制文件数据,可以放任何数据。
set key value
get key
append key value
strlen key
setex key time value
setnx key value
gettange key start end
setrange key offset value
incr key
decr
incrby/decrby key step
met key1 value1 key2 value2
mget key1 key2
getset key value
使用场景:
字符串列表,底层是双向列表
使用场景:
与list类似,都是列表,但是set会自动去重
是string类型的无序集合,底层是一个value值都是null的hash表,也就是字典,增删查改的时间是o(1)
使用场景:
本质是键值对的集合,也就是字典
使用场景:
与set类型,但是多了一个score分数功能,是专门用来排序的属性
也就是比set多了一个排序
通俗来说,就是每一个zset对象,都有一个score属性,我们通过这个属性,可以给所有对象排序
使用场景:
对二进制位的操作
本质是一个数组,数组的元素就是二进制的位
setbit key offset value
设置某个偏移量的值
统计用户信息:活跃天数,打卡天数,登录天数
因为是二进制位,只有0和1两个状态,通过统计01完成数据的统计,因为只占一个比特位,节省空间
下标从0开始
setbit zhangsan:3 0 1
setbit zhangsan:3 1 1
setbit zhangsan:3 2 0
setbit zhangsan:3 3 0
setbit zhangsan:3 4 1
setbit zhangsan:3 5 1 我们设置的对象是zhangsan:3,自定义的意思是张三三月份打卡次数。后面的第一个数值是占的位,第二个数值是哪个位赋的值。然后我们统计了张三三月份的打卡情况,就是110011,然后统计1和0的个数,计算打卡次数
getbit key offset
bitcount key [start end]
bitop and/or 新数组 旧数组1 旧数组2
使用场景:
就是定位信息,提供经纬度
应用场景:定位查询,范围查询,距离查询
实现场景:
统计数据,PV网站统计浏览量,UV游客数量
我们在统计每天的用户时候,都是把访问网站的用户,用户名存放到一个列表里面,这个列表就是数据集。
我们把这个数据集里面相同的元素进行去重操作,得到的就是基数集。这个基数集就是统计用户数的
应用场景是超大数据统计,快速计算
基数不大的时候,尽量不用,因为是大材小用。只能统计,不能查询
使用场景:
就像MySQL的navicat
先关防火墙
然后就可以了
在redis的桌面端,就可以看到16个数据库了
使用右键,单击任意一个库,就可以添加键值对了
在Linux里面的redis有一个配置文件redis.conf
参数:
还有很多配置文件,后面学到什么再说什么
redis执行命令的过程:
慢查询在第三布发生
客户端超时不一定是慢查询,但是慢查询是客户端超时的一个可能因素
慢查询日志存放在redis内存列表中
慢查询日志
是redis服务端在执行命令前后,计算该条命令的执行时间,一般是设定一个阈值,超过阈值,就记录下来这条命令
slowlog get [count] 获取慢查询的日志,后面可以指定慢查询命令的数量
127.0.0.1:6379> SLOWLOG get 3
1) 1) (integer) 0 慢查询的唯一标识
2) (integer) 1640056567 时间戳
3) (integer) 11780 执行时间,微秒为单位
4) 1) "FLUSHALL" 实际执行的命令
5) "127.0.0.1:43406" ip地址
6) ""
slowlog len 获取慢查询的长度 返回的就是慢查询的数量
config get slow*
修改慢查询的参数
就是缓存命令,然后打包给服务器,让服务器一次性处理好返回来。
没有pipeline,就只能一次给服务器一条命令
课中,用的是java测试了jedis和pipeline的效率
有一个持久化机制,用于故障恢复。因为redis缓存在内存中,每次开关机,都会清空内存,有的内容不想清空,只能写在硬盘里面
redis提供了两种持久化的方式:
是每隔多长时间,就对内存中的所有内容进行一次存储。
存储的文件是一个二进制压缩文件,RDB默认保存的文件名称是dump.rdb
这个默认名称在redisconf里面,可以修改
在文件里面的440行,叫dbfilename dump.rdb
在这个模块中,有rdb文件的保存路径,是dir ./ , 可以自己修改保存路径
这个内存快照是新的替换旧的,不会一直增长
RDB的触发条件,有三种
执行flushall 执行清空命令的时候,也会触发一次rdb
手动触发rdb,有两种save和bgsave
高级设置
优势
劣势
以日志的形式,记录所有往服务端写的操作
默认AOF不开启,RDB开启
开启AOF也要去修改配置文件
设置Yes:修改默认的appendonly no,改为yes。。。修改完需要重启redis服务。
可以在redis.conf中配置文件名称,默认为appendonly.aof。
有一个好处,就是,如果执行的误删的操作,可以去aof文件里面,删除刚刚的删除操作,就可以恢复到误删之前的状态了
AOF文件的保存路径,同RDB的路径一致,如果AOF和RDB同时启动,Redis默认读取AOF的数据。
AOF同步频率设置,就是我们往AOF写的时候,也不是一次写一条,而且集中处理
优势
劣势
不要仅仅使用RDB
RDB数据快照文件,都是每隔5分钟,或者更长时间生成一次,这个时候就得接受一旦redis进程宕机,那么会丢失最近5分钟的数据。
也不要仅仅使用AOF
综合使用AOF和RDB两种持久化机制
修复损坏的AOF或者RDB
数据库层面事务
数据库事务的四大特性
Redis事务
Redis事务三大特性
Redis 为了解决这个单一节点的问题,也会把数据复制多个副本部署到其他节点上进行复制,实现Redis的高可用,实现对数据的冗余备份从而保证数据和服务的高可用。
什么是主从复制
主从复制,是指将一台Redis服务器的数据,复制到其他的Redis服务器。前者称为主节点(master),后者称为从节点(slave),数据的复制是单向的,只能由主节点到从节点。
主从复制的作用
新建redis6379.conf
include /usr/local/redis/redis.conf # 复制redis的配置文件
pidfile /var/run/redis_6379.pid # 新建pid号
port 6379 # 新建端口号
dbfilename dump6379.rdb # 新建rdb文件
新建redis6380.conf
新建redis6381.conf
下面这两个把里面的数值替换一下就可以了
./redis-server ../redis6379.conf
./redis-server ../redis6380.conf
./redis-server ../redis6381.conf
需要分别去三个服务器窗口去执行命令,也可以是一台服务器多开窗口,分别执行命令,模拟多台服务器
#分别在三个窗口里面运行命令
./redis-cli -p 6379 # 在新的窗口启动
127.0.0.1:6379> info replication # 查看该窗口的redis配置信息
./redis-cli -p 6380
127.0.0.1:6380> info replication
./redis-cli -p 6381
127.0.0.1:6381> info replication
示例:给6380匹配6379主库。
127.0.0.1:6380> SLAVEOF 127.0.0.1 6379
主从复制可以分为3个阶段
主从同步策略
主从刚刚连接的时候,进行全量同步;全同步结束后,进行增量同步。当然,如果有需要,slave 在任何时候都可以发起全量同步。redis 策略是,无论如何,首先会尝试进行增量同步,如不成功,要求从机进行全量同步。
就是同步的时候,有一个预处理阶段,也就是一个新的库接受正在使用的库的内容,需要先把这个库之前的命令全部移植过来,这个叫全量同步。然后随着我们使用主库,所使用的写命令,也会被从库拷贝过去
offset就是偏移量,我们在主从服务器里面查看信息的时候,都可以看到服务器的偏移量
命令持续复制。
当主节点把当前的数据同步给从节点后,便完成了复制的建立流程。接下来主节点会持续地把写命令发送给从节点,保证主从数据一致性。
Redis主从复制缺点
当主机 Master 宕机以后,我们需要人工解决切换。一旦主节点宕机,写服务无法使用,就需要手动去切换,重新选取主节点,手动设置主从关系。
主从切换技术
当主服务器宕机后,需要手动把一台从服务器切换为主服务器,这就需要人工干预,费事费力,还会造成一段时间内服务不可用。这不是一种推荐的方式,更多时候,我们优先考虑哨兵模式。
哨兵概述
哨兵模式是一种特殊的模式,首先Redis提供了哨兵的命令,哨兵是一个独立的进程,作为进程,它会独立运行。其原理是哨兵通过发送命令,等待Redis服务器响应,从而监控运行的多个Redis实例。
哨兵作用
#端口
port 26379
#守护进程运行
daemonize yes
#日志文件
logfile "26379.log"
sentinel monitor mymaster 127.0.0.1 6379 2
参数:
sentinel monitor mymaster 192.168.92.128 6379 2 配置的含义是:该哨兵节点监控192.168.92.128:6379这个主节点,该主节点的名称是mymaster,最后的2的含义与主节点的故障判定有关:至少需要2个哨兵节点同意,才能判定主节点故障并进行故障转移。
然后再新建两个哨兵文件,也就是三个哨兵监督三个服务器
可以把上面的79,改成80和81
哨兵节点的启动两种方式
查看哨兵节点状态
使用命令./redis-cli -p 26379 进入哨兵模式
127.0.0.1:26379> info sentinel 输入命令,可以查看哨兵的信息
master0:name=mymaster,status状态=ok,address主节点=192.168.66.100:6379,slaves从节点数量=2,sentinels=3
因为哨兵通过不断的向redis数据库发消息,拿返回值判断是否正常运行,如果不正常的时候,可能是哨兵自己出问题,也可能是服务器出问题,这时候就需要别的哨兵进行判断,如果哨兵判断的时候,有两种结果,就需要哨兵之间进行表决,比如半数哨兵都不能访问服务器,就直接切换服务器了。防止有哨兵投票两边队伍相等,因为哨兵的数量必须是奇数,防止两边相等
我们之前配置好了三个哨兵和三个服务器数据库。
我们通过kill命令杀死主节点6379.然后再进入哨兵模式,查看信息。会发现master切换了。
会发现主节点还没有切换过来,因为哨兵发现主节点故障并转移,需要一段时间。
重启主节点,这个主节点的服务器也会变成从库
进入主节点的redis,查看信息,在第一行有一个role是角色,会变成slave,从节点
都是自动转移的
配置文件都会被改写,故障转移阶段,哨兵和主从节点的配置文件都会被改写
就是之前,为了解决主从库的切换,设计出了哨兵。因为哨兵投票的时候会有一段时间不能使用redis,所以又把哨兵也分成一个个独立的组织,也就是集群。哨兵投票的时候,就把主节点换成其他的哨兵集群。
Redis有三种集群模式
哨兵模式的缺点
Redis集群是一个由多个主从节点群组成的分布式服务集群,它具有复制、高可用和分片特性。
Redis的集群搭建最少需要3个master节点,我们这里搭建3个master,每个下面挂一个slave节点,总共6个Redis节点;
只针对超大型企业,拥有海量数据读写操作的问题
由于网络卡顿,导致一个正常的数据库无法被访问,被redis集群判定为无效节点,投票出新节点之后,网络恢复,就会同时出现两个主节点
注意:
此时存在两个不同的master节点,就像一个大脑分裂成了两个。集群脑裂问题中,如果客户端还在基于原来的master节点继续写入数据,那么新的Master节点将无法同步这些数据,当网络问题解决之后,sentinel集群将原先的Master节点降为slave节点,此时再从新的master中同步数据,将会造成大量的数据丢失。
就是启动服务器的时候,MySQL是加载在硬盘的,MySQL会先加载出来,服务器会直接跟MySQL建立连接,redis就没法使用,MySQL大概率会直接挂掉。所以要让redis比MySQL先启动,并且存放一定的数据,通过数据分析,提前缓存一些信息。
缓存穿透是指缓存和数据库中都没有的数据,而用户不断发起请求,如发起为id为“-1”的数据或id为特别大不存在的数据。这时的用户很可能是攻击者,攻击会导致数据库压力过大。
就是对手恶意攻击数据库,大量查询访问未知或违法元素,造成服务器过载。为了避免这种清空,要么单独判断,要么使用布隆过滤器
解决方案
某一个热点 key,在缓存过期的一瞬间,同时有大量的请求打进来,由于此时缓存过期了,所以请求最终都会走到数据库,造成瞬时数据库请求量大、压力骤增,甚至可能打垮数据库。
因为写操作,可能直接作用在数据库上,由于key过期需要新建key,大量访问这个key,就可能大量新建key。给服务器增加负担
解决方案
缓存雪崩是指在我们设置缓存时采用了相同的过期时间,导致缓存在某一时刻同时失效,请求全部转发到DB,DB瞬时压力过重雪崩。
在redis里面,设计键的名称时候,使用:冒号,可以自动生成多级目录。使用下划线就没用该功能
# 表名 主键 主键值 存储列名字
set user:user_id:1:name baizhan 这里面的每一个冒号,都是对应之前的下划线
set user:user_id:1:age 20
#查询这个用户
keys user:user_id:9*
value设计
拒绝bigkey,防止网卡流量、慢查询,string类型控制在10KB以内,hash、list、set、zset元素个数不要超过5000
命令使用
1、禁用命令
禁止线上使用keys、flushall、flushdb等,通过redis的rename机制禁掉命令,或者使用scan的方式渐进式处理。
2、合理使用select
redis的多数据库较弱,使用数字进行区分,很多客户端支持较差,同时多业务用多数据库实际还是单线程处理,会有干扰。
3、使用批量操作提高效率
原生命令:例如mget、mset。
非原生命令:可以使用pipeline提高效率。
但要注意控制一次批量操作的元素个数(例如500以内,实际也和元素字节数有关)。
4、不建议过多使用Redis事务功能
Redis的事务功能较弱(不支持回滚),而且集群版本(自研和官方)要求一次事务操作的key必须在一个slot上。
尽可能避免一些全局查询修改操作
从理论上来说,给缓存设置过期时间,是保证最终一致性的解决方案。
这套方案,大家是普遍反对的。为什么呢?
线程安全角度,同时有请求A和请求B进行更新操作,那么会出现
(1)线程A更新了数据库
(2)线程B更新了数据库
(3)线程B更新了缓存
(4)线程A更新了缓存
这就出现请求A更新缓存应该比请求B更新缓存早才对,但是因为网络等原因,B却比A更早更新了缓存。这就导致了脏数据,因此不考虑。
该方案会导致不一致的原因是。同时有一个请求A进行更新操作,另一个请求B进行查询操作。那么会出现如下情形:
(1)请求A进行写操作,删除缓存
(2)请求B查询发现缓存不存在
(3)请求B去数据库查询得到旧值
(4)请求B将旧值写入缓存
(5)请求A将新值写入数据库
注意:该数据永远都是脏数据。
这种情况存在并发问题吗?
(1)缓存刚好失效
(2)请求A查询数据库,得一个旧值
(3)请求B将新值写入数据库
(4)请求B删除缓存
(5)请求A将查到的旧值写入缓存
发生这种情况的概率又有多少?
发生上述情况有一个先天性条件,就是步骤(3)的写数据库操作比步骤(2)的读数据库操作耗时更短,才有可能使得步骤(4)先于步骤(5)。可是,大家想想,数据库的读操作的速度远快于写操作的,因此步骤(3)耗时比步骤(2)更短,这一情形很难出现。