解压 安装包 tar
安装 gcc yum install gcc
make 如果make 动作报错 用 make distclean
Hint: It's a good idea to run 'make test' ;)
make[1]: 离开目录“/root/redis-6.2.6/src”
出现上面两行 就可以安装
make install
make[1]: 进入目录“/root/redis-6.2.6/src”
CC Makefile.dep
make[1]: 离开目录“/root/redis-6.2.6/src”
make[1]: 进入目录“/root/redis-6.2.6/src”
Hint: It's a good idea to run 'make test' ;)
INSTALL redis-server
INSTALL redis-benchmark
INSTALL redis-cli
make[1]: 离开目录“/root/redis-6.2.6/src”
进入到 /usr/local/bin 目录
总用量 18904
-rwxr-xr-x. 1 root root 4829472 3月 9 15:19 redis-benchmark 性能测试工具
lrwxrwxrwx. 1 root root 12 3月 9 15:19 redis-check-aof -> redis-server 修改有问题的AOF文件
lrwxrwxrwx. 1 root root 12 3月 9 15:19 redis-check-rdb -> redis-server
-rwxr-xr-x. 1 root root 5003760 3月 9 15:19 redis-cli 客户端,操作入口
lrwxrwxrwx. 1 root root 12 3月 9 15:19 redis-sentinel -> redis-server redis集群使用
-rwxr-xr-x. 1 root root 9518888 3月 9 15:19 redis-server redis服务器启动命令
启动: 前台启动 ./redis-server &
后台启动 /root/redis-6.2.6 有个 redis.conf
cp redis.conf /etc/redis.conf
找到 daemonize no 修改为 daemonize yes
/usr/local/bin 执行
redis-server /etc/redis.conf
[root@master bin]# ps -ef |grep redis
root 6136 1388 0 15:32 pts/0 00:00:00 ./redis-server *:6379
root 16847 1388 0 15:40 pts/0 00:00:00 grep --color=auto redis
关闭 进入到 redis-cli shutdown
或者 kill -9 进程
dbsize 查看当前数据库的 key 的数量
flushdb 清空当前库
flushall 通杀全部库
redis 是单线程 + 多路IO 的复用技术
多路复用是指一个线程来检查多个文件描述符socket的就绪状态,比如调用select
和poll 函数,传入多个文件描述符,如果有一个文件描述符就绪,则返回,否则
阻塞直到超时,得到就绪状态后经行真正的操作可以在同一个线程里面执行,也可
启动线程执行(比如使用线程池)
string 字符串
类型操作:
set k liudh
keys *
exists key
type key
del key
unlink key 根据value选择非阻塞删除
仅将 keys 从 keyspace 元数据中删除,真正的删除会在后续的异步操作
expire key 10 10秒钟 设置过期时间
ttl key 查询还有多少秒过期 -1 永不过期 -2 表示已经过期
一个 key 的 value 最多可以是 512M
append k1 追加
strlen
setnx 存在的话 不执行 不存在的话 执行
incr 将key 中的存储的数字值+1
decr 将key 中存储的数字值 - 1
incrby
decrby
mset k1 v1 k2 v2 k3 v3
mget k1 k2 k3
msetnx 同时设置一个 或者 多个key-value 对 当且仅当所有给定的
key都不存在 (有一个存在 将不成功)
getrange
127.0.0.1:6379> set name lucymary
OK
127.0.0.1:6379> get name
"lucymary"
127.0.0.1:6379> GETRANGE name 0 3
"lucy"
setrange
127.0.0.1:6379> GETRANGE name 0 3
"lucy"
127.0.0.1:6379> SETRANGE name 3 aaa
(integer) 8
127.0.0.1:6379> get name
"lucaaary"
setex
127.0.0.1:6379> SETEX age 20 value30
OK
127.0.0.1:6379> get age
"value30"
127.0.0.1:6379> ttl age
(integer) 7
getset 旧值换新值
127.0.0.1:6379> GETSET name aaa
"lucaaary"
127.0.0.1:6379> get name
"aaa"
--------------------------------------------------------
list 列表
单键多值:
lpush rpush 从左边/右边 插入一个或者多个值
127.0.0.1:6379> LPUSH k1 v1 v2 v3
(integer) 3
127.0.0.1:6379> LRANGE k1 0 -1
1) "v3"
2) "v2"
3) "v1"
127.0.0.1:6379> RPUSH k2 v1 v2 v3
(integer) 3
127.0.0.1:6379> LRANGE k2 0 -1
1) "v1"
2) "v2"
3) "v3"
lpop rpop 从左边/右边吐出一个值 值在键在,值光键亡
127.0.0.1:6379> LPOP k1
"v3"
127.0.0.1:6379> RPOP k2
"v3"
rpoplpush key1 key2 从 key1 列表右边吐出一个值,插到 key2 列表的左边
127.0.0.1:6379> RPOPLPUSH k1 k2
"v1"
127.0.0.1:6379> LRANGE k1 0 -1
1) "v3"
2) "v2"
127.0.0.1:6379> LRANGE k2 0 -1
1) "v1"
2) "v1"
3) "v2"
lrange key start stop 按照索引下标获得元素 (从左到右)
lindex key index 按照索引下标获取元素(从左到右)
llen 获得列表长度
127.0.0.1:6379> LLEN k1
(integer) 2
127.0.0.1:6379> LLEN k2
(integer) 3
linsert
lrem
lset
set 集合 自动排重 ,但你需要存储一个列表数据,又不希望重复,set 是个很好的选择
set 是 string类型的无序集合,他底层实际是一个value为null 的hash表
所以添加 删除 查询复杂度都是 0(1)
127.0.0.1:6379> SADD k1 a b c
(integer) 3
127.0.0.1:6379> SMEMBERS k1
1) "b"
2) "a"
3) "c"
127.0.0.1:6379> SISMEMBER k1 c
(integer) 1
127.0.0.1:6379> SISMEMBER k1 cc
(integer) 0
127.0.0.1:6379> SCARD k1
(integer) 3
127.0.0.1:6379> SREM k1 a b
(integer) 2
127.0.0.1:6379> SCARD k1
(integer) 1
127.0.0.1:6379> SMEMBERS k1
1) "c"
sadd key value1 value2 将一个或者多个member元素加入到集合key中,已经存在的member元素将被忽略
smembers key 取出该集合所有值
sismember key value 判断集合key是否为该value值 有1 没有0
scard key 返回集合的元素个数
srem key value1 value2 删除集合中的某个元素
spop key 随机从集合中吐出一个值
127.0.0.1:6379> SPOP k1
"c"
127.0.0.1:6379> SPOP k1
(nil)
srandmember key n 随机从集合中吐出n个值,不会从集合中删除
smove source destination value 把集合中一个值从一个集合移动到另个集合
sinter key1 key2 返回两个集合交集元素
sunion key1 key2 返回两个集合并集元素
sdiff key1 key2 返回两个集合差集元素(key1 中 不包含key2中的)
hash 是一个键值对的集合 ,是一个string类型的 field 和 value 的映射表,hash特别
适用于存储对象
hset key field value 给 key 集合中的field 键 复制value
hget key field 从key1 集合 field 取出 value
127.0.0.1:6379> HSET user:1001 id 1
(integer) 1
127.0.0.1:6379> HSET user:1001 name zhangsan
(integer) 1
127.0.0.1:6379> HGET user:1001 id
"1"
127.0.0.1:6379> HGET user:1001 name
"zhangsan"
hmset key1 field value1 field2 value2.。。 批量设置hash值
127.0.0.1:6379> HMSET user:1002 id 1 name liudh age 30
OK
127.0.0.1:6379> HGET user:1002 id
"1"
127.0.0.1:6379> HGET user:1002 name
"liudh"
127.0.0.1:6379> HGET user:1002 age
"30"
hexists key1 field 查看哈希表 key 中 给定域 field 是否存在
127.0.0.1:6379> HEXISTS user:1002 age
(integer) 1
127.0.0.1:6379> HEXISTS user:1002 name
(integer) 1
127.0.0.1:6379> HEXISTS user:1002 sex
(integer) 0
hkeys key 列出该hash 集合所有的 field
hvals key 列出该hash 集合所有的 value
127.0.0.1:6379> HKEYS user:1001
1) "id"
2) "name"
127.0.0.1:6379> HVALS user:1001
1) "1"
2) "zhangsan"
hincrby key field increment 为哈希表 key 中的 域 field 值 增量 1 -1
hsetnx key field value 将 哈希表 key 中的 域 field 值设置为value 当且仅当域field不存在
127.0.0.1:6379> HINCRBY user:1002 age 2
(integer) 32
127.0.0.1:6379> HSETNX user:1002 age 40
(integer) 0
127.0.0.1:6379> HSETNX user:1002 gender 40
(integer) 1
zset 有序集合 没有重复元素的字符串集合
zadd 将一个或者多个member元素机器score值加入到有序集 key 当中
zrange key start stop 【withscores】 返回有序集 key 中 下表在 start 到 stop 之间的元素
127.0.0.1:6379> ZADD topn 200 java 300 c++ 400 mysql 500 php
(integer) 4
127.0.0.1:6379> ZRANGE topn 0 -1
1) "java"
2) "c++"
3) "mysql"
4) "php"
127.0.0.1:6379> ZRANGE topn 0 -1 withscores
1) "java"
2) "200"
3) "c++"
4) "300"
5) "mysql"
6) "400"
7) "php"
8) "500"
zrangebyscore by minmax 【withscores】 返回有序集 key 中 所有score 值 介于 min max 之间 包含min max 成员
127.0.0.1:6379> ZRANGebyscore topn 200 300
1) "java"
2) "c++"
zrevrangebyscore key 规则为 从大到小
127.0.0.1:6379> ZrevRANGebyscore topn 500 300
1) "php"
2) "mysql"
3) "c++"
127.0.0.1:6379> ZrevRANGebyscore topn 500 300 withscores
1) "php"
2) "500"
3) "mysql"
4) "400"
5) "c++"
6) "300"
zincrby key increment value 为 元素 score 加上增量
127.0.0.1:6379> ZINCRBY topn 10 php
"510"
127.0.0.1:6379> ZrevRANGebyscore topn 600 300 withscores
1) "php"
2) "510"
3) "mysql"
4) "400"
5) "c++"
6) "300"
zrem topn php 删除集合下 指定的元素
zcount key min max 统计该集合 分数区间内的元素个数
zrank key value 返回改制的集合中的排名 从 0 开始
127.0.0.1:6379> ZRANGE topn 0 -1 withscores
1) "java"
2) "200"
3) "c++"
4) "300"
5) "mysql"
6) "400"
7) "php"
8) "510"
127.0.0.1:6379> ZRANK topn mysql
(integer) 2
redis 配置文件------------
bind 127.0.0.1 -::1 一般配置本地Ip
protected-mode yes yes 修改为 NO 支持远程链接访问
tcp-backlog 511 设置tcp 的backlog, 其实就是一个链接队列,backlog队列
总和=未完成三次握手的队列 + 已经完成三次握手的队列
在高并发的环境下 你需要一个高backlog 值 来避免慢客户端连接问题
linux 内核会将这个值 减小到
[root@master ~]# cat /proc/sys/net/core/somaxconn
128
所以需要增大 /proc/sys/net/core/somaxconn 和
[root@master ~]# cat /proc/sys/net/ipv4/tcp_max_syn_backlog
128
来达到想要的效果
tcp-keepalive 300 心跳连接 , 连接上不操作 300秒 直接断开
daemonize yes 后台启动
pidfile /var/run/redis_6379.pid
loglevel notice log 级别
logfile "" 文件路径
databases 16
requirepass 设置密码
[root@master ~]# redis-cli
127.0.0.1:6379> CONFIG GET requirepass
1) "requirepass"
2) ""
127.0.0.1:6379> CONFIG SET requirepass '123456'
OK
127.0.0.1:6379> CONFIG GET requirepass
1) "requirepass"
2) "123456"
127.0.0.1:6379> auth 123456
OK
127.0.0.1:6379> CONFIG GET requirepass
1) "requirepass"
2) "123456"
maxclients 10000 客户端最大连接数
maxmemory 建议必须设置,否则 内存占满 造成服务器宕机,一旦到达内存使用上线
redis 将会试图移除内部数据,移除规则可以通过
maxmemory-policy 来指定
volatile-lru 使用lru算法移除key,只对设置了过期时间的key
allkeys-lru 在所有集合 key 中,使用lru算法移除key
volatile-random 在过期集合中移除随机的key 只对设置了过期时间的键
allkey-random 在所有集合 key 中 移除随机的key
volatile-ttl 移除那些ttl值最小的key 即那些最近要过期的key
noeviction 不进行移除 针对写操作,只是返回错误信息
redis 发布和订阅------------
redis 发布订阅是一种消息通信模式 发送者pub 发送消息,订阅者 sub 接收消息
redis 客户端可以订阅任意数量的频道
SUBSCRIBE channel1 订阅者
PUBLISH channel1 111 发布
redis 新数据类型------------新数据类型------------新数据类型------------新数据类型------------
bitmaps 本身不是一种数据类型,实际上他就是字符串 key-value 但是他可以对
字符串的位经行操作
实例:
每个独立用户是否访问过网站存放在bitmaps中,将访问的用户记做1,
没有访问的记做0 ,用偏移量作为用户的ID
127.0.0.1:6379> SETBIT user:20220321 1 1
(integer) 0
127.0.0.1:6379> SETBIT user:20220321 6 1
(integer) 0
127.0.0.1:6379> SETBIT user:20220321 11 1
(integer) 0
127.0.0.1:6379> SETBIT user:20220321 19 1
(integer) 0
127.0.0.1:6379> GETBIT user:20220321 6
(integer) 1
127.0.0.1:6379> GETBIT user:20220321 1
(integer) 1
127.0.0.1:6379> GETBIT user:20220321 11
(integer) 1
127.0.0.1:6379> GETBIT user:20220321 19
(integer) 1
计算访问用户数据量:
127.0.0.1:6379> BITCOUNT user:20220321
(integer) 4
setbit user:20220322 0 1
setbit user:20220322 1 1
setbit user:20220322 11 1
setbit user:20220322 14 1
计算出两天都访问过的网站用户数量:
and 交集 or 并集 not 非 xor 异或
127.0.0.1:6379> bitop and user:and:20220322_21 user:20220322 user:20220321
(integer) 3
bitmaps 与 set 对比
每个用户ID 占用空间 需要存储的用户量 全部内存
set 64位 50000000 64*50000000=400M
bitmaps 1位 100000000 1*1000000000=12.5M
但bitmaps 不是万金油 假如网站的每天独立访问用户很少,只有10W,那么两者对比 如下
每个用户ID 占用空间 需要存储的用户量 全部内存
set 64位 1000000 64*1000000=800KB
bitmaps 1位 100000000 1*1000000000=12.5M
HyperLogLog 在工作中 经常遇到与统计相关的功能需求,比如统计网站PV 可以
使用redis 的 incr incrby 轻松实现
但像UV 单独访客 单独IP 数 搜索记录数等要去重和计数问题如何解决
这种求集合中不重复元素个数的问题成为基数问题
解决基数问题很多种方案:
1:数据存储在mysql 表中 使用distinct count 计算不重复的个数
2:使用redis提供的hash set bitmaps 等数据结构来处理
以上方案结果精确,但随着数据的不断增加,导致占用空间越来越多,对于非常大
的数据集是不切实际的
redis hyperLoglog 是用来做基数统计的算法,Hyperloglog 优点是 在输入元素的数量或者体积
非常大时,计算基数所需要的空间总是固定的,并且是很小的
reids 里面 每个hyperloglog 键 只需要花费12Kb 内存,就可以计算接近2^64个不同元素的基数
比如基数集{1,3,5,7,5,7,8} 那么这个基数集为{1,3,5,7,8}基数为5 ,基数估计
就是再误差可接受范围内,快速计算基数
pfadd
127.0.0.1:6379> PFADD progam "java"
(integer) 1
127.0.0.1:6379> PFADD progam "php"
(integer) 1
127.0.0.1:6379> PFADD progam "java"
(integer) 0
127.0.0.1:6379> PFADD progam "c++" "mysql"
(integer) 1
127.0.0.1:6379> PFADD progam "c++" "mysql" "oracle"
(integer) 1
127.0.0.1:6379> PFCOUNT progam
(integer) 5
pfmerge
127.0.0.1:6379> PFCOUNT progam
(integer) 5
127.0.0.1:6379> PFADD k1 a
(integer) 1
127.0.0.1:6379> PFADD k1 b
(integer) 1
127.0.0.1:6379> PFCOUNT k1
(integer) 2
127.0.0.1:6379> PFMERGE k100 k1 progam
OK
127.0.0.1:6379> PFCOUNT k100
(integer) 7
Geospatial GEO缩写,地理信息 就是元素的2维坐标,再地图上就是经纬度
reids基于该类型 提供了经纬度设置,查询,范围查询,距离查询,经纬度hash等常见操作
geoadd
127.0.0.1:6379> GEOADD china:city 121.47 31.23 shanghai
(integer) 1
127.0.0.1:6379> GEOADD china:city 106.50 29.53 chongqing 114.05 22.52 shenzhen 116.38 39.90 beijing
(integer) 3
127.0.0.1:6379>
GEOPOS
127.0.0.1:6379> GEOPOS china:city shanghai
1) 1) "121.47000163793563843"
2) "31.22999903975783553"
127.0.0.1:6379> GEOPOS china:city beijing
1) 1) "116.38000041246414185"
2) "39.90000009167092543"
127.0.0.1:6379>
GEODIST 两个城市 直线距离 m 米 默认是 米 km 千米 mi 英里 ft 英尺
127.0.0.1:6379> GEODIST china:city beijing shanghai
"1068153.5181"
127.0.0.1:6379> GEODIST china:city beijing shanghai km
"1068.1535"
127.0.0.1:6379>
georadius 以给定的经纬度为中心 找出某一半内径的元素
经度 维度 距离 单位
127.0.0.1:6379> GEORADIUS china:city 110 30 1000 km
1) "chongqing"
2) "shenzhen"
Jedis 操作 redis
jedis 模拟验证码发送
springBoot整合redis
事务操作
redis 事务时一个单独的隔离操作,事务中的所有命令都会序列化,按照顺序地执行,事务在
执行过程中 不会被其他客户端发送来的命令请求所打断
redis 事务的主要作用是串联多个命令防止别的命令插队
从输入Multi 命令开始,输入的命令会一次进入命令队列中, 但不会执行,直到输入exec
后,redis会将之前的命令队列中的命令依次执行
组队的过程中可以通过discard 来放弃组队
Multi Exec/discard
127.0.0.1:6379> MULTI
OK
127.0.0.1:6379(TX)> set key1 value1
QUEUED
127.0.0.1:6379(TX)> set key2 value2
QUEUED
127.0.0.1:6379(TX)> exec
1) OK
2) OK
127.0.0.1:6379> get key1
"value1"
127.0.0.1:6379> get key2
"value2"
事务的错误处理
127.0.0.1:6379> MULTI
OK
127.0.0.1:6379(TX)> set b1 v1
QUEUED
127.0.0.1:6379(TX)> set b2 v2
QUEUED
127.0.0.1:6379(TX)> set b3
(error) ERR wrong number of arguments for 'set' command
127.0.0.1:6379(TX)> exec
(error) EXECABORT Transaction discarded because of previous errors.
127.0.0.1:6379> DISCARD
(error) ERR DISCARD without MULTI
127.0.0.1:6379> MULTI
OK
127.0.0.1:6379(TX)> set c1 v1
QUEUED
127.0.0.1:6379(TX)> INCR c1
QUEUED
127.0.0.1:6379(TX)> EXEC
1) OK
2) (error) ERR value is not an integer or out of range
127.0.0.1:6379> get c1
"v1"
事务冲突问题
一个请求想给金额减去8000
一个请求想给金额减去5000
一个请求想给金额将去1000
悲观锁 :每次拿数据的时候都认为别人会修改,所以每次在拿数据的时候会上锁,这样别人
想拿这个数据就会block直到它拿到锁,传统的关系型数据库里面就用到了很多这种
锁的机制,比如 行锁 表锁等,读锁 写锁,都是在操作之前先上锁
乐观锁 :每次拿数据的时候都认为别人不会修改,所以不会上锁,但是在更新的时候会
判断一下再次期间别人有没有去更新这个数据,可以使用版本号等机制,乐观锁用于多读的
应用类型,这样可以提高吞吐量,redis 就是利用这种 check-and-set 机制实现事务的
watch key
在执行multi之前 先执行 watch key1 可以监视一个或者多个key ,如果在事务执行之前这个key
被其他命令所改动,那么事务将被打断
开启两个窗口:
窗口1:
127.0.0.1:6379> KEYS *
1) "balance"
127.0.0.1:6379> WATCH balance
OK
127.0.0.1:6379> MULTI
OK
127.0.0.1:6379(TX)> INCRBY balance 10
QUEUED
127.0.0.1:6379(TX)> EXEC 先执行 提交
1) (integer) 110
窗口2:
127.0.0.1:6379> WATCH balance
OK
127.0.0.1:6379> MULTI
OK
127.0.0.1:6379(TX)> INCRBY balance 20
QUEUED
127.0.0.1:6379(TX)> EXEC 后执行的提交 结果是 空
(nil)
127.0.0.1:6379>
unwatch 取消watch 命令对所有key 的监视
如果在执行watch 命令后,exec命令或者discard命令先被执行的话 那么就不需要再执行unwatch 了
reids 事务三特性
单独的隔离操作
事务中的所有命令都会序列化,按照顺序执行,事务再执行的过程中,不会被其他客户端发来的命令请求打断
没有隔离级别的概念
队列中的命令没有提交之前不会实际被执行,因为事务提交前任何指令都不会实际执行
不保证原子性
事务中如果有一条命令执行失败,后面的命令仍然会被执行,没有回滚
reids 事务秒杀案例
reids 事务秒杀案例 ab工具模拟并发 centos6 默认已经安装, centos7 yum install httpd-tools
reids 事务秒杀案例 超卖和超时问题解决
reids 事务秒杀案例 库存遗留问题
reids 持久化操作 两个持久化方式 两个方式都开启清理,系统默认AOF 数据(数据不会存在丢失)
RDB reids Database
在指定的 时间间隔 内 将内存的数据集快照写入磁盘,也就是行话说的snapshot 快照
他恢复时 将快照读取到内存
redis 会单独创建fock 一个子进程 来经行持久化,会先将数据写入到一个临时文件中,待
持久化过程都结束了,在用这个临时文件替换上次持久化好的文件, 整个过程中,主进程是不
进行任何的IO操作,这就确保了极高的性能,如果需要经行大规模数据恢复,且对于数据恢复的
完整性不是非常的敏感,那RDB方式要比AOF方式更加高效,RDB 缺点就是最后一次持久化后的数据可能丢失
配置文件里面 有参数
dbfilename dump.rdb
dir ./
stop-writes-on-bgsave-error yes 当硬盘满了 就不在写如操作
rdbcompression yes 是否压缩存储
rdbchecksum yes 检查完整性 大约10%的性能消耗
# save 3600 1
# save 300 100
# save 60 10000
redis 在fork时用了 写时拷贝技术 但是如果数据庞大时候还是比较消耗性能
fork 时候 内存中的数据 被克隆了一份 大致2 倍的膨胀性 需要考虑
在备份周期在一定间隔时间做一次备份,所以如果redis 意外down 掉的话 就会丢失最后
一次快照后的修改
动态停止备份:
redis-cli config set save "" save给空置 表示禁用保存策略
AOF append OfFile 默认不开启
以日志的形式来记录每个写的操作 增量保持,将redis执行过的所有写的指令记录下来
(读操作不记录) 只需要追加文件但不可以改写文件,redis 启动之初会读取该文件的
重新构建数据,换言之 redis 重启的话 就根据日志文件的内容将写的指令从前到后执行一次
以完成数据的恢复工作
appendonly yes
appendfilename "appendonly.aof"
异常恢复:
修改默认的appendonly no 为 yes
如果遇到AOF 文件损坏 通过/usr/local/bin/redis-check-aof --fix appendonly.aof恢复
[root@master bin]# redis-check-aof --fix appendonly.aof
AOF analyzed: size=147, ok_up_to=147, ok_up_to_line=34, diff=0
AOF is valid
AOF文件损坏 会造成redis 启动失败 所以要修复
AOF 同步频率设置
appendfsync always
始终同步,每次redis 的写入都会立刻计入日志,性能比较差但数据完整性比较好
appendfsync everysec
每秒同步,每秒计入日志一次,如果当即,本秒的数据可能丢失
appendfsync no
redis 不主动同步,把同步的时机交给操作系统
rewrite 压缩
重写原理:
AOF 文件持续增长过大时候,会fork 出一条新的进程将文件重写 也就是先写临时文件最后再rename
redis4.0 版本后的重写 是指上就是把rdb的快照,以二进制的形式附在新的aof头部 作为已有的历史数据,替换掉原来的流水账操作
no-appendfsync-on-rewrite:
如果 no-appendfsync-on-rewrite = yes 不写入aof文件 只写入缓存,用户请求不会阻塞,但是他可以对
在这段时间如果宕机会丢失这段时间的缓存数据(降低数据安全性,提高性能)
如果 no-appendfsync-on-rewrite=no 还是会把数据往磁盘里面刷,但是遇到重新操作 可能发生组设(数据安全,但性能降低)
触发机制 何时重写
redis 会记录上次重写的 AOF 大小,默认值是当AOF 文件大小是上次rewrite后的大小的一倍
且文件大于64M时触发
AOF 持久化流程
1:客户端的请求写明了会被apped 追加到AOF 缓冲区内
2:AOF缓冲区根据AOF 持久化策略【always,everysec,no】 将操作的sync 同步到磁盘AOF文件中
3:AOF文件大小超过重写策略或手动重写时,会对AOF文件rewrite重写,压缩AOF文件容量
4:redis 服务重启时,会重新load 加载Aof文件中的写操作到达数据恢复的目的
reids 主从复制:
[root@master myreids]# cat redis6379.conf
include /usr/myreids/redis.conf
pidfile /usr/myreids/redis_6379.pid
port 6379
dbfilename dump6379.rdb
[root@master myreids]# cat redis6380.conf
include /usr/myreids/redis.conf
pidfile /usr/myreids/redis_6380.pid
port 6380
dbfilename dump6380.rdb
[root@master myreids]# cat redis6381.conf
include /usr/myreids/redis.conf
pidfile /usr/myreids/redis_6381.pid
port 6381
dbfilename dump6381.rdb
redis-server /usr/myreids/redis6379.conf
redis-server /usr/myreids/redis6380.conf
redis-server /usr/myreids/redis6381.conf
INFO replication
slaveof ip port 就可以搭建主从复制关系
127.0.0.1:6380> SLAVEOF 192.168.228.128 6379
OK
127.0.0.1:6381> SLAVEOF 192.168.228.128 6379
OK
127.0.0.1:6379> info replication
# Replication
role:master
connected_slaves:2
slave0:ip=192.168.228.128,port=6380,state=online,offset=42,lag=0
slave1:ip=192.168.228.128,port=6381,state=online,offset=42,lag=0
master_failover_state:no-failover
master_replid:ed575fa2e263b7624b59f196455c171e98105c65
master_replid2:0000000000000000000000000000000000000000
master_repl_offset:42
second_repl_offset:-1
repl_backlog_active:1
repl_backlog_size:1048576
repl_backlog_first_byte_offset:1
repl_backlog_histlen:42
slave 宕机后 重新启动后 要重新操作 slaveof 操作
启动后 直接从主库拉去 重新全库数据,并且保证 主从一致
主服务器挂后,从服务器 正常不会选主
主服务器 重启后,还是主服务器,还是老大哥
主从复制原理:
1:当从连接上主服务后,从服务器向主服务发送经行数据同步消息
2:主服务器连接到从服务器过来的同步消息,把主服务器数据经行持久化rdbs文件,把rdb文件发送
从服务器,从服务器拿到rdb 进行读取
3:每次主服务器经行写操作后,和从服务器经行数据同步
薪火相传 : 上一个slave 可以时下一个slave 的 master,slave 同样可以接收其他slaves 的连接
和同步请求,那么该slave 作为了链条中的下一个master,可以有效减轻master 的写压力
去中心化降低风险
反客为主: slaveof no one 将从机变为主机
reids 哨兵模式(sentinel)
反客为主的自动版,能够后台监控主机是否故障,如果故障了 根据投票数自动将从库转换为主库
[root@master myreids]# cat sentinel.conf
sentinel monitor mymaster 192.168.228.128 6379 1 mymaster为监控对象起的服务器名称 后面 1 为至少有多少个哨兵同意迁移的数量
直接启动
redis-sentinel sentinel.conf
17460:X 25 Mar 2022 17:42:52.364 # +monitor master mymaster 192.168.228.128 6379 quorum 1
17460:X 25 Mar 2022 17:42:52.365 * +slave slave 192.168.228.128:6380 192.168.228.128 6380 @ mymaster 192.168.228.128 6379
17460:X 25 Mar 2022 17:42:52.367 * +slave slave 192.168.228.128:6381 192.168.228.128 6381 @ mymaster 192.168.228.128 6379
6379 下线 后 走的 选主 流程
17460:X 25 Mar 2022 17:55:09.901 # +sdown master mymaster 192.168.228.128 6379
17460:X 25 Mar 2022 17:55:09.901 # +odown master mymaster 192.168.228.128 6379 #quorum 1/1
17460:X 25 Mar 2022 17:55:09.901 # +new-epoch 1
17460:X 25 Mar 2022 17:55:09.901 # +try-failover master mymaster 192.168.228.128 6379
17460:X 25 Mar 2022 17:55:09.910 # +vote-for-leader e8d2dbd9e2c0e29c9d800427c48a1e0f7b94924c 1
17460:X 25 Mar 2022 17:55:09.911 # +elected-leader master mymaster 192.168.228.128 6379
17460:X 25 Mar 2022 17:55:09.911 # +failover-state-select-slave master mymaster 192.168.228.128 6379
17460:X 25 Mar 2022 17:55:09.972 # +selected-slave slave 192.168.228.128:6380 192.168.228.128 6380 @ mymaster 192.168.228.128 6379
17460:X 25 Mar 2022 17:55:09.972 * +failover-state-send-slaveof-noone slave 192.168.228.128:6380 192.168.228.128 6380 @ mymaster 192.168.228.128 6379
17460:X 25 Mar 2022 17:55:10.059 * +failover-state-wait-promotion slave 192.168.228.128:6380 192.168.228.128 6380 @ mymaster 192.168.228.128 6379
17460:X 25 Mar 2022 17:55:11.071 # +promoted-slave slave 192.168.228.128:6380 192.168.228.128 6380 @ mymaster 192.168.228.128 6379
17460:X 25 Mar 2022 17:55:11.071 # +failover-state-reconf-slaves master mymaster 192.168.228.128 6379
17460:X 25 Mar 2022 17:55:11.135 * +slave-reconf-sent slave 192.168.228.128:6381 192.168.228.128 6381 @ mymaster 192.168.228.128 6379
17460:X 25 Mar 2022 17:55:12.083 * +slave-reconf-inprog slave 192.168.228.128:6381 192.168.228.128 6381 @ mymaster 192.168.228.128 6379
17460:X 25 Mar 2022 17:55:12.083 * +slave-reconf-done slave 192.168.228.128:6381 192.168.228.128 6381 @ mymaster 192.168.228.128 6379
17460:X 25 Mar 2022 17:55:12.149 # +failover-end master mymaster 192.168.228.128 6379
17460:X 25 Mar 2022 17:55:12.149 # +switch-master mymaster 192.168.228.128 6379 192.168.228.128 6380
17460:X 25 Mar 2022 17:55:12.149 * +slave slave 192.168.228.128:6381 192.168.228.128 6381 @ mymaster 192.168.228.128 6380
17460:X 25 Mar 2022 17:55:12.149 * +slave slave 192.168.228.128:6379 192.168.228.128 6379 @ mymaster 192.168.228.128 6380
17460:X 25 Mar 2022 17:55:42.180 # +sdown slave 192.168.228.128:6379 192.168.228.128 6379 @ mymaster 192.168.228.128 6380
选举操作 :
1:slave-priorty/replica-priority 100 值越小,优先级别越高
2:选主偏移量最大的
3:选主runid 最小的从服务(每个redis 实例会随机生成一个 40位的runid)
启动 6379 后 自动加入 集群
[root@master myreids]# cat sentinel.conf
sentinel monitor mymaster 192.168.228.128 6380 1
# Generated by CONFIG REWRITE
protected-mode no
port 26379
user default on nopass ~* &* +@all
dir "/usr/myreids"
sentinel myid e8d2dbd9e2c0e29c9d800427c48a1e0f7b94924c
sentinel config-epoch mymaster 1
sentinel leader-epoch mymaster 1
sentinel current-epoch 1
sentinel known-replica mymaster 192.168.228.128 6379
sentinel known-replica mymaster 192.168.228.128 6381
复制延迟:
master 同步到slave 机器有一定的延迟,当系统很繁忙的时候 延迟问题会更加严重,slave 机器数量的增加会是
这个问题更加严重
redis 集群
容量不够
并发写操作redis 如何分摊
3。0 提供了解决方案 无中心化集群配置
什么是集群
redis 集群实现了对redis的水平扩容,即启动N个redis节点,将整个数据库分布存储在
N个节点中,每个节点存储总数居的1/N
redis 集群通过分区 partion 来提供一定程度的可用性 availability 即集群中有一部分节点失效
或者无法经行通讯,集群也可以继续处理命令请求
删除持久化数据
将rdb AOF文件都删除掉
制作6个实例 6379 6380 6381 6389 6390 6391
[root@master myreids]# cat redis6379.conf
include /usr/myreids/redis.conf
pidfile "/usr/myreids/redis_6379.pid"
port 6379
dbfilename "dump6379.rdb"
# 打开集群模式
cluster-enabled yes
# 设定节点配置文件名字
cluster-config-file nodes-6379.conf
# 设定节点失联时间,超过该时间(毫秒)集群自动经行主从切换
cluster-node-timeout 15000
-rw-r--r--. 1 root root 333 4月 3 15:16 redis6379.conf
-rw-r--r--. 1 root root 333 4月 3 15:36 redis6380.conf
-rw-r--r--. 1 root root 333 4月 3 15:36 redis6381.conf
-rw-r--r--. 1 root root 333 4月 3 15:37 redis6389.conf
-rw-r--r--. 1 root root 333 4月 3 15:38 redis6390.conf
-rw-r--r--. 1 root root 333 4月 3 15:38 redis6391.conf
启动:
[root@master myreids]# redis-server redis6379.conf
[root@master myreids]# redis-server redis6380.conf
[root@master myreids]# redis-server redis6381.conf
[root@master myreids]# redis-server redis6389.conf
[root@master myreids]# redis-server redis6391.conf
[root@master myreids]# redis-server redis6390.conf
[root@master myreids]# ps -ef |Grep redis
-bash: Grep: 未找到命令
[root@master myreids]# ps -ef |grep redis
root 4978 1 0 15:40 ? 00:00:00 redis-server 0.0.0.0:6379 [cluster]
root 4984 1 0 15:40 ? 00:00:00 redis-server 0.0.0.0:6380 [cluster]
root 4990 1 0 15:40 ? 00:00:00 redis-server 0.0.0.0:6381 [cluster]
root 4996 1 0 15:40 ? 00:00:00 redis-server 0.0.0.0:6389 [cluster]
root 5002 1 0 15:40 ? 00:00:00 redis-server 0.0.0.0:6391 [cluster]
root 5008 1 0 15:40 ? 00:00:00 redis-server 0.0.0.0:6390 [cluster]
root 5016 4793 0 15:41 pts/0 00:00:00 grep --color=auto redis
[root@master myreids]# ll
总用量 168
-rw-r--r--. 1 root root 114 4月 3 15:40 nodes-6379.conf
-rw-r--r--. 1 root root 114 4月 3 15:40 nodes-6380.conf
-rw-r--r--. 1 root root 114 4月 3 15:40 nodes-6381.conf
-rw-r--r--. 1 root root 114 4月 3 15:40 nodes-6389.conf
-rw-r--r--. 1 root root 114 4月 3 15:40 nodes-6390.conf
-rw-r--r--. 1 root root 114 4月 3 15:40 nodes-6391.conf
-rw-r--r--. 1 root root 333 4月 3 15:16 redis6379.conf
-rw-r--r--. 1 root root 5 4月 3 15:40 redis_6379.pid
-rw-r--r--. 1 root root 333 4月 3 15:36 redis6380.conf
-rw-r--r--. 1 root root 5 4月 3 15:40 redis_6380.pid
-rw-r--r--. 1 root root 333 4月 3 15:36 redis6381.conf
-rw-r--r--. 1 root root 5 4月 3 15:40 redis_6381.pid
-rw-r--r--. 1 root root 333 4月 3 15:37 redis6389.conf
-rw-r--r--. 1 root root 5 4月 3 15:40 redis_6389.pid
-rw-r--r--. 1 root root 333 4月 3 15:38 redis6390.conf
-rw-r--r--. 1 root root 5 4月 3 15:40 redis_6390.pid
-rw-r--r--. 1 root root 333 4月 3 15:38 redis6391.conf
-rw-r--r--. 1 root root 5 4月 3 15:40 redis_6391.pid
将 6个节点合成一个集群
合成集群钱,请确保redis 启动 后 nodes-xxxx.conf 文件都正常
cd /root/redis-6.2.6/src 切记 这个地方 要用到 源码路径 去执行 才能顺序 一主一从
[root@master myreids]# redis-cli --cluster create --cluster-replicas 1 192.168.145.128:6379 192.168.145.128:6380 192.168.145.128:6381 192.168.145.128:6389 192.168.145.128:6390 192.168.145.128:6391
--replicas 1 采用最简单的方式配置集群,一台主机 一台从机
M: 115557ce76ac902ac0c126c8ab1fb98957857841 192.168.145.128:6379
slots:[0-5460] (5461 slots) master
M: 2b4202a0674f02dac7028c4292bb2e21d52ecd88 192.168.145.128:6380
slots:[5461-10922] (5462 slots) master
M: 6d2c1fa7e8bc3096ae257381b654a85609d914b2 192.168.145.128:6381
slots:[10923-16383] (5461 slots) master
S: 4dff65ec5892cf43c091298789fbaa3ef89fe159 192.168.145.128:6389
replicates 115557ce76ac902ac0c126c8ab1fb98957857841
S: 3733986b31a40bc71a095a9f483386ad967d6de0 192.168.145.128:6390
replicates 2b4202a0674f02dac7028c4292bb2e21d52ecd88
S: 40e2b454bb9e4f9a8671b7ed962330e3638bcef3 192.168.145.128:6391
replicates 6d2c1fa7e8bc3096ae257381b654a85609d914b2
[OK] All nodes agree about slots configuration.
>>> Check for open slots...
>>> Check slots coverage...
[OK] All 16384 slots covered.
链接集群 命令 设置数据会自动切换到相应的主机
redis-cli -c -p 6379
查看集群节点:
192.168.145.128:6379> CLUSTER NODES
6d2c1fa7e8bc3096ae257381b654a85609d914b2 192.168.145.128:6381@16381 master - 0 1648972661000 3 connected 10923-16383
3733986b31a40bc71a095a9f483386ad967d6de0 192.168.145.128:6390@16390 slave 2b4202a0674f02dac7028c4292bb2e21d52ecd88 0 1648972661153 2 connected
115557ce76ac902ac0c126c8ab1fb98957857841 192.168.145.128:6379@16379 myself,master - 0 1648972659000 1 connected 0-5460
40e2b454bb9e4f9a8671b7ed962330e3638bcef3 192.168.145.128:6391@16391 slave 6d2c1fa7e8bc3096ae257381b654a85609d914b2 0 1648972662177 3 connected
4dff65ec5892cf43c091298789fbaa3ef89fe159 192.168.145.128:6389@16389 slave 115557ce76ac902ac0c126c8ab1fb98957857841 0 1648972661000 1 connected
2b4202a0674f02dac7028c4292bb2e21d52ecd88 192.168.145.128:6380@16380 master - 0 1648972663199 2 connected 5461-10922
192.168.145.128:6379>
执行:
127.0.0.1:6379> set name liudh
-> Redirected to slot [5798] located at 192.168.145.128:6380
OK
192.168.145.128:6380> set v1 k1
-> Redirected to slot [1165] located at 192.168.145.128:6379
OK
分配原则
尽量保证每个主数据库运行在不同的IP地址,每个主库和从库不在一个IP地址上
什么是 slots 0 -16383 共 16384 个插槽
0-5460 5461-10922 10923-10383
这个报错要看懂
192.168.145.128:6379> mset name liudh age 30 address beijing
(error) CROSSSLOT Keys in request don't hash to the same slot
查看集群中的值
192.168.145.128:6381> CLUSTER KEYSLOT name
(integer) 5798
192.168.145.128:6380> set name1 zhang
-> Redirected to slot [12933] located at 192.168.145.128:6381
OK
192.168.145.128:6381> CLUSTER COUNTKEYSINSLOT 12933
(integer) 1
192.168.145.128:6381> CLUSTER GETKEYSINSLOT 12933 1
1) "name1"
故障恢复
如果主节点下线 从节点能否自动升级为主机点? 注意 15秒超时
关闭 6381 的 节点 192.168.145.128:6381> shutdown
127.0.0.1:6379> CLUSTER nodes
6381 已经断开了 6d2c1fa7e8bc3096ae257381b654a85609d914b2 192.168.145.128:6381@16381 master,fail - 1648977199466 1648977195375 3 disconnected
3733986b31a40bc71a095a9f483386ad967d6de0 192.168.145.128:6390@16390 slave 2b4202a0674f02dac7028c4292bb2e21d52ecd88 0 1648977271166 2 connected
115557ce76ac902ac0c126c8ab1fb98957857841 192.168.145.128:6379@16379 myself,master - 0 1648977272000 1 connected 0-5460
6391 已经成主了 40e2b454bb9e4f9a8671b7ed962330e3638bcef3 192.168.145.128:6391@16391 master - 0 1648977272198 7 connected 10923-16383
4dff65ec5892cf43c091298789fbaa3ef89fe159 192.168.145.128:6389@16389 slave 115557ce76ac902ac0c126c8ab1fb98957857841 0 1648977274247 1 connected
2b4202a0674f02dac7028c4292bb2e21d52ecd88 192.168.145.128:6380@16380 master - 0 1648977273219 2 connected 5461-10922
127.0.0.1:6379>
再启动6381 看看
[root@master myreids]# redis-server redis6381.conf
[root@master myreids]# ps -ef |grep redis
root 4978 1 0 15:40 ? 00:00:15 redis-server 0.0.0.0:6379 [cluster]
root 4984 1 0 15:40 ? 00:00:14 redis-server 0.0.0.0:6380 [cluster]
root 4996 1 0 15:40 ? 00:00:14 redis-server 0.0.0.0:6389 [cluster]
root 5002 1 0 15:40 ? 00:00:14 redis-server 0.0.0.0:6391 [cluster]
root 5008 1 0 15:40 ? 00:00:14 redis-server 0.0.0.0:6390 [cluster]
root 5250 1 0 17:16 ? 00:00:00 redis-server 0.0.0.0:6381 [cluster]
可以看到 6381 已经是 6391 的slave 了
127.0.0.1:6379> CLUSTER nodes
6d2c1fa7e8bc3096ae257381b654a85609d914b2 192.168.145.128:6381@16381 slave 40e2b454bb9e4f9a8671b7ed962330e3638bcef3 0 1648977451000 7 connected
3733986b31a40bc71a095a9f483386ad967d6de0 192.168.145.128:6390@16390 slave 2b4202a0674f02dac7028c4292bb2e21d52ecd88 0 1648977449415 2 connected
115557ce76ac902ac0c126c8ab1fb98957857841 192.168.145.128:6379@16379 myself,master - 0 1648977449000 1 connected 0-5460
40e2b454bb9e4f9a8671b7ed962330e3638bcef3 192.168.145.128:6391@16391 master - 0 1648977450439 7 connected 10923-16383
4dff65ec5892cf43c091298789fbaa3ef89fe159 192.168.145.128:6389@16389 slave 115557ce76ac902ac0c126c8ab1fb98957857841 0 1648977451467 1 connected
2b4202a0674f02dac7028c4292bb2e21d52ecd88 192.168.145.128:6380@16380 master - 0 1648977445325 2 connected 5461-10922
思考题:
如果所有某一段插槽的主从节点都宕机 redis 服务是否可以继续?
如果某一段插槽的主从都挂掉,而cluster-require-full-coverage 为 yes 那么整个集群都挂掉
如果某一段插槽的主从都挂掉,而cluster-require-full-coverage 为 no , 那么 该插槽的数据全部都不能使用,也无法存储
redis.conf 中的参数 cluster-require-full-coverage 去设置
集群的有点:
实现扩容
分摊压力
无中心化集群配置简单
集群的不足:
多建操作是不被支持的
多建的redis事务是不被支持的,lua 脚本不被支持
由于集群方案出现的比较晚,很多公司采用了其他集群方案,而代理或者客户端分片的方案想要迁移到
redis cluster 需要整体迁移而不是过渡迁移,复杂度较大
应用问题解决
缓存穿透
1 应用服务器压力变大
2 redis命中率降低
3 一直查询数据库
造成 redis 查询不到数据
出现很多非正常url 访问
解决方案:
对空置缓存
如果一个查询返回的数据为空,不管是否存在,我们仍然把这个空的结果 null 经常缓存,
这是空结果的过期时间很短,最长不超过5分钟
设置可访问的名单(白名单)
使用bitmaps类型定义一个可以访问的名单,名单的id 作为了bitmaps 偏移量
每次访问和bitmap 里面的ip 经行比较,如果访问的id 不在bitmaps 里面 惊醒拦截,不允许访问
采用布隆过滤器
进行实时监控
当发现redis 命中率开始急速下降,需要排查访问对象和访问的数据,和运维人员配合,设置黑名单限制
缓存击穿
1 数据访问压力瞬间增加
2 redis 的key没有大量过期
3 redis 正常的运行,但数据库已经压力很大
key 对应的数据存在,但在redis 中过期,此时如果有大量并大请求过来,这些请求发现缓存过期一般都会从
后端DB 加载数据并且回设到缓存,这个时候大并发的请求可能瞬间把后端DB 压垮
redis 某个key 过期了,大量访问使用这个key
解决方案:
预先设置热门数据
在redis 高峰访问之前,把一些热门数据提前存放到 redis 里面,加大这些热门数据 key 的时长
实时调整
现场监控哪些数据热门,实时调整key 的过期时长
使用锁
就是在缓存失效的时候(判断拿出来值为空)不是立即去load db
先使用缓存工具的某些带成功操作返回值的操作(比如 redis 的setnx)
缓存雪崩
key 对应的数据存在,但是在redis 中过期,此时有大量并发过来,这些请求发现缓存过期一般都会从
后端db 加载数据并且回设到缓存, 这个时候大并发的请求可能会瞬间把后端db 压垮
缓存雪崩和缓存击穿区别在于这里针对 很多 key 缓存,前者是 某一个key
解决方案:
构建多级缓存架构,nginx缓存+redis缓存+其他缓存等
使用锁或者队列
用加锁或者队列的方式保证不会有大量的线程对数据库一次性进行读写,从而避免失效的大量的并发请求落
到底层存储系统上,不适用高并发情况
设置过期标志更新缓存
将缓存失效时间分散开
分布式锁
主流的实现方案
1 基于数据库实现分布式锁
2 基于缓存 redis
3 基于 zookeeper
设置锁和过期时间
redis 使用setnx上锁,通过del 释放锁
锁一直没有释放,可以设置key 过期时间,自动释放
上锁后突然出现异常,无法设置过期时间
可以用上锁时候 设置过期时间 set user 10 nx ex 12
uuid防止误删
lua保证删除的原子性
新功能: 权限设置 IO多线程 工具支持cluster
[root@master myreids]# redis-cli
127.0.0.1:6379> acl list
1) "user default on nopass sanitize-payload ~* &* +@all"
127.0.0.1:6379> ACL setuser travelsky
OK
127.0.0.1:6379> acl list
1) "user default on nopass sanitize-payload ~* &* +@all"
2) "user travelsky off &* -@all"
127.0.0.1:6379> acl whoami
"default"
127.0.0.1:6379> acl setuser liudh on >woshimima ~cached:* +get
OK
127.0.0.1:6379> acl list
1) "user default on nopass sanitize-payload ~* &* +@all"
2) "user liudh on #229123a6f531553c9fe14d91deaacdd1cb6b0ace04c405bb1c50cded3b423d12 ~cached:* &* -@all +get"
3) "user travelsky off &* -@all"
切换用户登录
127.0.0.1:6379> auth liudh woshimima
OK
127.0.0.1:6379> acl whoami
(error) NOPERM this user has no permissions to run the 'acl' command or its subcommand
127.0.0.1:6379> set aaa aaa
(error) NOPERM this user has no permissions to run the 'set' command or its subcommand
127.0.0.1:6379> get cached:111
(nil)
多线程 io-threads-do-reads yes
io-threads 4
工具支持 cluster
redis 碎片整理 http://www.javashuo.com/article/p-agdjgpgb-nu.html
一、什么是redis内存碎片?
由于一块连续空闲的空间比所要申请的空间小,导致这块空间不可用,对于内存整体来说就是内存碎片。
二、redis内存碎片产生原因
常用的增删改redis都会产生一定的碎片。
1.写入数据
内存是根据分配策略固定的大小来划分内存空间的 , 为了减少分配次数,Redis 会根据申请的内存最接近的固定值分配相应大小的空间。
2.修改数据
键值对进行修改时,可能会变大也会变小,相应的就会占用额外空间或者释放不用的空间。
3.删除数据
删除某个value后,删除了字节,释放了空间。
三、redis内存碎片危害性
在 Redis 中,由于大量的碎片存在,会导致实际利用率变低。
四、如何解决
1.版本低于4.0
如果你的Redis版本是4.0以下的,Redis服务器重启后,Redis会将没用的内存归还给操作系统,碎片率会降下来。
2.版本高于4.0
可以在不重启的情况下,线上整理内存碎片 ,自动碎片清理,只要设置了如下的配置,内存就会自动清理了
config set activedefrag yes
下面参数都是满足任一条件后就可以进行清理:
active-defrag-ignore-bytes 100mb:表示内存碎片的字节数达到 100MB 时,开始清理;
active-defrag-threshold-lower 20:表示内存碎片空间占操作系统分配给 Redis 的总空间比例达到 20% 时,开始清理。
active-defrag-threshold-upper 100 :表示内存碎片超过 100%,尽最大清理。
Redis 同时还提供了监控 CPU 占用比例的参数,在满足以下条件时才会保证清理正常开展:
active-defrag-cycle-min 25: 表示自动清理过程所用 CPU 时间的比例不低于 25%,保证清理能正常开展;
active-defrag-cycle-max 75:表示自动清理过程所用 CPU 时间的比例不高于 75%,一旦超过,就停止清理,从而避免在清理时,大量的内存拷贝阻塞 Redis,导致响应延迟升高。
手动清理 :memory purge
查看内存 :info memory
这里有一个 mem_fragmentation_ratio 的指标,它表示的就是 Redis 当前的内存碎片率 。
mem_fragmentation_ratio = used_memory_rss/ used_memory
大于1:说明内存有碎片,一般在1到1.5之间是正常的。
大于1.5:说明内存碎片率比较大,需要考虑是否要进行内存碎片清理,要引起重视。
小于1:说明已经开始使用交换内存,也就是使用硬盘了,正常的内存不够用了,需要考虑是否要进行