Redis

基础

一、介绍

(一)Redis概念

1.Redis(Remote Dictionary Server),即远程字典服务,是一个开源的使用ANSI C语言编写、支持网络、可基于内存亦可持久化的日志型、Key-Value数据库,并提供多种语言的API。 2.Redis内存中的数据结构存储系统,它可以用作数据库、缓存和消息中间件。 3.Redis内置了 复制(replication),LUA脚本(Lua scripting),LRU驱动事件(LRU eviction),事务(transactions) 和不同级别的 磁盘持久化(persistence),并通过 Redis哨兵(Sentinel) 和 自动分区(Cluster)提供高可用性(high availability)。

(二)Redis特性

1.redis是基于内存操作,所以redis性能很快。 2.redis是单线程的 (单线程无需上下文切换,比起多线程可以节省上下文切换时间)。 3.redis是C语言写的 官方数据是每秒"100000+"QPS。 4.redis不区分大小写。

(三)Redis数据类型

基本数据类型: string(字符串) hash(散列) list(列表) set(集合) zset(sorted set有序集合)。 特殊数据类型: geospatial(地理空间) hyperloglogs(基数) bitmaps(位存储)。

二、使用方法

(一)安装

1.下载redis安装包,并上传至服务器。

2.解压安装包至任意目录。

shell 复制代码
tar -zxvf redis-6.2.6.tar.gz

3.基本环境安装

shell 复制代码
yum install gcc-c++

4.进入解压后的redis目录,安装redis

shell 复制代码
make
shell 复制代码
make install

5.进入redis安装目录

shell 复制代码
cd /usr/local/bin

6.将解压的redis配置文件拷贝到当前目录下(也可以直接使用解压的redis配置文件,这里拷贝的目的是为了方便使用)

shell 复制代码
cp /home/redis-6.2.6/redis.conf  myconf/

7.进入"myconf"目录 修改"redis.conf"配置文件将redis修改为后台启动(默认不是后台启动的)

shell 复制代码
cd myconf/
shell 复制代码
vim redis.conf

8.将redis.conf文件中的"daemonize no" 修改为 "daemonize yes"

9.启动redis服务端(通过指定的redis配置文件"myconf/redis.conf"启动服务)

shell 复制代码
./redis-server myconf/redis.conf 

10.启动redis客户端 指定6379端口连接服务(redis默认6379端口)

shell 复制代码
./redis-cli -p 6379

(二)关闭

1.关闭redis(在redis客户端执行)

shell 复制代码
shutdown
shell 复制代码
exit

(二)常用命令

数据库

1.修改数据库数量 (redis默认有16个数据库 在"redis.conf"配置文件中可以修改数量)

shell 复制代码
vim /usr/local/bin/myconf/redis.conf

将"databases 16" 修改为 "databases 目标数量" 保存并退出

2.清空当前数据库内容

shell 复制代码
flushdb

3.清空所有数据库内容

shell 复制代码
flushall

4.切换到第3个数据库 (默认使用第0个数据库)

shell 复制代码
select 3

5.查看当前数据库大小

shell 复制代码
DBSIZE

6.将当前数据库key移动到数据库5中

shell 复制代码
move key字段 5
身份验证

1.设置数据库密码

shell 复制代码
config set requirepass 密码

2.登录(验证身份)

shell 复制代码
auth 密码

3.查看redis密码

shell 复制代码
config get requirepass
数据

1.查看当前数据库所有的key

shell 复制代码
keys *

2.查看key是否存在

shell 复制代码
exists key字段

3.查看key的数据类型

shell 复制代码
type key字段

三、五大基本数据类型

(一)string详解

介绍
shell 复制代码
1.string的值可以是字符串,也可以是数字。
2.string的使用场景:计数器、统计多单位数量...
增删改查

1.增加,修改

shell 复制代码
set key字段 值

2.查看

shell 复制代码
get key字段

3.删除

shell 复制代码
del key字段
字符串操作

1.获取string的长度

shell 复制代码
strlen key字段

2.获取string指定下标区间的字符串 (闭区间) (结束下标为"-1"表示string末尾下标)

shell 复制代码
getrange key字段 开始下标 结束下标

3.string值追加 如果key不存在就set key

shell 复制代码
append key字段 要追加的字符串

4.替换指定位置开始的字符串

shell 复制代码
setrange key字段 开始下标 替换的字符串
过期时间

1.添加key并设置过期时间

shell 复制代码
setex key字段 过期时间 值

2.设置key的过期时间

shell 复制代码
expire key字段 过期时间(秒)

3.查看key剩余有效时间

shell 复制代码
ttl key字段
批量操作

1.批量创建key

shell 复制代码
mset key字段1 值1 key字段2 值2 key字段3 值3

2.批量创建key 如果不存在则创建,存在则不做任何操作 (原子性操作: 要么同时成功,要么同时失败)

shell 复制代码
setnx key字段1 值1 key字段2 值2 key字段3 值3	

3.批量获取key

shell 复制代码
mget key字段1 key字段2 key字段3
自增自减

1.key的值自增1

shell 复制代码
incr key字段

2.key的值自减1

shell 复制代码
decr key字段

3.key的值自增指定值

shell 复制代码
incrby key字段 指定值

4.key的值自减指定值

shell 复制代码
decrby key字段 指定值

ps:自增自减只能操作数字。

拓展

1.添加key 如果不存在则创建,存在则不做任何操作

shell 复制代码
setnx key字段 值

2.先获取再创建 如果不存在则返回nil,如果存在则先返回原来的值然后修改为当前命令的值

