Redis在不少方面与其余数据库解决方案不一样:它使用内存提供主存储支持,而仅使用硬盘作持久性的存储;它的数据模型很是独特,用的是单线程。另外一个大区别在于,你能够在开发环境中使用Redis的功能,但却不须要转到Redis。 html
转向Redis固然也是可取的,许多开发者从一开始就把Redis做为首选数据库;但设想若是你的开发环境已经搭建好,应用已经在上面运行了,那么更换数据库框架显然不那么容易。另外在一些须要大容量数据集的应用,Redis也并不适合,由于它的数据集不会超过系统可用的内存。因此若是你有大数据应用,并且主要是读取访问模式,那么Redis并非正确的选择。 redis
然而我喜欢Redis的一点就是你能够把它融入到你的系统中来,这就可以解决不少问题,好比那些你现有的数据库处理起来感到缓慢的任务。这些你就能够经过Redis来进行优化,或者为应用建立些新的功能。在本文中,我就想探讨一些怎样将Redis加入到现有的环境中,并利用它的原语命令等功能来解决传统环境中碰到的一些常见问题。在这些例子中,Redis都不是做为首选数据库。 算法
显示最新的项目列表 数据库
下面这个语句经常使用来显示最新项目,随着数据多了,查询毫无疑问会愈来愈慢。 缓存
SELECT * FROM foo WHERE ... ORDER BY time DESC LIMIT 10
在Web应用中,“列出最新的回复”之类的查询很是广泛,这一般会带来可扩展性问题。这使人沮丧,由于项目原本就是按这个顺序被建立的,但要输出这个顺序却不得不进行排序操做。 框架
相似的问题就能够用Redis来解决。好比说,咱们的一个Web应用想要列出用户贴出的最新20条评论。在最新的评论边上咱们有一个“显示所有”的连接,点击后就能够得到更多的评论。 memcached
咱们假设数据库中的每条评论都有一个惟一的递增的ID字段。 函数
咱们可使用分页来制做主页和评论页,使用Redis的模板: post
-每次新评论发表时,咱们会将它的ID添加到一个Redis列表: 性能
LPUSH latest.comments <ID>
-咱们将列表裁剪为指定长度,所以Redis只须要保存最新的5000条评论:
LTRIM latest.comments 0 5000
-每次咱们须要获取最新评论的项目范围时,咱们调用一个函数来完成(使用伪代码):
FUNCTION get_latest_comments(start,num_items):
id_list = redis.lrange("latest.comments",start,start+num_items-1)
IF id_list.length < num_items
id_list = SQL_DB("SELECT ... ORDER BY time LIMIT ...")
END
RETURN id_list
END
这里咱们作的很简单。在Redis中咱们的最新ID使用了常驻缓存,这是一直更新的。可是咱们作了限制不能超过5000个ID,所以咱们的获取ID函数会一直询问Redis。
只有在start/count参数超出了这个范围的时候,才须要去访问数据库。
咱们的系统不会像传统方式那样“刷新”缓存,Redis实例中的信息永远是一致的。SQL数据库(或是硬盘上的其余类型数据库)只是在用户须要获取“很远”的数据时才会被触发,
而主页或第一个评论页是不会麻烦到硬盘上的数据库了。
删除与过滤
咱们可使用LREM来删除评论。若是删除操做很是少,另外一个选择是直接跳过评论条目的入口,报告说该评论已经不存在。
有些时候你想要给不一样的列表附加上不一样的过滤器。若是过滤器的数量受到限制,你能够简单的为每一个不一样的过滤器使用不一样的Redis列表。毕竟每一个列表只有5000条项目,
但Redis却可以使用很是少的内存来处理几百万条项目。
排行榜相关
另外一个很广泛的需求是各类数据库的数据并不是存储在内存中,所以在按得分排序以及实时更新这些几乎每秒钟都须要更新的功能上数据库的性能不够理想。
典型的好比那些在线游戏的排行榜,好比一个Facebook的游戏,根据得分你一般想要:
-列出前100名高分选手
-列出某用户当前的全球排名
这些操做对于Redis来讲小菜一碟,即便你有几百万个用户,每分钟都会有几百万个新的得分。
模式是这样的,每次得到新得分时,咱们用这样的代码:
ZADD leaderboard <score> <username>
你可能用userID来取代username,这取决于你是怎么设计的。
获得前100名高分用户很简单:ZREVRANGE leaderboard 0 99。
用户的全球排名也类似,只须要:ZRANK leaderboard <username>。
按照用户投票和时间排序
排行榜的一种常见变体模式就像Reddit或Hacker News用的那样,新闻按照相似下面的公式根据得分来排序:
score = points / time^alpha
所以用户的投票会相应的把新闻挖出来,但时间会按照必定的指数将新闻埋下去。下面是咱们的模式,固然算法由你决定。
模式是这样的,开始时先观察那些多是最新的项目,例如首页上的1000条新闻都是候选者,所以咱们先忽视掉其余的,这实现起来很简单。
- 每次新的新闻贴上来后,咱们将ID添加到列表中,使用LPUSH + LTRIM,确保只取出最新的1000条项目。
- 有一项后台任务获取这个列表,而且持续的计算这1000条新闻中每条新闻的最终得分。计算结果由ZADD命令按照新的顺序填充生成列表,老新闻则被清除。这里的关键思路是排序工做是由后台任务来完成的。
过时项目处理
另外一种经常使用的项目排序是按照时间排序。咱们使用unix时间做为得分便可。
模式以下:
- 每次有新项目添加到咱们的非Redis数据库时,咱们把它加入到排序集合中。这时咱们用的是时间属性,current_time和time_to_live。
- 另外一项后台任务使用ZRANGE…SCORES查询排序集合,取出最新的10个项目。若是发现unix时间已通过期,则在数据库中删除条目。
计数
Redis是一个很好的计数器,这要感谢INCRBY和其余类似命令。
我相信你曾许屡次想要给数据库加上新的计数器,用来获取统计或显示新信息,可是最后却因为写入敏感而不得不放弃它们。
好了,如今使用Redis就不须要再担忧了。有了原子递增(atomic increment),你能够放心的加上各类计数,用GETSET重置,或者是让它们过时。
例如这样操做:
INCR user:<id> EXPIRE
user:<id> 60
你能够计算出最近用户在页面间停顿不超过60秒的页面浏览量,当计数达到好比20时,就能够显示出某些条幅提示,或是其它你想显示的东西。
特定时间内的特定项目
另外一项对于其余数据库很难,但Redis作起来却垂手可得的事就是统计在某段特色时间里有多少特定用户访问了某个特定资源。好比我想要知道某些特定的注册用户或IP地址,他们到底有多少访问了某篇文章。
每次我得到一次新的页面浏览时我只须要这样作:
SADD page:day1:<page_id> <user_id>
固然你可能想用unix时间替换day1,好比time()-(time()%3600*24)等等。
想知道特定用户的数量吗?只须要使用SCARD page:day1:<page_id>。
须要测试某个特定用户是否访问了这个页面?SISMEMBER page:day1:<page_id>。
实时分析正在发生的状况,用于数据统计与防止垃圾邮件等
咱们只作了几个例子,但若是你研究Redis的命令集,而且组合一下,就能得到大量的实时分析方法,有效并且很是省力。使用Redis原语命令,更容易实施垃圾邮件过滤系统或其余实时跟踪系统。
Pub/Sub
Redis的Pub/Sub很是很是简单,运行稳定而且快速。支持模式匹配,可以实时订阅与取消频道。
队列
你应该已经注意到像list push和list pop这样的Redis命令可以很方便的执行队列操做了,但能作的可不止这些:好比Redis还有list pop的变体命令,可以在列表为空时阻塞队列。
缓存
Redis的缓存部分值得写一篇新文章,我这里只是简单的说一下。Redis可以替代memcached,让你的缓存从只能存储数据变得可以更新数据,所以你再也不须要每次都从新生成数据了。
Redis能够解决你的问题!
如今你就能够用上Redis,让用户感到更轻松,让你的系统变得再也不复杂,让你的网站反应更快。你不须要改变现有的数据库结构,使用Redis给你的框架带来新的东西,来完成那些从前认为不可能作到/很难作到的,或是成本过高的任务。
原文地址:http://antirez.com/post/take-advantage-of-redis-adding-it-to-your-stack.html