原文地址http://oldblog.antirez.com/post/take-advantage-of-redis-adding-it-to-your-stack.html 
@(syoka)[redis|]

如何更好的利用redis

redis相比于其他数据库有诸多不同之处:

  • 它使用内存作为主存储,而硬盘存储则仅仅用来提供持久化
  • 数据模型相对比较单一(Redis数据类型)
  • 它是一个单线程等等
  • 另一个比较大的差异是:为了获取Redis的优势而将Redis应用于你的生产环境中并不要求你j切换Redis作为主库 
    你可以使用它去完成一些之前不可能的新功能或者去修复以前的问题

当然,切换使用Redis也是一个可选项,大部分开发者把Redis作为主数据库主要是为了新特性、写速度和延时功能,但是,试想对一个已经运行在线上的产品进行Redis切换是需要迈出很大的一步。同时对于一些特定场景的应用,Redis可能就不是一个好的选择。举一个例子,因为Redis数据大小不能超过可用内存,所以如果你有一些大数据应用,并且几乎全部都是读操作的话,Redis并不是一个好的选择。

我最喜欢redis是因为它可以帮我解决很多问题,比如将其加入栈中来处理那些在当前已有数据库条件下难以实现或是执行速度缓慢问题。在这个方面,Redis可是信心十足,让我们开始使用Redis去优化你的程序或是为你的程序点缀几笔吧。这篇博客将列举几个例子来说明如何在现有环境下加入Redis并充分利用Redis的一系列特性。我不会使用具体配置和站点名来举例,而是列举几个在Redis不作为主库的条件下能够解决的一些类别问题

需求显示最近的主页上的条目

你能想出一个解决存在大量数据情况导致查询缓慢的办法吗

SELECT * FROM foo WHERE ... ORDER BY time DESC LIMIT 10
  • 1

就像列出”最近被用户添加的条目”,或者”最近发生的事”之类的,在web应用中是非常常见的,也是一个可衡量的问题。直觉告诉我们,如果你想它们按照被创建的顺序进行显示的话,你就需要对其进行排序。

同样的问题可以使用Redis模式进行修复,举个例子吧, 当前有一个web应用用来显示最近20条用户所发布的评论,在最近评论的旁边还有一个显示全部的按钮,点下它,我们就可以看到超过20条的评论信息,并且也是按照分页进行显示的,同时我们还能看到整个评论的时间线排布

我们假定每一个评论都存在我们数据库,并且有一个唯一自增主键 
我们可以使用一种简单的Reids模式使数据可以快速的在主页框和评论时间线页面上进行分页 
+ 每当一个新的评论被追加时,就将它的ID加入Redis的list中,Lpush(FIFO类似队列)lastest.comment 
+ 我们可以限定这个list的容量,这样的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
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7

我们所做的其实很简单,在Redis我们经常说到实时缓存,最近的ID总是被更新着。但是,我们限制了它的长度是5000个,并且当系统第一次启动的时候,这些ID甚至可以全部为0,因此当前list并不存在。因此当我们获取这些最近时间的评论的ID时,总是会先去访问redis。如果我们开始或者计数的参数超过了这个限定范围的话,我们再回到原有数据库。

我们重来不需要刷新缓存,因为sql 数据库(或者其他一些在硬盘存储数据类型)只有在用户想看到间隔比较远的时候才会被ping通,因此,不要直接从sql数据库中读取。(感觉这句话不好理解!!!)

正如你所见,Redis正在作为一个新的螺丝钉,它并不是像传统的缓存,Redis不需要进行缓存刷新,因为实例总是一致的。它并不是作为一个数据库工作,正如你可以flush你的key。同时所有一切都将继续工作。我称呼它为活缓存,但是我打赌肯定还有更好的名字。

删除和过滤

我们可以通过LREM来删除评论,如果删除的仅仅是很少的一部分,那么有一个可选择的方案就是过滤掉要被删除的评论,因为我们的数据库会通过ID来获取评论,此时DB就会报告说该评论已经不存在了。