shell 复制代码
getset key字段  

3.创建对象user:01

shell 复制代码
mset user:01:name zhangsan user:01:age 15 user:01:sex 1

4.查看对象user01的信息

shell 复制代码
mget user:01:name user:01:age user:01:sex

(二)list详解

介绍
shell 复制代码
1.list中允许重复的元素。
2.list实际上是一个链表。在list两边插入或者修改元素,效率最高。中间相对来说效率会低点。
3.使用场景:栈、队列、阻塞队列...

1.向list中插入一个或多个元素,插入到list头部 (栈顶) (list不存在就创建)

shell 复制代码
lpush key字段 元素1 元素2 元素3

2.向list中插入一个或多个元素,插入到list尾部 (栈底) (list不存在就创建)

shell 复制代码
rpush key字段 元素1 元素2 元素3

3.向list中指定元素的顶部插入元素

shell 复制代码
linsert key字段 before 指定元素 插入元素

4.向list中指定元素的底部插入元素

shell 复制代码
linsert key字段 after 指定元素 插入元素

1.查看list的长度

shell 复制代码
llen key字段

2.通过下标获取list指定区间(闭区间)的元素 (结束下标为"-1"表示list末尾下标) (从栈顶向栈底)

shell 复制代码
lrange key字段 开始下标 结束下标

3.通过下标获取list中的某一个元素 (从栈顶向栈底)

shell 复制代码
lindex key字段 下标

1.删除list中指定的元素

shell 复制代码
lrem key字段 要删除的数量 要删除的元素

2.移除list栈顶元素

shell 复制代码
lpop key字段

3.移除list栈底元素

shell 复制代码
rpop key字段

1.修改list中指定下标的元素 (不存在就报错)

shell 复制代码
lset key字段 下标 要修改的元素

2.list通过下标截取指定区间(闭区间)内容,并将list更新为截取后的内容 (闭区间)

shell 复制代码
ltrim key字段 开始下标 结束下标
拓展

1.移除list栈底元素 并将他插入到目标list栈顶

shell 复制代码
rpoplpush key字段 目标key字段

2.移除list栈顶元素 并将他插入到目标list栈底

shell 复制代码
lpoprpush key字段 目标key字段

(三)set详解

介绍
shell 复制代码
1.set是无序的。
2.set中的元素不允许重复。
3.使用场景:用户关注、用户粉丝、用户收藏...

1.向set集合中添加一个或多个元素

shell 复制代码
sadd key字段 元素1 元素2 元素3

1.查看set集合中的所有元素

shell 复制代码
smembers key字段

2.查看set集合中元素的个数

shell 复制代码
scard key字段

1.删除set中指定元素

shell 复制代码
srem key字段 指定元素

2.删除set中多个指定元素

shell 复制代码
srem key字段 指定元素1 指定元素2 指定元素3

3.随机删除set中的一个元素

shell 复制代码
spop key字段

4.随机删除set中指定数量元素

shell 复制代码
spop key字段 指定数量
差并交集

1.以第一个set集合为参照物,查看两个或多个set集合的差集

shell 复制代码
sdiff set集合1 set集合2

2.查看两个或多个set集合的交集

shell 复制代码
sinter set集合1 set集合2

3.查看两个或多个set集合的并集

shell 复制代码
sunion set集合1 set集合2

ps:使用场景:用户关注的人放入一个set集合中,用set交集可以得到用户之间的 共同关注。

拓展

1.判断某个元素在不在set集合中

shell 复制代码
sismember key字段 元素

2.在set中随机获取一个元素

shell 复制代码
srandmember key字段

3.在set中随机获取指定数量的元素

shell 复制代码
srandmember key字段 指定数量

4.将set集合的指定元素移动到另一个set集合中

shell 复制代码
smove 原set 目标set 指定元素

(四)hash详解

介绍
shell 复制代码
1.hash的本质也是key-value,只不过hash中的value是个map集合。
2.使用场景:用户信息...

1.向hash中添加一个key-value

shell 复制代码
hset key字段 k v

2.向hash中添加多个key-value

shell 复制代码
hmset hash字段 k1 v1 k2 v2 k3 v3

1.查看hash的长度

shell 复制代码
hlen key字段

2.获取一个k值

shell 复制代码
hget key字段 k

3.获取多个k值

shell 复制代码
hmget key字段 k1 k2 k3

4.只查看hash中所有的k

shell 复制代码
hkeys key字段

5.只查看hash中所有的v

shell 复制代码
hvals key字段

6.获取hash中的所有内容

shell 复制代码
hgetall key字段

1.删除hash中指定的key-value

shell 复制代码
hdel key字段 k

2.删除hash中多个指定的key-value

shell 复制代码
hdel key字段 k1 k2 k3
拓展

1.判断hash中指定key-value是否存在

shell 复制代码
hexists key字段 k

2.向hash中添加key-value 如果不存在则添加,如果存在则不做任何操作

shell 复制代码
hsetnx key字段 k v

3.k字段自增

shell 复制代码
hincr key字段 k

4.k字段自增指定值

shell 复制代码
hincrby key字段 k 自增值

5.k字段自减

shell 复制代码
hdecr key字段 k

6.k字段自减指定值

shell 复制代码
hdecrby key字段 k 自增值

7.创建对象 user:01

shell 复制代码
hset user:01 name zhangsan adder beijing age 15 sex 1

8.查看对象 user:01 的 姓名、住址、年龄、性别

shell 复制代码
hgetall user:01

(五)zset详解

介绍
shell 复制代码
1.zset:有序集合,不允许重复。
2.使用场景:排行榜、热搜排行、工资表排序、成绩表排序...

