Redis的优缺点
优点
- 基于内存操作,读写性能优异,读的速度是110000次/s,写的速度是81000次/s。
- Redis是单线程的,
- 支持多种数据类型,包括String、Hash、List、Set、Zset等。
- 支持数据持久化,支持AOF和RDB两种持久化方式。
- 支持主从复制,主机会自动将数据同步到从机,可以进行读写分离。
缺点
- 数据库容量受到物理内存的限制,不能用作海量数据的高性能读写,因此Redis适合的场景主要局限在较小数据量的高性能操作和运算上。
- Redis 不具备自动容错和恢复功能,主机从机的宕机都会导致前端部分读写请求失败,需要等待机器重启或者手动切换前端的IP才能恢复。
- Redis 较难支持在线扩容,在集群容量达到上限时在线扩容会变得很复杂。
Redis为什么选择单线程
-
避免过多的上下文切换开销。程序始终运行在进程中单个线程内,没有多线程切换的场景。
-
避免同步机制的开销:如果 Redis选择多线程模型,需要考虑数据同步的问题,则必然会引入某些同步机制,会导致在操作数据过程中带来更多的开销,增加程序复杂度的同时还会降低性能。
-
实现简单,方便维护:如果 Redis使用多线程模式,那么所有的底层数据结构的设计都必须考虑线程安全问题,那么 Redis 的实现将会变得更加复杂。
Redis为什么这么快
-
基于内存:Redis是使用内存存储,没有磁盘IO上的开销。数据存在内存中,读写速度快。
-
单线程实现( Redis 6.IO0以前):Redis使用单个线程处理请求,避免了多个线程之间线程切换和锁资源争用的开销。
-
多路复用IO模型:Redis 采用 IO 多路复用技术。Redis 使用单线程来轮询描述符,将数据库的操作都转换成了事件,不在网络I/O上浪费过多的时间。
-
高效的数据结构:Redis 每种数据类型底层都做了优化,目的就是为了追求更快的速度。
Redis的数据类型
基本的数据类型:
-
String:String的数据结构为简单动态字符串,存储的key-value格式,是可以修改的字符串,内部结构实现上类似于Java的ArrayList,采用预分配冗余空间的方式来减少内存的频繁分配。
-
List:在 Redis 3.0 版本中 List 对象的底层数据结构由双向链表或压缩列表实现的,但是在 3.2 版本之后,List 数据类型底层数据结构是由 quicklist **(快速链表)**实现的。
-
Hash:
特殊的数据类型:
Redis的应用场景
-
缓存热点数据,缓解数据库的压力。
-
利用 Redis 原子性的自增操作,可以实现计数器的功能,比如统计用户点赞数、用户访问数等。
-
简单的消息队列,可以使用Redis自身的发布/订阅模式或者List来实现简单的消息队列,实现异步操作。
-
限速器,可用于限制某个用户访问某个接口的频率,比如秒杀场景用于防止用户快速点击带来不必要的压力。
-
好友关系,利用集合的一些命令,比如交集、并集、差集等,实现共同好友、共同爱好之类的功能。
Redis事务
Redis事务支持一次执行多个命令,一个事务中所有命令都会被序列化。在事务执行过程,会按照顺序串行化执行队列中的命令,其他客户端提交的命令请求不会插入到事务执行命令序列中。
总结说:redis事务就是一次性、顺序性、排他性的执行一个队列中的一系列命令。
执行阶段
- multi开启事务
- 命令进入队列
- exec执行事务
如果服务端收到有EXEC、DISCARD、WATCH、MULTI之外的请求,将会把请求放入队列中排队。
相关命令
Redis事务通过multi、exec、discard和watch来实现的,Redis会将一个事务中的所有命令序列化,然后按顺序执行。
-
如果事务在组队中某个命令出现了报告错误,执行时整个的所有队列都会被取消。
-
如果执行阶段某个命令报出了错误,则只有报错的命令不会被执行,而其他的命令都会执行,不会回滚。
- watch:它是一个乐观锁,为 Redis 事务提供 check-and-set (CAS)行为。可以监控一个或多个key,一旦其中有一个key被修改(或删除),之后的事务就不会执行,监控一直持续到EXEC命令。
- multi:用于开启一个事务。 MULTI执行之后,客户端可以继续向服务器发送任意多条命令,这些命令不会立即被执行,而是被放到一个队列中,当EXEC命令被调用时,所有队列中的命令才会被执行。
- exec:执行所有事务块内的命令。返回事务块内所有命令的返回值,按命令执行的先后顺序排列。 当操作被打断时,返回空值 nil 。
- discard:通过调用discard,客户端可以清空事务队列,并放弃执行事务, 并且客户端会从事务状态中退出。
- unwatch:取消watch对所有key的监控。
乐观锁和悲观锁
-
乐观锁:认为不会有其他事务来修改数据,所以不会对数据上锁,但是在更新的时候会判断一下在此期间别人有没有去更新这个数据。主要实现方式有版本号和时间戳机制。
-
悲观锁:认为一定会有其他事务来修改数据,所以每次在拿数据的时候都会上锁。传统数据库主要实现方式有排他锁、事务等。
Redis的持久化
持久化就是把内存的数据写到磁盘中,防止服务宕机导致内存数据丢失。
Redis支持两种方式的持久化,一种是 RDB 的方式,一种是 AOF 的方式。前者会根据指定的规则定时将
内存中的数据存储在硬盘上,而后者在每次执行完命令后将命令记录下来。一般将两者结合使用。