浅谈工作中celery与Redis遇到的一些问题

本文详细探讨了在使用Celery时遇到的内存泄漏问题,分析了Django中开启DEBUG模式对celery beat内存的影响,并提出了解决方案。此外,讨论了数据库连接的单例模式及其优缺点,以及如何理解和解决全局解释器锁(GIL)带来的限制。同时,文章还介绍了Redis事务的特性,指出其并不保证一致性,并对比了RDB和AOF两种持久化策略的优劣。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

celery的内存泄漏?  

  总结:   celery执行完任务不释放内存与原worker一直没有被销毁有关,因此CELERYD_MAX_TASKS_PER_CHILD可以适当配置小点,而任务并发数与CELERYD_CONCURRENCY配置项有关,   

  每增加一个worker必然增加内存消耗,同时也影响到一个worker何时被销毁,因为celery是均匀调度任务至每个worker,因此也不宜配置过大,适当配置。  

     CELERYD_MAX_TASKS_PER_CHILD 

      CELERYD_CONCURRENCY = 20  # 并发worker数 

      CELERYD_FORCE_EXECV = True    # 非常重要,有些情况下可以防止死锁  

      CELERYD_MAX_TASKS_PER_CHILD = 100    # 每个worker最多执行万100个任务就会被销毁,可防止内存泄露  

      CELERYD_TASK_TIME_LIMIT = 60    # 单个任务的运行时间不超过此值,否则会被SIGKILL 信号杀死   

    任务发出后,经过一段时间还未收到acknowledge , 就将任务重新交给其他worker执行 

      CELERY_DISABLE_RATE_LIMITS = True 

 

 在Django中使用celery内存泄漏问题?   

    在django下使用celery作为异步任务系统,十分方便。

    同时celery也提供定时任务机制,celery beat。使用celery beat 可以为我们提供 cron,schedule 形式的定时任务。

    在django下使用celery beat的过程中,发现了 celery beat进程 占用内存非常大,而且一直不释放。

    怀疑其有内存占用不释放的可能。

    因为之前使用django的时候,就知道在django中开启DEBUG模式,会为每次的SQL查询 缓存结果。   celery beat 作为 定时任务的timer和heartbeat程序,是长期运行的,而我使用了MYSQL作为存储定时任务的backend。

    因为每次heartbeat和timer产生的sql查询在开启了DEBUG模式下的django环境中,都会缓存查询结果集。因此 celery beat占用的 内存会一直不释放。在我的线上环境中 达到10G内存占用!

       解决: 关掉django的DEBUG模式,在setting中,设置DEBUG=False 即可。   关闭DEBUG模式后的celery beat程序 的内存占用大概 一直维持在150M左右。

       

 

数据库连接是单利吗? 有必要实现多例吗?

     单例数据库连接在连接池中只有一个实例,对系统资源的开销比较少,甚至可以长时间保持连接不回收,以节省创建连接和回收连接的时间。  

   但这样的连接在多用户并发时不能提供足够的效率,形象的来讲就是大家要排队。  初级程序员的作法是每个用户需求过来都打开一次连接,用完回收掉。  

   进阶的做法是建立一个连接池,连接池里面给定一些已打开的连接,用程序控制这些连接的分配与调度  

      数据库链接用单例模式的原因:

        单例只保留一个对象,可以减少系统资源开销。

   提高创建速度,每次都获取已经存在的对象因此提高创建速度全局共享对象。

   单例在系统中只存在一个对象实例,因此任何地方使用此对象都是一个对象避免多实例创建使用时产生的逻辑错误。

   例模式是一种常用的软件设计模式,它的核心结构只包含一个被称为单例的特殊类。它的目的是保证一个类仅有一个实例,并提供一个访问它的全局访问点,该实例被所有程序模块共享。

   单例模式有3种实现方式:懒汉式、饿汉式和双重锁的形式。

 

  单例模式优点 只允许创建一个对象,因此节省内存,加快对象访问速度,因此对象需要被公用的场合适合使用,如多个模块使用同一个数据源连接对象等等  因为类控制了实例化过程,所以类可以灵活更改实例化过程   

  单例模式会阻止其他对象实例化其自己的单例对象的副本,从而确保所有对象都访问唯一实例。  单例的缺点  就是不适用于变化的对象,如果同一类型的对象总是要在不同的用例场景发生变化,

  单例就会引起数据的错误,不能保存彼此的状态。 用单例模式,就是在适用其优点的状态下使用。    

    比如:   要进一个房间(数据库),就为这个房间开了一扇门(数据库类),一般情况下是一个人开一扇门,   不管你进出(数据库操作)这个房间多少次,门就这一扇(单例),

    当然一个人也可以开很多扇门(非单例),   但你知道一个房间能开的门的数量是有限的,因此你不使用单例的话,一是性能慢一些,二是走别人的门,让别人无门可进。。。

 

 

