OJ2.0中可能会遇到多用户并发提交代码的情况。如果每个用户的代码都要运行一段时间,甚至超时,那么我们怎么处理呢?一般的做法有两种:
1.我们单任务串行,也就是说一次只处理一个用户提交的代码,其他用户的请求处于等待状态。不过如果每个任务都处理很久,然后同时并发的用户请求达到一定数量的时候,那么我们的服务器由于要存储大量的等待的任务而导致资源耗尽,甚至奔溃。比如,OJ1.0在运行的过程中就有很多次崩溃了,我们不得不重启服务器。其实这和所谓的DOS攻击的原理差不多,但是我们不能采取丢掉任务,或者限制请求的方法来解决。
2.我们可以采取异步来处理任务,把用户的请求用一个队列来存储,然后使用很多个work进程来同时处理,这样就显然能加快处理速度,当然,后期我们也得做压力测试,测试存储请求队列在请求数量达到多大的情况下,由于work的任务队列处理不完而导致奔溃。
下面就来介绍OJ2.0 Rabbit+Celery的框架:
安装
需要安装RabbitMQ、Celery和Django-celery
Celery和Django-celery的安装直接pip install ,也可以先下载压缩包,然后解压安装。
安装RabbitMQ:
sudo pip install -n rabbitmq
启动RabbitMQ:
sudo rabbitmq-server -detached
安装celery:
sudo pip install -n celery
也可以到 http://pypi.python.org/pypi/celery#downloads 下载celery并安装:
tar xzvf celery-2.2.7.tar.gz cd celery-2.2.7 python setup.py build sudo python setup.py install
启动celery:
python manage.py celeryd -l info
安装django-celery:
sudo pip install -n djcelery
到 http://pypi.python.org/pypi/django-celery#downloads 下载 django-celery 并安装:
tar xzvf django-celery-2.2.4.tar.gz cd django-celery-2.2.4 python setup.py build sudo python setup.py install
这个过程会安装依赖包 django-picklefield,如有需要请自行下载编译。
建立测试应用程序:
django-admin.py startproject celerytest cd celerytest django-admin.py startapp hello cd hello
修改project中的settings.py,在INSTALLED_APPS中加入以下内容:
INSTALLED_APPS = ( ... 'djcelery', # 加入celery 'hello', # 测试应用程序 }
在project的settings.py末尾添加RabbitMQ的配置:
import djcelery djcelery.setup_loader() BROKER_HOST = "localhost" BROKER_PORT = 5672 BROKER_USER = "guest" BROKER_PASSWORD = "guest" BROKER_VHOST = "/"
当然,还得配置数据库选项,因为djcelery要用到数据库的。配置好之后执行:
python manage.py syncdb
可以执行 python manage.py 看一下,会发现 djcelery 应用程序给 manage.py 添加了许多celery*开头的命令, 这些就是控制worker的命令了。
接下来我们写个task。新建 hello/tasks.py,内容如下:
from celery.decorators import task @task def add(x, y): return x + y
修饰符 @task 将add函数变成了异步任务。在webapp中调用add并不会立即执行该函数,而是将函数名、 参数等打包成消息发送到消息队列中,再由worker执行实际的代码(return x + y)。
在一个终端启动celery。
在另一个终端测试:
$ python manage.py shell >>> from hello.tasks import add >>> r = add.delay(3,5) # 执行这一行就能在worker的日志中看到运行状况 >>> r.wait()
可以看到,add函数是在worker上运行的,实现了异步的效果。当然,队列的特性决定了任务并不是实时执行的,可能有延迟, 有时甚至还会丢失,因此,队列不适合执行关键任务。而那些执行结果无关痛痒、对实时性要求不高的任务, 就可以大胆地交给RabbitMQ去处理,将WebApp解放出来吧。
下面介绍OJ2.0的配置:地址