Redis使用场景
数据类型
String
常常用来做计算器 ,比如文章的阅读量,关注数,锁
计数:set {uid}:{articleId}:{views} 0 #设初始值为0
incrby {uid}:{articleId}:{views} 1 #每次阅读键值 +1
decr {uid}:{articleId}:{views} 1 #每次阅读 -1
get {uid}:{articleId}:{views} #获取该文章的阅读数量锁:setnx key value:
当键不存在时,对键进行设置操作并返回成功1,否则返回失败0。
Key是锁的唯一标识,一般按业务来决定命名;
Value 往往用来比较加锁的是哪一个线程或者哪一个消息,
一般使用UUID.randomUUID().toString()方法生成。
例如:setnx(key,1),一般建议将锁的过期时间设置为业务处理时间的一半以上
List(列表)
在redis里面,可以把list玩成,栈(一端开口,一端闭口,先进后出)、队列(一端进,一端出,先进先出lpush,rpop)、阻塞队列(两端都可以进出)!
list可以用来做消息队列(代替mq)
Set(无序非重复集合)
常用交集做共同关注,推荐好友
Hash(哈希)
map集合,key-map!值是一个map,hash更适合存储对象,可以做分布式锁
Zset(有序集合)

可以用zset做排序:
存储班级成绩表,工资表排序!
普通消息,1,重要消息2,带权重进行判断!
排行榜应用实现!
geospatial( 地理空间)
- geoadd:添加地理位置的坐标。
- geopos:获取地理位置的坐标。
- geodist:计算两个位置之间的距离。
- georadius:根据用户给定的经纬度坐标来获取指定范围内的地理位置集合。
- georadiusbymember:根据储存在位置集合里面的某个地点获取指定范围内的地理位置集合。
- geohash:返回一个或多个位置对象的 geohash 值。
get的底层实现是zset,可以用做 朋友的定位,计算两地之间的距离,附近的人
Hyperloglog (基数)
pfadd key element [element ...]
:将一个或多个元素添加到指定的 HyperLogLog 数据结构中pfcount key [key ...]
:获取一个或多个 HyperLogLog 数据结构的基数估计值。pfmerge destkey sourcekey [sourcekey ...]
:将一个或多个 HyperLogLog 数据结构合并成一个。合并后的 HyperLogLog 的基数估计值是所有指定 HyperLogLog 的基数估计值之和。
用做不重复的统计,如果允许容错,那么一定可以使用Hyperloglog !
如果不允许容错,就使用set或者自己的数据类型即可!
Bitmaps(位存储)
- setbit key offset value:将指定偏移量的位值设置为value。
- getbit key offset:获取指定偏移量的位值。
- bitcount key [start end]:计算指定偏移量以上的二进制位中值为1的个数。
- bitop[l] [command destkey key [key ...]]:执行多个Redis命令,其中command为BITOP命令,destkey为目标键名,key为源键名,可以传入多个键名。
常用做统计用户信息,活跃,不活跃!登录、未登录!打卡,365打卡!两个状态的,都可以使用Bitmaps !Bitmaps位图,数据结构!都是操作二进制位来进行记录,就只有0和1两个状态!
365天= 365 bit1字节= 8bit46个字节左右!
Redis 事务

