# redis-study
**Repository Path**: wuxingjun/redis-study
## Basic Information
- **Project Name**: redis-study
- **Description**: No description available
- **Primary Language**: Unknown
- **License**: Not specified
- **Default Branch**: master
- **Homepage**: None
- **GVP Project**: No
## Statistics
- **Stars**: 0
- **Forks**: 0
- **Created**: 2024-12-06
- **Last Updated**: 2025-07-21
## Categories & Tags
**Categories**: Uncategorized
**Tags**: None
## README
# Redis 学习
Before
After
Mysql极限 写: 600/s 读 2000/s
Redis 读: 110000/s 写80000/s
## Redis 为什么不能取代Mysql
- Redis它是非关系型数据库,对于复杂的业务会很不友好
- 因为Redis 是线程,在高并发的时候CPU占用会非常高
## Redis 能干嘛
```mermaid
flowchart LR
Redis-->E[介绍]-->EA[高可用 ,高扩展,高性能的内存缓存数据库]
Redis-->A[主流功能与应用]--> AG[分布工缓存,挡在DB之前的带刀护卫]
A-->AH[内存存储和持久化(RDB+AOF)]
A-->AB[高可用架构搭配]
A-->AC[缓存击穿,缓存雪崩,缓存穿透]
A-->AD[队列]
A-->AE[分布式]
A-->AF[排行榜+点赞]
Redis-->B[优势]
B-->BA[性能极高-Redis能读的速度是110000/s,写的速度是80000/s]
B-->BB[Redis数据类型丰富不仅仅支持简单的key-value类型的数据,还支持list,set,zset,hash等数据类型]
B-->BC[Redis可将数据进行持久化,当机器关机后Redis可以通过AOF的方式将数据持久化到磁盘,等到下一次Redis启动的时候再将数据加载到内存中]
B-->BD[Redis支持mast-slave方式的主从模式的数据备份]
Redis-->C[小总结]
C-->CA[应用场景]-->CAA[缓存加速]
CA-->CAB[分布式传话]
CA-->CAC[排行榜场景]
CA-->CAD[分布式计算器]
CA-->CAE[分布式锁]
```
```mermaid
gantt
title Redis 核心大版本核心特性回顾
dateFormat YYYY
section 发展历程
诞生 :a1, 2009, 1y
Redis1.0版本 :a2, after a1, 2y
Redis2.6版本 :a3, after a2, 1y
Redis2.8版本 :a4, after a3, 2y
Redis3.0版本 :a5, after a4, 1y
Redis4.0版本 :a6, after a5, 1y
Redis5.0版本 :a7, after a6, 3y
Redis6.0版本 :a8, after a7, 2y
Redis7.0版本 :a9, after a8, 1y
```
Redis 版本号第二位是奇数为非稳定版本,偶数则是稳定版本
## Redis7新特性
1. Redis Functions
2. Client evicatin
3. Multi -part AOF
4. ACL V2
5. list pack 替代ziplist
## Linux 安装Redis的条件
1. 安装gcc > 4.8.5 gcc -v 使用看版本 gcc是C语言的编译工具,因为Redis是用C语言开发的,所以需要安装gcc
redis-server -v 查看redis版本
#
Redis 下载地址 http://download.redis.io/releases/redis-7.2.6.tar.gz
# Linux 安装步骤
wget http://download.redis.io/releases/redis-7.2.6.tar.gz
tar -zxvf redis-7.2.6.tar.gz
cd redis-7.2.6
make
make install 或者 make && make install
出现 Hint: It's a good idea to run 'make test' ;) 就说明安装成功了
mkdir /data/redis
/opt/redis/redis-7.2.6 安装包目录
安装目录 /usr/local 类似Windows 的 C:/Program Files/
cd /usr/local/bin 我的这个目录下面什么也没有 这是因为只执行了make 命令 没有执行make install命令 执行完了就有了
## 三个常用的并发工具
- Semaphore 共享信号 拿到信号就跑
- CyclicBarrier 水坝 1 2 3 跑
- CountDownLatch 信号抢 321 跑
## Redis 缓存与数据库的一致性问题如何解决?
1. 数据库修改成功,但是Redis 未更新成功
2. 先删了Redis 再修改数据库,但同时有人访问了,就查了旧的数据库里的数据再加载到缓存中去,这时是错的
- 解决方案1: 将Redis 操作和db的操作放在同一个事务里面,这样最大程度得保证一致性
- 解决方案2:延迟双删 修改完数据库的数据之后,马上删除缓存,隔一段时间之后再删一次缓存
- 解决方案3:用订阅的机制 通过列表来实现,例如用户下单,数据库更新之后会向MQ中放一条数据,Redis 订阅消息队列做缓存的删除
- 解决方案4: 读写分离的架构
- 解决方案5: 通过Canal 订阅mysql的binlog日志来实现Redis的同步
## Linux 查找文件
find / -name redis-7.2.6
copy并给文件重命名
## Redis 配置文件修改
1. 配置文件修改 /opt/redis/redis-7.2.6/redis.conf
2. daemonize yes 让redis以守护进程的方式运行
3. protect-mode no 让redis可以远程连接
4. bind 127.0.0.1 让redis只能本地连,要把它注掉,不然就只能本机访问了
5. 添加redis密码 requirepass 123456
6. 重启Redis service redis-server /opt/redis/redis-7.2.6/redis.conf
7. 使用命令行连接Redis redis-cli -h 127.0.0.1 -p 6379 -a 123456
## 登录Redis 分两步的情况
```xshell
redis-cli
auth nimblex
```
- 第一步,说明你要登录Redis的客户端
- 第二步,是告诉它你的密码
## 启动报错 WARNING Memory overcommit must be enabled! Without it, a background save or replication may fail under low memory condition. Being disabled, it can also cause failures without low memory condition, see https://github.com/jemalloc/jemalloc/issues/1328. To fix this issue add 'vm.overcommit_memory = 1' to /etc/sysctl.conf and then reboot or run the command 'sysctl vm.overcommit_memory=1' for this to take effect.
解决方案: sudo sysctl vm.overcommit_memory=1
## Redis 7 连接上客户端报了一串文字‘
Warning: Using a password with '-a' or '-u' option on the command line interface may not be safe
解决方案: redis-7.2.6]# redis-cli -a nimblex -p 6379 2>/dev/null
## Redis 的默认端口为什么是6379 ?
它是手机9键 上的MERZ键的位置决定的 因为作者的朋友圈有一个人他不喜欢,然后叫那个人傻逼之类的,MERZ就刚好表达这个意思,故而选择了6379
## Redis 命令行操作
1. ping 检查是否连接成功
2. redis-cli -h 127.0.0.1 -p 6379 -a 123456 连接Redis
3. redis-cli shutdown 关闭Redis
## Redis 卸载
1. 删除Redis 安装包
2. 把Redis 的配置文件删除 /opt/redis/redis-7.2.6/redis.conf
3. 在Redis的安装目录下执行make uninstall
4. 删除 /usr/local/bin 下关于redis相关的文件
## Redis的10大数据类型说明
### 字符串 类型
String 类型是二进制安全的,就是说它支持序列化,所以你可以把一个对象保存到字符串里,然后取出来,还可以继续使用。可以包含任何数据类型
### List 列表
是简单的字符串列表,按照插入顺序排列,你可以添加任何一个元素到列表的头部或者尾部,它的底层是双端链表,可以包含2^32-1个元素
### Hash
是一个String类型的field-value的影射表,hash最适合存储对象,每个hash可以存储2^32-1个键值对
### Set 集合
Set 是String的无序集合,集合成员是唯一,不可重复的,集合对象的编码可以是intset 或者 hashtable
Redis中的set是通过 hash表来实现的,所以添加,删除,查询的复杂度都是O(1)
### Sorted Set 有序集合
Zset 是一个可排序的set集合 它的每个元素都会关联一个double类型的分数,redis正是通过集合中的分数来为集合进行排序的
zset的成员唯一,但是分数可以重复
### Geo 地理空间 ·1我111111111111111111111111111111111111111111111111111111111111111111111111
## Resi 10大数据类型基础命令
### String 命令
1. set key value 给key设置值
2. get key 获取key的值
3. llen key 获取key的长度
4. append key value 给key的值末尾追加值
5. getrange key start end 获取key的值的子串
6. setget key value 给key设置值,并且返回key原来的值
7. set key vlaue ex time 给key设置值,并且设置过期时间
8. set key value keepttl 给key设置值,并且保留原来的过期时间
9. incr key 给key的值自增1 前提是key的值必须是数字
10. decr key 给key的值自减1 前提是key的值必须是数字
11. incrby key value 给key的值自增value 就是增加步长
12. decrby key value 给key的值自减value 就是减少步长
13. setnx key value 给key设置值,如果key不存在,则设置成功,如果key存在,则设置失败
14. setxx key value 给key设置值,如果key存在,则设置成功,如果key不存在,则设置失败
15. mset key value key value key value 给多个key设置值, 如果其中一个key不存在,则设置失败,其实就是Java里面的事务
16. mget key1 v1 key2 v2 key3 v3 获取多个key的值
17.
### List 命令
1. lpush key value 给key的列表头部添加值
2. rpush key value1 value2 value3 给key的列表尾部添加值
3. lrange key start end 获取key的列表的子串 遍历出来,数据还在的
4. lpop key 从key的列表头部删除一个值,并且返回这个值 数据消费就没有了
5. rpop key 从key的列表尾部删除一个值,并且返回这个值 数据消费就没有了
6. llen key 获取key的列表的长度
7. lindex key index 获取key的列表的某个索引的值 ,数据还在
8. lrem key count value 删除key中count个等于value的元素
9. ltrim key start end 将key的list从start到end进行截取,然后把截取的结果再重新赋值给key
10. rpoplpush key1 key2 从key1的末尾取出一个值放到key的开头
11. lset key index value 给key的第index下标进行修改赋值 其实就相当于数组的array[index] = value
12. linsert key before/after pivot value 在key的pivot值之前或者之后插入一个值 如果pivot值不存在,则不进行任何操作
如果有多个,则从第遇到的第一个开始插入
#### List的应用场景
-
1. 消息队列
-
2. 公众号的订阅消息
## 常用命令
- set key1 v1 给某个key设置值
- get key1 查看key1 的值
- flushdb 清空当时库
- flushall 清空所有的库
- dbsize 查看当时库的数量
- expire key 秒钟 给一个key设置过期时间
- del key1 删除某个Key
- keys * 查看当时库所有的Key
- exists key 查看某个key是否存在
- type key 查看key的数据类型
- unlink key 非阻塞性删除,就是不会马上删除,会给这个key打个可以删除的标记,后面会统一删除
- ttl key 查看还有多少秒过期
- move key 3 把某个key 移动到3号库
- 切换库 select 3 3代表的是库的下标
## 几大数据类型的命令案例
### String
- set key1 keepttl 集成上一次设置的过期时间,避免因为直接使用set命令而将之间设置的过期时间给重置了或者没有过期时间了
- set key v1 ex 30 30秒过期时间
- set key1 v1 nx 之前没有则设置成功,有则设置不成功
- set key1 v1 xx 之前有设置成功,没有则不成功
- mset key1 v1 key2 v2 一次性设置多个key和value
- mget key1 key2 一次性获取多个key的值
- getrang key 0 3 相当于java中的subtring 功能 从一个字符串中截取某些值
- incr key 如果值是数字类型,可以直接+1操作
- 如果想一次加多个则使用incrby key 5 来实现
- decr key 它的功能和incr相反
- decrby key 它的功能和incrby 相反
- strlen key 想看key对应值的长度
- append key 给key的值后面追加内容 等同于java的stringbuffer.append
- set k1 v1 get : 先把原来的值查出来然后再把新的值赋值进去 类似于Java的 sava or update
### Hash
k-v键值对 v也是键值对
- hset user:001 id 001 name joy age 35 设置一个user:001的对象并放入基础值
- hget user:001 id 取key为user:001的id属性
- hgetall user:001 取所有的信息 包括属性和值
- hlen user:001 取key的长度
- hincrby key filed num 将key的fied属性增肌num步长 数据类型需要是intger
- hincrbyfloat key filed num 将浮点形的数据增肌num步长
- hsetnx key filed value 给key中新加一个filed属性并赋value 没有就成功 有则不成功
- hkeys key 查看key所有的属性
- hvals key 查询 key所有的值
### Set
- sadd key v1 v2 v3 给key中添加多个元素
- smembers key 查看key中所有的元素
- scard key 查看key中的元素的数量
- sismember key v1 检查key中是否包含v1元素 没有返回0 可以用来检查数元素是否喫上
- srem key v1 v2 删除key中的值为v1或者v2的元素
- spop key count 删除key中随机的count个元素,并返回删除的元素,元素会删除 可以作随机抽奖
- srandmember key count 随机返回key中count个元素,不会删除元素
- sunion key1 key2 将两个key1,key2 两个集合的元素合并成一个
- sunionstore key1 key2 sunion_set 将key1和key2的元素合并后放到一个新的key中
- sinter key1 key2 取两个集合的交集 可以用作查看两个是否有共同的好友
- sinterstore key1 key2 inter_set 取两个集合的交集,并放到一个新的key中
- sdiff key1 key2 取两个集合的差集,以key1为基准
- sdiffsotre key1 key2 diff_set 取两个集合的差集,并放到一个新的key中
- smove key1 key2 val 将key1中的val值移动到key2中
#### 使用场景及设计文案
##### 场景1 年会抽奖
抽奖需求: 每个用户只能参与一种奖项,一等奖一名,二等奖两名,三等奖三名,幸运奖10名
实现方案:设计一个二维码,员工到场后扫码参与,扫码要求员工填写自己的电话号码,提交后把电话号码放到一个set类型的集合中,然后根据这个集合中的数据,进行抽奖,抽奖的规则就是根据这个集合中的数据,进行抽奖,抽奖的规则就是根据这个集合中的数据,进行抽奖,抽奖的规则就是根据这个集合中的数据,进行抽奖,抽奖的规则就是根据这个集合中的数据,进行抽奖,抽奖的规则就是根据这个集合中的数据,进行抽奖,抽奖的规则就是根据这个集合中的数据,进行抽奖
抽奖的先抽奖三等奖 点击抽三等奖的时候 使用spop user:list 3 这样就随机抽出三个人作为三等奖,并在大屏上公布中奖人员电话号码,然后中奖人员上台领奖,
中奖人员的电话号码要入库,并记录是在等奖,其他奖项目类似,依次抽出二等奖,一等奖,最后抽出幸运奖
##### 场景2 qq 可能认识的人
### ZSet
- zadd key score1 member1 score2 member2 给key中添加多个元素,score是元素的权重,member是元素的值
- zcard key 查看key中元素的数量
- zrange key start end 获取key中元素的范围,start和end是索引,0代表第一个元素,-1代表最后一个元素,-2代表倒数第二个元素
- zrangebyscore key min max 获取key中元素的范围,min和max是权重,可以指定范围,比如min=0 max=10
- zrevrange key start end 获取key中元素的范围,start和end是索引,0代表第一个元素,-1代表最后一个元素,-2代表倒数第二个元素,倒序排列
- zrem key member1 member2 删除key中member1和member2的元素
- zremrangebyrank key start end 删除key中start和end之间的元素,start和end是索引,0代表第一个元素,-1代表最后一个元素,-2代表倒数第二个元素
- zrank key member1 获取key中member1的索引,从0开始
- zrevrank key member1 获取key中member1的索引,从0开始,倒序排列
- zscore key member1 获取key中member1的权重
## Geo 数据类型
- GEOADD key longitude latitude member 添加地理位置信息,longitude是经度,latitude是纬度,member是地理位置的名称
- GEOPOS key member 获取地理位置信息,longitude是经度,latitude是纬度,member是地理位置的名称
- GEODIST key member1 member2 unit 获取地理位置信息,longitude是经度,latitude是纬度,member是地理位置的名称,unit是距离单位,比如米,千米,英里,英尺,英里,英里,公里,英里,英里,公里,英里,英里,公里,英里,英里,公里,英里,英里,公里,英里,英里,公里,英里,英里,公里,英里,英里,公里,英里,英里,公里,英里,英里,公里,英里,英里,公里,英里,英里,公里,英里,英里,公里,英里,英里,公里,英里,英里,公里,英里,英里,公里
- GEORADIUS key longitude latitude radius unit count WITHCOORD WITHDIST WITHHASH ASC STORE key1 STOREDIST key2
## bitmap
- setbit key offset value 设置key中offset位置的值为value,value可以是0或1,0代表false,1代表true
- getbit key offset 获取key中offset位置的值,value可以是0或1,0代表false,1代表true
- bitcount key 获取key中1的个数
- bitpos key bit start end 获取key中bit的位置,bit可以是0或1,0代表false,1代表true
- bitop operation destkey key1 key2 key3 ... keyN
## Stream
Stream 就是Redis的MQ 在有Stream 中使用MQ的话 使用list 的 push rpop 来实现 如果有多个消费者的话铡使用sub/pub模式来实现
但是list没有ACK消息确认机制 ,如果消息费者消息失败,MQ里面的消息也没有了 就会造成数据的丢失,Stream就是为了解决这个痛点的
Redis的消息中间件+阻塞队列
它支持消息的持久化,支持自动生成全局唯一的ID,支持ACK消息确认机制,支持消费组模式,让消息队列更加稳定可靠。
### Stream 的底层结构和原理


