赞
踩
Redis是一个非常快速的开源非关系、Key-Value数据库,通常称为数据结构服务器;它存储了五种不同类型值的键映射。用作数据库,缓存和消息代理。
Redis和其他键值数据库之间的主要区别之一是Redis存储和操作高级数据类型的能力。这些数据类型是大多数开发人员熟悉的基本数据结构(列表,映射,集合和排序集)。Redis的卓越性能,简单性和数据结构的原子操作有助于解决使用传统关系数据库实现时难以实现或执行不佳的问题。
一个产品的使用场景肯定是需要根据产品的特性,先列举一下Redis的特点:
这里我们通过几个场景,不同维度说下Redis的应用。
缓存是Redis最常见的应用场景,之所有这么使用,主要是因为Redis读写性能优异。而且逐渐有取代memcached,成为首选服务端缓存的组件。而且,Redis内部是支持事务的,在使用时候能有效保证数据的一致性。
不过也有需要注意的地方:
redis中可以使用expire命令设置一个键的生存时间,到时间后redis会删除它。利用这一特性可以运用在限时的优惠活动信息、手机验证码等业务场景。
计数功能应该是最适合redis的使用场景之一,高频率读写特性完全可以发挥redis作为内存数据库的高效。在Redis的数据结构中,string, hash, 和sorted set都提供了incr方法用于原子性自增操作,下面举例说明它们各自的应用场景:
String
作为计数器,设定一个名为REGISTERED_COUNT_TODAY
的 key,并在初始化时给它设置一个到凌晨 0 点的过期时间,每当用户注册成功后便使用incr
命令使该 key 增长 1,同时当每天凌晨 0 点后,这个计数器都会因为 key 过期使值清零。hash
进行计数会更好,该计数器的key设为为weibo:weibo_id
,hash
的 field 为like_number
、comment_number
、forward_number
和view_number
,在对应操作后通过hincrby
使hash 中
的 field 自增。sorted set
吧,将集合的 key 设为POST_RANK
。当用户发帖后,使用zincrby
将该用户 id 的 score 增长 1。sorted set
会重新进行排序,用户所在排行榜的位置也就会得到实时的更新。使用sortedset可以轻松打造一个热度排行榜,zrevrangebyscore可以得到以分数倒序排列的序列,zrank可以得到成员在该排行榜中的作用。
在Redis2.6.12版本开始,string
的set命令增加了三个参数:
Ex
:设置键的过期时间(s)
Px
: 设置键的过期时间(ms)
NX
|XX
:当设置为NX
时,仅当key存在才进行操作,设置为xx时,仅当key不存在才会进行操作,这个操作是原子性的,可以简单实现一个分布式锁,例如:
set key "lock" Ex 1 xx
如果操作返回false,说明key的添加不成功,即当前有人占用这把锁,而如果返回true,说明得到了锁,可以继续进行操作,操作后通过del
释放掉锁,并且即使程序因为某些原因没有释放锁,设置了过期时间,所以该锁也会在1秒后自动释放。
伪代码:
- //产生锁
- while lock!=1
- //过期时间是为了避免死锁
- now = int(time.time())
- lock_timeout = now + LOCK_TIMEOUT + 1
- lock = redis_client.setnx(lock_key, lock_timeout)
-
- //真正要处理的业务
- doing()
-
- //释放锁
- now = int(time.time())
- if now < lock_timeout:
- redis_client.delete(lock_key)
比如在订单生产后我们占用了库存,10分钟后去检验用户是够真正购买,如果没有购买将该单据设置无效,同时还原库存。 由于redis自2.8.0之后版本提供Keyspace Notifications功能,允许客户订阅Pub/Sub频道,以便以某种方式接收影响Redis数据集的事件。 所以我们对于上面的需求就可以用以下解决方案,我们在订单生产时,设置一个key,同时设置10分钟后过期, 我们在后台实现一个监听器,监听key的实效,监听到key失效时将后续逻辑加上。 当然我们也可以利用rabbitmq、activemq等消息中间件的延迟队列服务实现该需求。
redis的set集合中提供了一个zrangebylex方法,语法如下:
ZRANGEBYLEX key min max [LIMIT offset count]
通过ZRANGEBYLEX zset - + LIMIT 0 10 可以进行分页数据查询,其中- +表示获取全部数据
zrangebylex key min max 这个就可以返回字典区间的数据,利用这个特性可以进行模糊查询功能,这个也是目前我在redis中发现的唯一一个支持对存储内容进行模糊查询的特性。
一篇介绍微博Redis应用的PPT中,其中提到微博的Redis主要用在计数和好友关系两方面,
《Redis设计与实现》中作者最开始使用Redis中的set
是因为传统数据库无法计算集合的交集。
对于一个用户A,将它的关注和粉丝的用户id都存放到两个set中:
A:follow
:存放A所有关注的用户id
A:follower
:存放A所有粉丝的用户id
那么通过sinter
命令便可以根据A:follow
和A:follower
的交集得到与 A 互相关注的用户。当 A 进入另一个用户 B 的主页后,A:follow
和B:follow
的交集便是 A 和 B 的共同专注,A:follow
和B:follower
的交集便是 A 关注的人也关注了 B。
Redis中的list
的数据结构实现的是双向链表,所以可以非常便捷的应用于消息队列(生产者/消费者模型)。消息的生产者只需要通过lpush将消息放入list,消费者可以通过rpop取出该消息,并且保证消息的有序性。
如果需要实现带有优先级的消息队列也可以选择**sorted list
。而pub/sub
**也可以作为发布者/订阅者模型的消息。由于Redis带有持久化功能,无需担心由于服务器故障导致消息丢失的情况发生。
list作为双向链表,不光可以作为队列使用,如果将它用作栈便可以成为一个公用的时间轴。当用户发完微博后,都通过lpush将它存放在一个key为LATEST_WEIBO的list中。之后便可以通过lrange取出最新的微博。
倒排索引是构造搜索功能的最常见的方式,Redis中也可以通过set建立倒排索引,这里以简单的拼音+前缀搜索城市功能举例:
假设一个城市北京
,通过拼音词库将北京
转为beijing
,再通过前缀分词将这两个词分为若干个前缀索引,有:北
、北京
、b
、be
…beijin
和beijing
。将这些索引分别作为set
的 key(例如:index:北
)并存储北京
的 id,倒排索引便建立好了。接下来只需要在搜索时通过关键词取出对应的set
并得到其中的 id 即可。
秒杀是现在互联网系统中常见的营销模式,作为开发者,其实最不愿意这样的活动,因为非技术人员无法理解到其中的技术难度,导致在资源协调上总是有些偏差。秒杀其实经常会出现的问题包括:
其实解决这些问题基本就两个方案:
现在说明一下,如果现在做一个秒杀,那么,Redis应该如何结合进行使用?
以上是一个简略的秒杀系统和Redis结合的方案,当然实际可能还会引入http缓存,或者将消息对接用MQ代替等方案,也会出现业务遗漏的情况,这个只是希望能抛砖引玉。
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。