1.添加一个元素

shell 复制代码
zadd key字段 元素score 元素

2.添加多个元素

shell 复制代码
zadd key字段 元素1score 元素1 元素2score 元素2 元素3score 元素3

1.查看zset集合中元素的个数

shell 复制代码
zcard key字段

2.查看所有元素

shell 复制代码
zrange key字段 0 -1

3.通过下标查看元素 (结束下标为"-1"表示zset集合末尾下标)

shell 复制代码
zrange key字段 起始下标 结束下标

4.查看指定区间的元素个数 (根据score筛选) (闭区间)

shell 复制代码
zcount key字段 score最小值 score最大值

1.删除元素

shell 复制代码
zrem key字段 元素
排序

1.查看所有元素(根据score从小到大排序) (-inf:负无穷大 +inf:正无穷大)

shell 复制代码
zrangebyscore key字段 -inf +inf

2.查看所有元素(根据score从大到小排序)

shell 复制代码
zrevrangebyscore key字段 +inf -inf
shell 复制代码
zrevrangebyscore key字段 0 -1

3.查看所有元素和元素的score(根据score从小到大排序)

shell 复制代码
zrangebyscore key字段 -inf +inf withscores

4.查看score小于500的元素和元素的score(根据score从大到小排序)

shell 复制代码
zrevrangebyscore key字段 500 -inf withscores

5.查看score大于500的元素和元素的score(根据score从小到大排序)

shell 复制代码
zrangebyscore key字段 500 +inf withscores

6.查看score大于300并且小于500的元素(根据score从小到大排序)

shell 复制代码
zrangebyscore key字段 300 500

四、三种特殊数据类型

(一)geospatial详解

介绍
shell 复制代码
1.geospatial:地理位置。
2.使用场景:好友定位,附近的人,打车距离计算...

3.geo底层的实现原理就是一个zset集合,我们也可以使用zset命令来操作geo
添加位置

1.添加一个地理空间

shell 复制代码
geoadd key字段 经度 纬度 地理空间名称

2.添加多个地理空间

shell 复制代码
geoadd key字段 经度1 纬度1 地理空间名称1 经度2 纬度2 地理空间名称2 经度3 纬度3 地理空间名称3

ps:有效的经度从-180度到180度,有效的维度从-85.05112878度到85.05112878度。两极无法添加。

查看经纬度

1.根据 地理空间名称 查看位置经纬度 (前提:位置要录入key集合中)

shell 复制代码
geopos key字段 地理空间名称
查看直线距离

1.根据 地理空间名称 查看 两个位置之间的直线距离 (前提:位置要录入key集合中)

shell 复制代码
geodist key字段 地理空间名称1 地理空间名称2 显示单位

显示单位(m:米 km:千米 mi:英里 ft:英尺)

查看附近的位置

ps:前提(位置要录入key集合中) 单位(m:米 km:千米 mi:英里 ft:英尺) 1.以指定的经纬度为中心,查看指定半径范围的位置

shell 复制代码
georadius key字段 经度 纬度 指定半径 单位

2.以key集合中的元素为中心,查看指定半径范围的位置

shell 复制代码
georadiusbymember key字段 地理空间名称 指定半径 单位

3.以指定的经纬度为中心,查看指定半径范围的位置,并显示到中心的直线距离

shell 复制代码
georadius key字段 经度 纬度 指定半径 单位 withdist

4.以指定的经纬度为中心,查看指定半径范围的位置,并显示位置的经纬度

shell 复制代码
georadius key字段 经度 纬度 指定半径 单位 withcoord

5.以指定的经纬度为中心,查看 前20个 指定半径范围的位置,并显示到中心的直线距离和位置的经纬度

shell 复制代码
georadius key字段 经度 纬度 指定半径 单位 withcoord  withdist count 20
拓展

1.根据 地理空间名称 查看位置经纬度的hash字符串 (将位置的经纬度转换成一个字符串)

shell 复制代码
geohash key字段 地理空间名称1 地理空间名称2 地理空间名称3

2.删除一个位置

shell 复制代码
zrem key字段 地理空间名称

3.查看所有位置

shell 复制代码
zrange key字段 0 -1

(二)hyperloglog详解

介绍
shell 复制代码
1.hyperloglog:基数统计。
2.使用场景:统计访问量、浏览量、播放量...

3.优点:占用的内存是固定的,2^64个不同元素的基数,只需占用12KB的内存。从内存角度考虑,hyperloglog首选。
4.hyperloglog的统计有0.81%的错误率;如果统计允许容错,首选hyperloglog;如果不允许容错,就使用set或者其他适合的数据类型。
添加

添加一个或多个元素

shell 复制代码
pfadd key字段 元素1 元素2 元素3
查看

查看key中基数数量

shell 复制代码
pfcount key字段
合并

将两个或多个key合并为一个新key

shell 复制代码
pfmerge 新key字段 key字段1 key字段2

(三)bitmaps详解

介绍
shell 复制代码
1.bitmaps:位存储。
2.使用场景:两个状态的事物,都可以用bitmaps 例如(登录、未登录   已打卡、未打卡  更新、未更新...)

3.bitmaps操作二进制位进行记录,只有0和1两种状态。
添加

1.添加一个记录(值只有0和1两种结果)

shell 复制代码
setbit key字段 下标 值
查看

1.查看某一下标的值

shell 复制代码
getbit key字段 下标
统计

1.统计值为1的数量

shell 复制代码
bitcount key字段

2.统计指定区间值为1的数量(闭区间)