### Stream 列表相关命令
1. xadd key value
## Redis 持久化
### RDB(Redis DataBase) 方式持久化
以类似照片记录效果的方式 就是把某一时刻的数据和状态以文件的形式写在磁盘上,也就是一个快照
这样一来,一旦Redis宕机,快照文件是不会丢失的
save 60 1 60 100 60 2 代表 1分钟后保存一次快照,如果快照文件大小超过100M,则保存一次快照,如果快照文件大小超过2M,则保存一次快照
不要把rdb文件放在Redis主机支行服务器上,否则,当Redis主机宕机时,快照文件就会丢失
#### RDB 手动触发
save 命令 它在主程序中执行,会阻塞当前程序,在执行save命令期间,Redis不能做其他任何的操作,线上禁止这样操作
bgsave 命令,它是另外启动一个子程序,
#### RDB 优点
定期对内存的数据进行持久化,以避免数据丢失
#### RDB 缺点
RDB并不保存数据绝对不丢失,当Redis非正常关闭的时候,它会因为没有达到备份的条件而导致最近的数据丢失(比如设置的5分钟内50次修改,但是宕机的近5分钟里并没有到达50次的数据修改,那么这5 分钟内的数据就会丢失)
当前数据量比较大的时候,RDB进行快照备份的时候很慢,甚至会影响主进程的运行,从而影响系统的正常使用
ROB在进行数据快照时,数据被临时克隆了一部分,如果数据量太大,它就会很占内存,甚至如果本身就占得多余一半的内存的时候
,它就就导致服务阻塞
#### RDB 文件修复
redis-check-rdb joy.rdb
#### RDB 什么情况下会生产一个RDB快照
1. 手动执行save , bgsave 命令
2. 一定时间内的修改频率到达配置的次数(比如配置的是5 秒钟2次修改,那么你在5秒内做了2次操作,它就会产生一个rdb快照)
3. 在执行flushdb flushdba 命令时,会生成一个rdb文件
4. 在执行shutdown 且没有开启AOF的时候也会产品一rdb文件
5. 主从复制时,主库会生产rdb快照
#### 快照的禁用
1. 动态修改 redis-cli config set save ""
2. 在配置文件中将save 配置改成save ""
#### RDB 优化配置项

