Redis应用场景梳理
缓存
作为Key-Value
形态的内存数据库,Redis 最先会被想到的应用场景便是作为数据缓存。而使用 Redis 缓存数据非常简单,只需要通过string
类型将序列化后的对象存起来即可,不过也有一些需要注意的地方:
- 必须保证不同对象的 key 不会重复,并且使 key 尽量短,一般使用类名(表名)加主键拼接而成。
- 选择一个优秀的序列化方式也很重要,目的是提高序列化的效率和减少内存占用。
- 缓存内容与数据库的一致性,这里一般有两种做法:
- 只在数据库查询后将对象放入缓存,如果对象发生了修改或删除操作,直接清除对应缓存(或设为过期)。
- 在数据库新增和查询后将对象放入缓存,修改后更新缓存,删除后清除对应缓存(或设为过期)。
消息队列
Redis 中list
的数据结构实现是双向链表,所以可以非常便捷的应用于消息队列(生产者 / 消费者模型)。消息的生产者只需要通过lpush
将消息放入 list,消费者便可以通过rpop
取出该消息,并且可以保证消息的有序性。如果需要实现带有优先级的消息队列也可以选择sorted set
。而pub/sub
功能也可以用作发布者 / 订阅者模型的消息。无论使用何种方式,由于 Redis 拥有持久化功能,也不需要担心由于服务器故障导致消息丢失的情况。
时间轴(Timeline)
list
作为双向链表,不光可以作为队列使用。如果将它用作栈便可以成为一个公用的时间轴。当用户发完微博后,都通过lpush
将它存放在一个 key 为LATEST_WEIBO
的list
中,之后便可以通过lrange
取出当前最新的微博。
排行榜
使用sorted set
和一个计算热度的算法便可以轻松打造一个热度排行榜,zrevrangebyscore
可以得到以分数倒序排列的序列,zrank
可以得到一个成员在该排行榜的位置(是分数正序排列时的位置,如果要获取倒序排列时的位置需要用zcard
-zrank
)。
计数器
计数功能应该是最适合 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
会重新进行排序,用户所在排行榜的位置也就会得到实时的更新。
好友关系
这个场景最开始是是一篇介绍微博 Redis 应用的 PPT 中看到的,其中提到微博的 Redis 主要是用在在计数和好友关系两方面上,当时对好友关系方面的用法不太了解,后来看到《Redis 设计与实现》中介绍到作者最开始去使用 Redis 便是希望能通过set
解决传统数据库无法快速计算集合中交集这个功能。后来联想到微博当前的业务场景,确实能够以这种方式实现,所以姑且猜测一下:
对于一个用户 A,将它的关注和粉丝的用户 id 都存放在两个 set 中:
A:follow
:存放 A 所有关注的用户 idA:follower
:存放 A 所有粉丝的用户 id那么通过
sinter
命令便可以根据A:follow
和A:follower
的交集得到与 A 互相关注的用户。当 A 进入另一个用户 B 的主页后,A:follow
和B:follow
的交集便是 A 和 B 的共同专注,A:follow
和B:follower
的交集便是 A 关注的人也关注了 B。
分布式锁
在 Redis 2.6.12 版本开始,string
的set
命令增加了三个参数:
EX
:设置键的过期时间(单位为秒)PX
:设置键的过期时间(单位为毫秒)NX
|XX
:当设置为NX
时,仅当 key 存在时才进行操作,设置为XX
时,仅当 key 不存在才会进行操作由于这个操作是原子性的,可以简单地以此实现一个分布式的锁,例如:
set key "lock" EX 1 XX
如果这个操作返回false
,说明 key 的添加不成功,也就是当前有人在占用这把锁。而如果返回true
,则说明得了锁,便可以继续进行操作,并且在操作后通过del
命令释放掉锁。并且即使程序因为某些原因并没有释放锁,由于设置了过期时间,该锁也会在 1 秒后自动释放,不会影响到其他程序的运行。
倒排索引
倒排索引是构造搜索功能的最常见方式,在 Redis 中也可以通过set
进行建立倒排索引,这里以简单的拼音 + 前缀搜索城市功能举例:
假设一个城市北京
,通过拼音词库将北京
转为beijing
,再通过前缀分词将这两个词分为若干个前缀索引,有:北
、北京
、b
、be
…beijin
和beijing
。将这些索引分别作为set
的 key(例如:index:北
)并存储北京
的 id,倒排索引便建立好了。接下来只需要在搜索时通过关键词取出对应的set
并得到其中的 id 即可。
一些建议
Redis 速度快是建立在内存数据库基础上的,但是一台服务器的内存要比磁盘金贵许多,所以在项目初期不要想什么都往 Redis 里放,这样当数据量上来后很快内存就会不够用,反而得不偿失。合理的利用有限的内存,将读(写)频繁的热数据放在 Redis 中才能更好感受到它带来的性能提升。
- Redis 虽然提供了
RDB
和AOF
两种持久化方式,但是普遍还是认为 Redis 的持久化并不是很靠谱。这也是我一直不敢尝试彻底的用 Redis 去实现第五点(好友关系)的原因。
Redis应用场景梳理的更多相关文章
- Redis应用场景-转载
1. MySql+Memcached架构的问题 实际MySQL是适合进行海量数据存储的,通过Memcached将热点数据加载到cache,加速访问,很多公司都曾经使用过这样的架构,但随着业务数据量的 ...
- Redis应用场景(转)
(来源:http://www.cnblogs.com/shanyou/archive/2012/09/04/2670972.html) Redis常用数据类型 Redis最为常用的数据类型主要有以下五 ...
- redis(二)Redis适用场景,如何正确的使用
网络IO模型 Memcached是多线程,非阻塞IO复用的网络模型,分为监听主线程和worker子线程,监听线程监听网络连接,接受请求后,将连接描述字pipe 传递给worker线程,进行读写IO, ...
- redis使用场景
Redis应用场景 Redis开创了一种新的数据存储思路,使用Redis,我们不用在面对功能单调的数据库时,把精力放在如何把大象放进冰箱这样的问题上,而是利用Redis灵活多变的数据结构和数据操作 ...
- <转>Redis 应用场景
http://blog.csdn.net/hguisu/article/details/8836819 1. MySql+Memcached 架构的问题 Memcached采用客户端-服务器的架构, ...
- Redis作者谈Redis应用场景
Redis作者谈Redis应用场景 毫无疑问,Redis开创了一种新的数据存储思路,使用Redis,我们不用在面对功能单调的数据库时,把精力放在如何把大象放进冰箱这样的问题上,而是利用Redis灵活多 ...
- Redis应用场景 及其数据对象 string hash list set sortedset
原文地址:http://www.cnblogs.com/shanyou/archive/2012/09/04/2670972.html Redis开创了一种新的数据存储思路,使用Redis,我们不用在 ...
- Redis应用场景-整理
1. MySql+Memcached架构的问题 Memcached采用客户端-服务器的架构,客户端和服务器端的通讯使用自定义的协议标准,只要满足协议格式要求,客户端Library可以用任何语言实现. ...
- NoSQL数据库:Redis适用场景及产品定位
传统MySQL+ Memcached架构遇到的问题 实际MySQL是适合进行海量数据存储的,通过Memcached将热点数据加载到cache,加速访问,很多公司都曾经使用过这样的架构,但随着业务数据量 ...
随机推荐
- am335x system upgrade rootfs for bridge-utils cross compile (十四)
bridge-utils移植 [目的] 移植bridge-utils的目是在AM335X开发板上使用bridge功能. [环境] 1. Ubuntu 16.04发行版 2. MC183平台 3. ...
- 【转】SignalR与ActiveMQ结合构建实时通信
一.概述 本教程主要阐释了如何利用SignalR与消息队列的结合,实现不同客户端的交互 SignalR如何和消息队列交互(暂使用ActiveMQ消息队列) SignalR寄宿在web中和其他Signa ...
- 【概率论】6-1:大样本介绍(Large Random Samples Introduction)
title: [概率论]6-1:大样本介绍(Large Random Samples Introduction) categories: - Mathematic - Probability keyw ...
- 洛谷P1052过河
题目 不看数据范围的话是一个很简单的DP,可是加上数据范围之后就之前的做法就不行了. 所以我们考虑一下路径压缩. 小数据Code #include <iostream> #include ...
- C语言实现多线程排序
#include <stdio.h> #include <pthread.h> #include <stdlib.h> #include <string.h& ...
- fuck-KUNLUN昆仑ECRS会员管理系统
写代码要认证一点,多一点测试, navigator.appName == 'Netscape'这么垃圾的代码都能写出来,握草. 怕时间就了就忘记怎么搞的了,MD经过前端各种断点,找到了这个垃圾玩意儿. ...
- golang-package fmt
package fmt import "fmt" mt包实现了类似C语言printf和scanf的格式化I/O.格式化动作('verb')源自C语言但更简单. Printing v ...
- Sklearn多元线性回归
Sklearn多元线性回归 1 正文 2 参考资料 Sklearn多元线性回归
- 用vue做的购物车结算的功能
<!-- 占位 --> <template> <div> <div class="product_table"> <div c ...
- bootstrap table插件动态加载表头
这篇文章主要为大家详细介绍了bootstrap table插件动态加载表头,具有一定的参考价值,感兴趣的小伙伴们可以参考一下 bootstrap的table属性已经很熟悉了,最近遇到一个问题,犹豫 ...