|
| 1 | +## Online Feature Store Benchmark Suite |
| 2 | + |
| 3 | +This directory provides the tools to quickly bootstrap the process of benchmarking the Hopsworks Online Feature Store. |
| 4 | + |
| 5 | +The benchmark suite is built around [locust](https://locust.io/) which allows you to quickly start so-called user classes to perform requests against a system. |
| 6 | + |
| 7 | +In the feature store context, a user class represents a serving application performing requests against the online feature store, looking up feature vectors. |
| 8 | + |
| 9 | +Locust takes care of the hard part of collecting the results and aggregating them. |
| 10 | + |
| 11 | +### Quickstart: Single process locust |
| 12 | + |
| 13 | +By default, each user class gets spawned in its own Python thread, which means, when you run locust in a single Python process, all user classes will share the same core. This is due to the Python Global Interpreter lock. |
| 14 | + |
| 15 | +This section illustrates how to quickly run locust in a single process, see the next section on how to scale locust with a master and multiple worker processes. |
| 16 | + |
| 17 | +#### Prerequisites |
| 18 | + |
| 19 | +1. Hopsworks cluster |
| 20 | + 1. You can follow the documentation on how to setup a cluster on [managed.hopsworks.ai](https://docs.hopsworks.ai/3.1/setup_installation/aws/cluster_creation/) |
| 21 | + 2. Ideally you create an extra node in the same VPC as the Hopsworks cluster, which you can use to run the benchmark suite from. The easiest way to do this is by using a dedicated [API node](https://docs.hopsworks.ai/3.1/setup_installation/common/rondb/#api-nodes). |
| 22 | + 3. Once the cluster is created you need the following information: |
| 23 | + - Hopsworks domain name: **[UUID].cloud.hopsworks.ai** which you can find in the *Details* tab of your managed.hopsworks.ai control plane |
| 24 | + - A project and its name on the hopsworks cluster. For that log into your cluster and create a project. |
| 25 | + - An API key for authentication. Head to your project and [create an API key for your account](https://docs.hopsworks.ai/3.1/user_guides/projects/api_key/create_api_key/). |
| 26 | +2. Python environment |
| 27 | + In order to run the benchmark suite, you need a Python environment. |
| 28 | + For that we will SSH into the created API node. Make sure that [SSH is enabled](https://docs.hopsworks.ai/3.1/setup_installation/common/services/) on your cluster. |
| 29 | + |
| 30 | + 1. On AWS all nodes have public IPs, so you can head to your cloud console to find the IP of the API node and SSH directly: |
| 31 | + `ssh ubuntu@[ip-of-api-node] -i your-ssh-key.pem` |
| 32 | + On Azure, you will have to proxy through the Hopsworks head node, you can either use the public IP or the Hopsworks domain name as noted above. |
| 33 | + On GCP, we don't attach SSH keys, but you can use the GCP CLI to create an ssh session. |
| 34 | + |
| 35 | + 2. API nodes come with Anaconda pre-installed, which we can use to create a python environment and install our dependencies: |
| 36 | + |
| 37 | + ```bash |
| 38 | + conda init bash |
| 39 | + ``` |
| 40 | + |
| 41 | + After this you need to create a new SSH session. |
| 42 | + |
| 43 | + ```bash |
| 44 | + conda create -n locust-benchmark python=3.10 |
| 45 | + conda activate locust-benchmark |
| 46 | + ``` |
| 47 | + |
| 48 | + Clone the feature-store-api repository to retrieve the benchmark suite and install the requirements. |
| 49 | + Make sure to checkout the release branch matching the Hopsworks version of your cluster. |
| 50 | + |
| 51 | + ```bash |
| 52 | + git clone https://github.com/logicalclocks/feature-store-api.git |
| 53 | + cd feature-store-api |
| 54 | + git checkout master |
| 55 | + cd locust_benchmark |
| 56 | + pip install -r requirements.txt |
| 57 | + ``` |
| 58 | + |
| 59 | +#### Creating feature group for lookups |
| 60 | + |
| 61 | +1. Save the previously created API key in a file named `.api_key` |
| 62 | + |
| 63 | +```bash |
| 64 | +echo "[YOUR KEY]" > .api_key |
| 65 | +``` |
| 66 | + |
| 67 | +2. Now we need to configure the test, for that modify the `hopsworks_config.json` template: |
| 68 | + |
| 69 | +```json |
| 70 | +{ |
| 71 | + "host": "[UUID].cloud.hopsworks.ai", |
| 72 | + "port": 443, |
| 73 | + "project": "test", |
| 74 | + "external": false, |
| 75 | + "rows": 100000, |
| 76 | + "schema_repetitions": 1, |
| 77 | + "recreate_feature_group": true, |
| 78 | + "batch_size": 100 |
| 79 | +} |
| 80 | +``` |
| 81 | + |
| 82 | +- `host`: Domain name of your Hopsworks cluster. |
| 83 | +- `port`: optional, for managed.hopsworks.ai it should be `443`. |
| 84 | +- `project`: the project to run the benchmark in. |
| 85 | +- `external`: if you are not running the benchmark suite from the same VPC as Hopsworks, set this to `true`. |
| 86 | +- `rows`: Number of rows/unique primary key values in the feature group used for lookup benchmarking. |
| 87 | +- `schema_repetitions`: This controls the number of features for the lookup. One schema repetition will result in 10 features plus primary key. Five repetitions will result in 50 features plus primary key. |
| 88 | +- `recreate_feature_group`: This controls if the previous feature group should be dropped and recreated. Set this to true when rerunning the benchmark with different size of rows or schema repetitions. |
| 89 | +- `batch_size`: This is relevant for the actual benchmark and controls how many feature vectors are looked up in the batch benchmark. |
| 90 | + |
| 91 | +3. Create the feature group |
| 92 | + |
| 93 | +```bash |
| 94 | +python create_feature_group.py |
| 95 | +``` |
| 96 | + |
| 97 | +Note, the `recreate_feature_group` only matters if you rerun the `create_feature_group.py` script. |
| 98 | + |
| 99 | +#### Run one process locust benchmark |
| 100 | + |
| 101 | +You are now ready to run the load test: |
| 102 | +```bash |
| 103 | +locust -f locustfile.py --headless -u 4 -r 1 -t 30 -s 1 --html=result.html |
| 104 | +``` |
| 105 | + |
| 106 | +Options: |
| 107 | +- `u`: number of users sharing the python process |
| 108 | +- `r`: spawn rate of the users in seconds, it will launch one user every `r` seconds until there are `u` users |
| 109 | +- `t`: total time to run the test for |
| 110 | +- `s`: shutdown timeout, no need to be changed |
| 111 | +- `html`: path for the output file |
| 112 | + |
| 113 | +You can also run only single feature vector or batch lookups by running only the respective user class: |
| 114 | + |
| 115 | +```bash |
| 116 | +locust -f locustfile.py FeatureVectorLookup --headless -u 4 -r 1 -t 30 -s 1 --html=result.html |
| 117 | +
|
| 118 | +locust -f locustfile.py FeatureVectorBatchLookup --headless -u 4 -r 1 -t 30 -s 1 --html=result.html |
| 119 | +``` |
| 120 | + |
| 121 | +### Distributed Locust Benchmark using Docker Compose |
| 122 | + |
| 123 | +As you will see already with 4 users, the single core tends to be saturated and locust will print a warning. |
| 124 | + |
| 125 | + |
| 126 | + |
| 127 | +``` |
| 128 | +[2023-03-09 12:02:11,304] ip-10-0-0-187/WARNING/root: CPU usage above 90%! This may constrain your throughput and may even give inconsistent response time measurements! See https://docs.locust.io/en/stable/running-distributed.html for how to distribute the load over multiple CPU cores or machines |
| 129 | +``` |
| 130 | + |
| 131 | +First we need to install docker, for which we will use [the provided convenience script](https://docs.docker.com/engine/install/ubuntu/#install-using-the-convenience-script), however, you can use any other method too: |
| 132 | +```bash |
| 133 | +curl -fsSL https://get.docker.com -o get-docker.sh |
| 134 | +sudo sh get-docker.sh |
| 135 | +``` |
| 136 | + |
| 137 | +#### Load the docker image |
| 138 | + |
| 139 | +```bash |
| 140 | +wget https://repo.hops.works/dev/moritz/locust_benchmark/locust-2.15.1-hsfs-3.3.0.dev1-amd64.tgz |
| 141 | +sudo docker load < locust-2.15.0-hsfs-3.2.0.dev1-amd64.tgz |
| 142 | +``` |
| 143 | + |
| 144 | +#### Create feature group and configure test |
| 145 | + |
| 146 | +See the above section to setup the `hopsworks_config.json` and create the feature group to perform lookups against. |
| 147 | + |
| 148 | +#### Run multiple locust processes using docker compose |
| 149 | + |
| 150 | +Using docker compose we can now start multiple containers, one dedicated master process, which is responsible for collecting metrics and orchestrating the benchmark, and a variable number of worker processes. |
| 151 | + |
| 152 | +```bash |
| 153 | +sudo docker compose up |
| 154 | +``` |
| 155 | + |
| 156 | +Similarly to the configuration of a single locust process, you have the possibility to configure the test using docker compose in the `docker-compose.yml` file. |
| 157 | + |
| 158 | +Locust command: modify the locust command in the same way as the parameters are described above. |
| 159 | + |
| 160 | +```yml |
| 161 | + command: -f /home/locust/locustfile.py --master --headless --expect-workers 4 -u 16 -r 1 -t 30 -s 1 --html=/home/locust/result.html |
| 162 | +``` |
| 163 | + |
| 164 | +- `--expect-workers`: this is the only option that's new with this setup and let's you control for how many worker containers locust will wait to be up and running before starting the load test |
| 165 | +- `u`: the number of users, is the total number of users which will be distributed evenly among the worker processes. So with 4 workers and 16 users, each worker will run 4 users. |
| 166 | + |
| 167 | +By default, docker compose will launch 4 worker instances, however, you can scale number of workers with |
| 168 | + |
| 169 | +```bash |
| 170 | +sudo docker compose up --scale worker=6 |
| 171 | +``` |
| 172 | + |
| 173 | +However, note that the number of workes shouldn't be lower than the `expect-workers` parameter. |
| 174 | +As a rule of thumb, you should be running one worker per core of your host. |
| 175 | +
|
| 176 | +#### Collect the results |
| 177 | +
|
| 178 | +By default, the directory with the test configuration will be mounted in the containers, and locust will create the `result.html` in the mounted directory, so you will be able to access it after the containers are shut down and the test concluded. |
0 commit comments