Beanstalkd入门

8/18/2021 MQ

# 概述

官网地址 (opens new window)

github地址 (opens new window)

学习参考 (opens new window)

# 特点

轻量级

高性能

易使用

分布式

内存队列

# 概念

  • Tube 这是一个「管道」的概念,「管道」就是指「队列」,一个队列系统,并非只能有一个「队列」,就像我们一个数据库系统,不止一个库一样。 不同的「管道」,代表着不同的内容类型,比如,举前面下单功能中的实际例子,我们发短信、发邮件两种类型的任务,就需要有两个分别处理他们的消费者,自然,这条任务(消息)也就需要存储在两个「管道」中。

    但是,这里的队列一词,我们不能把它与数据结构「队列」画上等号,这里的队列,类似于分类,用于区分 Job 的种类,而 beanstalkd 在底层根据 Job 状态进行存储时所用的「队列」才是数据结构上的队列。

    这里,你可以把 Tube 想象成一个书架,专门用于存放某一类书本。而书架内部,又被分为好几个区域,分别用于存放看过和没看过的书。 其中,书架就是 Tube ,区域就是数据结构之队列。

  • Job 「任务」的概念,就是指「消息」,它指存储在队列中的每一个具体成员,在前面的 demo 中,我们有设置一个 Job class ,那就是一个 Job 在代码中的呈现形式。

    生产者生成 Job ,将它放入特定的 Tube 中,再由消费者监听(订阅)特定的 Tube ,从中接收 Job 。

# 特性

在介绍 beanstalkd 的特性之前,我们应确保,已经读 Tube 和 Job 有了比较深刻的认知。

beastalkd 拥有以下特性:

  • 优先级(priority) beanstalkd 支持设置 Job 的优先级。 我们知道消息队列会根据 Job 被放入的先后顺序,将 Job 发送给消费者,它们就像是一群排着队买票的人,谁先进去,谁先买票。 但是,beanstalkd 支持优先级的特性,赋予了 Job 插队的能力。 设定 Job 优先级之后,可以让该 Job 在一堆 Job 中,更优先被消费者接收。(当然,如果你设置的优先级更低,则更晚被接收)

    可以联想到实际场景:vip 和 普通用户,我们可以为 vip 用户设置更高的优先级,让它优先被消费者消费。

  • 延迟(delay) beanstalkd 支持为 Job 设置延迟接收的属性,通常而言,生产者往消息队列中放入一条消息,只要有消费者空闲,就会被立马接收。 但 beanstalkd 的延迟特性,可以让 Job 在指定时间才被接收。

    比如,你希望用户下单成功时,大约五分钟之后,才给它发送短信通知。

    这里需要注意,被消费者执行的时间,不仅仅取决于延迟特性,同样也受消费者接收频率影响

  • 预留(bury) beanstalkd 支持设置 Job 的状态为预留,处于预留状态时,它不允许被消费,也不会被消费者接收。

    比如,我们想实现顺序消费:先发短信,再发邮件,此时,我们可以在邮件消费者中,检查该 Job 是否已经发送过短信(存在短信发送记录),如果还没发送过,就把它设置为预留状态,等到之后条件满足(存在短信发送记录)后,再进行消费。

  • 持久化(persistent data) beanstalkd 还可通过日志实现持久化,这样我们可以不必担心数据丢失,提升了消息可靠性。 至于如何操作,在后文会有介绍。

  • 超时重发( time-to-run ,ttr ) beanstalkd 拥有 TTR 的特性,在前文《使用消息队列的注意事项》中有所提及。 ttr 也是提升消息可靠性的一种手段。 它指,在消费者接收到 Job 之后,没能在一定时间内处理完毕,此时,beanstalkd 会认为该 Job 处理失败,将它从 reserved 的状态重新调整到 ready 状态。 这也是导致出现消息重复被消费的问题,因为消费者响应超时,可能由其它原因引起,比如网络原因,并不一定是真的处理失败了。

#

# Beanstalkd协议

# Job 生命周期

​ 一个 Job 由 put 命令创建,在它的生命周期以内,它必将处于以下四种状态中的一种:「ready」、「reserved」、「delayed」、「buried」 当使用完 put 命令,Job 一般从 「ready」 开始,它会在「ready」队列中等待,直到有「reserved」命令过来,当接收成功之后,则将该 Job 放入到 「reserved」 队列。接着,当进程处理完这个 Job 之后,则会发送一个「delete」命令,将这个 Job 从 beanstalkd 中删除。

状态 描述
ready 被放入 Tube 之后等待被接收和处理
reserved 当 Job 被 reserve 命令接收,Job 会进入这个状态,它代表被接收,但还没有得到其他反馈
delayed 延迟状态,等时间到了会变成 ready 状态
buried 预留状态,一般当消费者处理失败时,会将它设置为预留

# 问题管理

Cannot assign requested address

大致上是由于客户端频繁的连服务器,由于每次连接都在很短的时间内结束,导致很多的TIME_WAIT,以至于用光了可用的端 口号,所以新的连接没办法绑定端口,即“Cannot assign requested address”。是客户端的问题不是服务器端的问题。通过netstat,的确看到很多TIME_WAIT状态的连接。

解决办法是需要做一下内核参数优化:(需要root权限) sysctl -w net.ipv4.tcp_timestamps=1 开启对于TCP时间戳的支持,若该项设置为0,则下面一项设置不起作用 sysctl -w net.ipv4.tcp_tw_recycle=1 表示开启TCP连接中TIME-WAIT sockets的快速回收

但是开启net.ipv4.tcp_tw_recycle这个参数之后可能会有一些问题