你们是如何使用 redis 来监听任务的? - V2EX
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 8299 次点击
    这是一个创建于 1959 天前的主题,其中的信息可能已经有所发展或是发生改变。
    鄙人有个需求就是,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  
    &nsp;  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  
    PRO
       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 和内存。
    cocowind
        19
    cocowind  
       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     Solana     2848 人在线   最高记录 6679       Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 41ms UTC 14:30 PVG 22:30 LAX 06:30 JFK 09:30
    Do have faith in what you're doing.
    ubao msn snddm index pchome yahoo rakuten mypaper meadowduck bidyahoo youbao zxmzxm asda bnvcg cvbfg dfscv mmhjk xxddc yybgb zznbn ccubao uaitu acv GXCV ET GDG YH FG BCVB FJFH CBRE CBC GDG ET54 WRWR RWER WREW WRWER RWER SDG EW SF DSFSF fbbs ubao fhd dfg ewr dg df ewwr ewwr et ruyut utut dfg fgd gdfgt etg dfgt dfgd ert4 gd fgg wr 235 wer3 we vsdf sdf gdf ert xcv sdf rwer hfd dfg cvb rwf afb dfh jgh bmn lgh rty gfds cxv xcv xcs vdas fdf fgd cv sdf tert sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf shasha9178 shasha9178 shasha9178 shasha9178 shasha9178 liflif2 liflif2 liflif2 liflif2 liflif2 liblib3 liblib3 liblib3 liblib3 liblib3 zhazha444 zhazha444 zhazha444 zhazha444 zhazha444 dende5 dende denden denden2 denden21 fenfen9 fenf619 fen619 fenfe9 fe619 sdf sdf sdf sdf sdf zhazh90 zhazh0 zhaa50 zha90 zh590 zho zhoz zhozh zhozho zhozho2 lislis lls95 lili95 lils5 liss9 sdf0ty987 sdft876 sdft9876 sdf09876 sd0t9876 sdf0ty98 sdf0976 sdf0ty986 sdf0ty96 sdf0t76 sdf0876 df0ty98 sf0t876 sd0ty76 sdy76 sdf76 sdf0t76 sdf0ty9 sdf0ty98 sdf0ty987 sdf0ty98 sdf6676 sdf876 sd876 sd876 sdf6 sdf6 sdf9876 sdf0t sdf06 sdf0ty9776 sdf0ty9776 sdf0ty76 sdf8876 sdf0t sd6 sdf06 s688876 sd688 sdf86