【快速了解redis】五种数据类型-Lists篇

前记

各位在深圳的小伙伴们,不知大家有没有关注到前段时间,深圳的文和友在朋友圈火了一把,小伙伴们有没有抽空去打卡呢?

其中,“茶颜悦色”的开张,更是听说排了长长的一条队,最高峰足足5万人。着实让我这个还没喝过“茶颜悦色”的人对这个牌子产生了兴趣。

话说回来,为什么要讲这一段消息呢?因为这里隐藏了一个我们要讲的一个知识点:消息队列

我们这次用redis快速地实现消息队列,讲解一下,为什么要实现消息队列,消息队列的一些注意点,是怎么用redis来实现的

为什么要实现“消息队列”

首先什么是消息队列
消息队列在技术上讲,其实是一种数据存储方式,我们把要处理的数据,按照“排队”的方式管理起来,然后遵循“先到先处理”的方式处理数据。

消息队列的使用场景
借用“茶颜悦色”的例子,其实我们可以看到能用消息队列的经典场景了。
排好队的苹果们

当我们实现的应用程序要处理的请求过多时,要适时使用“消息队列”,让源源不断的请求,一个个地排好队,等待被处理。这种处理方式,在架构设计上,有一个词叫“削峰填谷”,很形象地概括了消息队列的经典作用。

所以,当你所负责的项目中,如果涉及到系统的突发性流量峰值的场景时,不妨考虑下“消息队列”的使用。

Lists数据类型

lists的意思是列表,他是基于链表(linked lists)实现的,我们用它来实现消息队列,我们假设队列是从左边排到右边的(左边是前头)具体步骤是:

第一步: 每次来一个请求,我们先把请求排到队列的最右边(后来的都是在前面的右边)

1
2
3
4
5
6
7
127.0.0.1:6379> rpush queue A # 把请求A排到最右边
127.0.0.1:6379> rpush queue B # 把请求B排到最右边
127.0.0.1:6379> rpush queue C # 把请求C排到最右边
127.0.0.1:6379> lrange queue 0 -1 # lrange 把queue查出来,-1表示末位
1) "A"
2) "B"
3) "C"

把数据排到最左边是lpush

你看是不是把请求的顺序都排好了。

第二步: 我们每次处理最前面的那个请求

1
2
127.0.0.1:6379> lpop queue # 把queue最左边的请求拿出来
"A"

把右边的数据拿出来是rpop

到此位置,一个消息队列的雏形已经有了,排好队,一个一个的处理。

但是,我们再想一想,这条队能让他一直排下去吗?特别是当应用的处理能力严重不足的时候

我们是不是该限定这个队列的长度呢?拿茶颜悦色的排队来说,我们就定这个队列只能5w个请求

事实上,redis的lists的长度可达到
位,但系统的负载不能仅仅从redis一方面去想,可能还要考虑请求的响应时间等等

所以,我们要对queue这个队列做长度限制,当长度大于5w时,我们该怎么办?这时候继续来的请求,我们该怎么处理呢?

第三步: 对队列做溢出处理策略,当队列已经有的请求达到5w时,后来的请求,我们只能不做相应,相应的需要将这种状态返回前端(消费端),正如我们会通知太靠后的群众择日再来一样

1
2
3
4
5
6
# 读取队列长度
127.0.0.1:6379> llen queue # 读取queue长度
# 伪代码(下面是伪代码,具体实现,视所使用的依赖包的具体用法)
if(redis.llen(queue) <50000){
redis.rpush(新请求)
}

好了,到此,我们也把lists的一个应用讲完了。(后续降到发布订阅时,我们尝试着使用lists+发布订阅的机制,实现一个简易的即时通讯功能)

拓展

lists和array的区别

回看了下redis的官方文档,发现有这么一个提醒

To explain the List data type it’s better to start with a little bit of theory, as the term List is often used in an improper way by information technology folks

大意就是说,我们对lists的理解需要从理论出发。而这里,不知大家是否发现,array和lists很像。但官网中提到,redis的lists类型是基于链表(linked list)实现的

在这里,我们得先认识几个概念
顺序表: 顺序表存储的每个数据称为一个元素,各个元素及其索引是一一对应的关系。而它的存储方式有两种

  • 顺序存储
  • 链式存储

其中,顺序存储方式的顺序表,我们可以把它理解成“数组”,它在存储的时候,是需要一块连续的存储空间的;

链式存储,则是我们所说的链表,它的存储方式不需要连续的存储空间,但它每一个数据,被成为节点(node),一个node上保存了数据和一个指向上一个数据的指针,这样,链表结构的数据得以串起来。

课后作业

redis官方文档给出了一段讲解链表和数组的优缺点的说明,大家尝试翻译一下。

from a very general point of view a List is just a sequence of ordered elements: 10,20,1,2,3 is a list. But the properties of a List implemented using an Array are very different from the properties of a List implemented using a Linked List.
Redis lists are implemented via Linked Lists. This means that even if you have millions of elements inside a list, the operation of adding a new element in the head or in the tail of the list is performed in constant time. The speed of adding a new element with the LPUSH command to the head of a list with ten elements is the same as adding an element to the head of list with 10 million elements.
What’s the downside? Accessing an element by index is very fast in lists implemented with an Array (constant time indexed access) and not so fast in lists implemented by linked lists (where the operation requires an amount of work proportional to the index of the accessed element).

上一篇文章里,有提到要讲讲“缓存击穿”等的一些知识点的,估计得推到下一次了。太晚了,太难了。

心有猛虎,细嗅蔷薇。