shell 复制代码
bitcount key字段 开始下标 结束下标

进阶

一、事务

(一)介绍

概念
shell 复制代码
redis事务的本质就是一组命令的集合。
特性
shell 复制代码
1.一个事务中所有命令会被序列化,在事务开始执行时,会按照顺序执行。
2.redis单条命令是保证原子性的,但是事务不保证原子性。
3.所有的命令在事务中并没有执行,只有发起执行命令时才会执行。

(二)使用方法

1.开启事务

shell 复制代码
multi 

2.提交事务

shell 复制代码
exec

3.回滚事务 (执行后,multi命令后的所有操作都不会被执行)

shell 复制代码
discard

(三)异常

shell 复制代码
1.编译型异常:事务中有命令使用错误,所有的命令都不会被执行。
2.运行异常:事务中有逻辑错误命令 无命令使用错误,出错命令抛出异常,其他命令不会被影响。

二、监控(锁)

(一)介绍

概念
shell 复制代码
1.悲观锁:认为什么时候都会出问题,无论做什么都会加锁。
2.乐观锁:认为什么时候都不会出问题,什么时候都不会上锁。
特性
shell 复制代码
乐观锁只会在更新数据时判断一下在此期间是否有人修改过数据(先获取version,更新时比较version)

(二)命令

1.加锁(监视key)

shell 复制代码
watch key字段

2.解锁 (无需指定key字段)

shell 复制代码
unwatch

(三)使用方法

1.开启事务

shell 复制代码
multi

2.解锁

shell 复制代码
unwatch

3.加锁,监控key

shell 复制代码
watch key字段

4.开始执行业务操作

5.提交事务

shell 复制代码
exec

(四)异常处理

shell 复制代码
1.执行失败:提交事务若返回nil表示执行失败 (执行时如果另一个线程修改了 监控的key,事务就会执行失败。)
2.原理:执行"exec"命令时,会先对比当前key的值与监视时key的值是否相同。如果相同,则事务执行成功;如果不同,则事务执行失败。
3.注意事项:若执行失败,重新操作时只需从解锁步骤重新开始即可。无需再开启事务。

三、性能测试

(一)使用方法

1.redis性能测试 (-h:主机地址 -p:端口 -c:并发数 -n:请求数量)

shell 复制代码
./redis-benchmark -h localhost -p 6379 -c 20 -n 1000

(二)结果解读

shell 复制代码
====== GET ======   # 测试请求类型 GET类型                                             
  1000 requests completed in 0.10 seconds	# 对1000个请求进行get测试
  20 parallel clients	# 20个并发客户端
  3 bytes payload	# 每次get大小 3个字节
  keep alive: 1		# 处理这些请求的服务器数量 1个
Latency by percentile distribution:
0.000% <= 0.791 milliseconds (cumulative count 2) # 第0.791毫秒时共处理了503个请求 约占总请求数的0.000%
50.000% <= 1.439 milliseconds (cumulative count 503) # 第1.439毫秒时共处理了503个请求 约占总请求数的50.000%
87.500% <= 1.879 milliseconds (cumulative count 876) # 第1.879毫秒时共处理了503个请求 约占总请求数的87.500%
100.000% <= 3.159 milliseconds (cumulative count 1000) # 第3.159毫秒时共处理了1000个请求 约占总请求数的100.000%

四、配置文件

(一)介绍

特性
shell 复制代码
1.配置文件内容不区分大小写。

(二)配置解读

包含文件

配置文件包含,当前配置文件可以包含其他一个或多个配置文件

shell 复制代码
include /path/to/other.conf
网络
shell 复制代码
bind 127.0.0.1	# 绑定ip
protected-mode yes	# 保护模式
port 6379	# 端口
通用
shell 复制代码
daemonize no  # 以守护进程的方式运行(后台运行) 默认no
pidfile /var/run/redis_6379.pid	# 如果是后台运行,就需要指定一个pid文件。
databases 16	# 数据库数量 默认16
always-show-logo no	# 是否总显示logo 默认no
日志
shell 复制代码
# 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	# 日志级别 (notice:生产环境)

logfile ""	# 日志的文件位置
限制
shell 复制代码
maxclients 10000	# 最大客户端数量
maxmemory <bytes>	# redis最大内存容量

maxmemory-policy noeviction # 内存到达上限后的处理策略
    volatile-lru	# 只对设置了过期时间的key进行LRU(默认值) 
    allkeys-lru		# 删除lru算法的key   
    volatile-random	# 随机删除即将过期key   
    allkeys-random	# 随机删除   
    volatile-ttl	# 删除即将过期的   
    noeviction		# 永不过期,返回错误
快照(持久化)
shell 复制代码
# 快照(持久化规则):在规定时间内,执行了多少次操作,redis就会将内存中的数据持久化到文件(.rdb文件 .aof文件)
# 我们可以自定义需要的规则
save 3600 1		# 3600秒内至少有1个key有更改,就进行持久化操作。
save 300 100	# 300秒内至少有100个key有更改,就进行持久化操作。
save 60 10000	# 60秒内至少有10000个key有更改,就进行持久化操作。
stop-writes-on-bgsave-error yes		# 持久化出错,快照功能是否还要继续工作。
rdb配置
shell 复制代码
rdbcompression yes	# 是否压缩rdb文件,需要消耗cpu资源。
rdbchecksum yes		# 保存rdb文件时,是否进行错误校验。
dir ./				# rdb文件保存目录 默认当前目录
dbfilename dump.rdb	 # rdb持久化的文件名
aof配置
shell 复制代码
appendonly no	# aof持久化模式默认不开启;默认使用rdb持久化模式,大部分情况下rdb模式完全够用。
appendfilename "appendonly.aof"	# aof持久化的文件名
appendfsync everysec 	# 同步策略
    everysec	# 每一秒钟同步一次 (默认,推荐)
    always 		# 每执行一个命令就同步一次 (消耗性能)
    no			# 不同步 (操作系统自己同步数据,速度最快)
auto-aof-rewrite-min-size 64mb	# 重写机制,如果aof文件大于64mb就会fork一个新的进程对aof文件进行重写(优化)。

五、数据持久化

(一)介绍

1.redis是内存数据库,如果不将内存中的数据保存到磁盘,那么一旦服务器进程退出,服务器内存中的数据也会消失,所以redis提供了数据持久化的功能。 2.redis两大持久化方式:rdb(redis database)持久化、aof(append only file)持久化。

(二)rdb持久化

原理和过程

1.原理:在指定的时间间隔内将内存中的数据集快照写入磁盘,也就是行话讲的snapshot快照,它恢复时是将快照文件直接读取到内存里。 2.rdb持久化过程:redis会单独创建(fork)一个子进程来进行持久化,先将数据写入一个临时文件中,待持久化过程都结束了,再用这个临时文件替换上次持久化好的文件。整个过程中主进程不进行任何IO操作,这确保了极高的性能。

优缺点
shell 复制代码
优点(使用场景):
1.大规模数据恢复,且对数据完整性要求不高。

缺点:
1.需要一定的时间间隔进行操作。
2.如果redis意外宕机,最后一次持久化的数据会丢失。
3.创建fork进程时会占用一定的内存空间。
注意事项
shell 复制代码
1.redis默认使用rdb持久化方式,一般情况下无需修改配置文件。
2.rdb保存的文件默认是"dump.rdb",可以在配置文件中修改文件名和保存路径。
3.在生产环境中一般会将"dump.rdb"文件进行备份,防止发生意外造成数据永久性丢失。

4.如果"dump.rdb"文件被破坏,启动redis就会报错。这时我们就需要手动修复rdb文件。
触发机制
shell 复制代码
满足以下条件,就会生成一个"dump.rdb"文件。(生成的文件在redis启动目录下)
1.满足配置文件中的"save"规则
2.执行flushall命令
3.正常退出redis
恢复数据
shell 复制代码
只需将rdb文件放在redis启动目录下即可。(redis启动时会自动检查启动目录下的"dump.rdb"文件,并恢复里面的数据到内存中。)
常用命令

1.修复rdb文件(暴力修复:删除被污染的命令),在redis启动目录下执行("redis-check-rdb"程序在启动目录下)。

shell 复制代码
redis-check-rdb --fix rdb文件

2.查看redis启动目录

shell 复制代码
config get dir

(三)aof持久化

原理和过程

1.原理:将所有的命令都记录下来,恢复的时候就把这个文件记录的所有命令从前到后执行一遍。 2.aof持久化过程:以日志的形式记录每个操作,将redis执行过的所有命令记录下来(读操作不记录),只许追加文件不可修改,redis启动时会读取该文件重新构建数据到内存中。

优缺点
shell 复制代码
优点:每一秒钟或每执行一个命令都同步一次,数据持久化文件完整性会更好。
缺点:aof数据持久化文件的大小远远大于rdb文件,恢复数据的速度会比rdb慢。由于aof效率比rdb低,所以redis默认使用rdb持久化。
注意事项
shell 复制代码
1.aof持久化默认是不开启的,我们需要在配置文件手动开启。(将appendonly改为yes,重启redis即可生效。)
2.aof保存的文件默认是"appendonly.aof",可以在配置文件中修改文件名和保存路径。

3.如果"appendonly.aof"文件被破坏,启动redis就会报错。这时我们就需要手动修复aof文件。
触发机制
shell 复制代码
# 根据配置文件中的 appendfsync 规则 触发
appendfsync everysec 	# 同步策略
    everysec # 每一秒钟同步一次,可能会丢失最后一秒数据。(默认,推荐)
    always 	 # 每执行一个命令就同步一次 (消耗性能)
    no		# 不同步 (操作系统自己同步数据,速度最快)
恢复数据
shell 复制代码
只需将aof文件放在redis启动目录下即可。(redis启动时会自动检查启动目录下的"appendonly.aof"文件,并恢复里面的数据到内存中。)
前提:要在配置文件中开启aof持久化,否则不会进行aof数据恢复操作。
常用命令

1.修复aof文件(暴力修复:删除被污染的命令),在redis启动目录下执行("redis-check-aof"程序在启动目录下)。

shell 复制代码
redis-check-aof --fix aof文件

2.查看redis启动目录

shell 复制代码
config get dir

(四)拓展

