Skip to content

First impressions good, but fails under load #98

Description

@mark-99

So first the good: I've ported the basic functionalty of our job system from RQ to MRQ and generally it went well, at least so far. Dashboard is certainly a huge improvement. The burst mode you added also works well (note as such I'm using latest code from github, rather than the pip install version).

Some observations/suggestions:

  • I couldn't actually find any example of queueing jobs from Python (vs command line). Eventually I reverse-engineered mrq-run.py and figured out I had to do this to get jop.queue_jobs() to work:
    mrq.context.set_current_config(mrq.config.get_config())
  • Python being untyped, it would be good to document params better. E.g. in RQ enqueue() takes a callable, but MRQ job.queue_job(s) takes a string. This isn't immediately obvious.
  • Dashboard frequently reads -ve jobs/second.

However big issue is that the system starts to fail above a certain number of workers, somewhere in the region of 1000. It seems like database updates fail or time out and aren't retried. In some cases the job fails with an exception, but mostly just the status is wrong, ie it gets permanently stuck in either "queued" or "started" state in the DB. Note that workers are still running (variously in "wait" or "full" status) but the queues are not consumed, ie there's an inconsistency between the worker process and/or mongo and/or redis which never resolves (I've just been wiping mongo+redis between tests).

'Failed' is perhaps fixable with the retry operations, but the stuck jobs where presumably some other part of the socket communications failed/timed out are more of an issue.

Here's a code snippet:

    for job_id in job_ids:
        job_res = mrq.job.get_job_result(job_id)
        if job_res["status"] == "queued": num_queued += 1
        elif job_res["status"] == "started": num_started += 1
        elif job_res["status"] == "success": num_finished += 1
        else: num_failed += 1

    log("num_queued: %d, num_started: %d, num_finished:%d, num_failed: %d" % 
            (num_queued, num_started, num_finished, num_failed))

Here's the final output for 50k jobs (number of jobs is less important than number of workers):
09:19:26.906279: num_queued: 32, num_started: 8, num_finished:49957, num_failed: 3

Different runs give different numbers of stuck or failed (sometimes it will complete ok). Fewer workers (<500) and it's always ok, it goes to zero queued+started, and my script exits. Note the stats also agree on the dashboard "Statuses" tab.

For the failed jobs, here's the backtrace:

Traceback (most recent call last): 
  File "/apps/infrafs1/matkinson/venv-infra/lib/python2.7/site-packages/mrq/worker.py", line 540, in perform_job 
    job.perform() 
  File "/apps/infrafs1/matkinson/venv-infra/lib/python2.7/site-packages/mrq/job.py", line 279, in perform 
    self.save_success(result) 
  File "/apps/infrafs1/matkinson/venv-infra/lib/python2.7/site-packages/mrq/job.py", line 364, in save_success 
    self._save_status("success", updates) 
  File "/apps/infrafs1/matkinson/venv-infra/lib/python2.7/site-packages/mrq/job.py", line 437, in _save_status 
    }, {"$set": db_updates}, w=w, j=j, manipulate=False) 
  File "/apps/infrafs1/matkinson/venv-infra/lib/python2.7/site-packages/pymongo/collection.py", line 1956, in update 
    with self._socket_for_writes() as sock_info: 
  File "/apps/infrafs1/matkinson/venv-infra/lib/python2.7/contextlib.py", line 17, in __enter__ 
    return self.gen.next() 
  File "/apps/infrafs1/matkinson/venv-infra/lib/python2.7/site-packages/pymongo/mongo_client.py", line 665, in _get_socket 
    with server.get_socket(self.__all_credentials) as sock_info: 
  File "/apps/infrafs1/matkinson/venv-infra/lib/python2.7/contextlib.py", line 17, in __enter__ 
    return self.gen.next() 
  File "/apps/infrafs1/matkinson/venv-infra/lib/python2.7/site-packages/pymongo/server.py", line 102, in get_socket 
    with self.pool.get_socket(all_credentials, checkout) as sock_info: 
  File "/apps/infrafs1/matkinson/venv-infra/lib/python2.7/contextlib.py", line 17, in __enter__ 
    return self.gen.next() 
  File "/apps/infrafs1/matkinson/venv-infra/lib/python2.7/site-packages/pymongo/pool.py", line 509, in get_socket 
    sock_info = self._get_socket_no_auth() 
  File "/apps/infrafs1/matkinson/venv-infra/lib/python2.7/site-packages/pymongo/pool.py", line 543, in _get_socket_no_auth 
    sock_info, from_pool = self.connect(), False 
  File "/apps/infrafs1/matkinson/venv-infra/lib/python2.7/site-packages/pymongo/pool.py", line 475, in connect 
    DEFAULT_CODEC_OPTIONS)) 
  File "/apps/infrafs1/matkinson/venv-infra/lib/python2.7/site-packages/pymongo/network.py", line 48, in command 
    response = receive_message(sock, 1, request_id) 
  File "/apps/infrafs1/matkinson/venv-infra/lib/python2.7/site-packages/pymongo/network.py", line 60, in receive_message 
    header = _receive_data_on_socket(sock, 16) 
  File "/apps/infrafs1/matkinson/venv-infra/lib/python2.7/site-packages/pymongo/network.py", line 84, in _receive_data_on_socket 
    raise AutoReconnect("connection closed") 
AutoReconnect: connection closed 

Any ideas? Thanks.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions