展现最新数据

Web应用常常要展现最新数据,就会根据时间对数据排序:

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

随着数据的增加,问题变得越来越复杂,速度也越来越慢。这种情况可以用Redis解决,如这个问题:一个web应用需要展示最新的20条用户评论。

  • 每当一条新评论产生时,将评论id加到redis的list中:LPUSH latest.comments <ID>
  • 裁剪list,保持固定长度(如只保留5000条):LTRIM latest.comments 0 5000
  • 当需要展示具体评论时,可以调用如下函数:

[plain] view plain copy

  1. FUNCTION get_latest_comments(start,num_items):
  2. id_list = redis.lrange("latest.comments",start,start+num_items-1)
  3. IF id_list.length < num_items
  4. id_list = SQL_DB("SELECT ... ORDER BY time LIMIT ...")
  5. END
  6. RETURN id_list
  7. END

在这里,redis做为一个实时缓存,无需不停的刷新。MySQL只有在需要更细节的信息和间隔可以较长的情况下被使用。

删除和筛选

注意到可以用LREM删除评论。如果删除不频繁,也可以在redis中保留这条记录,在我们去mysql查询时,会获取不到结果。

很多时候,你想筛选展现不同的数据表,使用多个redis list就可以了。每个list包含5000条,而redis用很少的内存就可以存储上百万的记录。

排行榜和相关问题

如果数据存储在DB中,且每秒都有很多更新。要想实时的展现一个分数排名榜,且要很好的性能,就会变得很困难。这个经典例子就是在线游戏的排名榜,如Facebook游戏,但是这种类型适用于很多场景。在线游戏里,你会收到非常多的用户分数更新,利用这些分数,你想完成如下功能:

  • 展现排名前100的分数
  • 展现用户自己的排名

即使你有数百万用户,每分钟有数百万的分数更新,使用Redis的sorted set处理这类问题也很容易。

处理方法:每当收到一个新分数时,就如下操作

[cpp] view plain copy

  1. ZADD leaderboard <score> <username>

得到前100用户排名只需:ZREVRANGE leaderboard 0 99

告诉用户自己的排名:ZREVRANK leaderboard <username>

补:ZRANK/ZRANGE是从小到大排序,ZREVRANK/ZREVRANGE是从大到小排序

你可以做的还有很多,如展示和用户排名相近的分数:ZRANGEBYSCORE leaderboard 500 700

根据用户投票和时间排序

上个例子是根据分数排名,但是新闻网站会采用下面的公式排名新闻。

[cpp] view plain copy

  1. score = points / time^alpha

用户投票会相应的提升排名,但是时间会指数式的拉低排名。可以发现可以展现在首页的新闻只可能在最新的新闻中选出(如最新的1000条),所以可以忽略其他的新闻:

  • 每当提交一条新闻时,将ID增加到list中:LPUSH + LTRIM(保证1000条)
  • 启动一个线程不断的读取list并计算最终的分数,然后使用zadd将结果存到sorted set中,同时将旧新闻从sorted set中清除

在这个例子中,我们使用了保存1000条新闻、根据分数排名的sorted set。这个sorted set可以支持每秒10万次的查询,很容易的适应网站的规模

数据过期

sorted set的另一个用处可以用时间来索引数据,如unix time做为score。但是更好的使用我们可以用来过期主库中的一些数据:

  • 当有新数据插入DB时,将它同时插入sorted set,用该数据应该过期的时间做为score(current_time + time_to_live)
  • 后台程序使用ZRANGE ... WITHSCORES来去最新的10条,如果表示时间的score已经过去了,我们就将这条数据从db中删除

计数

使用INCRBY和其他类似的命令,Redis可以成为一个很好的计数器。很多时候,你想在db中新增计数器来统计新信息,但又不得不避免使用它,因为对于db来说它是个写密集的任务。

使用Redis就没有这种顾忌了。原子自增实现计数,GETSET原子性的获得计数器当前值并清零,设置有效期来达到只在规定时间内进行计数的目的。

[cpp] view plain copy

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

如上,你可以计数用户60s内看了多少网页,如果达到20,你可以展现一些提示或者横幅。

固定时间内单独的N条数据

统计一段时间内浏览某资源的单独用户量,这个功能对于db很困难,但使用redis就很容易实现。例如,我想知道阅读一篇文章的单独注册用户数或者单独IP数。

每当获得一次页面浏览时,只需要做:

[cpp] view plain copy

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

day1可以用今天的第一秒(unix time: time() - (time()%3600*24))。

想知道单独用户数?SCARD page:day1:<page_id>

想知道某个用户是否已经看过该页面?SISMEMBER page:day1:<page_id>

实时分析

通过redis的各种命令和数据结构,可以很容易的实现大数据的实时统计,来增强反垃圾邮件系统或者用新信息来提高服务质量。

Pub/Sub

Redis的Pub/Sub非常简单、稳定、快速,而且支持模式匹配、动态订阅/取消订阅频道等等。

队列

你可能已经注意到list的push/pop命令很适合用来实现队列,当list没有元素时,你甚至可以使用BLPOP来阻塞POP命令。

Redis做为队列的使用可以参考Resque。

list的RPOPLPUSH,sorted set等都可以实现很多有趣的队列。

缓存

