Skip to content

Commit

Permalink
Merge pull request #1849 from locustio/make-FastHttpUser-available-di…
Browse files Browse the repository at this point in the history
…rectly-on-locust-package

FastHttpUser: Add it directly under locust package, make the documentation less scary.
  • Loading branch information
cyberw authored Aug 14, 2021
2 parents b056a39 + 1910bf1 commit 4d74ea8
Show file tree
Hide file tree
Showing 5 changed files with 22 additions and 30 deletions.
1 change: 1 addition & 0 deletions .github/workflows/tests.yml
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@ jobs:
verify_docker_build:
name: Always - Docker verify, push to tag 'master' if on master
runs-on: ubuntu-latest
if: github.event_name != 'pull_request' # PR build doesnt get proper version, so dont try to build it
steps:
- uses: actions/checkout@v2
with:
Expand Down
42 changes: 16 additions & 26 deletions docs/increase-performance.rst
Original file line number Diff line number Diff line change
@@ -1,48 +1,38 @@
.. _increase-performance:

==============================================================
Increase Locust's performance with a faster HTTP client
Increase performance with a faster HTTP client
==============================================================

Locust's default HTTP client uses `python-requests <http://www.python-requests.org/>`_.
The reason for this is that requests is a very well-maintained python package, that
provides a really nice API, that many python developers are familiar with. Therefore,
in many cases, we recommend that you use the default :py:class:`HttpUser <locust.HttpUser>`
which uses requests. However, if you're planning to run really large scale tests,
Locust comes with an alternative HTTP client,
:py:class:`FastHttpUser <locust.contrib.fasthttp.FastHttpUser>` which
uses `geventhttpclient <https://github.com/gwik/geventhttpclient/>`_ instead of requests.
This client is significantly faster, and we've seen 5x-6x performance increases for making
HTTP-requests. This does not necessarily mean that the number of users one can simulate
per CPU core will automatically increase 5x-6x, since it also depends on what else
the load testing script does. However, if your locust scripts are spending most of their
CPU time in making HTTP-requests, you are likely to see significant performance gains.

It is impossible to say what your particular hardware can handle, but in a *best case* scenario
you should be able to do close to 5000 requests per second per core, instead of around 850 for
the normal HttpUser (tested on a 2018 MacBook Pro i7 2.6GHz)
It provides a nice API that many python developers are familiar with, and is very well-maintained. But if you're planning to run tests with very high throughput and have limited hardware for running Locust, it is sometimes not efficient enough.

Because of this, Locust also comes with :py:class:`FastHttpUser <locust.contrib.fasthttp.FastHttpUser>` which
uses `geventhttpclient <https://github.com/gwik/geventhttpclient/>`_ instead.
It provides a very similar API and uses significantly less CPU time, sometimes increasing the maximum number of requests per second on a given hardware by as much as 5x-6x.

It is impossible to say what your particular hardware can handle, but in a best case scenario
a test using FastHttpUsers will be able to do close to 5000 requests per second per core, instead of around 850 for HttpUser (tested on a 2018 MacBook Pro i7 2.6GHz). In reality your results may vary, and you'll see smaller gains if your load tests also do other CPU-intensive things.

.. note::

As long as your load generator CPU is not overloaded, FastHttpUser's response times should be almost identical to those of HttpUser. It is not "faster" in that sense. And of course, it cannot speed up the system you are testing.

How to use FastHttpUser
===========================

Subclass FastHttpUser instead of HttpUser::
Just subclass FastHttpUser instead of HttpUser::

from locust import task, between
from locust.contrib.fasthttp import FastHttpUser
from locust import task, FastHttpUser
class MyUser(FastHttpUser):
wait_time = between(2, 5)
@task
def index(self):
response = self.client.get("/")


.. note::

Because FastHttpUser uses a different client implementation with a slightly different API,
it may not always work as a drop-in replacement for HttpUser.

FastHttpUser/geventhttpclient is very similar to for HttpUser/python-requests, but sometimes there are subtle differences. This is particularly true if you work with the client library's internals, e.g. when manually managing cookies.

API
===
Expand Down
4 changes: 1 addition & 3 deletions examples/fast_http_locust.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
from locust import HttpUser, TaskSet, task, between
from locust.contrib.fasthttp import FastHttpUser
from locust import FastHttpUser, task


class WebsiteUser(FastHttpUser):
Expand All @@ -9,7 +8,6 @@ class WebsiteUser(FastHttpUser):
"""

host = "http://127.0.0.1:8089"
wait_time = between(2, 5)
# some things you can configure on FastHttpUser
# connection_timeout = 60.0
# insecure = True
Expand Down
2 changes: 2 additions & 0 deletions locust/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
from .user import wait_time
from .user.task import task, tag, TaskSet
from .user.users import HttpUser, User
from .contrib.fasthttp import FastHttpUser
from .user.wait_time import between, constant, constant_pacing
from .shape import LoadTestShape

Expand All @@ -21,6 +22,7 @@
"tag",
"TaskSet",
"HttpUser",
"FastHttpUser",
"User",
"between",
"constant",
Expand Down
3 changes: 2 additions & 1 deletion locust/test/test_fasthttp.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,8 @@
from tempfile import NamedTemporaryFile

from locust.user import task, TaskSet
from locust.contrib.fasthttp import FastHttpSession, FastHttpUser
from locust.contrib.fasthttp import FastHttpSession
from locust import FastHttpUser
from locust.exception import CatchResponseError, InterruptTaskSet, ResponseError
from locust.main import is_user_class
from .testcases import WebserverTestCase, LocustTestCase
Expand Down

0 comments on commit 4d74ea8

Please sign in to comment.