一、RDB持久化方式能够在指定的时间间隔内对你的数据进行快照存储。 二、AOF 持久化方式记录每次对服务器写的操作,当服务器重启的时候会重新执行这些命令来恢复原始的数据,,AOF命令以Redis协议追加保存每次写的操作到文件末尾,Redis还能对AOF文件进行后台重写,使得AOF文件的体积不至于过大。 三、只做缓存,如果你只希望你的数据在服务器运行的时候存在,你也可以不使用任何持久化。 四、同时开启两种持久化方式: 1.在这种情况下,当redis重启的时候会优先载入AOF文件来恢复原始的数据,因为在通常情况下AOF文件保存的数据集要比RDB文件保存的数据集要完整。 2.RDB的数据不实时,同时使用两者时服务器重启也只会找AOF文件,那要不要只使用AOF呢?作者建议不要,因为RDB更适合用于备份数据库( AOF在不断变化不好备份),快速重启,而且不会有AOF可能潜在的Bug,留着作为一个万一的手段。 五、性能建议: 1.因为RDB文件只用作后备用途,建议只在Slave上持久化RDB文件,而且只要15分钟备份一 次就够了,只保留 save 900 1 这条规则。 2.如果开启AOF,在最恶劣情况下也只会丢失不超过两秒数据,启动脚本较简单只load自己的AOF文件就可以了,代价一是带来了持续的IO,二是AOF rewrite的最后将rewrite过程中产生的新数据写到新文件造成的阻塞几乎是不可避免的。只要硬盘许可,应该尽量减少AOF rewrite的频率,AOF重写的基础大小默认值64M太小了,可以设到5G以上,默认超过原大小100%大小重写可以改到适当的数值。 3.如果不开启AOF,仅靠Master-Slave Repllcation实现高可用性也可以,能省掉一大笔IO,也减少了rewrite时带来的系统波动。代价是如果Master/Slave 同时挂掉,会丢失 十几分钟的数据,启动脚本也要比较两个Master/Slave中的RDB文件,载入较新的那个,微博就是这种架构。

高级

一、发布订阅

(一)介绍

shell 复制代码
redis发布订阅是一种消息通信模式:发送者发送消息到redis,redis将该消息通知给所有订阅者,订阅者收到消息。
使用场景:实时消息系统、实时聊天、订阅关注系统...

Redis是使用C实现的,通过分析Redis源码里面的pubsub.c文件,了解发布和订阅机制的底层实现,可加深对Redis的理解。

(二)常用命令

Redis通过 PUBLISH、SUBSCRIBE 和 PSUBSCRIBE 等命令实现发布和订阅功能。

1.订阅一个或多个频道

shell 复制代码
subscribe 频道名

2.将消息发送到指定频道

shell 复制代码
publish 频道 消息内容

3.退订频道

shell 复制代码
unsubscribe 频道名

(三)原理

shell 复制代码
通过 SUBSCRIBE 命令订阅某频道后,redis-server 里维护一个字典,字典的键就是一个个channel,而字典的值则是一个链表,链表中保存了所有订阅这个channel的客户端。SUBSCRIBE命令的关键,就是将客户端添加到给定 channel 的订阅链表中。

通过 PUBLISH 命令向订阅者发送消息,redis-server 会使用给定的频道作为键,在它所维护的 channel 字典中查找记录了订阅这个频道的所有客户端的链表,遍历这个链表,将消息发布给所有订阅者。

Pub/Sub 从字面上理解就是发布(Publish)与订阅(Subscribe),在Redis中,你可以设定对某一个key值进行消息发布及消息订阅,当一个key值上进行了消息发布后,所有订阅它的客户端都会收到相应的消息。这一功能最明显的用法就是用作实时消息系统,比如普通的即时聊天,群聊等功能。

二、主从复制

(一)介绍

引出

一般来说,要将redis运用于工程项目中,只使用一台redis是万万不能的,原因如下: 1.单个redis服务器会发生单点故障。 2.一台服务器需要处理所有请求负载,压力较大。 3.单个redis服务器内存有限(单台redis服务器最大使用内存不应该超过20G)。 为了解决上述问题,就有了 主从复制 技术。

概念

主从复制,是指将一台redis服务器的数据,复制到其他redis服务器。前者称为主节点(master/leader),后者成为从节点(slave/follower)。数据的复制是单向的,只能由主节点复制到从节点,master以写为主,slave以读为主。(redis在实际使用中80%都是读操作)(大部分网站一般都是一次上传无数次浏览,即"读多写少")

(二)作用

1.数据冗余:主从复制实现了数据的热备份,是数据持久化之外的一种数据冗余方式。 2.故障恢复:当主节点发生意外时,可以由从节点提供服务,实现快速的故障恢复,实际上是一种服务的冗余。 3.负载均衡:在主从复制的基础上,配合读写分离(主节点提供写服务,从节点提供读服务),可以分担服务器负载;尤其是在写少读多的情况下,通过多个从节点分担读负载,大大提高redis服务器的并发量。 4.高可用基石:主从复制是哨兵和集群能够实施的基础,所以说主从复制是redis高可用的基础。

(三)命令

1.查看当前节点信息

shell 复制代码
info replication

2.配置从节点(绑定主节点)

shell 复制代码
slaveof 主节点地址 端口

3.恢复为主节点(取消绑定主节点)

shell 复制代码
slaveof no one

(四)实战

注意:真实项目中主从配置应该是在配置文件中配置好的,无需命令配置。 1.背景:一主(127.0.0.1:6379)二从(127.0.0.1:6380 127.0.0.1:6381) 2.复制3个redis配置文件,分别修改配置文件对应信息(运行端口、pid名字、log文件名、dump.rdb文件名) 3.通过修改的3个配置文件分别启动redis服务器

shell 复制代码
./redis-server myconf6379/redis.conf 
shell 复制代码
./redis-server myconf6380/redis.conf 
shell 复制代码
./redis-server myconf6381/redis.conf 

4.启动三个客户端分别连接6379、6380、6381端口的redis服务器

shell 复制代码
./redis-cli -p 6379
shell 复制代码
./redis-cli -p 6380
shell 复制代码
./redis-cli -p 6381

5.配置从节点(两个从节点分别执行该命令) (默认情况下,每台redis都是主节点,我们只需配置从节点即可)

shell 复制代码
slaveof 127.0.0.1 6379

