REmote DIctionary Server(Redis)是完全开源免费的,遵守 BSD 协议,是一个高性能的key-value数据库。它通常被称为数据结构服务器,因为值(value)可以是 字符串(String), 哈希(Hash), 列表(list), 集合(sets) 和 有序集合(sorted sets)等类型。
注:BSD开源协议(original BSD license、FreeBSD license、Original BSD license)是一个给于使用者很大自由的协议,BSD 代码鼓励代码共享,但需要尊重代码作者的著作权。
一个产品的使用场景肯定是需要根据产品的特性,所以下面根据Redis特点延伸对应的应用场景。
Redis的特点有7个,分别是:读写性能优异,数据类型丰富,单线程,数据自动过期,支持发布订阅,分布式,持久化。
高性能适合当做缓存,缓存是Redis最常见的应用场景,之所以这么使用,主要是因为Redis读写性能优异。而且逐渐有取代memcached成为首选服务端缓存组件的趋势,而且,Redis内部是支持事务的,在使用时候能有效保证数据的一致性。
作为缓存使用时,一般有两种方案保存数据:
读取前,先去读Redis,如果没有数据,读取数据库,将数据拉入Redis。
避免缓存击穿。(数据库没有就需要命中的数据,导致Redis一直没有数据,而一直命中数据库。)使用redis的 setnx方法构建一个互斥锁,只有一个请求线程获得锁去更新数据,其他请求等待,之后去请求最新缓存。
数据的实时性相对会差一点。
插入数据时,同时写入Redis。
Redis相比其他缓存,有一个非常大的优势,就是支持多种数据类型。
Redis最为常用的数据类型主要有以下五种:
String 数据结构是简单的key-value类型,value其实不仅是String,也可以是数字。
2.1.1. 常用命令
get、set、incr、decr、mget等。
2.1.2. 使用场景
常规key-value缓存应用适合最简单的k-v存储,类似于memcached的存储结构,常规计数(微博数, 粉丝数),短信验证码,配置信息等,就用这种类型来存储。
2.1.3. 实现方式
String在redis内部存储默认就是一个字符串,被redisObject所引用,当遇到incr,decr等操作时会转成数值型进行计算,此时redisObject的encoding字段为int。
hash格式,hash类型的格式为:键名->字段名,适合ID-Detail这样的场景。
2.2.1. 常用命令
hget,hset,hgetall 等。
2.2.2. 使用场景
存储部分变更数据,如商品详情,个人信息详情,新闻详情等。
2.2.3. 实现方式
Redis Hash对应Value内部实际就是一个HashMap,实际这里会有2种不同实现:
简单的list,顺序列表,支持首位或者末尾插入数据
2.3.1. 常用命令
lpush,rpush,lpop,rpop,lrange等。
2.3.2. 使用场景及实现方式
因为list是有序的,比较适合存储一些有序且数据相对固定的数据。如省市区表、字典表等,适合根据写入的时间来排序,如:最新的***,消息队列等。
2.3.2.1. 消息队列系统
使用list可以构建队列系统,使用sorted set甚至可以构建有优先级的队列系统。
比如:将Redis用作日志收集器
实际上还是一个队列,多个端点将日志信息写入Redis,然后一个worker统一将所有日志写到磁盘。
2.3.2.2. 取最新N个数据的操作
记录前N个最新登陆的用户Id列表,超出的范围可以从数据库中获得。
比如sina微博:
在Redis中我们的最新微博ID使用了常驻缓存,这是一直更新的。但是我们做了限制不能超过5000个ID,因此我们的获取ID函数会一直询问Redis。只有在start/count参数超出了这个范围的时候,才需要去访问数据库。
我们的系统不会像传统方式那样“刷新”缓存,Redis实例中的信息永远是一致的。SQL数据库(或是硬盘上的其他类型数据库)只是在用户需要获取“很远”的数据时才会被触发,而主页或第一个评论页是不会麻烦到硬盘上的数据库了。
无序list,查找速度快,适合交集、并集、差集处理
2.4.1. 常用命令
sadd,spop,smembers,sunion 等。
2.4.2. 使用场景
可以简单的理解为ID-List的模式,如微博中一个人有哪些好友,set最牛的地方在于,可以对两个set提供交集、并集、差集操作。例如:查找两个人共同的好友等。
2.4.3. 实现方式
set 的内部实现是一个 value永远为null的HashMap,实际就是通过计算hash的方式来快速排重的,这也是set能提供判断一个成员是否在集合内的原因。
有序的set
2.5.1. 常用命令
zadd,zrange,zrem,zcard等
2.5.2. 使用场景
是set的增强版本,增加了一个score参数,自动会根据score的值进行排序。比较适合类似于top 10等不根据插入的时间来排序的数据。
比如:一个存储全班同学成绩的Sorted Set,其集合value可以是同学的学号,而score就可以是其考试得分,这样在数据插入集合的时候,就已经进行了天然的排序。另外还可以用Sorted Set来做带权重的队列,比如普通消息的score为1,重要消息的score为2,然后工作线程可以选择按score的倒序来获取工作任务。让重要的任务优先执行。
2.5.3. 实现方式
Redis sorted set的内部使用HashMap和跳跃表(SkipList)来保证数据的存储和有序,HashMap里放的是成员到score的映射,而跳跃表里存放的是所有的成员,排序依据是HashMap里存的score,使用跳跃表的结构可以获得比较高的查找效率,并且在实现上比较简单。
Pub/Sub 从字面上理解就是发布(Publish)与订阅(Subscribe),在Redis中,你可以设定对某一个key值进行消息发布及消息订阅,当一个key值上进行了消息发布后,所有订阅它的客户端都会收到相应的消息。
5.1. 常用命令:PSUBSCRIBE,PUBSUB,PUBLISH,SUBSCRIBE,PUNSUBSCRIBE,UNSUBSCRIBE等。
5.2. 使用场景
5.3. 实现方法
Redis提供了发布订阅功能,可以用于消息的传输,Redis的发布订阅机制包括三个部分,发布者,订阅者和Channel。
发布者和订阅者都是Redis客户端,Channel则为Redis服务器端,发布者将消息发送到某个的频道,订阅了这个频道的订阅者就能接收到这条消息。
Redis的这种发布订阅机制与基于主题的发布订阅类似,Channel相当于主题。
可以有效应对海量数据和高并发。
Redis 3.0版本时候官方加入了分布式的支持,主要是两个方面:
而且Redis虽然是一个内存缓存,数据存在内存,但是Redis支持多种方式将数据持久化,写入硬盘,所以,Redis数据的稳定性也是非常有保障的,结合Redis的集群方案,有的系统已经将Redis当做一种NoSql数据存储来使用。
6.1. 持久化
如果Redis服务器只作为缓存使用,Redis中存储的数据来自其他地方同步过来的备份,那么就没有必要开启数据持久化的选项。
Redis提供了将数据定期自动持久化至硬盘的能力,包括RDB和AOF两种方案,两种方案分别有其长处和短板,可以配合起来同时运行,确保数据的稳定性。
6.1.1. RDB
定期保存数据快照至一个rbd文件中,并在启动时自动加载rdb文件,恢复之前保存的数据。
6.1.1.1. 优点
1) 对性能影响最小:Redis在保存RDB快照时会fork出子进程进行,几乎不影响Redis处理客户端请求的效率。
2) 每次快照会生成一个完整的数据快照文件,所以可以辅以其他手段保存多个时间点的快照(例如把每天0点的快照备份至其他存储媒介中),作为非常可靠的灾难恢复手段。
3) 使用RDB文件进行数据恢复比使用AOF要快很多。
6.1.1.2. 缺点
1) 由于快照是定期生成的,所以在Redis crash时或多或少会丢失一部分数据。
2) 如果数据集非常大且CPU不够强(比如单核CPU),Redis在fork子进程时可能会消耗相对较长的时间,影响Redis对外提供服务的能力。
6.1.1.3. 实现方式
6.1.1.3.1. 自动保存
修改配置文件,配置Redis进行快照自动保存的时机,例如:
save 60 100
让Redis每60秒检查一次数据变更情况,如果发生了100次或以上的数据变更,则进行RDB快照保存。
注:
1) 可以配置多条save指令,让Redis执行多级的快照保存策略。
2) Redis默认开启RDB快照。
6.1.1.3.2. 手动保存
通过BGSAVE命令手动触发RDB快照保存。
6.1.2. AOF
Redis会把每一个写请求都记录在一个日志文件里。在Redis重启时,会把AOF文件中记录的所有写操作顺序执行一遍,确保数据恢复到最新。
6.1.2.1. 优点
1) 最安全:在启用appendfsync always时,任何已写入的数据都不会丢失,使用在启用appendfsync everysec也至多只会丢失1秒的数据。
2) AOF文件在发生断电等问题时也不会损坏:即使出现了某条日志只写入了一半的情况,也可以使用redis-check-aof工具轻松修复。
3) AOF文件易读,可修改:在进行了某些错误的数据清除操作后,只要AOF文件没有rewrite,就可以把AOF文件备份出来,把错误的命令删除,然后恢复数据。
6.1.2.2. 缺点
1) AOF文件通常比RDB文件更大
2) 性能消耗比RDB高
3) 数据恢复速度比RDB慢
6.1.2.3. 实现方式
AOF默认是关闭的,如要开启,进行如下配置:
appendonly yes
AOF提供了三种fsync配置,always/everysec/no,通过配置项[appendfsync]指定:
1) appendfsync no:不进行fsync,将flush文件的时机交给OS决定,速度最快
2) appendfsync always:每写入一条日志就进行一次fsync操作,数据安全性最高,但速度最慢
3) appendfsync everysec:折中的做法,交由后台线程每秒fsync一次
随着AOF不断地记录写操作日志,因为所有的操作都会记录,所以必定会出现一些无用的日志。大量无用的日志会让AOF文件过大,也会让数据恢复的时间过长。不过Redis提供了AOF rewrite功能,可以重写AOF文件,只保留能够把数据恢复到最新状态的最小写操作集。
AOF rewrite可以通过BGREWRITEAOF命令触发,也可以配置Redis定期自动进行:
auto-aof-rewrite-percentage 100auto-aof-rewrite-min-size 64mb
上面两行配置的含义是,Redis在每次AOF rewrite时,会记录完成rewrite后的AOF日志大小,当AOF日志大小在该基础上增长了100%后,自动进行AOF rewrite。同时如果增长的大小没有达到64mb,则不会进行rewrite。
6.1.3. 数据持久化引发的延迟
Redis的数据持久化工作本身就会带来延迟,需要根据数据的安全级别和性能要求制定合理的持久化策略:
1) AOF + fsync always的设置虽然能够绝对确保数据安全,但每个操作都会触发一次fsync,会对Redis的性能有比较明显的影响
2) AOF + fsync every second是比较好的折中方案,每秒fsync一次
3) AOF + fsync never会提供AOF持久化方案下的最优性能
4) 使用RDB持久化通常会提供比使用AOF更高的性能,但需要注意RDB的策略配置
5) 每一次RDB快照和AOF Rewrite都需要Redis主进程进行fork操作。fork操作本身可能会产生较高的耗时,与CPU和Redis占用的内存大小有关。根据具体的情况合理配置RDB快照和AOF Rewrite时机,避免过于频繁的fork带来的延迟。
7.1. 新浪微博
大多数的数据还是落地到mysql的,按照那边DB组同学说法,mysql在新浪只用来存储数据,Redis是用来抗量的。
7.2. 百度的LBS(基于位置服务——Location Based Service)
大量的使用Redis,很多信息都交给Redis来存储,不过同样也是对Redis进行了定制和扩展——增加了数据切分、服务监控、自动扩容等。 按照业务来看,核心业务建议数据还是落地到mysql,redis在异常情况下回丢数据。
8.1. 产品初期
业务需求多变,数据量很小,数据结构朝令夕改,这时候如果用mysql很有可能会在改数据库结构上疲于奔命,如果用Redis,由于没有Scheme约束,数据结构的变更相对容易,比起mysql能轻松不少。
8.2. 产品中期
业务需求逐渐稳定,可以将核心数据导到mysql中落地,其余数据仍然放在Redis中。
8.3. 产品后期
业务需求基本稳定,数据应该尽量都落地到mysql,Redis做高速缓存,或者先写到Redis,再异步刷到mysql。
Redis-使用场景
Redis高级特性及应用场景
redis学习(八)——redis应用场景
Redis发布订阅和应用场景
聊聊redis数据持久化
Redis 可以用来做数据库吗
最后,谢谢各位读者的耐心阅读,如有语句不通顺或者不准确的地方,大家也可以提提改善的意见!(^__^)