我的日常

登录/注册
您现在的位置:论坛 资料库 开源社区 > 让Redis在你的系统中发挥更大作用
总共48086条微博

动态微博

查看: 1516|回复: 1

让Redis在你的系统中发挥更大作用

[复制链接]
admin    

1244

主题

544

听众

1万

金钱

管理员

  • TA的每日心情

    2021-2-2 11:21
  • 签到天数: 36 天

    [LV.5]常住居民I

    管理员

    跳转到指定楼层
    楼主
    发表于 2016-02-04 09:16:46 |只看该作者 |正序浏览
    Redis在很多方面与其他数据库解决方案不同:它使用内存提供主存储支持,而仅使用硬盘做持久性的存储;它的数据模型非常独特,用的是单线程。另一个大区别在于,你可以在开发环境中使用Redis的功能,但却不需要转到Redis。


    转向Redis当然也是可取的,许多开发者从一开始就把Redis作为首选数据库;但设想如果你的开发环境已经搭建好,应用已经在上面运行了,那么更换数据库框架显然不那么容易。另外在一些需要大容量数据集的应用,Redis也并不适合,因为它的数据集不会超过系统可用的内存。所以如果你有大数据应用,而且主要是读取访问模式,那么Redis并不是正确的选择。


    然而我喜欢Redis的一点就是你可以把它融入到你的系统中来,这就能够解决很多问题,比如那些你现有的数据库处理起来感到缓慢的任务。这些你就可以通过Redis来进行优化,或者为应用创建些新的功能。在本文中,我就想探讨一些怎样将Redis加入到现有的环境中,并利用它的原语命令等功能来解决传统环境中碰到的一些常见问题。在这些例子中,Redis都不是作为首选数据库。


    显示最新的项目列表


    下面这个语句常用来显示最新项目,随着数据多了,查询毫无疑问会越来越慢。


    SELECT * FROM foo WHERE ... ORDER BY time DESC LIMIT 10
    在Web应用中,“列出最新的回复”之类的查询非常普遍,这通常会带来可扩展性问题。这令人沮丧,因为项目本来就是按这个顺序被创建的,但要输出这个顺序却不得不进行排序操作。


    类似的问题就可以用Redis来解决。比如说,我们的一个Web应用想要列出用户贴出的最新20条评论。在最新的评论边上我们有一个“显示全部”的链接,点击后就可以获得更多的评论。


    我们假设数据库中的每条评论都有一个唯一的递增的ID字段。


    我们可以使用分页来制作主页和评论页,使用Redis的模板:


    -每次新评论发表时,我们会将它的ID添加到一个Redis列表:


    LPUSH latest.comments <ID>
    -我们将列表裁剪为指定长度,因此Redis只需要保存最新的5000条评论:


    LTRIM latest.comments 0 5000
    -每次我们需要获取最新评论的项目范围时,我们调用一个函数来完成(使用伪代码):


    FUNCTION get_latest_comments(start,num_items):
       id_list = redis.lrange(&quot;latest.comments&quot;,start,start+num_items-1)
       IF id_list.length &lt; num_items
           id_list = SQL_DB(&quot;SELECT ... ORDER BY time LIMIT ...&quot;)
       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-adv ... -to-your-stack.html


    科帮网 1、本主题所有言论和图片纯属会员个人意见,与本社区立场无关
    2、本站所有主题由该帖子作者发表,该帖子作者与科帮网享有帖子相关版权
    3、其他单位或个人使用、转载或引用本文时必须同时征得该帖子作者和科帮网的同意
    4、帖子作者须承担一切因本文发表而直接或间接导致的民事或刑事法律责任
    5、本帖部分内容转载自其它媒体,但并不代表本站赞同其观点和对其真实性负责
    6、如本帖侵犯到任何版权问题,请立即告知本站,本站将及时予与删除并致以最深的歉意
    7、科帮网管理员和版主有权不事先通知发贴者而删除本文


    JAVA爱好者①群:JAVA爱好者① JAVA爱好者②群:JAVA爱好者② JAVA爱好者③ : JAVA爱好者③

    admin    

    1244

    主题

    544

    听众

    1万

    金钱

    管理员

  • TA的每日心情

    2021-2-2 11:21
  • 签到天数: 36 天

    [LV.5]常住居民I

    管理员

    沙发
    发表于 2016-02-04 09:18:49 |只看该作者
    毫无疑问,Redis开创了一种新的数据存储思路,使用Redis,我们不用在面对功能单调的数据库时,把精力放在如何把大象放进冰箱这样的问题上,而是利用Redis灵活多变的数据结构和数据操作,为不同的大象构建不同的冰箱。希望你喜欢这个比喻。
    下面是一篇新鲜出炉的文章,其作者是Redis作者@antirez,他描述了Redis比较适合的一些应用场景,NoSQLFan简单列举在这里,供大家一览:
    1.取最新N个数据的操作
    比如典型的取你网站的最新文章,通过下面方式,我们可以将最新的5000条评论的ID放在Redis的List集合中,并将超出集合部分从数据库获取
    使用LPUSH latest.comments<ID>命令,向list集合中插入数据
    插入完成后再用LTRIM latest.comments 0 5000命令使其永远只保存最近5000个ID
    然后我们在客户端获取某一页评论时可以用下面的逻辑(伪代码)
    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
    如果你还有不同的筛选维度,比如某个分类的最新N条,那么你可以再建一个按此分类的List,只存ID的话,Redis是非常高效的。
    2.排行榜应用,取TOP N操作
    这个需求与上面需求的不同之处在于,前面操作以时间为权重,这个是以某个条件为权重,比如按顶的次数排序,这时候就需要我们的sorted set出马了,将你要排序的值设置成sorted set的score,将具体的数据设置成相应的value,每次只需要执行一条ZADD命令即可。
    3.需要精准设定过期时间的应用
    比如你可以把上面说到的sorted set的score值设置成过期时间的时间戳,那么就可以简单地通过过期时间排序,定时清除过期数据了,不仅是清除Redis中的过期数据,你完全可以把Redis里这个过期时间当成是对数据库中数据的索引,用Redis来找出哪些数据需要过期删除,然后再精准地从数据库中删除相应的记录。
    4.计数器应用
    Redis的命令都是原子性的,你可以轻松地利用INCR,DECR命令来构建计数器系统。
    5.Uniq操作,获取某段时间所有数据排重值
    这个使用Redis的set数据结构最合适了,只需要不断地将数据往set中扔就行了,set意为集合,所以会自动排重。
    6.实时系统,反垃圾系统
    通过上面说到的set功能,你可以知道一个终端用户是否进行了某个操作,可以找到其操作的集合并进行分析统计对比等。没有做不到,只有想不到。
    7.Pub/Sub构建实时消息系统
    Redis的Pub/Sub系统可以构建实时的消息系统,比如很多用Pub/Sub构建的实时聊天系统的例子。
    8.构建队列系统
    使用list可以构建队列系统,使用sorted set甚至可以构建有优先级的队列系统。
    9.缓存
    这个不必说了,性能优于Memcached,数据结构更多样化。

    回复

    使用道具 举报

    快速回复
    您需要登录后才可以回帖 登录 | 立即注册

       

    关闭

    站长推荐上一条 /1 下一条

    发布主题 快速回复 返回列表 联系我们 官方QQ群 科帮网手机客户端
    快速回复 返回顶部 返回列表