数据类型的堆栈存储?  

   堆栈是一个后进先出的数据结构,其工作方式就像一堆汽车排队进去一个死胡同里面,最先进去的一定是最后出来。  

   队列是一种先进先出的数据类型,它的跟踪原理类似于在超市收银处排队,队列里的的第一个人首先接受服务,新的元素通过入队的方式添加到队列的末尾,而出队就是将队列的头元素删除。  

   栈:是一种容器,可存入数据元素、访问元素、删除元素  

   特点:只能从顶部插入(入栈)数据和删除(出栈)数据  

   原理:LIFO(Last In First Out)后进先出  栈可以使用顺序表实现也可使用链表实现 使用python列表实现代码:  class Stack(object):   """   栈   使用python列表实现   """

      def __init__(self):    self.items = list()

      def is_empty(self):    """判空"""    return self.items == []

      def size(self):    """获取栈元素个数"""    return len(self.items)

      def push(self, item):    """入栈"""    self.items.append(item)

      def pop(self):    """出栈"""    self.items.pop()

      def peek(self):    """获取栈顶元素"""    if self.is_empty():     raise IndexError("stack is empty")    return self.items[-1]      

  

 

flask的jwt?  

  一篇文章需求分析:(Flask + flask-jwt 实现基于Json Web Token的用户认证授权)

   jwt是flask的一个第三方库:flask-jwt-------->可以实现基于Json Web Token的用户认证授权

   使用 JWT 让你的 RESTful API 更安全  什么是 JWT ?   

    JWT 及时 JSON Web Token,它是基于 RFC 7519 所定义的一种在各个系统中传递紧凑和自包含的 JSON 数据形式。   

    紧凑(Compact) :由于传送的数据小,JWT 可以通过GET、POST 和 放在 HTTP 的 header 中,同时也是因为小也能传送的更快。   

    自包含(self-contained) : Payload 中能够包含用户的信息,避免数据库的查询。  JSON Web Token 由三部分组成使用 .

    分割开:   Header   Payload   Signature     一个 JWT 形式上类似于下面的样子:   xxxxx.yyyy.zzzz     

    Header 一般由两个部分组成:   alg   typ     alg 是是所使用的 hash 算法例如 HMAC SHA256 或 RSA,typ 是 Token 的类型自然就是 JWT。   {     "alg": "HS256",     "typ": "JWT"   }         

### 配置 Celery 使用 Redis 作为消息代理 为了使 Celery 能够利用 Redis 进行任务调度和管理,需先完成必要的软件包安装。通过命令 `pip install celery[redis]` 可以一次性安装 Celery 和其针对 Redis 的依赖项[^1]。 #### 创建项目结构并定义任务 创建名为 `celery_test` 的目录用于存放所有相关文件: ```bash mkdir -p celery_test/ cd celery_test/ ``` 接着,在此目录下编写 Python 文件 `tasks.py` 来定义具体要执行的任务逻辑。这里展示了一个简单的例子,其中包含了两个函数——一个是普通的加法操作,另一个则是模拟耗时较长的操作过程。 ```python from celery import Celery app = Celery('tasks', broker='redis://localhost:6379/0') @app.task def add(x, y): return x + y @app.task(bind=True) def long_task(self): """Background task that runs a long function with progress reports.""" verb = ['Starting up', 'Working ', 'Almost there', 'Finished'] for i in range(4): self.update_state(state='PROGRESS', meta={'current': i, 'total': 3, 'status': verb[i]}) time.sleep(5) return {'current': 3, 'total': 3, 'status': verb[-1], 'result': 42} ``` 上述代码片段展示了如何初始化一个基于 RedisCelery 应用实例,并注册了两种不同类型的任务:即时计算型 (`add`) 和长时间运行型 (`long_task`)。对于后者而言,还实现了进度更新功能以便跟踪任务状态变化情况。 #### 启动 Worker 并监控任务执行状况 确保本地已启动 Redis 服务后,可以通过如下指令开启一个新的 worker 实例来监听来自客户端发送过来的消息请求。如果希望这个 worker 特定于某个 queue,则可以加上 `-Q` 参数指定对应的队列名;如果不特别设置,默认会连接到所有的可用 queues 上去工作[^3]。 ```bash celery -A tasks worker --loglevel=info [-Q your_queue_name] ``` 此时,任何向该应用提交的新任务都将被自动分配给空闲中的 workers 去处理。而关于这些任务的状态信息(比如成功否),则可通过调用 `.AsyncResult().state` 方法获取得到。 ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值