Redis的使用场景

Redis的数据结构主要有字符串(string),散列(hash),列表(list),集合(set),有序集合(sort set),HyperLogLog,位图,流。通过灵活使用,可以实现许多功能。

缓存

对数据进行缓存是Redis最常见的用法之一,因为缓存操作是指把数据存储在内存而不是硬盘上,而访问内存远比访问硬盘的速度要快得多,所以用户可以通过把需要快速访问的数据存储在Redis中来提升应用程序的速度。

一个简单的实现是使用SET命令将需要缓存的数据存储到指定的字符串键中,并使用GET命令来从指定的字符串键中获取被缓存的数据。
同时我们可以通过使用MSET命令、MSETNX命令以及MGET命令,我们可以实现批量设置操作和批量获取操作。如当用户想在博客中撰写一篇新文章的时候,程序就需要把文章的标题、内容、作者、发表时间等多项信息存储起来,并在用户阅读文章的时候取出这些信息。此外我们还可以通过,STRLEN命令,GETRANGE命令给文章存储程序加上文章长度计数功能和文章预览功能。

不过比起用多个字符串键来存储文章的各项数据,更好的做法是把每篇文章的所有数据都存储到同一个散列中。
在这里插入图片描述

Redis拥有多种数据结构,可以用来缓存各种各样的数据。

锁是一种同步机制,用于保证一项资源在任何时候只能被一个进程使用,如果有其他进程想要使用相同的资源,那么就必须等待,直到正在使用资源的进程放弃使用权为止。

我们可以使用字符串键实现的锁程序,根据给定的字符串键是否有值来判断锁是否已经被获取,而针对锁的获取操作和释放操作则是分别通过设置字符串键和删除字符串键来完成的。

SET key value_of_lock NX
DEL key 

NX选项的值确保了代表锁的字符串键只会在没有值的情况下被设置:如果给定的字符串键已经有值了,那么说明锁已经被获取,SET命令将放弃执行设置操作,并将result变量的值设置为None。

实际使用中应结合事务,乐观锁的特性实现更加安全可靠的锁机制。

计数器

计数器也是构建应用程序时必不可少的组件之一,如对于网站的访客数量、用户执行某个操作的次数、某首歌或者某个视频的播放量、论坛帖子的回复数量等,记录这些信息都需要用到计数器。

把计数器的值存储在一个字符串键里面,并通过INCRBY命令和DECRBY命令对计数器的值执行加法操作和减法操作,在需要时,用户还可以通过调用GETSET方法来清零计数器并取得清零之前的旧值。

同样也可以通过使用散列实现计数器,充分地发挥了散列的优势:它允许用户将多个相关联的计数器存储到同一个散列键中实行集中管理,而不必像字符串计数器那样,为每个计数器单独设置一个字符串键。与此同时,通过对散列中的不同字段执行HINCRBY命令,程序可以对指定的计数器执行加法操作和减法操作,而不会影响到存储在同一散列中的其他计数器。

在这里插入图片描述

通过使用不同的散列存储不同类型的计数器,程序能够让代码生成的数据结构变得更容易理解,并且在针对某种类型的计数器执行批量操作时也会变得更加方便。比如,当我们不再需要下载计数器的时候,只要把download_counters散列删除就可以移除所有下载计数器了。

在某些情况下,我们需要一种要求更为严格的计数器,这种计数器只会对特定的动作或者对象进行一次计数而不是多次计数。如用户数量记录。我们把这种对每个对象只进行一次计数的计数器称为唯一计数器(unique counter)。

可以使用集合实现的唯一计数器,通过把被计数的对象添加到集合来保证每个对象只会被计数一次,然后通过获取集合的大小来判断计数器目前总共对多少个对象进行了计数。

不过使用这种方式的唯一计数器占用能存比较大,可以使用HyperLogLog实现唯一计数器:无论被计数的元素有多少个,使用HyperLogLog实现的唯一计数器的内存开销总是固定的,并且因为每个HyperLogLog只占用12KB内存,所以即使程序使用多个HyperLogLog,也不会带来明显的内存开销。

另外,可以使用位图实现更加节省空间的紧凑计数器。

ID生成器

在构建应用程序的时候,我们经常会用到各式各样的ID(identif ier,标识符)。

可以使用字符串键实现的ID生成器,这个生成器通过执行INCR命令来产生新的ID,并且可以通过执行SET命令来保留指定数字之前的ID,从而避免用户为了得到某个指定的ID而生成大量无效ID。

限速器

为了保障系统的安全性和性能,并保证系统的重要资源不被滥用,应用程序常常会对用户的某些行为进行限制。

使用字符串键实现的限速器,这个限速器程序会把操作的最大可执行次数存储在一个字符串键里面,然后在用户每次尝试执行被限制的操作之前,使用DECR命令将操作的可执行次数减1,最后通过检查可执行次数的值来判断是否执行该操作。

短网址映射

创建短网址本质上就是要创建出短网址ID与目标网址之间的映射,并在用户访问短网址时,根据短网址的ID从映射记录中找出与之相对应的目标网址。比如在前面的例子中,微博的短网址程序就将短网址http://t.cn/RqRRZ8n中的ID值RqRRZ8n映射到了http://redisdoc.com/geo/index.html这个网址上面,当用户访问短网址http://t.cn/RqRRZ8n时,程序就会根据这个短网址的ID值RqRRZ8n找出与之对应的目标网址http://redisdoc.com/geo/index.html,并将用户引导至目标网址上面去。

Redis的散列非常适合用来存储短网址ID与目标网址之间的映射,所以我们可以基于Redis的散列实现一个短网址程序。

在这里插入图片描述

实现用户登录会话

为了方便用户,网站一般都会为已登录的用户生成一个加密令牌,然后把这个令牌分别存储在服务器端和客户端,之后每当用户再次访问该网站的时候,网站就可以通过验证客户端提交的令牌来确认用户的身份,从而使得用户不必重复地执行登录操作。
另外,为了防止用户因为长时间不输入密码而遗忘密码,以及为了保证令牌的安全性,网站一般都会为令牌设置一个过期期限(比如一个月),当期限到达之后,用户的会话就会过时,而网站则会要求用户重新登录。
上面描述的这种使用令牌来避免重复登录的机制一般称为登录会话(loginsession),通过使用Redis的散列,我们可以构建出登录会话程序。

在这里插入图片描述

先进先出队列

先进先出队列(f irst in f irst out queue)是一种非常常见的数据结构,一般都会包含入队(enqueue)和出队(dequeue)这两个操作,其中入队操作会将一个元素放入队列中,而出队操作则会从队列中移除最先入队的元素。
先进先出队列的应用非常广泛,各式各样的应用程序中都有使用。很多电商网站都会在节日时推出一些秒杀活动,这些活动会放出数量有限的商品供用户抢购,秒杀系统的一个特点就是在短时间内会有大量用户同时进行相同的购买操作,如果使用事务或者锁去实现秒杀程序,那么就会因为锁和事务的重试特性而导致性能低下,并且由于重试行为的存在,成功购买商品的用户可能并不是最早执行购买操作的用户,因此这种秒杀系统实际上是不公平的。
解决上述问题的方法之一就是把用户的购买操作都放入先进先出队列里面,然后以队列方式处理用户的购买操作,这样程序就可以在不使用锁或者事务的情况下实现秒杀系统,并且得益于先进先出队列的特性,这种秒杀系统可以按照用户执行购买操作的顺序来判断哪些用户可以成功执行购买操作,因此它是公平的。

使用Redis的列表数据结构实现,通过命令LPUSH,RPOP或者RPUSH,LPOP实现先进先出。

分页

将给定的元素有序地放入一个列表中,然后使用LRANGE命令从列表中取出指定数量的元素,从而实现分页。

待办事项

使用两个列表来分别记录待办事项和已完成事项:当用户添加一个新的待办事项时,程序就把这个事项放入待办事项列表中。当用户完成待办事项列表中的某个事项时,程序就把这个事项从待办事项列表中移除,并放入已完成事项列表中。

消息队列

使用Redis的列表数据结构实现的消息队列,使用RPUSH命令将消息推入队列,并使用BLPOP命令从队列中取出待处理的消息。之所以使用BLPOP命令而不是LPOP命令来实现出队操作,是因为阻塞弹出操作可以让消息接收者在队列为空的时候自动阻塞,而不必手动进行休眠,从而使得消息处理程序的编写变得更为简单直接,并且还可以有效地节约系统资源。

不过流是使用Redis实现消息队列应用的最佳选择。
流是一个包含零个或任意多个流元素的有序队列,队列中的每个元素都包含一个ID和任意多个键值对,这些元素会根据ID的大小在流中有序地进行排列。

打标签

为了对网站上的内容进行分类标识,很多网站都提供了打标签(tagging)功能。比如论坛可能会允许用户为帖子添加标签,这些标签既可以对帖子进行归类,又可以让其他用户快速地了解到帖子要讲述的内容。
使用集合实现的打标签程序,可以为不同的对象添加任意多个标签:同一个对象的所有标签都会被放到同一个集合里面,集合里的每一个元素就是一个标签。

同时,帮一个分类创建一个集合,里面可以存储这个分类下的所有对象,实现双向索引。

点赞

为了让用户表达自己对某一项内容的喜欢和赞赏之情,很多网站都提供了点赞(like)功能,除了点赞之外,很多网站还有诸如“+1”“顶”“喜欢”等功能,这些功能的名字虽然各有不同,但它们在本质上和点赞功能是一样的。

使用集合来存储对内容进行了点赞的用户,从而确保每个用户只能对同一内容点赞一次,并通过使用不同的集合命令来实现查看点赞数量、查看所有点赞用户以及取消点赞等功能。

社交关系

微博、Twitter以及类似的社交网站都允许用户通过加关注或者加好友的方式,构建一种社交关系。这些网站上的每个用户都可以关注其他用户,也可以被其他用户关注。

