V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
推荐学习书目
Learn Python the Hard Way
Python Sites
PyPI - Python Package Index
http://diveintopython.org/toc/index.html
Pocoo
值得关注的项目
PyPy
Celery
Jinja2
Read the Docs
gevent
pyenv
virtualenv
Stackless Python
Beautiful Soup
结巴中文分词
Green Unicorn
Sentry
Shovel
Pyflakes
pytest
Python 编程
pep8 Checker
Styles
PEP 8
Google Python Style Guide
Code Style from The Hitchhiker's Guide
smallgoogle
V2EX  ›  Python

你们是如何使用 redis 来监听任务的?

  •  
  •   smallgoogle · 2020-08-11 10:32:46 +08:00 · 7626 次点击
    这是一个创建于 1600 天前的主题,其中的信息可能已经有所发展或是发生改变。
    鄙人有个需求就是,A 服务把数据推到 redis,B 服务一直监听 redis list,如果有数据就弹出。
    我在 B 服务里用的是 blpop,可这个命令是阻塞的。意思是如果 redis 的 list 一直没有数据 这个位置就一直阻塞,直到监听到一个数据 然后弹出。。。
    那么问题就来了,先不说程序效率不效率的,或者是超时不超时的。因为目前我发现我还没等到超时呢,内存就溢出了。。或者说这个阻塞导致了系统自动结果了 B 服务的进程。因为我报错如下:
    ```
    OSError: [Errno 12] Cannot allocate memory
    ```

    那么问题来了,我如何可以优雅的监听 list 是否有新数据呢?
    第 1 条附言  ·  2020-08-11 11:19:44 +08:00
    各位大佬,其实我用 redis 的原因 大部分是想兼顾其他数据的临时缓存,顺带把这个事情也做了。数据不重要,所以大家不需要考虑丢失的问题。我觉得大家让我用 mq 是没错的。只是我还达不到要用 mq 。。所以现在就在 redis 这个地方卡一下。。
    第 2 条附言  ·  2020-08-13 14:06:22 +08:00
    好了。大家不要刚了。。溢出是我的多进程问题。。redis 确实没问题。。感谢大家呲醒。 还有刚 mq 的。其实业务不大,虽然也不小。但是可以使用 redis 解决大多数问题。就懒得上别的东西了。毕竟上的多了。管理起来也费劲。毕竟不只是一个业务板块在手上。
    56 条回复    2020-08-12 13:40:44 +08:00
    fdingiit
        1
    fdingiit  
       2020-08-11 10:35:38 +08:00
    为什么不选择专业的而选择二道贩子
    smallgoogle
        2
    smallgoogle  
    OP
       2020-08-11 10:46:32 +08:00
    @fdingiit 我是不是应该在 A 服务里写一个频道通知? 然后 B 服务监听频道,收到频道通知 再去取 list ?
    wangritian
        3
    wangritian  
       2020-08-11 10:46:56 +08:00
    blpop 换成 lpop 然后加一个取到空数据的小延迟
    xkeyideal
        4
    xkeyideal  
       2020-08-11 10:48:26 +08:00
    redis 啥时候可以干数据变化推送的功能了
    FaceBug
        5
    FaceBug  
       2020-08-11 10:51:21 +08:00
    B 服务 lpop,如果有数据就一直取数据,并进行相关业务

    一旦再次取到空数据,就 sleep 几秒再检查

    如果业务量比较小,且 A 服务来数据没有什么规律

    通常连续几个 sleep (可能 3 、5 分钟)之后就把 B 服务结束了

    配合一个 15 分钟甚至更长的 crontab 再来唤醒 B 服务
    smallgoogle
        6
    smallgoogle  
    OP
       2020-08-11 10:52:54 +08:00
    @cepczkd 觉得你这是个好办法。但是如果我在 B 服务做个频道监听,让 A 推送数据的时候顺带发布一下频道,这样会不会更优?
    fdingiit
        7
    fdingiit  
       2020-08-11 10:54:51 +08:00
    @smallgoogle 我觉得你应该先考虑为什么选择 redis,以及 redis 的几个常见问题,比如灾备丢数据如何处理
    qiayue
        8
    qiayue  
       2020-08-11 10:55:52 +08:00
    MQ
    soulzz
        9
    soulzz  
       2020-08-11 10:57:04 +08:00
    kafka 比较适合这个场景
    prenwang
        10
    prenwang  
       2020-08-11 10:57:24 +08:00   ❤️ 4
    redis 有 pubsub 可以试试.

    楼上不要抬杠, redis 做这类轻量级消息场景非常好用, API 简单, redis 的部署管理也很方便. 性能港港, 优势明显

    不大的项目动不动上卡夫卡等重量级消息队列找虐, 管理维护,api 易用性都不能和 redis 比.

    @smallgoogle 你也可以使用 beanstalkd 这个轻量级的消息队列, 易用性和 redis 差不多. 小型项目的话性能绰绰有余
    kiracyan
        11
    kiracyan  
       2020-08-11 10:57:29 +08:00
    lpop 加阻塞 然后 A 推送数据的时候打开 长时间没数据就继续阻塞?
    palmers
        12
    palmers  
       2020-08-11 10:59:08 +08:00
    为啥使用 redis 而不用 mq 呢?
    KallyDev
        13
    KallyDev  
       2020-08-11 10:59:32 +08:00
    这事应该让消息队列来做,可以试试 RabbitMQ 还是蛮好用的

    Redis 也不是不可以,但不适合去做这些,参考 https://cn.v2ex.com/t/562561
    话说 Redis 的作者也写过一个消息队列插件 https://github.com/antirez/disque-module,不过看样子是已经弃坑了
    wei745359223
        14
    wei745359223  
       2020-08-11 11:02:54 +08:00
    huntcool001
        15
    huntcool001  
       2020-08-11 11:03:43 +08:00   ❤️ 1
    如果是 Redis 5.0 版本以上,用 Stream, 里面的 XREAD 命令加上 BLOCK 参数. 这个不会丢失消息,比 pub sub 好.
    Redis 5.0 以下的版本就用 PUB -SUB 好了.

    B 服务的进程不应该终结吧,是不是你代码写法有问题. 一个线程不停等就好了,咋会内存溢出.

    实在有这个问题的话,业务又允许一定延迟,你就分布式 cronJob 一秒执行一次吧
    FaceBug
        16
    FaceBug  
       2020-08-11 11:04:09 +08:00
    @smallgoogle

    建议先解决内存溢出的问题

    这个和 blpop 还是别的什么 pop 应该没什么关系的

    既然你还要做一下监听,那么就说明 B 业务一直是运行的

    个人觉得和直接监听 list 有没有数据没什么差别

    另外如果你的数据如果是有顺序操作的

    你用监听+取数据的操作就要考虑到并发的问题
    huntcool001
        17
    huntcool001  
       2020-08-11 11:04:42 +08:00
    当然, RabbitMQ 之类的队列更适合. 专业的东西做专业的事. 除非你们业务真的很小,消息队列都没部署
    xuanbg
        18
    xuanbg  
       2020-08-11 11:05:55 +08:00
    MQ 是专业干这个的。放着专业的不用,为啥要用半吊子的 redis ?


    @prenwang RabbitMQ 一点都不重,用 docker 安装使用都十分简单,而且几乎不占 cpu 和内存。
    sss495088732
        19
    sss495088732  
       2020-08-11 11:07:48 +08:00
    0.0,kafka,rabbitmq,nsq....redis 是最后的选择,自己基于 redis 写一个 MQ..
    Immortal
        21
    Immortal  
       2020-08-11 11:22:14 +08:00
    我觉得内存溢出问题不是 redis 的队列引起的 再检查下
    blpop 就是这么用的 我不是很支持楼上说的 lpop 然后 sleep
    而且我也建议继续使用 redis 没必要动不动上 mq 服务架构越简单越好 不得不上的时候才会考虑加第三方组件
    berserk
        22
    berserk  
       2020-08-11 11:25:05 +08:00
    显然这个需求应该用 kafka.
    vissssa
        23
    vissssa  
       2020-08-11 11:28:48 +08:00
    明显不是 blpop 的问题,都歪楼成啥样了
    以前用 blpop 监听过任务,没出现过问题。
    Pythoner666666
        24
    Pythoner666666  
       2020-08-11 11:45:11 +08:00
    sleep 的操作建议别用 会阻塞 cpu 。 blpop 本身就是楼主这种用法 另外设置超时时间 没有数据就不会一直阻塞 会进入 sleep 状态 有新数据就会再次唤醒 这样比较合理 但是会有另外一个坑 就是 sleep 时间太久 redis 客户端会断开连接 所以得 catch 异常 然后假重连。
    wysnylc
        25
    wysnylc  
       2020-08-11 12:28:02 +08:00   ❤️ 1
    redis sub/pub
    jenlors
        26
    jenlors  
       2020-08-11 12:50:14 +08:00 via Android
    redis5.0 以上支持 stream,当做轻量级队列使用还是不错的。
    bigggge
        27
    bigggge  
       2020-08-11 12:56:56 +08:00
    借楼问下,Node.js 用 https://github.com/OptimalBits/bull/ 的时候,BRPOPLPUSH 导致写时延一直是 5s,触发监控报警咋办?
    tikazyq
        28
    tikazyq  
       2020-08-11 14:04:49 +08:00
    上代码
    tikazyq
        29
    tikazyq  
       2020-08-11 14:05:43 +08:00
    选 redis 没错,这个方案也可行,内存溢出一般是程序本身的问题,检查一下哪里写了 bug 了
    lenqu
        30
    lenqu  
       2020-08-11 14:14:11 +08:00
    轻量级,redis 我觉得很好用,消息队列并不适合单一的场景业务
    gemini767
        31
    gemini767  
       2020-08-11 14:16:43 +08:00
    思路有点绕,可以用 redis 的订阅
    也可以当前一个事务处理完直接调用下一个服务
    也可以 eventbus 之类的
    不知道手写 一边写一边读的意义
    lenqu
        32
    lenqu  
       2020-08-11 14:20:42 +08:00
    还有如果是一个在内网,一个在外网,我觉得消息队列在这种业务下是不合适的,因为队列服务器无法主动连接
    cnoder
        33
    cnoder  
       2020-08-11 14:32:56 +08:00
    大概率不是 redis 的问题,用法没错
    shenlanAZ
        34
    shenlanAZ  
       2020-08-11 16:41:18 +08:00
    lpush 把消息放到队列里,brpop 消费,这里面会有一个 timeout 当 timeout 过了之后,brpop 就结束了会返回 null, 需要进入下一个循环。

    内存溢出应该和这些方法没问题,建议检查一下逻辑代码。
    timidadonis
        35
    timidadonis  
       2020-08-11 16:59:23 +08:00
    消息队列他不香吗
    byzf
        36
    byzf  
       2020-08-11 17:27:51 +08:00
    和你需求基本相同, 用 lrange + ltrim, 每次取固定数量, 代码大概五十行吧, 跑了几年至今没遇到过超时和内存溢出.

    仿佛来到了卡巴, 20 块钱配置出的问题, 一堆人让买八路泰坦.
    ToBeHacker
        37
    ToBeHacker  
       2020-08-11 17:42:57 +08:00
    你这个内存溢出跟 redis 应该没啥关系吧
    dzdh
        38
    dzdh  
       2020-08-11 17:47:06 +08:00
    @KallyDev 并不是弃坑,而是作为一个 redis 扩展可选安装。不再默认整合在 redis 代码中。
    Leigg
        39
    Leigg  
       2020-08-11 17:50:30 +08:00 via Android
    出问题先检查自己代码
    robinlovemaggie
        40
    robinlovemaggie  
       2020-08-11 17:54:05 +08:00
    不太清楚你的 blpop 在做什么逻辑的阻塞,感觉像是出现了死锁
    simonlu9
        41
    simonlu9  
       2020-08-11 19:29:37 +08:00
    redis stream 你值得拥有
    ichou
        42
    ichou  
       2020-08-11 20:55:00 +08:00 via iPhone
    blpop/brpop 很可靠的哈,开源社区有不少队列项目都是基于这个实现的,比如 Sidekiq
    检查一下内存溢出的原因吧
    misaka19000
        43
    misaka19000  
       2020-08-11 21:02:50 +08:00
    @prenwang #10 redis 的 pubsub 太弱了
    MarioLuo
        44
    MarioLuo  
       2020-08-12 00:40:30 +08:00 via Android
    小项目中常用 redis 这么干,Java 语言用 brpop 没遇到过内存溢出,不过有一点就是全局配置的超时时间必须大于 brpop 阻塞时间,否则会出现消息丢失
    scnace
        45
    scnace  
       2020-08-12 02:24:00 +08:00 via Android
    Redis 有个 disque module (
    yuzo555
        46
    yuzo555  
       2020-08-12 03:03:40 +08:00
    Redis 的 Stream
    yc8332
        47
    yc8332  
       2020-08-12 08:23:35 +08:00
    内存溢出是你自己程序的问题。找找哪里一直申请内存
    atonku
        48
    atonku  
       2020-08-12 08:51:24 +08:00
    redis 做这个真的不好用
    edk24
        49
    edk24  
       2020-08-12 09:30:07 +08:00
    没有达不达的到, 我连个上传视频异步转码切片都用上了. 哈哈 除非你想折腾自己

    用适合的东西做适合的事情, 不然脑瓜疼
    raptor
        50
    raptor  
       2020-08-12 09:58:55 +08:00
    如果是 python 的话,直接用 celery,后端用 redis 即可
    encro
        51
    encro  
       2020-08-12 09:58:56 +08:00
    非常常规的用法,
    通常可能是取出太多了吧,
    或者采用了异步一堆协程去取阻塞类似?
    hxy91819
        52
    hxy91819  
       2020-08-12 10:26:24 +08:00
    刚看第一句话,感觉就应该用消息队列
    tairan2006
        53
    tairan2006  
       2020-08-12 10:31:32 +08:00
    pub/sub or xstream
    someonedeng
        54
    someonedeng  
       2020-08-12 11:33:54 +08:00
    其实重点是,B 服务会炸掉这个问题
    killerv
        55
    killerv  
       2020-08-12 13:36:34 +08:00
    很多人上来就是换 MQ,真是服了,内存溢出的原因大概率是楼主程序问题。把消费队列换成 MQ,还是会内存溢出。
    killerv
        56
    killerv  
       2020-08-12 13:40:44 +08:00
    小服务用 Redis 队列很好用的,我们 MQ 和 Redis 的 list 都有在用,说实话没发现 Redis 有你们说的那么不堪,作为消息队列很稳。不管是服务端还是客户端,Redis 配置比 MQ 简单多了。
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   实用小工具   ·   2652 人在线   最高记录 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 27ms · UTC 15:15 · PVG 23:15 · LAX 07:15 · JFK 10:15
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.