有多少次,你想要使用不同的过滤方法来过滤不同的List。当某些过滤器受限于通过数字来筛选的话(比如目录),你可以使用另一个Redis链表来充当你的过滤器(取交集),毕竟你只需要将每5000个数据放进一个list中,这样Redis就仅仅用了一少部分内存却获得了百万条数据,通过来说你不得不做出妥协,发挥你的创造力吧!

排行榜以及相关问题

另一个常见的需求就是很难利用现有模型在那些按照分数排序且每秒都有很多次更新又不能从内存中获取列表的那些数据。

一个经典的例子就是线上比赛的积分榜,比如一个脸书游戏,这种模式不能应用于各种场景。比如在游戏例子中,你收到了来自许多用户的积分,这些积分时时刻刻都在被这些用户刷新,对于这些积分,你可能想要: 
+ 展现榜单前100名 
+ 展示用户当前的全球积分 
对于这些零散操作使用带排序的set来说是最好不过的,即使你有在每分钟有百分用户的百万新积分需要应付。

就是这样一种模式,每当收到一个用户的新积分的时候,我们这样做:

ZADD leaderboard <score> <username>
  • 1

备注:你可能会用用户id来替代名字,这个由你决定

为了获取前100用户的积分,只需ZREVRANGE leaderboard 0 99.

同样的,告诉某个用户他的全球积分,你只需ZRANK leaderboard .

现在你可以做的更多,比如显示当前用户积分附近的用户信息,也就是说你可以显示积分榜中一部分顾客的积分了。

按投票次数和时间排序

像上述那样排行模式的只是一个类似ReDDIT或黑客新闻这样的网站的实现。他们都可以根据相同的公式

score = points / time^alpha
  • 1

这样用户通过投票方式来提升新闻的占比,随着时间而慢慢下降占比,具体算法由你决定,但是不会改变我们的模式

这种工作模式适用于这种情况:只从最近的开始观察,比如,1000条非常适合放在首页的新闻,我们可以忽略掉其他所有,实现也是非常简单:

  • 每当一个新闻被发布的时候我们将它的ID加入一个List,使用LPUSH+LTRIM去只取最近的1000项
  • 这里有一个工人去获得这个list并且不断计算最终这1000条新闻的最终积分。最终结果使用ZADD填充至一个排序set。老的新闻将会被移除当前set。

这是我们有一个由1000个新闻通过积分排序的set。这个set可以以每秒查询100000次的速度显示最高积分的新闻,这个方式可以以一种相当间的方式衡量

关键的地方在于我们的排序,它是由后台工作者创建的,与当前正在看新闻网站的用户来说不成比例

对于刚才发布的那个,我们可以使用原始的IDS列表,或者使用本文博客中的第一个模式

实现条目的过期 
另一种使用排序Set的方法是使用时间索引,我们可以把单个时间比作分数,通常可以按照时间来索引某些东西,但是一个值得注意的地方就是当超过某个给定时间的时候,需要过期我们的主库

这种模式:

  • 每当一个新的数据被加载我们数据库时,我们把它加入排序set集,就像操作分数一样我们使用时间来决定哪些项应该被过期,用另一句话说还有当前时间+残留时间有效
  • 这里有一个后台工作者在排序集合中使用ZRANGE….WITHSCORES去查询最近10项。如果有分数代表unix times已经过期的话,那么我们将它从数据库中删除。

统计事物 
Redis是一个很好的计数器,感谢INCRBY和其他相似的命令

有多少次你想要在你的数据库里面添加一个机器数,用来统计或者暂时你用户新信息,因为它对于数据库来说是一项需要大量写入的任务所以不得不避免使用它,以前困扰了我太多次

但是,使用Redis并不需要考虑它,使用原子自增的它,你可以使用于所有你需要计数的地方,使用原子性操作的GETSET对它不断重置,在你的计数器中设置过期,以便只有在这些事件之间的时间差小于给定的秒数时才可以进行事件计数。

像下面这样:

INCR user:<id>
EXPIRE user:<id> 60
  • 1
  • 2