使用集合来记录社交关系的方法:
程序为每个用户维护两个集合,一个集合存储用户的正在关注名单,而另一个集合则存储用户的关注者名单。当一个用户(关注者)关注另一个用户(被关注者)的时候,程序会将被关注者添加到关注者的正在关注名单中,并将关注者添加到被关注者的关注者名单里面。当关注者取消对被关注者的关注时,程序会将被关注者从关注者的正在关注名单中移除,并将关注者从被关注者的关注者名单中移除。

同时共同关注可以通过求两个集合的交集得到。

抽奖

为了推销商品并回馈消费者,商家经常会举办一些抽奖活动,每个符合条件的消费者都可以参加这种抽奖,而商家则需要从所有参加抽奖的消费者中选出指定数量的获奖者,并向他们赠送物品、金钱或者其他购物优惠。
使用集合实现的抽奖程序,把所有参与抽奖活动的玩家都添加到一个集合中,然后通过SRANDMEMBER命令随机地选出获奖者。

排行榜

我们在网上常常会看到各式各样的排行榜,比如,在音乐网站上可能会看到试听排行榜、下载排行榜、华语歌曲排行榜和英语歌曲排行榜等。
使用有序集合实现的排行榜程序:
这个程序使用ZADD命令向排行榜中添加被排序的元素及其分数,并使用ZREVRANK命令去获取元素在排行榜中的排名,以及使用ZSCORE命令去获取元素的分数。
当用户不再需要对某个元素进行排序的时候,可以调用由ZREM命令实现的remove()方法,从排行榜中移除该元素。
如果用户想要修改某个被排序元素的分数,那么只需要调用由ZINCRBY命令实现的increase_score()方法或者decrease_score()方法即可。
当用户想要获取排行榜前N位的元素及其分数时,只需要调用由ZREVRANGE命令实现的top()方法即可。

时间线

同样的道理,将事件与时间戳存入有序集合,即可实现时间线。
通过对时间线中的元素执行ZREVRANGE命令或者ZREVRANGEBYSCORE命令,用户可以以分页的方式按顺序取出时间线中的元素,或者从时间线中取出指定时间区间内的元素。

商品推荐,喜欢这个东西的人也喜欢那个东西

在浏览网上商城的时候,我们常常会看到类似“购买此商品的顾客也同时购买”这样的商品推荐功能。从抽象的角度来讲,这些推荐功能实际上都是通过记录用户的访问路径来实现的:如果用户在对一个目标执行了类似浏览或者购买这样的操作之后,也对另一个目标执行了相同的操作,那么程序就会对这次操作的访问路径进行记录和计数,然后程序就可以通过计数结果来知道用户在对指定目标执行了某个操作之后,还会对哪些目标执行相同的操作。
使用以上原理实现的路径统计程序:每当用户从起点origin对终点destination进行一次访问,程序都会使用ZINCRBY命令对存储着起点origin访问记录的有序集合的destination成员执行一次分值加1操作。在此之后,程序只需要对存储着origin访问记录的有序集合执行ZREVRANGE命令,就可以知道用户在访问了起点origin之后,最经常访问的目的地有哪些。

自动补全

包含大量信息的网站常常会在搜索或者查找功能上提供自动补全特性,这一特性可以帮助用户更快速地找到他们想要的信息。比如,当我们在搜索引擎中输入“黄”字的时候,搜索引擎的自动补全特性就会列出一些比较著名的以“黄”字开头的人或者物,以便用户可以更快速地找到相关信息。
使用有序集合实现的自动补全程序,通过存储可能得结果及权重,按照权重的大小有序地返回结果的,实现自动补全。

另外可以通过更新过期时间,保持热门结果,淘汰冷门结果。

用户行为记录器

为了对用户的行为进行分析并借此改善服务质量,很多网站都会对用户在网站上的一举一动进行记录。比如记录哪些用户登录了网站,哪些用户发表了新的文章,哪些用户进行了消费,诸如此类。

为了尽可能地节约内存,并且精确地记录特定用户是否执行了指定的行为,我们可以使用位图实现用户行为记录器:
用户是否执行了指定行为这一信息可以通过一个二进制位来记录。通过将用户ID与位图中的二进制位偏移量进行一对一映射,我们可以使用一个位图来记录所有执行了指定行为的用户,每当用户执行指定行为时,我们就调用SETBIT命令,将用户在位图中对应的二进制位的值设置为1。通过调用GETBIT命令并判断用户对应的二进制位的值是否为1,我们可以知道用户是否执行了指定的行为。通过对位图执行BITCOUNT命令,我们可以知道有多少用户执行了指定行为。

存储地理坐标,查找附近用户

Redis GEO[插图]是Redis在3.2版本中新添加的特性,通过这一特性,用户可以将经纬度格式的地理坐标存储到Redis中,并对这些坐标执行距离计算、范围查找等操作。

参考书籍:《Redis使用手册》–黄健宏

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值