原文地址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. 【BZOJ 3156】防御准备

    [链接] 链接 [题意] 在这里输入题意 [题解] 把a倒过来 设f[i]表示在i放一个防御塔的最小花费; 我们如果从j转移过来 就表示j+1..i-1这一段放人偶. s[i] = 1 + 2 + . ...

  2. [React Native] Disable and Ignore Yellow Box Warnings in React Native

    Yellow box warnings in react native can be intrusive. We will use console.disableYellowBox to disabl ...

  3. php curl header头

    工作中第一次用到header做个记录 工作中需要在heaer里面加上 Authorization 用来验证身份 public function index() { $url = "http: ...

  4. 详解HTML的a标签(超链接标签)

    原文 简书原文:https://www.jianshu.com/p/d6a2499db73b 大纲 1.什么是<a>标签 2.<a>标签的几个重要属性 3.a标签的运行机制 4 ...

  5. ds finder 唤醒

    http://www.hangge.com/blog/cache/detail_594.html

  6. 指针知识梳理6-const与指针

    const 定义的变量为仅仅读变量.在语法层面上通过这个变量去改动内存是不同意的. 可是对于下面代码.就有非常多人绕了: const int  *p1;  //p1能变.*p1不能变 int cons ...

  7. css3-5 css3鼠标、列表和尺寸样式怎么用(文字有关的样式会被继承)

    css3-5  css3鼠标.列表和尺寸样式怎么用(文字有关的样式会被继承) 一.总结 一句话总结:css标签中文字有关的样式会被继承.由常用样式记起. 1.鼠标常用样式有哪些? cursor:poi ...

  8. 【u007】血色先锋队

    Time Limit: 1 second Memory Limit: 128 MB [问题描述] 巫妖王的天灾军团终于卷土重来,血色十字军组织了一支先锋军前往诺森德大陆对抗天灾军团,以及一切沾有亡灵气 ...

  9. Snmp常用oid

    http://blog.csdn.net/youngqj/article/details/7311849 系统参数(1.3.6.1.2.1.1)   OID 描述 备注 请求方式 .1.3.6.1.2 ...

  10. SendMessageTimeout 的使用

    在WINDOW编程中,发送消息的常用API有SendMessage,PostMessage,PostThreadMessage. 一般每个线程有两个队列:一个用来接收通过Send函数的消息,另外一个队 ...