数据结构
-
string
-
命令
- set key value #设置 key-value 类型的值
- get key # 根据 key 获得对应的 value
- exists key # 判断某个 key 是否存在
- strlen key # 返回 key 所储存的字符串值的长度
- del key # 删除某个 key 对应的值
- incr key # 将 key 中储存的数字值+1
- decr key # 将 key 中储存的数字值-1
-
性质
- 不光可以保存文本数据还可以保存二进制数据
-
使用场景
- 一般常用在需要计数的场景,比如用户的访问次数、热点文章的点赞转发数量等
-
-
list
-
性质
- 双向链表,既可以当做栈使用,也可以当做队列使用。
-
命令
-
rpush myList value1 # 向 list 的头部(右边)添加元素
-
lpop myList # 将 list的尾部(最左边)元素取出
-
lrange myList 0 1 # 查看对应下标的list列表, 0 为 start,1为 end
- 通过 lrange 命令,基于 list 实现分页查询
-
llen myList
-
-
应用场景
- 消息队列,慢查询
-
-
hash
-
命令
- hmset userInfoKey name “guide” age “24” # 存储对象
- hexists userInfoKey name # 查看 key 对应的 value中指定的字段是否存在
- hget userInfoKey name # 获取存储在哈希表中指定字段的值
-
性质
- 数组+链表实现方式,hash 是一个 string 类型的 field 和 value 的映射表,特别适合用于存储对象
-
应用场景
- 系统中对象数据的存储
-
-
set
-
性质
- set 类型是一种无序集合,集合中的元素没有先后顺序,元素不能重复,集合可以进行交集,差集,并集操作
-
命令
- sadd mySet value1 value2 # 添加元素进去
-
应用场景
- 需要存放的数据不能重复以及需要获取多个数据源交集和并集等场景
-
-
sorted set
-
性质
- 和 set 相比,sorted set 增加了一个权重参数 score,使得集合中的元素能够按 score 进行有序排列,还可以通过 score 的范围来获取元素的列表。
-
命令
- zadd myZset 2.0 value2 1.0 value3
- zscore myZset value1 # 查看某个 value 的权重
- zrange myZset 0 1 # 顺序输出某个范围区间的元素,0 为 start 1 为 stop
-
-
bitmap
EXPIRE:设置过期时间,TTL:剩余生存时间
过期数据删除策略
- 惰性删除:只会在取出 key 的时候才对数据进行过期检查。这样对 CPU 最友好,但是可能会造成太多过期 key 没有被删除。
- 定期删除: 每隔一段时间抽取一批 key 执行删除过期 key 操作。并且,Redis 底层会通过限制删除操作执行的时长和频率来减少删除操作对 CPU 时间的影响。
- 定时删除:设置键的过期时间的同时,创建一个定时器(timer),让定时器在键的过期时间来临时,立即执行对键的删除操作
内存淘汰机制
- volatile-lru(least recently used):从已设置过期时间的数据集(server.db[i].expires)中挑选最近最少使用的数据淘汰
- volatile-ttl:从已设置过期时间的数据集(server.db[i].expires)中挑选将要过期的数据淘汰
- volatile-random:从已设置过期时间的数据集(server.db[i].expires)中任意选择数据淘汰
- allkeys-lru(least recently used):当内存不足以容纳新写入数据时,在键空间中,移除最近最少使用的 key(这个是最常用的)
- allkeys-random:从数据集(server.db[i].dict)中任意选择数据淘汰
事务
-
MULTI:·MULTI命令用于开启一个事务,它总是返回OK。MULTI执行之后,客户端可以继续向服务器发送任意多条命令,这些命令不会立即被执行,而是被放到一个队列中,当EXEC命令被调用时,所有队列中的命令才会被执行。
-
EXEC:执行所有事务块内的命令。返回事务块内所有命令的返回值,按命令执行的先后顺序排列。当操作被打断时,返回空值nil。
-
DISCARD:通过 DISCARD 命令取消一个事务,它会清空事务队列中保存的所有命令。
-
WATCH:WATCH 命令用于监听指定的键,当调用 EXEC 命令执行事务时,如果一个被 WATCH 命令监视的键被修改的话,整个事务都不会执行,直接返回失败。
-
不支持回滚(roll back),不满足原子性和持久性
- 即使事务中有某个/某些命令在执行时产生了错误, 事务中的其他命令仍然会继续执行。
- 失败的命令是由编程错误造成的,而这些错误应该在开发的过程中被发现,而不应该出现在生产环境中。
Redis单线程模型
-
IO多路复用
- Redis 基于 Reactor 模式开发了自己的网络事件处理器: 这个处理器被称为文件事件处理器(file event handler);
文件事件处理器使用 I/O 多路复用(multiplexing)程序来同时监听多个套接字, 并根据套接字目前执行的任务来为套接字关联不同的事件处理器;
当被监听的套接字准备好执行连接应答(accept)、读取(read)、写入(write)、关闭(close)等操作时, 与操作相对应的文件事件就会产生, 这时文件事件处理器就会调用套接字之前关联好的事件处理器来处理这些事件;
文件事件处理器以单线程方式运行, 但通过使用 I/O 多路复用程序来监听多个套接字, 文件事件处理器既实现了高性能的网络通信模型, 又可以很好地与 redis 服务器中其他同样以单线程方式运行的模块进行对接, 这保持了 Redis 内部单线程设计的简单性。
- Redis 基于 Reactor 模式开发了自己的网络事件处理器: 这个处理器被称为文件事件处理器(file event handler);
-
优点
- 纯内存访问:数据存放在内存中,内存的响应时间大约是100纳秒,这是Redis每秒万亿级别访问的重要基础。
- 基于非阻塞的IO多路复用机制
- 避免了多线程的频繁上文切换带来的性能问题
缓存问题
-
缓存雪崩
-
场景
- (1)缓存在同一时间大面积的失效,后面的请求都直接落到了数据库上,造成数据库短时间内承受大量请求。
- (2)有一些被大量访问数据(热点缓存)在某一时刻大面积失效,导致对应的请求直接落到了数据库上。
-
解决方案:
- 采用 Redis 集群,避免单机出现问题整个缓存服务都没办法使用。
- 限流,避免同时处理大量的请求。
- 设置不同的失效时间比如随机设置缓存的失效时间。
- 缓存永不失效。
-
-
缓存穿透
-
定义:缓存穿透是指缓存和数据库中都没有的数据,而用户不断发起请求,如发起为id为“-1”的数据或id为特别大不存在的数据。这时的用户很可能是攻击者,攻击会导致数据库压力过大。
-
解决方案:
-
参数校验,eg:id<=0的直接拦截
-
缓存无效key,针对重复请求的无效key,缓存其value为null
-
布隆过滤器
- 布隆过滤器说某个元素存在,小概率会误判。布隆过滤器说某个元素不在,那么这个元素一定不在。(原理:hash冲突)
-
-
-
缓存击穿
-
定义:缓存击穿是指缓存中没有但数据库中有的数据(一般是缓存时间到期),这时由于并发用户特别多,同时读缓存没读到数据,又同时去数据库去取数据,引起数据库压力瞬间增大,造成过大压力
-
解决方案:
- 设置热点数据永远不过期。
- 加互斥锁,此方法只允许一个线程重建缓存, 其他线程等待重建缓存的线程执行完, 重新从缓存获取数据即可
-
Redis集群
-
主从模式
-
策略:数据库分为两类,一类是主数据库(master),另一类是从数据库(slave)。主数据库可以进行读写操作,当写操作导致数据变化时会自动将数据同步给从数据库。而从数据库一般是只读的,并接受主数据库同步过来的数据。一个主数据库可以拥有多个从数据库,而一个从数据库只能拥有一个主数据库。
-
优点
- 读写分离
- 方便做容灾恢复
-
缺点
- 不具备自动容错和恢复功能
- 主机宕机,宕机前有部分数据未能及时同步到从机,切换IP后还会引入数据不一致的问题,降低了系统的可用性
- Redis 较难支持在线扩容,在集群容量达到上限时在线扩容会变得很复杂
-
-
哨兵模式
-
策略:这种模式在主从的基础上新增了哨兵节点,但主库节点宕机后,哨兵会发现主库节点宕机,然后在从库中选择一个库作为进的主库,另外哨兵也可以做集群,从而可以保证但某一个哨兵节点宕机后,还有其他哨兵节点可以继续工作。
-
优点
- 哨兵模式是基于主从模式的,具有主从模式的所有优点。
- 主从可以自动切换,系统更健壮,保证Redis集群的高可用性。
-
缺点
- Redis较难支持在线扩容,在集群容量达到上限时在线扩容会变得很复杂。
-
-
Cluster模式
-
策略: Cluster 集群模式,实现了 Redis 的分布式存储,也就是说每台 Redis 节点上存储不同的内容。所有的redis节点彼此互联(PING-PONG机制),内部使用二进制协议优化传输速度和带宽。redis cluster有固定的16384个hash slot,对每个key计算CRC16值,然后对16384取模,可以获取key对应的hash slot。redis cluster中每个master都会持有部分slot。
-
优点
-
哨兵模式是基于主从模式的,所有主从的优点,哨兵模式都具有。
-
无中心架构,支持动态扩容
- 增加一个master,就将其他master的hash slot移动部分过去,减少一个master,就将它的hash slot移动到其他master上去
-
-
缺点:每个Node承担着互相监听、高并发数据写入、高并发数据读出,工作任务繁重,如果一个节点宕机,整个集群不可用。生产环境中,cluster模式与主从模式搭配使用,即可避免出现的集群宕机问题
-
-
参考博客
- https://segmentfault.com/a/1190000022
持久化机制
-
RDB持久化
-
方式:在指定的时间间隔内将内存中的数据集快照写入磁盘,实际操作过程是fork一个子进程,先将数据集写入临时文件,写入成功后,再替换之前的文件,用二进制压缩存储。
-
优点
- RDB 在恢复大数据集时的速度比 AOF 的恢复速度要快;
- RDB 可以最大化 Redis 的性能:父进程在保存 RDB 文件时唯一要做的就是 fork 出一个子进程,然后这个子进程就会处理接下来的所有保存工作,父进程无须执行任何磁盘 I/O 操作。
- RDB快照是一个压缩过的非常紧凑的文件,保存着某个时间点的数据集,适合做数据的备份,灾难恢复
-
缺点
- RDB的数据安全性是不如AOF的,保存整个数据集的过程是比繁重的,根据配置可能要几分钟才快照一次,如果服务器宕机,那么就可能丢失几分钟的数据
- Redis数据集较大时,fork的子进程要完成快照会比较耗CPU、耗时
-
-
AOF持久化
-
方式:以文本日志的形式记录Redis的每一个写入、删除请求(查询请求不处理),它是以追加的方是(append-only)写入,没有磁盘寻址的开销,所以写入速度非常快(类似mysql的binlog)
-
优点
- 数据更完整,安全性更高,秒级数据丢失(取决fsync策略,如果是everysec,最多丢失1秒的数据)
- AOF文件是一个只进行追加的日志文件,且写入操作是以Redis协议的格式保存的,内容是可读的,适合误删紧急恢复;
-
缺点
- 对于相同的数据集,AOF文件的体积要大于RDB文件,数据恢复也会比较慢;
- 根据所使用的fsync策略,AOF的速度可能会慢于RDB。 不过在一般情况下,每秒fsync的性能依然非常高
-
使用场景
-
缓存
- 缓存现在几乎是所有中大型网站都在用的必杀技,合理的利用缓存不仅能够提升网站访问速度,还能大大降低数据库的压力。Redis提供了键过期功能,也提供了灵活的键淘汰策略,所以,现在Redis用在缓存的场合非常多。
-
排行榜
- 很多网站都有排行榜应用的,如京东的月度销量榜单、商品按时间的上新排行榜等。Redis提供的有序集合数据类构能实现各种复杂的排行榜应用。
-
计数器
- 什么是计数器,如电商网站商品的浏览量、视频网站视频的播放数等。为了保证数据实时效,每次浏览都得给+1,并发量高时如果每次都请求数据库操作无疑是种挑战和压力。Redis提供的incr命令来实现计数器功能,内存操作,性能非常好,非常适用于这些计数场景
-
分布式锁
- 在很多互联网公司中都使用了分布式技术,分布式技术带来的技术挑战是对同一个资源的并发访问,如全局ID、减库存、秒杀等场景,并发量不大的场景可以使用数据库的悲观锁、乐观锁来实现,但在并发量高的场合中,利用数据库锁来控制资源的并发访问是不太理想的,大大影响了数据库的性能。可以利用Redis的setnx功能来编写分布式的锁,如果设置返回1说明获取锁成功,否则获取锁失败,实际应用中要考虑的细节要更多
-
社交网络
- 点赞、踩、关注/被关注、共同好友等是社交网站的基本功能,社交网站的访问量通常来说比较大,而且传统的关系数据库类型不适合存储这种类型的数据,Redis提供的哈希、集合等数据结构能很方便的的实现这些功能。
-
消息队列
- 消息队列是大型网站必用中间件,如ActiveMQ、RabbitMQ、Kafka等流行的消息队列中间件,主要用于业务解耦、流量削峰及异步处理实时性低的业务。Redis提供了发布/订阅及阻塞队列功能,能实现一个简单的消息队列系统。另外,这个不能和专业的消息中间件相比。
主从复制
-
定义:主从复制,是指将一台Redis服务器的数据,复制到其他的Redis服务器。前者称为主节点(master),后者称为从节点(slave);数据的复制是单向的,只能由主节点到从节点。
-
作用
- 数据冗余:主从复制实现了数据的热备份,是持久化之外的一种数据冗余方式。
- 故障恢复:当主节点出现问题时,可以由从节点提供服务,实现快速的故障恢复;实际上是一种服务的冗余。
- 负载均衡:在主从复制的基础上,配合读写分离,可以由主节点提供写服务,由从节点提供读服务(即写Redis数据时应用连接主节点,读Redis数据时应用连接从节点),分担服务器负载;尤其是在写少读多的场景下,通过多个从节点分担读负载,可以大大提高Redis服务器的并发量。
- 高可用基石:除了上述作用以外,主从复制还是哨兵和集群能够实施的基础,因此说主从复制是Redis高可用的基础。
-
过程
-
连接建立阶段
- 该阶段的主要作用是在主从节点之间建立连接,为数据同步做好准备。
-
数据同步阶段
-
主从节点之间的连接建立以后,便可以开始进行数据同步,该阶段可以理解为从节点数据的初始化。具体执行的方式是:从节点向主节点发送psync命令(Redis2.8以前是sync命令),开始同步
-
全量复制
- 用于初次复制或其它无法进行部分复制的情况,将主节点中的所有数据都发送给从节点。当数据量过大的时候,会造成很大的网络开销。
-
增量复制
- 用于处理在主从复制中因网络闪退等原因造成数据丢失场景,当从节点再次连上主节点,如果条件允许,主节点会补发丢失数据给从节点,因为补发的数据远远小于全量数据,可以有效避免全量复制的过高开销。但需要注意,如果网络中断时间过长,造成主节点没有能够完整地保存中断期间执行的写命令,则无法进行部分复制,仍使用全量复制 。
-
-
-
命令传播阶段
- 数据同步阶段完成后,主从节点进入命令传播阶段;在这个阶段主节点将自己执行的写命令发送给从节点,从节点接收命令并执行,从而保证主从节点数据的一致性。
-