redis相关文章
----redis原理概述
-----redis集群方案
----redis分区(分片)原理
----Redis实现分布式锁
----redis缓存穿透、雪崩和解决方案
一、概述
1、redis的作用
- 读写性能优异, Redis能读的速度是110000次/s,写的速度是81000次/s,因为数据存在内存中,类似于HashMap,HashMap的优势就是查找和操作的时间复杂度都很低
- 支持数据持久化,支持AOF和RDB两种持久化方式
- 支持事务,Redis的所有操作都是原子性的,同时Redis还支持对几个操作合并后的原子性执行
- 数据结构丰富,除了支持string类型的value外还支持hash、set、zset、list等数据结构
- 丰富的特性:可用于缓存,消息,按key设置过期时间,过期后将会自动删除
- 采用单线程,避免了不必要的上下文切换和竞争条件,也不存在多进程或者多线程导致的切换而消耗 CPU,不用去考虑各种锁的问题,不存在加锁释放锁操作,没有因为可能出现死锁而导致的性能消耗
- 使用底层模型不同,它们之间底层实现方式以及与客户端之间通信的应用协议不一样,Redis直接自己构建了 VM 机制 ,因为一般的系统调用系统函数的话,会浪费一定的时间去移动和请求
- 使用多路 I/O 复用模型,非阻塞 IO
2、Redis 的数据类型
- String
- set
- zset
- Hash
- List
- Pub/Sub–拓展类型
- HyperLogLog
- Geo
3、事物支持
操作都是原子性, 所谓的原子性就是对数据的更改要么全部执行, 要么全部不执行
4、Redis 的持久化机制
1. RDB
RDB(Redis DataBase)持久化方式:是指用数据集快照的方式半持久化模式) 记录 redis 数据库的所有键值对,在某个时间点将数据写入一个临时文件, 持久化结束后, 用这个临时文件替换上次持久化的文件, 达到数据恢复
1.1 优点
- 只有一个文件 dump.rdb, 方便持久化
- 容灾性好, 一个文件可以保存到安全的磁盘
- 性能最大化, fork 子进程来完成写操作, 让主进程继续处理命令, 所以是 IO 最大化,使用单独子进程来进行持久化,主进程不会进行任何 IO 操作,保证了 redis 的高性能
- .相对于数据集大时, 比AOF 的启动效率更高
1.2 缺点
- 数据安全性低。RDB 是间隔一段时间进行持久化,如果持久化之间 redis 发生故障, 会发生数据丢失。所以这种方式更适合数据要求不严谨的时候
2. AOF
AOF(Append-only file)持久化方式: 是指所有的命令行记录以 redis 命令请求协议的格式完全持久化存储)保存为 aof 文件
2.1 优点
- 数据安全, aof 持久化可以配置 appendfsync 属性, 有 always, 每进行一次命令操作就记录到aof 文件中一次
- 通过 append 模式写文件, 即使中途服务器宕机, 可以通过 redis-check-aof 工具解决数据一致性问题
- AOF 机制的 rewrite 模式。AOF 文件没被 rewrite 之前( 文件过大时会对命令进行合并重写), 可以删除其中的某些命令( 比如误操作的 flushall))
2.2 缺点
- AOF 文件比 RDB 文件大, 且恢复速度慢
- 数据集大的时候, 比 rdb 启动效率低
5、Redis 的回收策略(淘汰策略)
5.1 淘汰策略
- volatile-lru:从已设置过期时间的数据集( server.db[i].expires)中挑选最近最少使用的数据淘汰
- volatile-ttl: 从已设置过期时间的数据集( server.db[i].expires) 中挑选将要过期的数据淘汰
- volatile-random: 从已设置过期时间的数据集( server.db[i].expires) 中任意选择数据淘汰
- allkeys-lru: 从数据集( server.db[i].dict) 中挑选最近最少使用的数据淘汰
- allkeys-random: 从数据集( server.db[i].dict) 中任意选择数据淘汰
- no-enviction( 驱逐) : 禁止驱逐数据
5.2 使用策略规则
- 如果数据呈现幂律分布,也就是一部分数据访问频率高,一部分数据访问频率 低, 则使用 allkeys-lru
- 如果数据呈现平等分布, 也就是所有的数据访问频率都相同, 则使用allkeys-random
6、Redis 的同步机制
主从同步。第一次同步时,主节点做一次 bgsave, 并同时将后续修改操作记录到内存buffer, 待完成后将 rdb 文件全量同步到复制节点, 复制节点接受完成后将 rdb 镜像加载到内存。加载完成后, 再通知主节点将期间修改的操作记录同步到复制节点进行重放就完成了同步过程
7、Redis的应用场景
7.1 计数器
可以对 String 进行自增自减运算,从而实现计数器功能。Redis 这种内存型数据库的读写性能非常高,很适合存储频繁读写的计数量
7.2 缓存
将热点数据放到内存中,设置内存的最大使用量以及淘汰策略来保证缓存的命中率
7.3 会话缓存
可以使用 Redis 来统一存储多台应用服务器的会话信息。当应用服务器不再存储用户的会话信息,也就不再具有状态,一个用户可以请求任意一个应用服务器,从而更容易实现高可用性以及可伸缩性
7.4 全页缓存(FPC)
除基本的会话token之外,Redis还提供很简便的FPC平台。以Magento为例,Magento提供一个插件来使用Redis作为全页缓存后端。此外,对WordPress的用户来说,Pantheon有一个非常好的插件 wpredis,这个插件能帮助你以最快速度加载你曾浏览过的页面
7.5 消息队列(发布/订阅功能)
List 是一个双向链表,可以通过 lpush 和 rpop 写入和读取消息
7.6 分布式锁实现
在分布式场景下,无法使用单机环境下的锁来对多个节点上的进程进行同步。可以使用 Redis 自带的SETNX 命令实现分布式锁,除此之外,还可以使用官方提供的 RedLock 分布式锁实现
7.7 查找表
例如 DNS 记录就很适合使用 Redis 进行存储。查找表和缓存类似,也是利用了 Redis 快速的查找特性。但是查找表的内容不能失效,而缓存的内容可以失效,因为缓存不作为可靠的数据来源
8、redis 过期键的删除策略
- expire(过期时间)
- persist(永久有效)
1. 定时删除
- 在设置键的过期时间的同时,创建一个定时器 timer). 让定时器在键的过期时间来临时,立即执行对键的删除操作,
- 对内存友好,会占用大量的CPU资源去处理过期的数据,影响缓存的响应时间和吞吐量
2. 惰性删除
- 放任键过期不管,但是每次从键空间中获取键时,都检查取得的键是 否过期, 如果过期的话, 就删除该键;如果没有过期, 就返回该键
- 最大化地节省CPU资源,却对内存非常不友好,极端情况可能出现大量的过期key没有再次被访问,从而不会被清除,占用大量内存
3. 定期删除
每隔一段时间程序就对数据库进行一次检查,删除里面的过期键。至于要删除多少过期键, 以及要检查多少个数据库, 则由算法决定
9、内存优化
- 利用Hash,list,sorted set,set等集合类型数据,因为通常情况下很多小的Key-Value可以用更紧凑的方式存放到一起。尽可能使用散列表(hashes),散列表(是说散列表里面存储的数少)使用的内存非常小,所以你应该尽可能的将你的数据模型抽象到一个散列表里面
- 比如你的web系统中有一个用户对象,不要为这个用户的名称,姓氏,邮箱,密码设置单独的key,而是应该把这个用户的所有信息存储到一张散列表里面
二、线程模型
1、定义
Redis基于Reactor模式开发了网络事件处理器,这个处理器被称为文件事件处理器(file eventhandler)。它的组成结构为4部分
- 多个套接字
- IO多路复用程序
- 文件事件分派器
- 事件处理器
文件事件分派器队列的消费是单线程的,所以Redis才叫单线程模型
流程
- 文件事件处理器使用 I/O 多路复用(multiplexing)程序来同时监听多个套接字
- 根据套接字目前执行的任务来为套接字关联不同的事件处理器
- 被监听的套接字准备好执行连接应答(accept)、读取(read)、写入(write)、关闭(close)等操作
- 操作相对应的文件事件就会产生, 这时文件事件处理器就会调用套接字之前关联好的事件处理器来处理这些事件
总结
然文件事件处理器以单线程方式运行, 但通过使用 I/O 多路复用程序来监听多个套接字, 文件事件处理器既实现了高性能的网络通信模型, 又可以很好地与 redis 服务器中其他同样以单线程方式运行的模块进行对接, 这保持了 Redis 内部单线程设计的简单性
三、事务
1、 什么是事务
- 事务是一个单独的隔离操作:事务中的所有命令都会序列化、按顺序地执行。事务在执行的过程中,不会被其他客户端发送来的命令请求所打断
- 事务是一个原子操作:事务中的命令要么全部被执行,要么全部都不执行
2、Redis事务的概念
- Redis 事务的本质是通过MULTI、EXEC、WATCH等一组命令的集合。事务支持一次执行多个命令,一个事务中所有命令都会被序列化。在事务执行过程,会按照顺序串行化执行队列中的命令,其他客户端提交的命令请求不会插入到事务执行命令序列中
- 总结说:redis事务就是一次性、顺序性、排他性的执行一个队列中的一系列命令
3、Redis事务的三个阶段
- 事务开始 MULTI
- 命令入队
- 事务执行 EXEC
- 事务执行过程中,如果服务端收到有EXEC、DISCARD、WATCH、MULTI之外的请求,将会把请求放入队列中排队
4、Redis事务相关命令
Redis事务功能是通过MULTI、EXEC、DISCARD和WATCH 四个原语实现的,Redis会将一个事务中的所有命令序列化,然后按顺序执行
- redis 不支持回滚,“Redis 在事务失败时不进行回滚,而是继续执行余下的命令”, 所以 Redis 的内部可以保持简单且快速
- 如果在一个事务中的命令出现错误,那么所有的命令都不会执行
- 如果在一个事务中出现运行错误,那么正确的命令会被执行
1、命令
-
MULT
用于开启一个事务,它总是返回OK。 MULTI执行之后,客户端可以继续向服务器发送任意多条命令,这些命令不会立即被执行,而是被放到一个队列中,当EXEC命令被调用时,所有队列中的命令才会被执行 -
EXEC
执行所有事务块内的命令。返回事务块内所有命令的返回值,按命令执行的先后顺序排列。 当操作被打断时,返回空值 nil -
DISCARD
清空事务队列,并放弃执行事务, 并且客户端会从事务状态中退出 -
WATCH
是一个乐观锁,可以为 Redis 事务提供 check-and-set (CAS)行为。 可以监控一个或多个键,一旦其中有一个键被修改(或删除),之后的事务就不会执行,监控一直持续到EXEC命令 -
UNWATCH
UNWATCH命令可以取消watch对所有key的监控
5、事务管理(ACID)概述
1、ACID
- 原子性(Atomicity)
原子性是指事务是一个不可分割的工作单位,事务中的操作要么都发生,要么都不发生 - 一致性(Consistency)
事务前后数据的完整性必须保持一致 - 隔离性(Isolation)
多个事务并发执行时,一个事务的执行不应影响其他事务的执行 - 持久性(Durability)
持久性是指一个事务一旦被提交,它对数据库中数据的改变就是永久性的,接下来即使数据库发生故障也不应该对其有任何影响
2、Redis事务支持隔离性
Redis 是单进程程序,并且它保证在执行事务时,不会对事务进行中断,事务可以运行直到执行完所有事务队列中的命令为止。因此,Redis 的事务是总是带有隔离性的
3、不保证原子性、且没有回滚
Redis中,单条命令是原子性执行的,但事务不保证原子性,且没有回滚。事务中任意命令执行失败,其余的命令仍会被执行
4、 Redis事务其他实现
- 基于Lua脚本,Redis可以保证脚本内的命令一次性、按顺序地执行
- 其同时也不提供事务运行错误的回滚,执行过程中如果部分命令运行错误,剩下的命令还是会继续运行完* 基于中间标记变量,通过另外的标记变量来标识事务是否执行完成,读取数据时先读取该标记变量判断是否事务执行完成。但这样会需要额外写代码实现,比较繁琐
redis相关文章
----redis原理概述
-----redis集群方案
----redis分区(分片)原理
----Redis实现分布式锁
----redis缓存穿透、雪崩和解决方案