redis笔记

本文详细介绍了Redis的各种数据结构,包括键操作、字符串、列表、集合、哈希、有序集合,以及Redis的配置文件、发布订阅、事务、持久化(RDB和AOF)、主从复制、哨兵模式和集群。还探讨了Redis在秒杀活动中的事务操作、集群的优缺点及应对缓存穿透、雪崩等问题的策略。最后提到了Redis的面试常见问题。
摘要由CSDN通过智能技术生成
nosql 减少io的操作,解决io压力,当缓存使用
not only sql 不仅仅是sql,是非关系数据库,key-value
使用场景
对数据高并发的读写
海量数据的读写
对数据高可拓展性的
不支持复杂逻辑的关系.
redis:支持
mongoDB: 文档行数据库,key-value, value支持json,可替代redis

redis 的操作是原子性的.计数器,秒杀,手机验证码
redis-server 是服务前端启动,不推荐,启动redis-端口号6379
修改 /etc/redis.conf 中的字段daemmonize的值为yes,可以后台启动
启动命令: redis-server /etc/redis.conf  服务端启动
ps -ef | grep redis
redis-cli  通过客户端链接redis
redis-cli shutdown 关闭redis
redis-cli -p 6379 shutdown 指定端口关闭
端口号6379的来源
串行
多线程+锁(memcache的实原理, 支持单一的数据类型)
单线程+多路IO复用(redis的内部实现原理)

3.1 Redis键key的操作

先设置值set k1 lucy, set k2 mary, set k3 jack
keys   查看档期库所有key 
exists k1  判断某个key是否存在
del k2  删除指定key 为k2的数据
type k3 查看key是什么类型
unlink k3  根据value选择非阻塞删除(将keys从keyspace元数据中删除,真正的删除会在后续一部操作)
expire k1 10  表示k1的值10秒后国企
ttl k1 查看k1还有多少秒过期, -1表示永远有效,-2表示已过期

select命令切换数据库

dbsize 查看当前数据库的key的数量
flushdb 清空当前库中的所有key
flushdball 清空所有库中的key

3.2 Redis 字符串String

*NX 当数据库中key 不存在时,可将key-value添加数据库
*XX 当数据库中key 存在时,可将key-value添加数据库,与NX参数互斥
*EX 设置key的超时秒数
*PX 设置key的超时毫秒数,与EX互斥
set 添加值
get 查询key对应的值
apped key value 将给key追加原值的末尾
strlen key 获取key对应只给的长度
setnx key value 只有key不存在时,设置key的值
incr key 对key的值每次加1
decr key 对key的值每次减1
incrby/decrby key 步长 将key中存储的值自增自减步长

原子性操作:不会被线程调度机制打断的操作. 原子性,有一个失败则都失败.

操作一旦开始,就一直运行到结束,中间不会切换到另一个线程.

在单线程中,能够在单挑指令中完成的操作,都可以成为原子操作.(因为终端只能存在于指令之间)
在多线程中,不能被其它进程/线程打断的操作叫原子操作.
redis单命令的原子性主要得益于Redis的单线程.

3.3 Redis 列表 list

底层时双向链表

3.4 Redis 集合 Set

set自动排重(无序不重复) 底层是一个value为null的hash表.所以添加,删除,查找的复杂度都是o(1).

一个算法,随着数据的增加,执行时间的长短,如果是O(1),数据增加,查找数据的时间不变.

3.5 Redis哈希 Hash

Redis hash 是一个string类型的field 和 value的直射表.类似java里的map<String,Object>

3.6 Redis 有序集合 Zset(sorted set)

Zset 有序不重复

set 无序不重复

SortedSet(zset)类似于java里的Map<String,Double>,zset可给每个元素value赋一个权重值score.

zset又类似于TreeSet,内部的元素会按照权重score排序.

zset底层用了两个数据结构:hash+跳跳表

4. Redis 配置文件介绍etc/redis.conf

4.1 units 单位只支持bytes,不支持bit,大小写不敏感.

4.2 includes 包含

4.3 network 网络相关

默认bind=127.0.0.1 只能接受本机的访问请求. 不写bind,不受限制.

生产环境需要写应用服务区的地址;服务器需要远程访问的,需要注释 # bind.

若开启了protected-mode  yes,且bind ip没设密码, redis只允许接受本机的响应.

protected-mode no 支持远程访问.

4.3.3 port 