您可以计算用户最近做了多少页面浏览量,而页面浏览量之间没有超过60秒的停顿时间。例如,当这个计数达到20时,是时候展示一些横幅,提醒,提示或者你想要的东西。

在给定的时间内唯一N项

统计数据的另一个有趣的例子是使用Redis,但使用其他类型的数据库看有多少不同的用户在给定的时间内访问指定的资源是非常困难的。例如,我想知道在线报纸上访问特定文章的唯一注册用户数量或IP地址数量。

每次我想要查看一个新的页面浏览量时,我会这么做

SADD page:day1:<page_id> <user_id>
  • 1

当然,你可能想要使用今天的第一秒,作为unix时间,如:time() - (time()%3600 * 24),或类似的东西

如何知道用户的数量,使用 SCARD page:day1:.

想要测试制定的用户是不是已经进入这个页面了,使用SISMEMBER page:day1:

实时分析正在发生的事情,统计数据,反垃圾邮件或其他内容

我们只举了一小部分例子,但是如果您学习Redis命令集并以有趣的方式组合这些数据结构,则可以毫不费力地为大量实时统计数据建模,以便为增强你的反垃圾邮件系统或提升服务质量。

发布/订阅

你知道Redis包含相当高性能的发布和订阅的实现吗吗?

Redis 发布和订阅的使用非常简单,稳定且快速,支持模式匹配,能够订阅/取关那些运行的频道等等。您可以在Redis PubSub官方文档中阅读关于它的更多信息

队列

您可能已经注意到Redis命令如List推送和List弹出是如何使用链表取实现队列的,但您可以做的不仅仅于此,Redis具有当执行链表弹出命令时,如果此时列表为空,它将阻塞阻止列表的变体

Redis作为队列的常见用法是Resque库,由Github的人员实施和推广

通过我们的http://redis.io/commands/rpoplpush list旋转命令,可以实现具有有趣语义的队列,这将使您的后台工作者更快乐! (例如,您可以实施一个轮换列表来一次又一次获取RSS提要,这样每个工作人员都可以选择过去提取的RSS,因此需要尽快更新)。同样,使用排序集可以轻松实现优先级队列。

缓存 
这一节本身就值得一个特定的博客文章…所以简而言之,我会说Redis可以用作memcached的替代品,以便将缓存变成能够以更简单的方式存储数据的东西,所以每次都不需要重新生成数据。请参阅本文中发布的第一个模式以供参考

Redis无所不能,吹一波

你可以立马使用Redis来完成让用户更爽,让你的系统更简单,让你的网站响应的更快。你不需要为了使用Redis而替换你现有的配置,仅仅使用Redis来完成其他方式无法完成或难以完成或着代价过高的新事物。