### AOF (Append to Only File)
所谓的AOP 就是把所有的写命令记录下来,在Redis重启的时候,把这些命令再执行一遍从而达到数据恢复的目的
#### AOF的三种写回策略
1. no 先把命令写进磁盘缓冲区,由操作系统控制写入磁盘,很容易丢失数据
2. always 同步写回,只要操作一次,就会把命令写进磁盘,这样会影响性能,因为频繁得IO操作
3. everysec 将命令先写入磁盘缓冲区,然后每秒同步一次
```lombok.config
appendonly yes # 请AOF打开
appendfsync everysec # 每秒同步一次
appenddirname "aof" # aof文件的路径名,这个写文件目录名,不能写全路径
appendfilename "appendonly.aof" # aof的文件名
```
#### AOF 文件出现了问题怎么处理?
redis-check-aof.exe --fix .\rdb\aof\appendonly.aof.1.incr.aof
注意事项
1. 一定要加--fix 不然它只进行检查,不进行修复
2. 要指定文件名
3. 其他两个文件不需要修复,只需要修复incr.aof的文件就可以了,因为操作命令主要记录在这个文件里面的,
#### AOF 优缺点
优点:
1. 当有误操作的时候可以将aof中的错误命令给删掉,再进行数据恢复
2. 数据保存完整性好,因为它是记得的每次操作的命令
3. 当aof文件出现损坏时,也可以进行用redis-check-aof.exe 进行文件的修复
4. 安全,因为它是把命令记录到磁盘的文件中,就算是非正常关闭redis,它也只会损失及少一部分数据
5. AOF文件重写,当文件太长的时候,它会对AOF文件进行整理,记录数据的最终状态
总结: 可以更好得保护数据,性能高,可作紧急性数据修复,顺序IO比随机IO要快
缺点:
1. 同样数据量的情况下aof文件比rdb文件占的空间要大
2. 根据确切的策略,AOF可能比RDB慢
#### AOF 重写机制
随着不断得往aof文件中写数据,那么aof文件会一直变大,当大到一定的程度,redis就会触发重写机制
将文件进行重写,只保留可以恢复文件的最小指定集
触发机制:
1. 自动触发: 满足配置文件条件后,Redis就会重写AOF,Redis会记录上次重写aof文件的大小,一般是超过上次aof文件的一倍时
主会触发
auto-aof-rewrite-percentage 100 新的文件超过原文件多少的时候
auto-aof-rewrite-min-size 1k 文件最小达到多少
2. 手动触发: 执行bgrewriteaof命令