4.34 tcp-backlog,backlog是一个链接队列总和 = 未完成3次握手的队列+已完成3次握手的队列.

4.35 pidfile redis进程文件详情

4.5 limits  设置最大客户端链接数

5. Redis 的发布和订阅

5.1 消息通信模式:发送者pub 发送消息,订阅者sub接收消息.

6. Redis 新数据类型

6.1 Bitmaps 

6.2 HyperLogLog 页面访问量,基数的计算.

6.3 GEO 地理位置的缩写geographic

7. Jedis操作Redis6

用Java操作redis,是客户端语言.

idea 里的maven 工程,加依赖

修改配置文件etc/redis.conf中的两个值: 注释bind + protected-mode no 支持远程访问 + 重启redis

8. Redis_Jedis 实例

9. SpringBoot 整合Redis

10. Redis中事务操作

事务的作用是串联多个命令,防止别的命令插队.

会执行,不会回滚.

悲观锁是每次操作都上锁,别的操作只能等我释放后才能执行.只能一个一个的使用,不能同时使用..

乐观锁是通过版本号进行控制,每次操作前,先跟数据库的版本号做对比.一样时能操作.

抢票用的是乐观锁,很多人都可以抢到票,但最终只有一个人可以付款.

10.5.3 乐观锁

10.5.4 WATCH key [key...]

在执行multi之前,先执行 watch key 可以监视一个或多个key,如果在事务执行之前key被其他命令所改动,那么事务将被打断.

开启了两个客户端:客户端1:

客户端2:

10.6 Redis 事务三特性

单独的隔离操作:事务中所有命令都会被序列化,按顺序地执行,事务在执行的过程中,不会被其他客户端发送来的命令请求所打断.

没有隔离级别的概念:队列中的命令没有提交之前都不会实际被执行,因为事务提交前任何质量都不会被执行.(mysql有这个概念)

不保证原子性:事务中如果有一条命令执行失败,其后的命令仍然被执行,没有回滚.

11. Redis 事务实例-秒杀活动

1. uid 和 prodid非空判断

2. 链接redis

3. 拼接key

3.1 库存key

3.2 秒杀成功用户key

4. 获取库存,如果库存null,秒杀还没开始

5. 判断用户是否重复秒杀操作

6. 判断如果商品数据,库存数量小于1,秒杀结束

7. 秒杀过程

7.1 库存-1

7.2 把秒杀成功用户添加清单里面

1. uid 和 prodid非空判断
if(uid == null || prodid == null){
    return false
}
2. 链接redis
Jedis jedis = new Jedis(host,port:6379)

3. 拼接key
3.1 库存key
String kcKey = "sk:"+prodid+":qt"
3.2 秒杀成功用户key
String userKey = "sk:"+prodid+":user"

4. 获取库存,如果库存null,秒杀还没开始
String kc = jedis.get(kcKey);
if(kc == null){
    sout("秒杀还没开始,请稍等")
}
5. 判断用户是否重复秒杀操作
if(jedis.sismember(userKey,uid)){
    sout("已经秒杀成功了,不能重复秒杀")
    jedis.close()
}
6. 判断如果商品数据,库存数量小于1,秒杀结束
if(Integer.parseInt(kc)<=0){
    sout("秒杀已经结束了")
    jedis.close()
}
7. 秒杀过程
7.1 库存-1
jedis.decr(kcKey)
7.2 把秒杀成功用户添加清单里面
jedis.sadd(userKey,uid)
jedis.close()

11.2 Redis 事务-秒杀并发模拟工具-ad

ad 工具模仿多人参加秒杀,爆出两个问题:

1. 超卖,秒杀商品库存为10,但卖出了12个.

2. 链接超时的问题.

加乐观锁结果超卖的问题.

//监视库存
jedis.watch(kcKey);
// 在第4步前监视kcKey 库存
4. 获取库存,如果库存为null,秒杀还没开始
7. 秒杀过程
7.1 库存-1
//使用事务
Transaction multi = jedis.multi();
//组队操作-7.2 把秒杀成功用户添加清单里面
multi.decr(kcKey); //jedis.decr(kcKey)
multi.sadd(userKey,uid); //jedis.sadd(userKey,uid)
//执行
List<> results = nulti.exec();
if(results == null || results.size()==0){
    sout("秒杀失败了...")
    jedis.close()
}