如何更好的利用redis的更多相关文章

  1. ssm+redis 如何更简洁的利用自定义注解+AOP实现redis缓存

    基于 ssm + maven + redis 使用自定义注解 利用aop基于AspectJ方式 实现redis缓存 如何能更简洁的利用aop实现redis缓存,话不多说,上demo 需求: 数据查询时 ...

  2. 利用Redis cache优化app查询速度实践

    注意:本篇文章译自speeding up existing app with a redis cache,如需要转载请注明出处. 发现问题 在应用解决方法之前,我们需要对我们面对的问题有一个清晰的认识 ...

  3. 利用redis写webshell

    redis和mongodb我之所见 最近自己在做一些个人的小创作.小项目,其中用到了mongodb和redis,最初可能对这二者没有深入的认识.都是所谓的“非关系型数据库”,有什么区别么? 实际上,在 ...

  4. 利用redis实现分布式锁知识点总结及相关改进

    利用redis实现分布式锁知识点总结及相关改进 先上原文,本文只为总结及对相关内容的质疑并提出若干意见,原文内容更详细https://www.cnblogs.com/linjiqin/p/800383 ...

  5. Watchdogs利用Redis实施大规模挖矿,常见数据库蠕虫如何破?

    背景 2月20日17时许,阿里云安全监测到一起大规模挖矿事件,判断为Watchdogs蠕虫导致,并在第一时间进行了应急处置. 该蠕虫短时间内即造成大量Linux主机沦陷,一方面是利用Redis未授权访 ...

  6. 【Redis】利用 Redis 实现分布式锁

    技术背景 首先我们需要先来了解下什么是分布式锁,以及为什么需要分布式锁. 对于这个问题,我们可以简单将锁分为两种--内存级锁以及分布式锁,内存级锁即我们在 Java 中的 synchronized 关 ...

  7. Docker环境复现利用Redis未授权访问漏洞 >> 批量扫描检测利用

    关于Redis Redis(Remote Dictionary Server ),即远程字典服务,是一个开源的使用ANSI C语言编写.支持网络.可基于内存亦可持久化的日志型.Key-Value数据库 ...

  8. 大数据学习day34---spark14------1 redis的事务(pipeline)测试 ,2. 利用redis的pipeline实现数据统计的exactlyonce ,3 SparkStreaming中数据写入Hbase实现ExactlyOnce, 4.Spark StandAlone的执行模式,5 spark on yarn

    1 redis的事务(pipeline)测试 Redis本身对数据进行操作,单条命令是原子性的,但事务不保证原子性,且没有回滚.事务中任何命令执行失败,其余的命令仍会被执行,将Redis的多个操作放到 ...

  9. 利用Redis解决Url过长的问题

    做网站,接手别人的代码,发现url有时候会过长导致页面直接翻掉. 后来想了一下可以利用redis将太长的地方暂存,加载页面时获取即可. 存Redis: /// <summary> /// ...

随机推荐

  1. spring与memcache的整合

    1. pom.xml文件增加: <dependency> <groupId>com.whalin</groupId> <artifactId>Memca ...

  2. 利用Attribute实现Aop

    Aop“面向切面编程”,与OOP“面向对象编程”一样是一种编程思路.个人理解:在不改变原有逻辑的基础上,注入其他行为. 基础代码(仿MVC拦截器实现) namespace HGL.Toolkit.Ao ...

  3. cocos2d-x 3.0 android mk文件 之 自己主动遍历*.cpp文件

    还记得上一篇android mk 文件的写法吗?传送门, 我们须要手动去加入 cpp文件.假设cpp一多,那不是要累死? LOCAL_PATH := $(call my-dir) include $( ...

  4. Android中ImageView.ScaleType属性值

    1 android:scaleType="center" (1)当图片大于ImageView的宽高:以图片的中心点和ImageView的中心点为基准,按照图片的原大小居中显示,不缩 ...

  5. 【30.93%】【codeforces 558E】A Simple Task

    time limit per test5 seconds memory limit per test512 megabytes inputstandard input outputstandard o ...

  6. 从0開始学习 GitHub 系列之「07.GitHub 常见的几种操作」

    之前写了一个 GitHub 系列,反响非常不错,突然发现居然还落下点东西没写,前段时间 GitHub 也改版了,借此机会补充下. 我们都说开源社区最大的魅力是人人多能够參与进去,发挥众人的力量,让一个 ...

  7. Hadoop1.2.1伪分布模式安装指南 分类: A1_HADOOP 2014-08-17 10:52 1346人阅读 评论(0) 收藏

    一.前置条件 1.操作系统准备 (1)Linux可以用作开发平台及产品平台. (2)win32只可用作开发平台,且需要cygwin的支持. 2.安装jdk 1.6或以上 3.安装ssh,并配置免密码登 ...

  8. Lucene学习总结之五:Lucene段合并(merge)过程分析 2014-06-25 14:20 537人阅读 评论(0) 收藏

    一.段合并过程总论 IndexWriter中与段合并有关的成员变量有: HashSet<SegmentInfo> mergingSegments = new HashSet<Segm ...

  9. html css div img垂直居中

    <head> <meta charset="UTF-8"> <meta name="Generator" content=&quo ...

  10. jquery formcheck.js

    demo下载链接http://pan.baidu.com/s/1hrDCC3y     /* Jquery 表单验证插件 janchie 2010.1 janchie@163.com 1.01版 */ ...