|
| 1 | +# RND-380: MongoDB Connection Pooling |
| 2 | + |
| 3 | +## Goal |
| 4 | + |
| 5 | +Experiment with [MongoDB connection |
| 6 | +pooling](https://www.mongodb.com/docs/drivers/node/v4.15/fundamentals/connection/connection-options/ |
| 7 | +) to evaluate impact on application performance. |
| 8 | + |
| 9 | +## Methodology |
| 10 | + |
| 11 | +1. Start Meadowlark fully in Docker, using MongoDB as the backend and OpenSearch |
| 12 | + as the search provider. (See below for environment settings). |
| 13 | + |
| 14 | + ```pwsh |
| 15 | + cd Meadowlark-js |
| 16 | + ./reset-docker-compose.ps1 |
| 17 | + ``` |
| 18 | + |
| 19 | +2. Bulk upload the "partial grand bend" data set, capturing the time taken. |
| 20 | + |
| 21 | + ```pwsh |
| 22 | + cd ../eng/bulkLoad |
| 23 | + Measure-Command { .\Invoke-LoadPartialGrandBend.ps1 } |
| 24 | + ``` |
| 25 | + |
| 26 | +3. Repeat for a total of 5 measurements with the same settings |
| 27 | +4. Tune the connection pooling via the `MONGO_URI` setting in the `.env` file. |
| 28 | +5. Repeat the measurement process. |
| 29 | + |
| 30 | +An Ed-Fi ODS/API v5.3-patch4 environment was configured on the same VM in order |
| 31 | +to make a comparison between the two platforms. In this repository's |
| 32 | +`eng/ods-api` directory, the reader will find a PowerShell script `reset.ps1` |
| 33 | +that builds a fresh Docker container environment running the two Ed-Fi database |
| 34 | +images and the API image. Since this is for raw testing and head-to-head |
| 35 | +comparison, this solution does not use NGiNX or PG Bouncer. To run against the |
| 36 | +ODS/API, alter step 2 above to use `Invoke-LoadPartialGrandbend-ODSAPI.ps1` |
| 37 | + |
| 38 | +## Environment |
| 39 | + |
| 40 | +All tests run on a Windows Server 2019 virtual machine as Docker host, running |
| 41 | +the latest version of Docker Desktop, using WSL2. The VM has 12 cores assigned |
| 42 | +to it using Intel Xeon Gold 6150 @ 2.70 GHz with 24.0 GB of memory and plenty of |
| 43 | +disk space. Docker is configured to use up to 8 CPUs, 12 GB of memory, 2 GB of |
| 44 | +swap space, and limit of 64 GB on virtual disk. |
| 45 | + |
| 46 | +Baseline `.env` configuration file: |
| 47 | + |
| 48 | +```none |
| 49 | +OAUTH_SIGNING_KEY=<omitted> |
| 50 | +OWN_OAUTH_CLIENT_ID_FOR_CLIENT_AUTH=meadowlark_verify-only_key_1 |
| 51 | +OWN_OAUTH_CLIENT_SECRET_FOR_CLIENT_AUTH=meadowlark_verify-only_secret_1 |
| 52 | +OAUTH_SERVER_ENDPOINT_FOR_OWN_TOKEN_REQUEST=http://localhost:3000/local/oauth/token |
| 53 | +OAUTH_SERVER_ENDPOINT_FOR_TOKEN_VERIFICATION=http://localhost:3000/local/oauth/verify |
| 54 | +OAUTH_HARD_CODED_CREDENTIALS_ENABLED=true |
| 55 | +
|
| 56 | +OPENSEARCH_USERNAME=admin |
| 57 | +OPENSEARCH_PASSWORD=admin |
| 58 | +OPENSEARCH_ENDPOINT=http://localhost:9200 |
| 59 | +OPENSEARCH_REQUEST_TIMEOUT=10000 |
| 60 | +
|
| 61 | +AUTHORIZATION_STORE_PLUGIN=@edfi/meadowlark-mongodb-backend |
| 62 | +DOCUMENT_STORE_PLUGIN=@edfi/meadowlark-mongodb-backend |
| 63 | +QUERY_HANDLER_PLUGIN=@edfi/meadowlark-opensearch-backend |
| 64 | +LISTENER1_PLUGIN=@edfi/meadowlark-opensearch-backend |
| 65 | +
|
| 66 | +MONGODB_USER=mongo |
| 67 | +MONGODB_PASS=<omitted> |
| 68 | +MONGO_URI=mongodb://${MONGODB_USER}:${MONGODB_PASS}@mongo1:27017,mongo2:27018,mongo3:27019/?replicaSet=rs0&maxPoolSize=100 |
| 69 | +
|
| 70 | +FASTIFY_RATE_LIMIT=false |
| 71 | +FASTIFY_PORT=3000 |
| 72 | +# Next line commented out, therefore it will auto-cluster to match number of |
| 73 | +# available CPUs. |
| 74 | +# FASTIFY_NUM_THREADS=4 |
| 75 | +
|
| 76 | +MEADOWLARK_STAGE=local |
| 77 | +LOG_LEVEL=debug |
| 78 | +IS_LOCAL=true |
| 79 | +
|
| 80 | +BEGIN_ALLOWED_SCHOOL_YEAR=2022 |
| 81 | +END_ALLOWED_SCHOOL_YEAR=2034 |
| 82 | +ALLOW_TYPE_COERCION=true |
| 83 | +ALLOW__EXT_PROPERTY=true |
| 84 | +
|
| 85 | +SAVE_LOG_TO_FILE=true |
| 86 | +LOG_FILE_LOCATION=c:/temp/ |
| 87 | +``` |
| 88 | + |
| 89 | +The API bulk client loader runs on the VM host, connecting to the Docker |
| 90 | +network. It is configured to use maximum of 100 connections, 50 tasks buffered, |
| 91 | +and 500 max simultaneous requests. Retries are disabled. All of the XML files |
| 92 | +load without error at this time. |
| 93 | + |
| 94 | +## Results |
| 95 | + |
| 96 | +Times below are given in seconds. In the default settings, there was one extreme |
| 97 | +outlier that significantly impacted the average time, as seen by the high |
| 98 | +standard deviation. |
| 99 | + |
| 100 | +| Scenario | Avg | St Dev | |
| 101 | +| ------------------------ | ------ | ------ | |
| 102 | +| 8 threads, pool size 1 | 182.04 | 17.33 | |
| 103 | +| 8 threads, pool size 5 | 169.55 | 9.01 | |
| 104 | +| 8 threads, pool size 100 | 173.27 | 9.04 | |
| 105 | +| 8 threads, pool size 150 | 166.23 | 13.44 | |
| 106 | +| 1 threads, pool size 1 | 536.75 | 9.39 | |
| 107 | +| 1 threads, pool size 150 | 367.13 | 8.84 | |
| 108 | +| 4 threads, pool size 150 | 166.06 | 10.18 | |
| 109 | +| ODS/API | 89.20 | 4.32 | |
| 110 | + |
| 111 | +See [RND-380.csv](RND-38.csv) for raw data. |
| 112 | + |
| 113 | +## Analysis |
| 114 | + |
| 115 | +In the default configuration, the Meadowlark API startup process forks itself as |
| 116 | +many times as there are CPU's available. Thus, in default settings, there are |
| 117 | +eight API processes running in parallel. Although these were initiated by the |
| 118 | +same NodeJs process, each process is isolated with respect to memory. Thus, each |
| 119 | +of the eight processes has a separate pool of connections. Within each forked |
| 120 | +process there is still potential for connection pool re-use, thanks to the use |
| 121 | +of asynchronous processing. However, it is clear that the connection pool |
| 122 | +settings have little impact compared to the threading. Even a pool size of five |
| 123 | +proved adequate when running with eight CPUs. Interestingly, the pool size of |
| 124 | +150 with only four CPU's also yields consistent results compared to the tests |
| 125 | +with eight CPU's. |
| 126 | + |
| 127 | +The only time we see a discernible difference in results is when we reduce the |
| 128 | +number of threads used by the API (`FASTIFY_NUM_THREADS`). For this data set, |
| 129 | +the performance is discernibly worse with only one thread, whether using one or |
| 130 | +150 connections in the pool. However, the connection pooling in such a low CPU |
| 131 | +scenario does clearly yield an improved experience, reducing the average time to |
| 132 | +complete the test by roughly 69%. |
| 133 | + |
| 134 | +> **Note** Five executions of each test appears to be useful, but where timings |
| 135 | +> are very close to one another, the number of data points is insufficient for |
| 136 | +> giving a useful statistical significance. |
| 137 | +
|
| 138 | +The difference between Meadowlark and the ODS/API is obviously significant: the |
| 139 | +ODS/API is almost 50% faster. |
| 140 | + |
| 141 | +## Conclusions |
| 142 | + |
| 143 | +Under the environment conditions described above, this research spike does not |
| 144 | +find significant benefit to tuning the size of the MongoDB connection pool, |
| 145 | +given there are at least four process threads running. |
| 146 | + |
| 147 | +If a Meadowlark API container has only one or two virtual CPUs available, then |
| 148 | +tuning the connection pooling could theoretically be beneficial. However, out of |
| 149 | +the box, the MongoDB client has a default value of 100 connections available, |
| 150 | +which may be appropriate for many situations. |
| 151 | + |
| 152 | +Those with expertise in MongoDB might find that there are other connection pool |
| 153 | +settings, such as timeouts, that could be relevant for a given situation. |
0 commit comments