修改第2步
//Jedis jedis = new Jedis(post,port);
//通过连接池得到jedis对象
JedisPool jedisPoolInstance = JedisPoolUtil.getJedisPoolInstance();
Jedis jedis = jedisPoolINstance.getResource();

11.6 解决乐观锁导致的库存遗留问题

lua时小巧的脚本语言,lua的解释器部超过200k,嵌入式脚本一样.可以调C++代码,也可以被C++调用.

lua脚本在Redis中的优势:

lua类似于redis事务,有一定的原子性,不会被其他命令插队,可以完成一些redis是事务性操作.

将复杂的多步redis操作,写一个脚本,一次提交给redis执行,减少返回链接redis的次数,提升性能.

redis 2.6后,通过lua脚本解决争抢问题,实际上是redis 利用单线程的特性,用任务队列的方式解决多任务并发问题.

12 Redis 持久化之RDB

rdb 是 指定时间间隔内,将内存的数据集快照写入磁盘.

etc/SNOP

dir ./   在那个目录启动redis 就在那个目录下生成rdb文件

save 3600 1
save 30 10  # 30秒内10个key变化或10条数据变化,就操作
save 60 10000 

30秒内12个key变化了,先将前10个值持久化,从第11开始从新计算时间.

save 手动保存.不推荐使用

bgsava redis会在后台异步进行快照操作,快照同时还可以响应客户端请求.
stop-writes-on-bgsave-error yes  当redis 无法写入磁盘的化,直接关掉redis的写操作.推荐yes

rdbchecksum yes 在存储快照后,还可以让redis使用crc64算法来进行数据校验.

fork 写时复制技术:临时文件替换dump.rdb的过程.

12.2.8 rdb的备份

先通过config get dir 查询rdb文件的目录

将*.rdb的文件拷贝到别的地方

rdb的恢复
关闭redis
先把备份的文件拷贝到工作目录下 cp dump2.rdb dump.rdb
启动Redis 备份数据会直接加载

13.2.9 rdb 优势

适合大规模的数据恢复
对数据完整性和一致性要求不高更适合使用
节省磁盘空间
恢复速度快

劣势:因需要创建临时文件,所以会浪费磁盘空间.

13. Redis 持久化-AOF

aof 是以日志的形成来记录写操作.(增量保存) 读操作不记录. 只需追加文件但不改写文件.

redis 启动的时候,会读取文件.

修改/etc/redis.conf 中 appendonly的值改为yes 

生成 appendonly.aof 文件

aof 和 rdb 同时开启时, redis 用aof的.

13.1.5 AOF 启动/修复/恢复

正常恢复

下盖默认的appendonly no 改为yes
将有数据的aof文件复制一份保存到对应目录(查看目录 config get dir)
恢复:重启redis,然后重新加载rof文件内容

异常恢复

修改默认的appendonly no 改为yes
如遇到aof文件损坏,通过/usr/local/bin/redis-check-aof--fix   appendonly.aof进行恢复
备份被写坏的aof文件
恢复:重启redis,然后重新加载aof文件内容

13.1.6  aof 同步频率设置

appendfsync always 始终同步,每次redistribution的写入都会立刻记入日志;性能差数据完整

appendfsysnc everysec 每秒同步,如果宕机,本秒的数据可能丢失

appendfsyns no 不主动进行同步,把同步时机交给操作系统

13.1.7 aof 文件重写

auto-aof-rewrite-percentage 设置重写的基准值,文件达到100%时开始重写(即下面重写基准值的2倍时触发)

auto-aof-rewrite-min-size 设置重写的基准值,最小文件64MB

如果redis 的aof 的大小>= base_size + base_size*100%  且 文件>64Mb时, redis会对aof重写

13.1.2  AOF 持久化流程

1 客户端的请求写命令会被append追加到AOF缓冲区内;
2 AOF缓冲区根据AOF持久化策略(always/everysec/no)将操作sync同步到磁盘的AOF文件中.
3 AOF文件大小超过重写策略或手动重写时,会对AOF文件rewirte重写,压缩AOF文件容量.
4 redis服务重启时,会重新load 加载AOF文件中的写操作达到数据恢复的目的.

14.主从复制

自动同步到备机的master/slaver机制,Master以写为主,slave以读为主.

读写分离,性能扩展.容灾快速恢复

14.1 一主两从

