Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Reduce memory consumption of
RecentBlockCache
(#2102)
# Description Our `RecentBlockCache` works like this: 1. somebody requests liquidity 2. cache checks if it's already known 3. if it's not in the cache query the blockchain 4. store in cache 5. remember requested liquidity source for updating it in the background Whenever we see a new block we fetch the current liquidity for all the liquidity sources and write them to the cache together with their block. We have a max cache duration. Whenever the cached state exceeds that duration we remove the oldest entries. This implementation uses unnecessarily much memory in 2 ways: 1. We can fetch liquidity for quotes. For those requests it's okay to return liquidity that is not 100% up-to-date. However, we still remember the requested liquidity source for future updates. This is not great because we can receive quote requests for all sorts of random tokens we'll never see again. 2. We cache state for the same liquidity source for multiple blocks. But the cache only has 2 access patterns: * "Give me the most recent available on the blockchain" * "Give me the most recent available in the cache" There is no access pattern "Give me cached liquidity specifically from an older block with number X" That means it's enough to keep the most recent data for any liquidity pool cached at any point. We can see these 2 things at play with this [log](https://production-6de61f.kb.eu-central-1.aws.cloud.es.io/app/discover#/?_g=(filters:!(),refreshInterval:(pause:!t,value:0),time:(from:'2023-11-28T16:18:27.243Z',to:'2023-11-28T17:55:08.577Z'))&_a=(columns:!(log),filters:!(),grid:(columns:('@timestamp':(width:164))),index:c0e240e0-d9b3-11ed-b0e6-e361adffce0b,interval:auto,query:(language:kuery,query:'mainnet%20and%20driver%20and%20(log:%20%22the%20cache%20now%20contains%20entries%22%20or%20log:%20%22fetched%20liquidity%20sources%22)'),sort:!(!('@timestamp',desc)))). After ~1h of operation it shows a single `RecentBlockCache` holding ~20K items. On an average auction we can fetch ~800 uni v2 sources. We currently have a configuration where we cache up to 10 blocks worth of data. Meaning we have roughly 8K cache entries for liquidity that is needed in auction and 12K entries that's only needed for quotes. Also this is only for a single univ2 like liquidity source. In total we have 4 different ones configured in our backend. # Changes We address `1` by not remembering liquidity sources for background updates for quote requests. We address `2` by throwing away all the duplicated data. ## How to test I did a manual set up where I run an autopilot locally in shadow mode (fetch auction from prod mainnet) and a driver with all liquidity sources enabled. I collected 3 graphs in total to measure the impact of this change on the memory. 1. This graph is the status quo (very noisy and not really reproducable across runs) <img width="1617" alt="0_current_no_optimizations" src="https://github.com/cowprotocol/services/assets/19190235/0997b34f-8f30-43c4-a797-5e3cf7bccbbf"> 2. This graph applies one optimization that is not part of this PR to make the memory consumption more predictable across runs. I want to merge that optimization as well but right now it's very hacky. However, I will include this optimization in all my graphs because it makes the impact of each optimization easier to spot. <img width="1420" alt="1_with_univ2_call_optimization" src="https://github.com/cowprotocol/services/assets/19190235/6f259fa4-4fcd-45dd-ba37-160962065ab3"> 3. The effects of this PR's optimization. The memory usage is more stable over all and grows less over time. <img width="1607" alt="2_cache_eviction" src="https://github.com/cowprotocol/services/assets/19190235/ec5b5712-e4e3-4c4e-8feb-dc46e2cfa3f3">
- Loading branch information