## Redis 练习题
### String 类型练习
1. 设置一个key 为 name value 为Joy的
2. 向redis中放一个age 并对age进行加1 减1
3. 一次性设置多个key 和value
### List 类型练习
1. 向redis中放一个key 为list的值 并向里面设置元素 1 2 3 4 5
2. 获取list的长度
3. 从右边/左边消费一个元素
4. 取list 中 0 到 2 的元素
5. 获取list的长度
6. 将list 2到5的元素重新放到list中
7. 在list 3的后面插入一个元素2.5a
8. 取list 中下标为4的值
9. 从listk中删除2个值为3的元素
10. 将list 中下标为2的元素替换成9
### Hash 类型练习
1. 将用户joy 的基础信息放到Redis中 并指定其 name age addr score
2. 给joy的age,score进行+1 或者 -1
3. 查询joy的addr
4. 获取joy的长度
5. 查看joy所有的属性
6. 查询joy所有的值
7. 查询joy的所有信息 包含属性和值
### Set 类型练习
1. 将joy 的朋友放到redis中
2. 查询joy一共有多少个朋友
3. 查看joy所有的朋友
4. 检查joy是否有朋友 a
5. 删除joy的朋友 b
6. 将 yuandao 的朋友放到redis中
7. 查询joy和yuandao共同的朋友
8. 查看joy和yuandao所有的朋友
9. 查询joy可能通过yuandao认识的朋友
10. 将公司所有的员工放到redis中
11. 从公司的员工工随机抽取10个员工作为幸运奖,这10个员工还可以参与别的奖项抽取
12. 从公司的员工中随机抽取3个员工作为3等奖,这个3个员工不可以再参与别的奖项抽取,同理抽出2个2等奖和1个1等奖
### Sorted Set 类型练习
1. 所有的游戏及其访问量放到redis中
2. 查询排名前10的游戏名称
3. 查询最后10名的游戏名称
4. 查看收集了多少种游戏
5. 查看王者荣耀的访问量
6. 查看王者荣耀的在所有游戏中的排名(从访问量的角度)
7. 查看访问量在1000到10000的游戏名
### Geo 类型练习
1. 将省会城市(包含直辖市) 的经纬度放到Redis中
2. 计算北京到上海的直线距离
3. 搜索在北京附近2000公里内的城市
4. 查看武汉的经纬度
### bitmap 类型练习
1. 将公司所有员工 2025年5月每天的出勤情况放到redis中
2. 统计joy 2025年5月一共出勤了多少天
3. 统计2025年5月21号一共出勤了多少人
4.