1 创建/myredis 文件夹
2 复制 redis.conf配置文件中
3 配置一主两从,创建三个配置文件
.redis6379.conf
.redis6380.conf
.redis6381.conf
4 在三个配置文件中写内容
5 启动三个redis服务
查看当前主机运行状况
在从机上执行slaveof 主机ip端口号 slaveof 127.0.0.1 6379

14.3 查看三台主机运行情况

info replication 打印主从复制的相关信息

14.3.7 配从不配主  

slaveof <ip><port> 成为某个实例的从服务器

在6380和6381上执行slaveof 127.0.0.1 6379

14.4.1 一主二仆

问题:slave1,slave2是从头开始复制还是从切入点开始复制?比如从k4进来,那之前的k1,k2,k3是否也剋有i复制?

主机是6379, 从机端口6380的从服务器挂了,重启后,是重头开始复制的.

问题:从机是否可以写? set可否? 从服务器只能读,不能写

问题:主机shutdown后情况如何?从机是上位还是原地待命? 主服务器挂后,从服务器不会上位.

若从服务器挂了之后重启后,默认是主服务器,需要再次执行slaveof 主机ip port

14.4.2 薪火相传

14.4.3 反客为主

当master 宕机后,后面的slave可以立刻升为master,其后面的slave不用做任何修改.

用 slaveof no one 将从机变主机

14.6 哨兵模式

反客为主的自动版.后台监控主机是否故障,如果故障根据投票数自动将从库转换为主库.

1 自定义的/myredis 目录下
2 新建 sentinel.conf文件(名字不能错)
3 配置哨兵,填写内容 sentinel monitor mymaster 127.0.0.1 6379 1
(其中mymaster是为监控者的名称, 1表示为至少有1个哨兵同意迁移数量-若为2就是两个哨兵同意迁移)

当主机挂掉后,从机选举中产生的新的主机

大概10秒最用可以看到哨兵窗口日志,切换了新的主机

那个从机会被选举为主机呢? 依据是什么?  根据优先级别 slave-priority / replica-priority

原主机重启后会变为从机

优先级在redis.conf中默认replica-priority 100 , 值越小优先级越高

偏移量是指获得源主机数据最全的.(偏移量就是数据与主机相差多少.)

每个redis实例启动后都会随机生成一个40位的runid

14.6.2 复制延时

由于所有的写操作都是在master上操作,然后同步到slave上,所以从master同步到slave机器有一定的延迟,当系统很繁忙的时候,延迟问题会更加严重,slave机器数量的增加也会使这个问题更加严重.

14.6.3 主从复制的Java实现

端口号改为:哨兵端口号

15. Redis 集群

问题:容量不够,redis 如何进行扩容?  集群扩容

问题:并发写操作,redis 如何分摊? 集群分摊写的压力

问题:主从模式,薪火相传模式,主机宕机,导致ip地址发生变化,应用程序中配置需要修改独赢的主机地址 端口等信息.

之前通过代理主机来解决,但是redis3.0 中提供了解决方法.就是无中心化集群配置.

总结:
1. 到myredis 目录下,清理rdb文件
2. 创建6个conf文件
3. 给6个文件加内容
4. 启动6个服务 redis-server redis6379.conf
5. 6个服务节点合体
6. 到redis-6.2.1的安装目录下 cd /opt/redis-6.2.1/src
7. redis-cli --cluster create --cluster-replicas 1 192.168.11.101:6379 192.168.11.101:6380 192.168.11.101:6381 192.168.11.101:6389 192.168.11.101:6390 192.168.11.101:6391 
8. 测试集群 redis-cli -c -p 6379

15.2  什么是集群

特点: 任何一台机器,都可以作为集群的入口.

redis 集群实现了对redis的水平扩容,即启动N个redis节点,将整个数据库分布存储在这N个节点中,每个节点存储总数居的1/N.

redis 集群通过分区partition 来提供一定程度的可用性.即使集群中有一部分节点失效或者无法进行通讯,集群也可以继续处理命令请求.

15.3 删除持久化数据

将rdb / aof 文件都删掉(因为重启后rdb会对数据恢复,对后面演示有影响)

15.4 制作6个实例: 6379,6380,6381, 6389,6390,6391

15.4.2 redis cluster 配置修改

cluster-enable yes 打开集群模式

cluster-config-file  nodes-6379.conf 设定节点配置文件名

cluster-node-timeout  15000 设定节点失联时间,超过该时间(毫秒),集群自动进行主从切换

