V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
tanteng
V2EX  ›  Redis

关于 Redis 队列的一道面试题

  •  
  •   tanteng ·
    tanteng · 2016-03-08 15:01:55 +08:00 · 30546 次点击
    这是一个创建于 3200 天前的主题,其中的信息可能已经有所发展或是发生改变。

    面试的时候讲到自己做的一个项目,我说用了 Redis 队列, lpush 进, rpop 出,面试官打断问:一般入队列没有问题,如果出对列阻塞了怎么办?实际生产环境中在这里没有出现问题,而且队列量很大,我没有太理解面试官问的什么。

    Redis 作队列需要注意什么问题?如果是高并发情况下怎么办?谢谢大家指点!

    第 1 条附言  ·  2016-03-08 15:54:51 +08:00
    还问有没有考虑队列的长度呢,我在实际开发中,没有考虑过这个问题, redis 可以一直入队列吧,不过如果队列太大,有可能占满内存,那这种情况怎么办?
    38 条回复    2018-03-17 13:20:35 +08:00
    tanteng
        1
    tanteng  
    OP
       2016-03-08 15:11:08 +08:00
    还有另外的地方用的是 HTTPSQS 消息队列系统,还有 Kafka
    CosWind
        2
    CosWind  
       2016-03-08 15:38:13 +08:00
    同没有 get 到面试官的点,队列阻塞也分很多种情况,和业务挂钩;
    如果是单纯的处理能力不够,增加 consumer 就可以;
    如果对顺序有要求,要对消息作 shard 。。

    但这么问,实在 get 不到点呀
    gaocheng
        3
    gaocheng  
       2016-03-08 15:41:23 +08:00
    1 、队列阻塞问题做好报警
    2 、从业务方面考虑能够动态调控提高队列处理能力
    sampeng
        4
    sampeng  
       2016-03-08 15:43:09 +08:00
    面试官的意思就是字面意思啊。。堵塞。。消费者挂掉 or 太慢。怎么处理
    sampeng
        5
    sampeng  
       2016-03-08 15:44:26 +08:00   ❤️ 1
    单纯加 cunsumer 真可以么。。资源不是无限的。
    我这线上就有一个典型例子,消费者突然处理变慢,加到能加的极限了,然后,然后就 redis 的内存吃满领便当了。
    tanteng
        6
    tanteng  
    OP
       2016-03-08 15:59:16 +08:00
    @sampeng 那如何解决的呢
    Mirana
        7
    Mirana  
       2016-03-08 16:17:04 +08:00
    我怎么觉得阻塞的意思是队列空了呢
    iyaozhen
        8
    iyaozhen  
       2016-03-08 16:17:17 +08:00   ❤️ 2
    最近就遇到这个问题了。

    消费者的速度没有生产者快,增加消费者也缓解不了, Redis 会被打满,直到挂掉(影响其它业务功能)。而且 Redis 目前的数据清理策略是根据 key 的,如果设置了清理用作队列的那个 list key 会被清掉,如果这是业务代码写的不是太好的话消费者和生产者都会挂掉。消费者最好还是异步消费,不要阻塞队列。

    当然还是要对队列长度做监控。

    目前已经转投 Kafka 了。
    iyaozhen
        9
    iyaozhen  
       2016-03-08 16:18:50 +08:00
    @Mirana 空了没关系吧, sleep 几秒。或者使用 brpop 指令。
    tanteng
        10
    tanteng  
    OP
       2016-03-08 16:19:55 +08:00
    @iyaozhen 消费者异步消费?这里能具体讲讲吗
    sampeng
        11
    sampeng  
       2016-03-08 16:23:39 +08:00   ❤️ 1
    kafka 是正理。。
    redis 只适合快速消费不会堆积的业务场景上,数据存内存里实在太贵了。。
    lecher
        12
    lecher  
       2016-03-08 16:24:10 +08:00 via Android   ❤️ 3
    出队列阻塞就是消费者的处理速度跟不上生产者产生的任务,加消费者提高处理速度。
    消费者加到极限还处理不过来,实在有爆内存的风险的时候,可以考虑将任务数据持久化,避免数据丢失,先把任务状态保存下来,根据具体业务做优化调整,等待异常问题解决之后再继续处理。
    Mirana
        13
    Mirana  
       2016-03-08 16:26:28 +08:00   ❤️ 1
    消费和生产有数量级的差异的话,增加消费者也是没用的,数据重要就放到数据库里,不重要就直接丢掉。
    tabris17
        14
    tabris17  
       2016-03-08 16:26:29 +08:00   ❤️ 1
    使用支持持久化的队列消息,比如 rabbitmq
    iyaozhen
        15
    iyaozhen  
       2016-03-08 16:26:35 +08:00
    @tanteng 额,可能说的不是太专业。看具体业务吧,你拿到数据肯定是需要做一些处理,这个过程可以异步操作,比如异步写文件,异步入库等。甚至继续向下游业务抛,压力往后转移。
    tanteng
        16
    tanteng  
    OP
       2016-03-08 16:35:10 +08:00
    @CosWind
    @sampeng
    增加消费者会不会存在并发取 redis 队列的情况,这种情况要如何处理
    cYcoco
        17
    cYcoco  
       2016-03-08 16:37:11 +08:00
    用 kafka 好了吧。在我印象里 redis 更适合做类 memcached 这种内存缓存吧。不过对 redis 不太了解。。
    lijinma
        18
    lijinma  
       2016-03-08 17:12:03 +08:00   ❤️ 1
    关于你的问题我遇见过:
    1. Redis 关于内存满了如何处理的策略要配置好,是使用 lru 还是 noviction 等,一定要想清楚, Redis 可使用的内存大小要配置适当,最好是你 Redis 内存使用峰值的几倍甚至 10 倍。

    2. Redis 内存要做好报警,简单的做法是每分钟或更短的时间使用 info 指令获取内存使用情况,如果超过某个值要马上想办法处理。

    3. 如果能多加 consumer ,就尝试多加 consumer 解决。

    4. 如果还没有解决,你可能需要想办法提升 Redis 内存占用,可能想办法平行扩展 Redis Server 。

    5. 如果还没有解决,就只能想办法用 kafka 这种可以持久化的方式了,或者你自己设计一种 Redis 的持久化方式,因为内存总归是有限的且稀缺的。
    tanteng
        19
    tanteng  
    OP
       2016-03-08 17:23:52 +08:00
    稍微总结一下:对于大数据的队列不适合用 Redis 弄,考虑 HTTPSQS , RabbitMQ 之类的消息队列系统,或者 Kafka , Redis 队列适合小型,快速,消费也快的场景。
    neoblackcap
        20
    neoblackcap  
       2016-03-08 17:32:33 +08:00 via iPhone
    @tanteng 不会, redis 就是一单线程实现,所有操作都是顺序执行
    Lucups
        21
    Lucups  
       2016-03-08 17:35:22 +08:00   ❤️ 1
    首先, Redis 是支持持久化的,所以队列数据完全可以持久化;其次, Consumer(Worker) 消化不了扛不住,先尝试多开一些,如果还不行,说明硬件或其他地方(如数据库存储)存在瓶颈,跟队列本身有毛关系?真以为上 Kafka 就能解决问题了?感觉题主没有 Get 到要点。
    keakon
        22
    keakon  
       2016-03-08 17:37:50 +08:00
    其实是让你用 epoll 之类的注册事件,等到可读时再去读…
    hxsf
        23
    hxsf  
       2016-03-08 17:48:45 +08:00
    @tanteng redis 单线程,不存在并发读写,总会有个先来后到的。
    hxsf
        24
    hxsf  
       2016-03-08 17:54:32 +08:00
    @keakon 直接 BRPOP 不就好了,读不到就阻塞,直到读到了再返回。
    wikimore
        25
    wikimore  
       2016-03-08 18:00:27 +08:00
    BRPOP 一个时间周期(如阻塞 30 秒)轮询,不能一直阻塞,因为长时间连接没有读写可能会被系统干掉,作为客户端就永远阻塞在那里了,而同时服务端的队列里可能有很多消息了。
    500miles
        26
    500miles  
       2016-03-08 18:00:44 +08:00   ❤️ 2
    按我的理解, 是说 " consumer 吞吐量太弱, 不及 producer 生产速度, 此时何解? "

    这就难玩儿了. . 就好比要解决北上广住房问题 .


    不考虑移民 (投靠其他技术选型),

    1. 监控队列, 动态调配 consumer, 适时增加 consumer

    最简单有效的办法, 从根本上解决问题. 当然你得花钱加机器

    2. 做好降级方案, 达到预设阀值, 出队后暂不处理, 直接先持久化再说


    3. consumer 投递异步任务, 不要阻塞出队列

    这个比较难玩儿
    wikimore
        27
    wikimore  
       2016-03-08 18:07:37 +08:00   ❤️ 1
    redis 做队列主要问题应该就是内存,如果使用到 swap 的话, redis 的队列会异常的慢,还有就是消息的大小,不要超过 1K ,再大写入基本就是很慢了,还有就是主从保证高可用,如果量非常大,可以多实例做 partition ,不过这时候用 Kafka 明显更划算, Redis 做做小业务玩玩还是可以的。
    bengol
        28
    bengol  
       2016-03-08 18:12:11 +08:00
    允许请求超时 /失败,做好失败后处理
    imlewc
        29
    imlewc  
       2016-03-08 18:28:01 +08:00
    分布式 一键解决
    keakon
        30
    keakon  
       2016-03-08 19:00:38 +08:00
    @hxsf 你的服务有 10 万并发时,第一个堵塞了,后面的都傻眼?
    isno
        31
    isno  
       2016-03-08 19:24:23 +08:00 via iPhone
    涉及队列的任务学会先消费后处理
    CosWind
        32
    CosWind  
       2016-03-08 19:45:45 +08:00
    @tanteng 还是不要用 redis 吧,我们用的是 rabbitmq
    22too
        33
    22too  
       2016-03-08 19:52:57 +08:00
    我们也是 rabbitmq
    hxsf
        34
    hxsf  
       2016-03-08 20:42:46 +08:00   ❤️ 1
    @keakon 读不到才阻塞(阻塞消费者),后面的消费者也会一起排队,有内容的时候按先后顺序解除阻塞啊。
    redis 文档上的啊,做队列用的时候建议使用 R

    官网文档 http://redis.io/commands/brpop

    以下引用他人翻译的

    列表的阻塞操作 (blocking)
    列表有一个特别的特性使得其适合实现队列,通常作为进程间通信系统的积木:阻塞操作。

    假设你想往一个进程的列表中添加项,用另一个进程来处理这些项。这就是通常的生产者消费者模式,可以使用以下简单方式实现:

    生产者调用 LPUSH 添加项到列表中。
    消费者调用 RPOP 从列表提取 / 处理项。
    然而有时候列表是空的,没有需要处理的, RPOP 就返回 NULL 。所以消费者被强制等待一段时间并重试 RPOP 命令。这称为轮询(polling),由于其具有一些缺点,所以不合适在这种情况下:

    强制 Redis 和客户端处理无用的命令 (当列表为空时的所有请求都没有执行实际的工作,只会返回 NULL)。
    由于工作者受到一个 NULL 后会等待一段时间,这会延迟对项的处理。
    于是 Redis 实现了 BRPOP 和 BLPOP 两个命令,它们是当列表为空时 RPOP 和 LPOP 的会阻塞版本:仅当一个新元素被添加到列表时,或者到达了用户的指定超时时间,才返回给调用者。
    moe3000
        35
    moe3000  
       2016-03-08 21:04:38 +08:00
    1 、 brpop 可以解决
    2 、 redis 分布式部署?具体没研究过。。
    keakon
        36
    keakon  
       2016-03-09 02:22:12 +08:00
    @hxsf 我觉得我已经说得够清楚了,你实际去做的话,就知道面试官为什么会这样问了…
    solaro
        37
    solaro  
       2016-03-09 11:12:14 +08:00
    @wikimore 咦,才 1K ,我之前做的都是限制 10K 以内, 5000/S 的吞吐量还是很快的。大促高峰期内存各种报警
    jinya
        38
    jinya  
       2018-03-17 13:20:35 +08:00
    马克
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   实用小工具   ·   917 人在线   最高记录 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 28ms · UTC 19:32 · PVG 03:32 · LAX 11:32 · JFK 14:32
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.