单单这部分就可以用一篇专门的博客来介绍。这里长话短说,Redis可以做为memcached的替代,让你的cache更新更容易,数据管理更方便。

Redis现在就可以修复你的问题

现在就使用redis吧,会让你的用户更满意,系统更简单,网址响应更快。不需要使用redis来替换已有的组件,用redis去解决更加不可能、更加困难、更有价值的事吧。Redis3.0集群与应用场景

Redis 操作数据的更多相关文章

  1. Java连接redis操作数据

    选择2.9.0 jar 版本下载: jedis-2.9.0.jar package com.hao.redis; import org.junit.Before;import org.junit.Te ...

  2. SpringBoot笔记十二:缓存

    目录 非缓存项目 缓存 JSR-107 Spring缓存抽象 @Cacheable @CachePut @CacheEvict @Caching @CacheConfig 整合Redis 先在Dock ...

  3. Redis数据结构详解之List(二)

    序言 思来想去感觉redis中的list没什么好写的,如果单写几个命令的操作过于乏味,所以本篇最后我会根据redis中list数据类型的特殊属性,同时对比成熟的消息队列产品rabbitmq,使用red ...

  4. Redis为什么使用单进程单线程方式也这么快

    [转] http://www.syyong.com/db/Redis-why-the-use-of-single-process-and-single-threaded-way-so-fast.htm ...

  5. redis总结

    redis总结 redis与memcached redis支持更多的数据结构 redis支持数据持久化 redis支持两种存储方式:snapshot(快照)和aof(append only mode) ...

  6. 基于Redis的爬虫平台的实现

    一.需求: 1.数据抓取:目标数据的下载.解析.入库功能. 2.数据服务:黑名单.灰名单等查询服务. 3.平台监控:平台各个模块的数据实时监控. 二.WEB端效果展示: 三.架构设计 下载器.解析器. ...

  7. redis之(二十一)redis之深入理解Spring Redis的使用

    关于spring redis框架的使用,网上的例子很多很多.但是在自己最近一段时间的使用中,发现这些教程都是入门教程,包括很多的使用方法,与spring redis丰富的api大相径庭,真是浪费了这么 ...

  8. redis使用心得

    原创文章转载请注明出处:@协思, http://zeeman.cnblogs.com   redis是继memcached之后兴起的内存数据库,作者非常崇尚简洁高效,力求以最简单的方式最高效的解决问题 ...

  9. Redis教程(十四):内存优化介绍

    转载于:http://www.itxuexiwang.com/a/shujukujishu/redis/2016/0216/142.html 一.特殊编码: 自从Redis 2.2之后,很多数据类型都 ...

随机推荐

  1. mysql主从同步失败Last_IO_Error: Got fatal error 1236 from master解决方法

    mysql教程主从同步失败Last_IO_Error: Got fatal error 1236 from master解决方法 遇到这样的错误如:“Last_IO_Error: Got fatal ...

  2. 使用Axure RP原型设计实践04,了解全局变量

    变量是一个可以变的数,可以看作是一个数据的容器.变量有2个操作,一个是读,一个是写.Axure的全局变量是指任何时候都可以对这个变量进行读写操作. 点击工具栏Project下的Global Varia ...

  3. java根据模板文件导出pdf

    原文:https://www.cnblogs.com/wangpeng00700/p/8418594.html 在网上看了一些Java生成pdf文件的,写的有点乱,有的不支持写入中文字体,有的不支持模 ...

  4. frame与bounds的区别比较

    翻译文档上的
bounds是指这个view在它自己坐标系的坐标和大小 而frame指的是这个view在它superview的坐标系的坐标和大小
区别主要在坐标系这一块.

很明显一个是自己为原点的坐标 ...

  5. ArcGIS 在高清屏中主界面界面字体和图标显示过小,如何解决?

    作者:安日链接:https://www.zhihu.com/question/40658050/answer/132382971来源:知乎著作权归作者所有.商业转载请联系作者获得授权,非商业转载请注明 ...

  6. cocos2d-x retain和release倒底怎么玩?

    转载请注明,原文地址: http://blog.csdn.net/musicvs/article/details/8689345 正文: 1. 为什么会有retain? C++和Java不一样,Jav ...

  7. python测试开发django-29.发送html格式邮件

    前言 上一篇已经通过send_mail()函数发送纯文本的邮件,发送成功了,如果我们想发送一个html格式的邮件,如何实现呢? 发送html格式的邮件实际上还是调用send_mail()函数 ,只需多 ...

  8. SharePoint 取消分享时的默认发邮件

    前言 最近遇到一个需求,就是sharepoint默认分享的时候,会默认勾选发送邮件的功能.而用户,经常会用到分享的功能,但是不需要发送邮件,需要默认不勾选这个操作. 这样,就需要修改sharepoin ...

  9. 较老版本 AFNetworking 使用心得

    较老版本的 AFNetworking 下载链接 http://pan.baidu.com/s/14Cxga 将压缩包中的文件夹拖入xcode工程项目中并引入如下的框架 简单的 JOSN 解析例子    ...

  10. Python中的文件IO操作(读写文件、追加文件)

    Python中文件的读写包含三个步骤:打开文件,读/写文件,关闭文件. 文件打开之后必须关闭,因为在磁盘上读写文件的功能是由操作系统提供的,文件作为对象,被打开后会占用操作系统的资源,而操作系统在同一 ...