15.4.5 使用查找替换修改另外5个文件 %s/6379/6380

15.4.5 启动6台redis服务

15.5.6 将6台服务,6个节点合成一个集群

6台服务怎么变成一个集群呢? 合体 cd /opt/redis-6.2.1/src (最开始redis的安装路径)

redis-cli --cluster create --cluster-replicas 1 192.168.11.101:6379 192.168.11.101:6380 192.168.11.101:6381 192.168.11.101:6389 192.168.11.101:6390 192.168.11.101:6391 

此处的192.168.11.101是window机器的ipv4地址, 不要用127.0.01,用真是的ip地址

redis-cli 命令 需要在src目录下执行

--cluster 表集群操作 

--cluster-replicas 创建集群的模式,

--replicas 1  采用最简单的方式配置集群,一台主机,一台从机,正好三组.

15.6 -c采用集群策略链接,设置数据会自动切换到相应的写主机

15.7 通过 clustrer nodes 命令查看集群信息

15.8 redis cluster 如何分配这六个节点?

一个集群至少要有3个主机节点.

--cluster-replicas1 表示集群中每个主节点创建一个从节点.

分配原则: 保证每个主数据库运行在不同的ip地址,每个从库不在一个ip地址上.

15.9 什么是slots

15.10 在集群中录入值

在redis-cli 每次录入,查询键值,redis 都会计算出该key应该送往的插槽,如果不是该客户端对应服务器的插槽,redis会报错,并告知应前往的redis实例地址和端口.

redis-cli 客户端提供了 -c 参数实现自动重定向.

15.11 查询集群中的值

cluster keyslot cust   # 4847 返回查看键对应的插槽值

cluster countkeysinslot   4847(插槽值)   # 3   返回计算插槽里有几个键

cluster getkeysinslot 4847 10  # 返回插槽4847里 10 个键对应的值

15.12 故障恢复

如果主节点下线? 从节点能否自动升为主节点? 注意15秒超时   从机可以自动升主机

主节点恢复后,主从关系会如何?主节点回来变成从机

如果所有某一段插槽的主从节点都宕掉,redis服务是否还能继续? 不一定

如果某一段插槽的主从机都挂掉,而 redis.conf 中的 cluster-require-full-coverage 为yes, 整个集群都挂掉. 如果为no, 那么该段插槽数据全不能使用,也没法存储.

15.13 集群的jedis 开发

即使链接都不是主机,集群会自动切换主机存储.主机写,从机读.

无中心化主从集群. 无论从那台主机写的数据,其他主机上都能读到数据.

15.14 redis集群的好处

实现扩容, 分摊压力,无中心配置相当简单.

15.15 Redis 集群的不足

多键操作不被支持.

多键的redis 事务时不被支持的,lua脚本不被支持.

由于集群方案出现较晚,很多公司已经采用了其他的集群方案,而代理或客户端分片的方案想要迁移至redis cluster ,需要整体迁移而不是逐步过渡,复杂度较大.

16.  Redis 缓存穿透

16.1 缓存穿透解决方案

16.3 缓存雪崩

16.4 分布式锁

重启 服务集群,通过网关压力测试.

ad 工具测试并发

ad -n 1000 -c 100 http://192.168.110.1:8080/test/testLock

1000个请求100个并发

设置所的同时+过期时间

压力测试肯定也没问题.

问题: 可能会释放其他服务器的锁.

16.4.5  优化UUID防误删

具体步骤如下:

17. ACL

redis ACL 是access control list 访问控制列表的缩写,根据可执行命令和可访问键来限制某些链接.

ACL 命令

17 IO多线程

redis 6 加入多线程. 专门用来执行网络请求的.

平时执行命令还是单线程

工具支持cluster. redis版本低的化,需要装工具,redis 版本高的化就不用单独装了.

redis 面试题

一. 为什么使用缓存?

1. 高性能

2. 高可用

二. 什么是缓存穿透? 缓存击穿?缓存雪崩?怎么解决?

1. 缓存穿透,redis 查不到,数据库也查不到.  

缓存穿透的解放方案: 1 对参数进行合法性校验.  2 将数据库中没有查到结果的数据也写入到缓存.(要注意防止 无效的key 会把redis堆满,这一类缓存的有效期设置的短一点.)

2.

三.如何保证Redis与数据一致?

四. 如何设计一个分布式锁?如何对锁性能进行优化?

五.

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值