一组命令中如果右一条命令的语法错误,那么所有的命令都会失败;如果是命令的语法正确,但是逻辑错误(比如给字符串自增),那么其他正确的命令依然能执行成功,这点和MySQL不同
Redis乐观锁
监控!(Watch)
悲观锁:
很悲观,认为什么时候都会出问题,无论做什么都会加锁!(安全,但性能低)
乐观锁∶
很乐观,认为什么时候都不会出问题,所以不会上锁!更新数据的时候去判断一下,在此期间是否有人修改过这个数据,在MySQL中用version来判断(获取version,然后比较)
watch money 监视money,给money加锁并获取money 值,跟新时会比较money的值是否变化,如果变化,事务执行失败。
数据备份
持久化RDB
1、save的规则满足的情况下,会自动触发rdb规则
2、执行flushall命令,也会触发我们的rdb规则!
3、退出redis,也会产生rdb 文件! 备份就自动生成一个dump.rdb
优点:由于rdb文件都是二进制文件,所以很小,在灾难恢复的时候会快些。
他的效率(主进程处理命令的效率,而不是持久化的效率)相对于aof要高(bgsave而不是save),因为每来个请求他都不会处理任何事,只是bgsave的时候他会fork()子进程且可能copyonwrite,但copyonwrite只是一个寻址的过程,纳秒级别的。而aof每次都是写盘操作,毫秒级别。没法比
缺点:数据可靠性比aof低,也就是会丢失的多。因为aof可以配置每秒都持久化或者每个命令处理完就持久化一次这种高频率的操作,而rdb的话虽然也是靠配置进行bgsave,但是没有aof配置那么灵活,也没aof持久化快,因为rdb每次全量,aof每次只追加。
基于配置m秒内数据修改n次,就触发 bgsave操作
- 开始bgsave: 当执行bgsave命令时,主进程会fork出一个子进程。这个子进程在初始阶段会共享主进程的内存数据。
- 读取内存数据: 完成fork之后,子进程会开始读取主进程的内存数据。这是通过读取共享内存实现的,也就是主进程执行读操作的时候。
- 写入RDB文件: 子进程将读取到的内存数据写入新的RDB文件。
- 替换旧文件: 最后,子进程会将新的RDB文件替换旧的RDB文件。
关于copy-on-write技术:
这种技术是实现持久化的关键。在fork主进程得到子进程这一过程中,实际上是使用了写时复制(copy-on-write,简称COW)技术。
- 当主进程执行读操作时: 写时复制技术允许主进程和子进程共享相同的物理内存页,直到有写操作发生改变页内容时,才会复制一份新的页。因此,当主进程执行读操作时,它会直接访问共享的内存,无需创建新的副本。
- 当主进程执行写操作时: 如果主进程执行写操作,改变了某个页的内容,那么这个页就会被复制出来一份新的页,这个新的页会被标记为只写(write-only)。然后,主进程和子进程都会使用这个新的只写页。这样做的目的是为了确保在发生写操作时,不会影响到其他进程的内存页。
AOF(追加文件)
两者对比
实践开发中更多是两者结合使用,开启rdb和aof的everysec,具体需要看需求
Redis发布订阅
可以用redis的发布订阅功能简单的做 :
1.实时消息系统
2.实时聊天室(频道当做聊天室,将信息回显给所有人即可)
3.订阅、关注都是可以的
但是稍微复杂的场景会使用 消息中间件 MQ
Redis主从
******主节点可以读写,从节点只能读******(读写分离)
配置主从关系:
在redis.conf文件中设置bind属性值来允许连接的 IP
在slaveof中配置:
Redis哨兵
哨兵的作用和原理
搭建哨兵集群
# 端口号设置为27001
port 27001
# 宣布主服务器的IP地址为192.168.150.101
sentinel announce-ip 192.168.150.101
# 监视主服务器mymaster,IP地址为192.168.150.101,端口号为7001,权重为2
sentinel monitor mymaster 192.168.150.101 7001 2
# 当主服务器mymaster不可用时,如果在5000毫秒内仍然不可用,则认为主服务器已下线
sentinel down-after-milliseconds mymaster 5000
# 当主服务器mymaster发生故障时,如果在60000毫秒内仍然无法进行故障转移,则认为故障转移失败
sentinel failover-timeout mymaster 60000
# 数据目录设置为"/tmp/s1"
dir " /tmp/s1"
要运行多少个sentinel 实例就创建多少个目录,并创建sentinel.conf文件
启动sentinel 实例的命令 ; (类似DockerCompose)
redis-sentinel /path/to/your/sentinel.conf
RedisTemplate的哨兵模式
Redis分片集群
搭建分片集群
假设一主已从,3个主就需要6个redis服务,在6个目录分别创建redis.conf文件
配置reids.conf文件:
1 port 6379 # 设置Redis监听的端口号为6379(其他目录要去修改)
2 cluster-enabled yes # 开启集群功能
3 cluster-config-file /tmp/6379/nodes.conf # 集群的配置文件名称,不需要我们创建,由redis自己维护
4 cluster-node-timeout 5000 # 节点心跳失败的超时时间
5 dir /tmp/6379 # 持久化数据存放目录
6 bind 0.0.0.0 # 绑定地址,设置为0.0.0.0表示允许所有IP访问
7 daemonize yes # Redis后台运行
8 replica-announce-ip 192.168.150.10 # 设置主节点IP地址
9 protected-mode no # 关闭保护模式,不用设置密码
10 databases 1 # 设置数据库数量为1个
11 Logfile /tmp/6379/run.log # 日志文件路径
redis-server path/redis.conf #按照path/redis.conf的配置启动redis服务
这6个redis服务还没有任何联系,所有建立联系:
散列插槽
如果要连接redis来测试一定要加 -c 参数,表示集群模式连接:
[root@localhost tmp]# redis-cli -c -p 7001
集群伸缩
散列插槽:
在集群中,Redis会把每一个master节点映射到0~16383共16384个插槽(hash slot)上,数据key不是与节点绑定,而是与插槽绑定。redis会根据key的有效部分计算 slot ,分两种情况:
1、key中包含"{}",且“{}”中至少包含1个字符,“{}”中的部分是有效部分
2、key中不包含“{}”,整个key都是有效部分
例如:key 是 num,那么有效部分就算 num,就根据 num 计算插槽;如果是 {test}num,则根据 test 计算。计算方式是利用CRC16算法得到一个hash值,然后对16384取余,得到的结果就是插槽值。那么这个 key 就会存储在对于的插槽中。
我们 master1 节点上在取数据的是时候,如果 key不在 master1 分配的插槽中,那么就会重定向到对应 插槽去取数据,但这一过程会损耗一咩咩的性能。所有可以将一批数据存储在同一节点的插槽中进行优化,那么可以在 key 的前面统一加大括号,大括号里面的字符串要一样,这样计算出来的 slot 值是一样的。
集群伸缩 -- 添加节点与删除节点:
1、先创建一个 redis 实例:
docker run -d --name redis-new --net=host redis redis-server --cluster-enabled yes --port 7010
2、将新节点以 master 添加到集群:
docker exec -it redis-new /bin/bash
redis-cli --cluster add-node 192.168.222.129:7010 192.168.222.129:7001
--cluster add-node:新增节点
前面的 ip:prot 是新增节点的
后面的 ip:prot 是集群任意节点的
默认是 master 添加,如果想 slave 添加,需要添加 -- cluster-slave 参数,并指定 master ip:prot
其他参数上网查阅即可
3、为新的 master 节点重新分配插槽,否则无法写入
重新分槽:redis-cli --cluster reshard 192.168.222.129:7001,将7001节点的插槽分配一部分给是新节点
移动多少插槽给新节点? 1000
最后输入,然后yes,可以上网查交互过程
删除节点的话就直接删除就好了,Redis 集群将自动重分配被删除节点 负责的槽位给其他节点,具体命令上网查即可。
故障转移
RedisTemplate访问分片集群
Redis最佳实战
Redis键值设计
键命名
BigKey
选择数据类型当key
批处理优化
也可以使用RedisTemlate管道技术