redis是什么
redis(Remote Dictionary Server ,即远程字典服务),是使用 C语言编写的,基于内存存储,Key-Value类型的数据库。它支持网络,亦可持久化。可用作数据库,高速缓存和消息队列代理。是为了解决高并发、高扩展,大数据存储等一系列的问题而产生的数据库解决方案。
reids支持的数据结构,如字符串(strings),散列(hashes),列表(lists),集合(sets),有序集合(sorted sets),数据流(steam)。
redis支持的范围查询,如 bitmaps, hyperloglogs 和地理空间(geospatial)索引半径查询。
redis支持的数据备份,有一种是RDB,一种是AOF
redis支持的运行模式,有哨兵模式(Sentinel)和自动分区的集群模式(Cluster),来提供高可用性(high availability)。
redis支持的运行功能,如复制(replication), LUA脚本(Lua scripting), LRU驱动事件(LRU eviction),事务(transactions)。
Redis与其他key-value存储有什么不同
Redis有着更为复杂的数据结构并且提供对他们的原子性操作,这是一个不同于其他数据库的进化路径。Redis的数据类型都是基于基本数据结构的同时对程序员透明,无需进行额外的抽象。
Redis运行在内存中但是可以持久化到磁盘,所以在对不同数据集进行高速读写时需要权衡内存,因为数据量不能大于硬件内存。在内存数据库方面的另一个优点是,相比在磁盘上相同的复杂的数据结构,在内存中操作起来非常简单,这样Redis可以做很多内部复杂性很强的事情。同时,在磁盘格式方面他们是紧凑的以追加的方式产生的,因为他们并不需要进行随机访问。
Redis优势
速度快性能极高:redis数据读写速度非常快,因为它把数据都读取到内存当中操作,而且redis是用C语言编写的,是最“接近”操作系统的语言,所以执行速度相对较快。Redis能读的速度是110000次/s,写的速度是81000次/s 。
丰富的数据类型:Redis支持二进制案例的 Strings, Lists, Hashes, Sets 及 Ordered Sets 数据类型操作。
支持操作原子性:redis的所有操作都是原子性,支持事务,所谓的原子性就是对数据的更改要么全部执行,要么全部不执行。单个操作是原子性的。多个操作也支持事务,即原子性,通过MULTI和EXEC指令包起来。
支持丰富的特性:redis支持主从复制,主机会自动将数据同步到从机,可以进行读写分离。Redis还支持 publish/subscribe,通知, key 过期等等特性。
Redis缺点
是数据库容量受到物理内存的限制,不能用作海量数据的高性能读写,因此Redis适合的场景主要局限在较小数据量的高性能操作和运算上。
redis的八大特性
1.速度快
正常情况下,Redis执行命令的速度非常快,官方给出的数字是读写性能可以达到10万/秒,当然这也取决于机器的性能,但这里先不讨论机器性能上的差异,只分析一下是什么造就了Redis除此之快的速度,可以大致归纳为以下三点:
Redis的所有数据都是存放在内存中的,所以把数据放在内存中是Redis速度快的最主要原因。
Redis是用C语言实现的,一般来说C语言实现的程序“距离”操作系统更近,执行速度相对会更快。
Redis使用了单线程架构,预防了多线程可能产生的竞争问题。
基于键值对的数据结构服务器
几乎所有的编程语言都提供了类似字典的功能,例如Java里的map、Python里的dict,类似于这种组织数据的方式叫作基于键值的方式,与很多键值对数据库不同的是,Redis中的值不仅可以是字符串,而且还可以是具体的数据结构,这样不仅能便于在许多应用场景的开发,同时也能够提高开发效率。Redis的全称是REmote Dictionary Server,它主要提供了5种数据结构:字符串、哈希、列表、集合、有序集合。
丰富的功能
除了5种数据结构,Redis还提供了许多额外的功能:
提供了键过期功能,可以用来实现缓存。
提供了发布订阅功能,可以用来实现消息系统。
支持Lua脚本功能,可以利用Lua创造出新的Redis命令。
提供了简单的事务功能,能在一定程度上保证事务特性。
提供了流水线(Pipeline)功能,这样客户端能将一批命令一次性传到Redis,减少了网络的开销。
简单稳定
Redis的简单主要表现在三个方面。
Redis的源码很少。
Redis使用单线程模型,这样不仅使得Redis服务端处理模型变得简单,而且也使得客户端开发变得简单。
Redis不需要依赖于操作系统中的类库(例如Memcache需要依赖libevent这样的系统类库),Redis自己实现了事件处理的相关功能。
Redis虽然很简单,但是不代表它不稳定。维护的上千个Redis为例,没有出现过因为Redis自身bug而宕掉的情况。
客户端语言多
Redis提供了简单的TCP通信协议,很多编程语言可以很方便地接入到Redis,并且由于Redis受到社区和各大公司的广泛认可,所以支持Redis的客户端语言也非常多,几乎涵盖了主流的编程语言,例如Java、PHP、Python、C、C++、Nodejs等。
持久化
通常看,将数据放在内存中是不安全的,一旦发生断电或者机器故障,重要的数据可能就会丢失,因此Redis提供了两种持久化方式:RDB和AOF,即可以用两种策略将内存的数据保存到硬盘中(如图所示)这样就保证了数据的可持久性。
主从复制
Redis提供了复制功能,实现了多个相同数据的Redis副本(如图所示),复制功能是分布式Redis的基础。
高可用和分布式
Redis从2.8版本正式提供了高可用实现Redis Sentinel,它能够保证Redis节点的故障发现和故障自动转移。Redis从3.0版本正式提供了分布式实现Redis Cluster,它是Redis真正的分布式实现,提供了高可用、读写和容量的扩展性。
redis应用场景
Redis 是完全开源免费的,是一个高性能的key-value类型的内存数据库。整个数据库统统加载在内存当中进行操作,定期通过异步操作把数据库数据flush到硬盘上进行保存。因为是纯内存操作,Redis的性能非常出色,每秒可以处理超过 10万次读写操作,是已知性能最快的Key-Value DB。Redis的出色之处不仅仅是性能,Redis最大的魅力是支持保存多种数据结构,此外单个value的最大限制是1GB,因此Redis可以用来实现很多有用的功能,比方说用List来做FIFO双向链表,实现一个轻量级的高性 能消息队列服务,用他的Set可以做高性能的tag系统等等。另外Redis也可以对存入的Key-Value设置expire时间。
解决应用服务器的CPU和内存压力。
减少I/O的读操作,减轻I/O的压力。
关系型数据库的扩展性不强,难以改变表结构。
nosql数据库没有关联关系,数据结构简单,拓展表比较容易。
nosql读取速度快,对较大数据处理快。
-
适用场景
Redis虽然是一个内存缓存,数据存在内存,但是Redis支持多种方式将数据持久化,写入硬盘,所有,Redis数据的稳定性也是非常有保障的,结合Redis的集群方案,有的系统已经将Redis当做一种NoSql数据存储来适用。
数据高并发的读写。
海量数据的读写。
对扩展性要求高的数据。 -
不适场景
用Redis去保存用户的基本信息,虽然它能够支持持久化,但是它的持久化方案并不能保证数据绝对的落地,并且还可能带来Redis性能下降,因为持久化太过频繁会增大Redis服务的压力。总结就是数据量太大、数据访问频率非常低的业务都不适合使用Redis,数据太大会增加成本,访问频率太低,保存在内存中纯属浪费资源。
需要事务支持(非关系型数据库)。
基于sql结构化查询储存,关系复杂。
Redis应用场景
数据缓存
热点数据的缓存。由于redis访问速度块、支持的数据类型比较丰富,所以redis很适合用来存储热点数据,另外结合expire,我们可以设置过期时间然后再进行缓存更新操作,这个功能最为常见,我们几乎所有的项目都有所运用。
会话缓存
可以使用 Redis 来统一存储多台应用服务器的会话信息。当应用服务器不再存储用户的会话信息,也就不再具有状态,一个用户可以请求任意一个应用服务器,从而更容易实现高可用性以及可伸缩性。以PHP为例,默认Session是保存在服务器的文件中,如果是集群服务,同一个用户过来可能落在不同机器上,这就会导致用户频繁登陆;采用Redis保存Session后,无论用户落在那台机器上都能够获取到对应的Session信息。
全页缓存
Redis还提供很简便的FPC平台。以Magento为例,Magento提供一个插件来使用Redis作为全页缓存后端。此外,对WordPress的用户来说,Pantheon有一个非常好的插件 wp-redis,这个插件能帮助你以最快速度加载你曾浏览过的页面。大型互联网公司都会使用Redis作为缓存存储数据,提升页面相应速度。即使重启了Redis实例,因为有磁盘的持久化,用户也不会看到页面加载速度的下降。
计数器
可以对 String 进行自增自减运算,从而实现计数器功能。Redis 这种内存型数据库的读写性能非常高,很适合存储频繁读写的计数量。由于 incrby 命令可以实现原子性的递增,所以可以运用于高并发的秒杀活动、分布式序列号的生成、具体业务还体现在比如限制一个手机号发多少条短信、一个接口一分钟限制多少请求、一个接口一天限制调用多少次等等。利用Redis中原子性的自增操作,我们可以统计类似用户点赞数、用户访问数等,这类操作如果用MySQL,频繁的读写会带来相当大的压力;限速器比较典型的使用场景是限制某个用户访问某个API的频率,常用的有抢购时,防止用户疯狂点击带来不必要的压力。
排行榜
Redis在内存中对数字进行递增或递减的操作实现的非常好。集合(Set)和有序集合(Sorted Set)也使得我们在执行这些操作的时候变的非常简单在使用传统的关系型数据库(mysql、oracle等)来做这个事儿,非常的麻烦,而利用Redis的SortSet(有序集合)数据结构能够简单的搞定。
好友关系
利用集合的一些命令,比如求交集、并集、差集等。可以方便搞定一些共同好友、共同爱好之类的功能。Redis set对外提供的功能与list类似是一个列表的功能,特殊之处在于set是可以自动排重的,当你需要存储一个列表数据,又不希望出现重复数据时,set是一个很好的选择,并且set提供了判断某个成员是否在一个set集合内的重要接口,这个也是list所不能提供的。 又或者在微博应用中,每个用户关注的人存在一个集合中,就很容易实现求两个人的共同好友功能。 这个在奶茶活动中有运用,就是利用set存储用户之间的点赞关联的,另外在点赞前判断是否点赞过就利用了sismember方法,当时这个接口的响应时间控制在10毫秒内,十分高效。
消息队列(发布/订阅功能)
除了Redis自身的发布/订阅模式,我们也可以利用List来实现一个队列机制,比如:到货通知、邮件发送之类的需求,不需要高可靠,但是会带来非常大的DB压力,完全可以用List来完成异步解耦。你应该已经注意到像list push和list pop这样的Redis命令能够很方便的执行队列操作了,但能做的可不止这些:比如Redis还有list pop的变体命令,能够在列表为空时阻塞队列。现代的互联网应用大量地使用了消息队列(Messaging)。消息队列不仅被用于系统内部组件之间的通信,同时也被用于系统跟其它服务之间的交互。消息队列的使用可以增加系统的可扩展性、灵活性和用户体验。非基于消息队列的系统,其运行速度取决于系统中最慢的组件的速度(注:短板效应)。而基于消息队列可以将系统中各组件解除耦合,这样系统就不再受最慢组件的束缚,各组件可以异步运行从而得以更快的速度完成各自的工作。
延时操作
举个该特性的应用场景。 比如在订单生产后我们占用了库存,10分钟后去检验用户是够真正购买,如果没有购买将该单据设置无效,同时还原库存。 由于redis自2.8.0之后版本提供Keyspace Notifications功能,允许客户订阅Pub/Sub频道,以便以某种方式接收影响Redis数据集的事件。 所以我们对于上面的需求就可以用以下解决方案,我们在订单生产时,设置一个key,同时设置10分钟后过期, 我们在后台实现一个监听器,监听key的实效,监听到key失效时将后续逻辑加上。 当然我们也可以利用rabbitmq、activemq等消息中间件的延迟队列服务实现该需求。
分布式锁
这个主要利用redis的setnx命令进行,setnx:"set if not exists"就是如果不存在则成功设置缓存同时返回1,否则返回0 ,这个特性在俞你奔远方的后台中有所运用,因为我们服务器是集群的,定时任务可能在两台机器上都会运行,所以在定时任务中首先 通过setnx设置一个lock,如果成功设置则执行,如果没有成功设置,则表明该定时任务已执行。 当然结合具体业务,我们可以给这个lock加一个过期时间,比如说30分钟执行一次的定时任务,那么这个过期时间设置为小于30分钟的一个时间 就可以,这个与定时任务的周期以及定时任务执行消耗时间相关。
分页、模糊搜索
redis的set集合中提供了一个zrangebylex方法,如下:通过ZRANGEBYLEX zset - + LIMIT 0 10 可以进行分页数据查询,其中- +表示获取全部数据。zrangebylex key min max 这个就可以返回字典区间的数据,利用这个特性可以进行模糊查询功能,这个也是目前我在redis中发现的唯一一个支持对存储内容进行模糊查询的特性。
数据结构 | 持久化数据 |
---|---|
通过List实现按自然时间排序的数据 | 最新N个数据 |
利用zset(有序集合) | 排行榜、TOP N |
Expire过期 | 时效性数据如:手机验证码 |
原子性,自增防范INCR、DECR | 去除大量数据中的重复数据 |
利用Set集合 | 构建队列 |
pub/sub模式 | 发布订阅消息系统 |