-
Notifications
You must be signed in to change notification settings - Fork 632
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Implement test for local congestion control #8920
Comments
I plan to start working on this on 1 May. |
I have started thinking about this. Reusing #8847 sounds good and all. But I am contemplating whether it's a bit of an overkill for a congestion test that specifically doesn't care about performance. Maybe a pytest on a single machine would be simpler and give us the same results? For now, I will try to come up with a sketch for what I think is a good test workload for local congestion. Then I will see how easy it is to integrate it in #8847. |
There is a way to launch that test on a single machine without any additional setup steps using nearcore/pytest/tests/loadtest/loadtest2.py Lines 391 to 402 in a5ed70b
One of the reasons why we also extended it to work with a cluster started in advance is to simplify export of Grafana metrics which is tricky to do in pytest/local run environment. For this test, Grafana will at least be useful to track the size of transaction pools, though arguably we can try to query that metric directly from the test runner. |
The PR introduces a limit to the size of the transaction pool for each shard and a logic that rejects transactions that go over this limit. The reasoning for this work is described in #3284. To start, the limit will be disabled (effectively set to infinity) and this PR shouldn't have any effect. The node operators can override it with a config option. In the future, we will come up with a safe value to set by default (probably between 10 MiB - 1 GiB). We also start with a simple option where the RPC client will not know if their transaction runs into this limit. We will need to rework this part in the future, but it will have to touch the transaction forwarding code in a non-trivial way, and I would prefer to work on this when we have a congestion test ready #8920. Lastly, this PR adds some nuance to handling reintroducing transactions back to the pool after reorg or producing a chunk (`reintroduce_transactions` method), by acknowledging that not all transactions might have been included and logging the number of dropped transactions.
Some thoughts on testing the transaction pool size limit (#8878): During the test, we should vary the pool size and observe the behavior of the system. If everything works correctly, there will be a threshold such that setting the limit higher than the threshold should not influence the throughput of the network. The threshold will be based on the chunk gas limit and will need to be high enough to saturate the chunk capacity. Rounding up, 150 MiB should be enough. In the test, we can try values [50MiB, 100MiB, 150MiB, 200 MiB, 500 MiB, Unlimited] and see how they affect the throughput. |
With the recent progress in #9118 I will soon shift my focus over here. The locust setup should be good enough now to simulate congestion. Next week I'll try to produce a mocknet-like setup with Prometheus / Grafana integration to look at different queue lengths. Then I will report my findings around how our system generally behaves under congestion. From there it should be easy to come up with useful test scenarios and define them using locust. Increased receipt sizes combined with lowered TX pool size limits will be one of the first things I want to play around with. |
I've ran a quick and dirty test with the following setup:
The test ran for 5 minutes, with latency creeping towards 10s timeout and the transaction pool growing to 30 MB. Then all the nodes crashed for an unknown reason. Will be looking into logs to understand why this happened. |
I did a further investigation - with 20 users, the network works without changes to latency, but with 40 users, the chunk production stalls and we get forks in the chain: This could be potentially explained by the fact that both the network and the loadtest run on the same machine and there is resource contention between then, though I've checked that nodes are doing fine and the CPU is only 70% utilized. UPD: The node0 has became unreachable and its logs contain the following lines:
|
With 1 node and 1 shard, I was reliably able to get to a regime that represents a congested network.
This load generated around 12 seconds of congestion in the delayed receipts queue. This in turn resulted in all locust requests timing out, which is expected. The chain is utilized most of the time: The detailed Grafana graphs for the relevant period can be found here: https://nearinc.grafana.net/goto/PRNdCRlVR?orgId=1 Next up, I want to introduce a backpressure in the delayed receipts queue and confirm that this workload generates an increasing transaction pool queue size. I also will look into adding a metric about the delayed receipts queue size mentioned in #8880 |
This PR introduces a Locust Workload for the Congestion Test: #8920. A typical run would be: ```sh CONTRACT="path/to/nearcore/runtime/near-test-contracts/res/test_contract_rs.wasm" locust -H 127.0.0.1:3030 \ CongestionUser \ --congestion-wasm=$CONTRACT \ --funding-key=$KEY \ --tags congestion ``` Then cranking up the number of users to 50-200 should be enough to cause congestion. Wishlist of things I want to improve: - Remove the need to specify `CONTRACT` variable every time as we know which contract we want to use for each workload type, we just don't know where it is stored - We can use the same approach as "runtime/runtime-params-estimator/res/" - submitting WASM contracts that this test depends on alongside the code and update them once in a while. - Make it possible to specify which exact method of Congestion workload to run as a parameter
We now have the workload that can reproduce congestion and the bursty workload described in #8920 (comment). I'm resolving this, as the functional part is there and it's now just a matter of analyzing how the system performs under this load. |
We should have a test that generates an interesting workload with non-trivial congestion metrics. This test will quickly evaluate the various designs that attempt to solve the congestion problem.
The concrete test for the local congestion control milestone would evaluate liveness when the system receives 1000 transactions per second (eventually every transaction should be processed after the load is stopped). This simulates a short bursty sustained load (e.g. for a minute) at 10x of the network capacity.
It is intended as a functional correctness test, not a performance test.
As a part of the test, we should track the following:
We should aim to reuse a framework from #8847
Some related work issues:
The text was updated successfully, but these errors were encountered: