Redis介绍
Redis是一个开源的key-value数据库,支持多种数据类型,可以用作数据库、缓存和消息中间件。支持范围查询和磁盘持久化
Redis vs Memcached
Redis有丰富的数据类型支持,MemCached没有
Redis比MemCached快很多
Redis可以对数据做持久化
Redis支持对数据做主备
常见IO模型
BIO
阻塞IO,每次都需要创建一个新进程/线程
NIO
同步非阻塞NIO:每次都需要去轮询kernel,文件描述符过多时效率低
多路复用NIO select:将fd列表拷贝给kernel,有数据时通知用户态去读取
多路复用NIO poll:将select的fd列表从数组改为链表
多路复用NIO epoll:select和poll在文件描述符很多时会拷来拷去,效率低下。epoll用mmap开辟共享空间,避免了将fds从用户态拷贝到核心态
AIO
异步非阻塞IO
为什么要用Redis做缓存
随着文件里的数据越存越大,磁盘IO成为瓶颈
磁盘寻址单位是ms,内存是ns,内存在寻址上比磁盘快10w倍
- QPS
每秒能处理的请求数 - TPS
每秒能处理的事务数
数据库连接数是有限的,当并发访问量很大时,数据库宕机会导致服务不可用
Redis的5种value类型
String
- 字符类型
相关命令
get、set、mget、mset
getrange、setrange
strlen、append
- 数值类型
相关命令
incr
- bitmap
相关命令
setbit
bitpos、bitcount、bittop
##### Hash
相关命令
hget、hset、hmget、hmset
hkeys、hvals、hgetall
list
- 栈
lpush、lpop、rpush、rpop - 队列
lrange、lindex、lset - 数组
linsert、lrem、llen - 阻塞队列
blpop、bltrim
set
相关命令
sadd、smembers、srem
sinter、sinterstore
sunion、sdiff
srandmember
sorted_set(Zset)
- 相关命令
zadd、zrange、zrangebyscore、zrevrange
zscore、zrank
底层实现
跳表- 给链表加多级索引
- 插入的时候根据随机函数来决定要不要向上层添加索引,删除的时候如果本身是索引也要将索引删除
- 能够按照区间查找数据,迭代输出有序序列
Redis5种value类型使用场景
##### string
- 缓存
- 计数器
- 共享session
hash
- 点赞、收藏、详情页
- 用户信息
list
- 消息队列
set
- 随机事件、抽奖、集合操作
- 标签
sorted_set
- 排行榜
Redis相关场景题
腾讯:有10亿个QQ号,如何快速判断QQ号是否存在?
使用bitmap,每一位代表一个QQ号
统计用户登录天数,且窗口随机
使用bitmap,每个bit代表一个天数,0或1代表该天是否登录
京东:统计活跃用户在线送礼物,随机时间窗口,连续登录要去重
将天数设置为key,value为bitmap,每一个bit代表一个用户
Redis作为数据库和缓存的区别
缓存数据不重要,不是全量数据,只存储热数据
缓存应该随着访问变化
数据库的内容不能丢,应该做持久化
Redis做缓存如何保证缓存里一直是热数据(因为内存大小是有限制的)?
根据业务逻辑设置key的有效期
随着业务运转使用缓存淘汰策略淘汰掉冷数据,比如LRU和LFU
Redis过期的数据何时删除?(过期判定原理)
主动访问时发现过期
被动每10s随机测试20个key,删除已过期的key,如果超过1/4,则重复进行(意思是每次最最多清除1/4)
- 留一部分过期key未删除,稍微牺牲小内存,但是保住了redis性能
Redis是单进程的吗?
工作线程是单线程的,使得访问有序
IO线程是多线程的
为什么是单线程的?
- Redis的瓶颈主要来源于内存和网络带宽,而不是CPU。使用多线程为了避免发生线程安全问题涉及到加锁和线程的频繁切换,这会消耗CPU
Redis如何保证命令的顺序性
Redis的事务支持
Redis支持事务,但是只支持一次性执行多个单命令的原子性,多命令不支持
指令
- multi事务开始
- exec事务提交
Redis持久化机制
RDB(快照)
copy on write机制
恢复速度快
只保存某时点的数据,时点间的数据容易丢失
AOF(日志)
Redis的写操作记录在文件中
数据全
丢失数据少,数据恢复慢
如果开启了AOF模式,只会用AOF恢复
- 4.0以前恢复时是纯指令的日志文件
- 4.0以后在RDB快照的基础上再用AOF恢复
缓存常见问题
缓存击穿
- 原理
key过期(LRU、LFU淘汰)造成并发访问数据库 解决方案
当查询key为null时setnx竞争分布式锁,只有获得锁的采取访问数据库- 新问题:拿到锁的线程挂掉,导致死锁怎么办?
给锁设置超时时间
新问题:拿到锁的线程没有挂,但此时由于网络或CPU等原因导致原线程的锁超时自动释放,产生并发问题怎么办
- 使用多线程,开启一个线程监控原线程执行状态,更新锁时间
- 新问题:拿到锁的线程挂掉,导致死锁怎么办?
缓存雪崩
- 原理
大量的key同时失效,简介造成大量访问直接落到数据库 - 解决方案
对时点性无关的key设置随机过期时间
对时点强依赖的,设置一点延迟
缓存穿透
- 原理
查询的是数据库根本不存在的数据,大量并发查询导致系统被攻击 解决方案
使用布隆过滤器(用bitmap实现)对请求过滤- 布隆过滤器原理:使用多个哈希函数来确定一个值是否存在,但会有误判,不存在的值有可能会被误判为存在
新问题:布隆过滤器不支持删除
- 使用支持删除的过滤器如布谷鸟过滤器
双写一致性
- 先更新数据库,再删除缓存
推荐 - 先删除缓存,再更新数据库
有可能拿到更新前的脏数据,采用延迟双删解决 - 先更新数据库,再更新缓存
不推荐:并发情况下会拿到脏数据
Redis集群
高可用
- 哨兵(Sentinel)
Sentinel可以管理多个Redis实例,他能监控和自动故障转移 复制(Replication)
Replication对一个Redis做多主备复制- 异步复制
可扩展性
- 主从
- 一致性Hash(未使用)
- 哈希槽
根据CRC16对16384取模,决定将key放在哪里 - 数据分片
1 条评论
555