文章目录
1. Redis 有哪些数据类型
数据类型 | 可以存储的值 | 操作 | 应用场景 |
---|---|---|---|
STRING | 字符串、整数或者浮点数 | 对整个字符串或者字符串的其中一部分执行操作, 对整数和浮点数执行自增或者自减操作,对整数和浮点数执行自增或者自减操作 | 可用作计数器 |
LIST | 列表 | 从两端压入或者弹出元素,对单个或者多个元素 ,进行修剪,只保留一个范围内的元素 | 可用作队列 |
SET | 无序集合 | 添加、获取、移除单个元素,检查一个元素是否存在于集合中,计算交集、并集、差集,从集合里面随机获取元素 | 可求交集差集,如共同爱好 |
HASH | 包含键值对的无序散列表 | 添加、获取、移除单个键值对,获取所有键值对,检查某个键是否存在 | 数据缓存 |
ZSET | 有序集合 | 添加、获取、删除元素,根据分值范围或者成员来获取元素,计算一个键的排名 | 可用于排序功能 |
2. Redis 内部结构
- dict字典:使用拉链法保存哈希冲突
- 跳跃表:相对于红黑树,有更好的插入效率,减少了旋转等操作,且更容易实现
Redis 内部数据结构详解——skiplist
3. Redis 使用场景
-
计数器
-
会话缓存
-
分布式锁:通过SETNX方式实现,并加入expire方法,对值加入超时时间,避免死锁
- 获取锁(jedis.ttl(key)==-1为判断是否有设置超时时间,若没有设置,则进行设置,避免其中一个应用获取了锁后还未来得及设置超时而挂掉,从而导致死锁的情况):
- 释放锁:
-
共同好友
-
排行榜
4. Redis 持久化机制
- RDB:对当前数据拍快照,性能较好,但会存在数据丢失,默认采取此种方式持久化
- AOF:将对数据的操作记录在文件中,性能较差,但数据完整性好
- RDB-AOF混合持久化:前半部分是RDB,后半部分是AOF,优点是快速加载的同时,也避免丢失过多数据,缺点是文件可读性差
5. Redis 集群方案与实现
高可用方案
- master/slave
- 实现:修改slave节点的
redis.conf
文件,增加slaveof masterip masterport
该配置 - 原理:
- slave节点启动时:
- slave节点发送SYNC命令给master节点
- master将新收到的操作命令加入缓冲区
- master节点将rdb快照发送给slave(若未配置rdb持久化,会使用无硬盘复制和增量复制)
- slave清空内存数据,执行rdb快照,实现同步
- slave节点启动后,master节点操作数据时:将操作数据的命令发送给slave节点,slave节点执行命令,保持同步
- slave节点启动时:
- 哨兵机制:master挂掉后的,slave选举
- 实现:修改
sentinel.conf
的文件,并启动哨兵 - 原理:通过哨兵的集群监控redis的master,当发现master挂掉后,会修改redis的配置文件,建立新的master
- 实现:修改
- 实现:修改slave节点的
高性能方案
-
redis-cluster方案:
-
redis-cluster把所有的物理节点划分到16383个槽点上,当有多个redis的node时,会将相应的槽点分配给node,当数据插入时,会根据数据的值计算出插入哪个槽点,从而插入哪个redis的节点中,获取也同样
-
当有超过半数的节点无法ping通一个节点时,则该节点失效
-
增加或删除节点时,需要手动迁移数据(需要手动,该方案使用较少)
-
-
redis shardding方案:jedis客户端就支持,通过对数据hash取模的方式找到对应的节点进行数据操作
-
codis方案:基于redis2.8.13分支开发了一个codis-server,相当于一个代理,类似于mycat的模式,还支持节点的扩容和删除时的数据迁移
-
twemproxy:twitter提供的开源解决方案
6. Redis 为什么是单线程的
- 纯内存操作,操作快速
- 避免了频繁切换上下文
- 采用非阻塞I/O多路复用机制,不会在io上浪费时间
7. 缓存雪崩、缓存穿透、缓存热点
- 缓存雪崩:如缓存服务器宕机
- 事前:保证redis集群高可用
- 事中:通过hystrix限流,加入ehcache缓存
- 事后:尽快恢复redis缓存
- 缓存穿透:黑客频繁请求不存在的数据,从而会一直查询数据库。
- 对不存在的数据进行Null缓存,并设置超时时间;
- 使用Boolm Filter,对可能存在的数据才进行查询
- 缓存热点:有大量请求,同时请求redis的key
- 若redis不存在该key,数据库存在该key,可通过分布式锁的方式加锁请求数据库,避免数据库奔溃
- 若redis存在
- 发现热key
1.1. 通过服务端进行统计,如通过flink流式计算
1.2. 通过redis-cli --hotkeys 进行获取
1.3. 通过经验事先判断
1.4. 通过抓包统计 - 解决热key问题
2.1. 通过在服务端进行缓存,内存或ehcache的方式缓存,服务端可通过集群的方式均摊压力
2.2. 通过redis读写分离的方式,对读节点进行扩容,来分摊压力
Redis-避免缓存穿透的利器之BloomFilter
阿里一面:关于【缓存穿透、缓存击穿、缓存雪崩、热点数据失效】问题的解决方案
缓存雪崩和缓存穿透问题解决方案
你所不知道的Redis热点问题以及如何发现热点
8. 使用缓存的合理性问题
- 提高软件的性能和并发量,无需经过数据库,而从缓存中获取,速度将会得到很大的提高,且并发量也得到提高
9. Redis常见的回收策略
- 从标记了超时时间的数据中随机淘汰
- 从标记了超时时间的数据中淘汰快到期的
- 从标记了超时时间的数据中淘汰最少使用的
- 从所以数据中随机淘汰
- 从所有数据中淘汰最少使用的
- 不淘汰数据
11. Redis超时的数据如何删除
- 定期删除:定时任务随机检验设置了超时时间的20个KEY是否超时,若超时则进行剔除
- 惰性删除:查询KEY时,判断是否超时,若超时,则剔除并不返回数据
11. Redis的setnx命令原理
只有数据不存在时,才进行设置。又因为redis是单线程的,从而保证了原子性。
12. Redis性能优化
1. 避免耗时命令
-
不要把 List 当做列表使用,仅当做队列来使用
-
通过机制严格控制 Hash、Set、Sorted Set 的大小
-
可能的话,将排序、并集、交集等操作放在客户端执行
-
绝对禁止使用 KEYS 命令,原因如下:
- 没有limit,我们只能一次性获取所有符合条件的key,如果结果有上百万条,那么等待你的就是“无穷无尽”的字符串输出。
- keys命令是遍历算法,时间复杂度是O(N)。如我们刚才所说,这个命令非常容易导致Redis服务卡顿。因此,我们要尽量避免在生产环境使用该命令。
-
避免一次性遍历集合类型的所有成员,而应使用 SCAN 类的命令进行分批的,游标式的遍历,原因如下:
- scan命令的时间复杂度虽然也是O(N),但它是分次进行的,不会阻塞线程。
- scan命令提供了limit参数,可以控制每次返回结果的最大条数。
2. 持久化机制的选择
- AOF性能较差,每一行命令都需要保存,RDB通过快照方式性能更优
3. 数据淘汰优化
- 当同一秒内有大量 key 过期时,也会引发 Redis 的延迟。在使用时应尽量将 key 的失效时间错开。
4. 读写分离
- Redis 的主从复制能力可以实现一主多从的多节点架构,在这一架构下,主节点接收所有写请求,并将数据同步给多个从节点。
- 在这一基础上,我们可以让从节点提供对实时性要求不高的读请求服务,以减小主节点的压力。
- 尤其是针对一些使用了长耗时命令的统计类任务,完全可以指定在一个或多个从节点上执行,避免这些长耗时命令影响其他请求的响应。
5. 其他
- 使用长连接或连接池,避免频繁创建连接
- swap引发的延迟