前言:
现在咱们对“python假死”都比较重视,我们都想要知道一些“python假死”的相关资讯。那么小编也在网络上网罗了一些对于“python假死””的相关内容,希望看官们能喜欢,我们快快来学习一下吧!上次我们分享了我们团队Java应用Docker化部署GC变长的踩坑经历,发现还真的帮助很多同学解决了他们项目中同样的问题。这对我们来说真的是很大的一个激励,所以我们决定后面会不定期分享一些我们团队的踩坑经历,今天分享的是 Spring-RabbitMQ consumer 的两个坑,希望能对大家有所帮助。
坑 No.1: consumer 假死,无真正的消费能力背景
spring-rabbit 版本变更至 1.6.2.RELEASE
现象
consumer 数量正常,mq 控制面板的 prefetch 参数始终是1, 消息无法正常 ack, 队列处于假死状态, 系统报异常 org.springframework.amqp.rabbit.listener.exception.ListenerExecutionFailedException
异常原因
ListenerExecutionFailedException
根据官方文档说明,是 consumer 在消息消费时发生了异常, 默认情况下,该消息会被 reject, 并重新回到队列中, 但如果异常发生在到达用户代码之前的异常,此消息将会一直投递。
org.springframework.amqp.AmqpIllegalStateException
该异常抛出,RabbitMQ无法收到消息回应,将一直处于等待状态。
No default listener method specified: Either specify a non-null value ...
找不到 consumer OnMessage 的方法, 猜测是类加载错误,于是重新开始检查 consumer 类定义,最终发现 rabbit:listener 的 ID 和 真实 consumer 的 ID 冲突,导致真实的 consumer Bean 无效,找不到接受消息的方法,而 rabbitmq 在与 client 端通信过程中发生异常,会停止消费。
解决办法
删除 rabbit:listener 的 ID 属性
坑 No.2:consumer 数量异常背景
原服务有 6 个队列,每个队列起 10 个 consumer, task-executor 线程池设置为 90, 后因数据量增加,发现消费能力不足,决定增加 consumer 数量,调整 listener-container 的 concurrency 为 20,重启服务器。
现象
部分队列 consumer 数量不足,缺失项始终为 xml 中声明在后的队列
异常定位
回退 concurrency 参数为 10 异常消失,观察异常现场,发现 consumer 消失队列有先后顺序之分,且 consumer 数量存在上限值为 90,猜测是收参数限制,检查配置参数如下:
异常原因
经排查对比,发现上限值与 task-executor ThreadPoolTaskExecutor 参数 corePoolSize、maxPoolSize 极为接近,查询相关资料发现,多个 queue 的 consumer 会共用 taskExecutor 的线程池数量,如果线程池数量不足,consumer 无法创建。 后发现官方文档已有明确说明.
解决办法
增大 task-executor corePoolSize 和 maxPoolSize 的值为 200,重启服务,解决。
总结在 spring 容器管理中,ID 是一个对象的引用,必须仅且只有一个无重复的 ID, 包含 Bean 及其他自定义标签(如 rabbit:listener), 即使在不同文件也需要注意。spring-rabbit task-exeutor 默认使用 SimpleAsyncTaskExecutor 作为异步线程池,每次请求新开线程,没有最大线程数设置. 其不是真的线程池,这个类不重用线程,每次调用都会创建一个新的线程。可改用 ThreadPoolTaskExecutor 替代,但存在多个 queue 时需要 ThreadPoolTaskExecutor 线程池足够可用,尤其针对多个 listener-container 共用一个 task-executor 的情况。
艳杰。擅长 Python 与 JAVA , 现任饿了么物流团队资深 Python 工程师,负责分流核心链路, 专注于系统业务分析及稳定性建设。
标签: #python假死