2013-08-20 155 views
1

我正在使用Django,CeleryRabbitMQ。我有一个简单的任务发送电子邮件。这项任务很有效,但速度很慢。慢芹菜任务时间

例如,我送5000电子邮件,所有5000个电子邮件直奔的RabbitMQ正常,但在消息中间件一次后,进入大约需要30分钟才能完成并清除所有任务。

没有芹菜这些相同的任务将需要几分钟时间来处理所有5000个任务。

我错过了配置的东西吗?如果有人能够发现我的速度问题,这将是非常有帮助的。

task.py

class SendMessage(Task): 
    name = "Sending SMS" 
    max_retries = 10 
    default_retry_delay = 3 

    def run(self, message_id, gateway_id=None, **kwargs): 
     logging.debug("About to send a message.") 


     try: 
      message = Message.objects.get(pk=message_id) 
     except Exception as exc: 
      raise SendMessage.retry(exc=exc) 

     if not gateway_id: 
      if hasattr(message.billee, 'sms_gateway'): 
       gateway = message.billee.sms_gateway 
      else: 
       gateway = Gateway.objects.all()[0] 
     else: 
      gateway = Gateway.objects.get(pk=gateway_id) 

     account = Account.objects.get(user=message.sender) 
     if account._balance() >= message.length: 
      response = gateway._send(message) 

      if response.status == 'Sent': 
       # Take credit from users account. 
       transaction = Transaction(
        account=account, 
        amount=- message.charge, 

       ) 
       transaction.save() 
       message.billed = True 
       message.save() 
     else: 
      pass 

settings.py

# Celery 
BROKER_URL = 'amqp://admin:[email protected]xxx.xxx.xxx:5672//' 
CELERY_SEND_TASK_ERROR_EMAILS = True 

Apache配置

<VirtualHost *:80> 
ServerName www.domain.com 

DocumentRoot /srv/project/domain 


WSGIDaemonProcess domain.com processes=2 threads=15 display-name=%{GROUP} 
WSGIProcessGroup domain.com 

WSGIScriptAlias//srv/project/domain/apache/django.wsgi 
ErrorLog /srv/project/logs/error.log 
</VirtualHost> 

CONF

# Name of nodes to start, here we have a single node 
#CELERYD_NODES="w1" 
# or we could have three nodes: 
CELERYD_NODES="w1 w2 w3" 

# Where to chdir at start. 
CELERYD_CHDIR="/srv/project/domain" 

# How to call "manage.py celeryd_multi" 
CELERYD_MULTI="$CELERYD_CHDIR/manage.py celeryd_multi" 

# How to call "manage.py celeryctl" 
CELERYCTL="$CELERYD_CHDIR/manage.py celeryctl" 

# Extra arguments to celeryd 
CELERYD_OPTS="--time-limit=900 --concurrency=8" 

# %n will be replaced with the nodename. 
CELERYD_LOG_FILE="/srv/project/logs/celery/%n.log" 
CELERYD_PID_FILE="/srv/project/celery/%n.pid" 

# Workers should run as an unprivileged user. 
CELERYD_USER="root" 
CELERYD_GROUP="root" 

# Name of the projects settings module. 
export DJANGO_SETTINGS_MODULE="domain.settings" 

# Celery Beat Settings. 

# Where to chdir at start. 
CELERYBEAT_CHDIR="/srv/project/domain" 

# Path to celerybeat 
CELERYBEAT="$CELERYBEAT_CHDIR/manage.py celerybeat" 
+0

有多少员工在完成任务? –

+0

@Mark Lavin 3名工人 – GrantU

+0

@Mark Lavin我已经添加了工人配置的东西供审查。 – GrantU

回答

6

您正在处理〜2.78个任务/秒(30分钟内完成5000个任务),我可以同意的并不是那么高。您有3个节点,每个节点的并发性为8,因此您应该能够并行处理24个任务。

检查事项:

CELERYD_PREFETCH_MULTIPLIER - 这是默认设置为4,但如果你有大量的短期任务,它可以是值得予以增加。它会减少从经纪人那里收到消息的时间所带来的影响,但代价是任务不会在工作人员中均匀分配。

数据库连接/查询 - 我计数5+ DB查询正在执行的成功案例。如果您正在使用django-celery的默认结果后端,则会有额外的查询将任务结果存储在数据库中。 django-celery在每次任务之后还会关闭并重新打开数据库连接,这会增加一些开销。如果你有5个查询,每个需要100毫秒,那么你的任务至少需要500毫秒,有无芹菜。自行运行查询是一回事,但您还需要确保任务中没有任何内容锁定表/行,以防止其他任务并行高效运行。

网关响应时间 - 您的任务似乎调用远程服务,我假设这是一个短信网关。如果该服务器响应缓慢,那么你的任务将会很慢。对于单次呼叫,当您在峰值负载下进行此操作时,响应时间可能会不同。在美国,长码SMS只能以每秒1次的速率发送,并且取决于网关正在进行速率限制的位置,因此可能会减慢您的任务速度。

+1

哇这真的很有帮助。你会介意告诉你如何从我的代码中破解〜2.78个任务/秒(30分钟内执行5000个任务),这是怎么解决的?它真的会帮助我,谢谢。 – GrantU

+0

>所以你应该能够并行处理24个任务---我应该尝试更多的工人和更多的并发任务吗?这会工作吗? – GrantU

+1

30分钟内5000个任务是您在问题主体中的主张,而不是我的主张。 –