6.查看每个节点的信息,检查是否配置成功

shell 复制代码
info replication

(五)细节

shell 复制代码
1.默认情况下,每台redis都是主节点,我们只需配置从节点即可。
2.一个主节点可以有多个从节点(或没有从节点),但一个从节点只能有一个主节点。
3.主机可以写,但从机只能读不能写。
4.主机中所有的信息都会被从机自动备份。
6.主机断开连接,从机依旧正常可以连接到主机。此时如果主机重新连接,从机依旧可以获取到主机的内容。

7.如果是命令行配置的主从,从机重启后就会变主节点。只要重新绑定原主节点变回从机,就可以读取主节点的所有内容。
原理:从机启动并成功连接到主节点后会发送一个同步命令。主节点接收到同步命令后,收集所有修改数据集的命令并启动后台存盘进程,当后台存盘进程执行完毕后,主机会将整个数据文件发送给从机,从机收到数据文件后执行一次完全同步(全量复制)。
全量复制:从机接收到数据文件后将其存盘并加载到内存中。	# 从机只要重新连接到主节点,一次全量复制会被自动执行。
增量复制:主节点将新的修改数据集的命令依次发送给从机进行同步。

(六)拓展

1.另一种主从模复制:层层链路 (6379是6380的主节点,6380是6381的主节点)

shell 复制代码
slaveof 127.0.0.1 6379	# 6380执行该命令
shell 复制代码
slaveof 127.0.0.1 6380	# 6381执行该命令
shell 复制代码
如果6379断开连接,6380可以使用命令"slaveof no one"让自己变为主节点,其他节点可以手动连接到这个新的主节点。
此时即使6379修复重启也不再是6380的主节点了。

三、哨兵模式

(一)介绍

引出

主从复制切换主机的方法:当主机宕机后,需要手动将一台从机切换为主节点,这就需要人工干预,费时费力,还会造成一段时间服务不可用。为了解决上面的问题,redis从2.8提供了Sentinel(哨兵)架构来解决这个问题。

概述

哨兵:哨兵模式是一种特殊的模式,首先redis提供了哨兵的命令;哨兵是一个独立的进程,作为进程,它会独立运行并在后台监控主机是否故障,如果主机故障了根据投票数自动将一台从机转换为主节点。 原理:是哨兵通过发送心跳包,等待redis服务器响应,从而监控运行的多个redis实例。

(二)作用

1.通过发送心跳包,等待redis服务器响应监控其运行状态,包括主节点和从节点。 2.当哨兵检测到主节点故障,自动将一个从节点切换为主节点,然后通过"发布订阅模式"通知其他服务器修改配置文件,让他们切换主机。

(三)使用方法

启动

1.背景:一主二从(主127.0.0.1:6379端口 从127.0.0.1:6380端口、127.0.0.1:6381端口)

2.进入redis启动目录

shell 复制代码
cd /usr/local/bin

3.进入自己的配置文件存放目录

shell 复制代码
cd myconf/

4.配置哨兵配置文件

shell 复制代码
vim sentinel.conf

5.编写哨兵配置文件内容

shell 复制代码
sentinel monitor testredis 127.0.0.1 6379 1
shell 复制代码
sentinel monitor 自定义配置名 要监控的主机 端口 选举触发数	
1表示只要有一个哨兵检测到master故障,就进行选举投票(故障转移)

6.通过刚才配置的 哨兵配置文件 启动哨兵

shell 复制代码
redis-sentinel myconf/sentinel.conf

7.哨兵启动成功,哨兵开始工作。

测试
shell 复制代码
1.分别启动三个端口的服务器(修改配置文件),启动三个客户端分别连接三个端口的服务器。
2.配置主从(哨兵监听6379节点,所以6379一定要是主机)。
3.查看哨兵是否监听到6380、6381的加入。(如果监听到,那么哨兵配置成功并正常工作)。
shell 复制代码
1.关掉127.0.0.1:6379节点。(master故障,哨兵会自动在从节点中选一个节点切换为master (通过一定的投票算法))。
2.重启127.0.0.1:6379节点(如果故障的主机修复并重启,只能归并到新的master下作为其从节点,这就是哨兵模式的规则)。

(四)优缺点

优点
shell 复制代码
1.主从复制的所有优点哨兵模式都有。
2.哨兵模式就是主从复制的升级,手动到自动,更加健壮。
3.自动切换,故障转移,系统的可用性更好。
缺点
shell 复制代码
1.在线扩容困难,集群容量一旦到达上限,在线扩容就十分麻烦。
2.哨兵模式的配置比较繁琐。

(五)配置文件

ps:哨兵的配置文件需自己编写,编写完成后通过 "redis-sentinel 哨兵配置文件" 命令 即可启动哨兵。

shell 复制代码
port 26379 # 哨兵运行的端口
dir /tmp	# 哨兵工作目录

# sentinel monitor 自定义配置名 要监控的主机 端口 选举触发数	
# 1表示只要有一个哨兵检测到master故障,就进行选举投票(故障转移)
sentinel monitor 自定义哨兵name 127.0.0.1 6379 1 # 哨兵监控的节点

sentinel auth-pass 自定义哨兵name 密码	# 密码验证 当要监控的节点需要密码验证才能连接时

sentinel down-after-milliseconds 自定义哨兵name 30000 # 当监控的节点指定时间没有答复时,哨兵主观上认为它下线
sentinel parallel-syncs 自定义哨兵name 2	 # 指定故障转移时,最多可以有多少台从机同时对master进行数据同步操作
sentinel failover-timeout 自定义哨兵name 1800000 # 故障转移超时时间

sentinel notification-script 自定义哨兵name 脚本路径 # 发生故障时执行该路径的脚本(可以写故障报警脚本等)
sentinel client-reconfig-script 自定义哨兵name 脚本路径	# master节点切换时执行该路径的脚本(可以写ip切换通知脚本等)

四、多哨兵模式

(一)介绍

引出

一个哨兵进程对redis服务器进行监控,可能会出现问题,例如哨兵进程停止运行等,为此我们可以使用多个哨兵进行监控。

原理

每个哨兵都对所有服务器都进行监控,各个哨兵之间还会相互监控,这样就形成了多哨兵模式。

(二)实战

1.背景:一主二从(主:6379端口 从:6380端口、6381端口),三个哨兵(1号、2号、3号) 2.主节点(6379端口)宕机,哨兵1先检测到结果并不会马上进行failover过程,仅仅是哨兵1主观认为主节点不可用。这个线程称为主观下线。 3.当其他哨兵也检测到主节点不可用,并且数量达到一定值(一般为总哨兵数的一半)时,那么哨兵之间会进行一次投票(选举主节点),投票(选举主节点)结果任由一个哨兵发起,进行failover故障转移操作。 4.切换成功后,通过发布订阅模式,让各个哨兵把自己监控的master节点切换为选举后的节点,这个过程称为客观下线。

五、缓存

(一)什么是缓存

redis缓存的使用,极大的提升了应用程序的性能和效率,特别是数据查询方面。但同时它也带来了一些问题,其中最要害的问题就是数据一致性问题,从严格意义上来讲,这个问题是无解的。如果对数据一致性要求很高,那么就不能使用缓存。

(二)缓存穿透

原理

缓存穿透的概念很简单,用户想要查询一个数据,发现redis缓存中没有该数据,也就是缓存没有命中;于是就向持久层数据库去查询,发现数据库也没有,本次查询失败。当并发很多时缓存都没有命中(即缓存秒杀),于是都去请求了持久层数据库,这会给持久层数据库造成很大的压力,这个情况被称为缓存穿透。# 理解:查不到

解决方案

1.布隆过滤器:布隆过滤器是一种数据结构,对所有可能查询的参数以hash的形式存储,在控制层先进行校验,不符合则丢弃,从而避免了对底层存储系统的查询压力。 2.缓存空对象:当存储层被命中后,即使返回空对象也将其缓存起来,同时会设置一个过期时间;之后再请求这个数据将会从缓存中获取(即使是空对象),保护了持久层数据库。

注意事项

1.缓存空对象:将空值缓存起来,这也意味着缓存需要更多空间来存储这些空值的键。 2.缓存空对象:即使空值设置了过期时间,还是会存在缓存层和存储层的数据有一段时间不一致,这对于需要保持数据一致性的业务会有影响。

(三)缓存击穿

原理

缓存击穿是指一个热点key,在不停的扛着大并发,大并发集中对这一个点进行访问;当这个key的缓存在失效的瞬间,持续的大并发会穿破缓存全部请求数据库来查询数据,并且回写缓存,导致数据库瞬间压力巨大,就像在一个屏障上凿开了一个洞。# 理解:失效空档量太大

解决方案

1.设置热点数据永不过期:热点key在缓存中没有过期时间,所以不会出现热点key过期后产生的问题。 2.加互斥锁:使用分布式锁,保证对于每个key同时只有一个线程去查询后端服务,其他线程没有获得分布式锁的权限只能等待。这种方式将高并发的压力转移到了分布式锁,因此对分布式锁的考验很大。

(四)缓存雪崩

原理

缓存雪崩是指在某一个时间段缓存集中过期失效,此时所有的请求都会打到存储层,存储层的调用量暴增,严重的会造成存储层挂掉的情况。

解决方案

1.redis高可用:增加redis服务器的节点数量,这样一台redis挂掉之后其他的还可以继续工作,其实就是搭建集群。 2.限流降级:在缓存失效后,通过加锁或队列来控制读数据库写缓存的线程数量。 3.数据预热:在即将发生大并发访问前手动加载热点数据到缓存中,设置不同的过期时间,让缓存失效的时间点尽量均匀。

拓展

其实缓存数据集中过期不是非常致命,比较致命的缓存雪崩是缓存服务器某个节点宕机(断电、故障)或断网。因为自然形成缓存雪崩一定是在某个时间段集中创建缓存,这个时候数据库也是可以顶住压力的,无非就是对数据库产生周期性的压力而已。而缓存服务节点宕机,对数据库造成的压力是不可预知的,很有可能瞬间就把数据库压垮。

相关推荐
Ting-yu2 分钟前
零基础学习Redis(14) -- Spring中使用Redis
redis·学习·spring
woai33641 小时前
首页实现多级缓存
redis·缓存·caffeine
码上库利南2 小时前
详解Redis数据库和缓存不一致的情况及解决方案
数据库·redis·缓存
持之以恒的天秤4 小时前
Redis-CPP 5大类型操作
数据库·redis
格格步入6 小时前
Redis 如何模糊搜索 Scan 😂😂😂
redis·后端·搜索引擎
凉、介1 天前
CPU Cache 的映射与寻址
linux·arm开发·数据库·redis·缓存·嵌入式
MarkGosling1 天前
【开源项目】当大模型推理遇上“性能刺客”:LMCache 实测手记
redis·python·llm
xiaolin03331 天前
【黑马点评】Redis解决集群的session共享问题
java·redis
萌新小码农‍1 天前
Redis后端的简单了解与使用(项目搭建前置)
数据库·redis·缓存