mirror of
https://github.com/kvcache-ai/Mooncake.git
synced 2026-11-05 01:17:55 +00:00
[GH-ISSUE #467] mooncake X LMCache performance #163
Labels
No labels
ascend
auto-closed
bug
bug
CI/Build
Common
documentation
enhancement
feature request
good first issue
help wanted
high priority
MetaX
nightly-failure
pull-request
PyTorch Backend
question
RFC
Roadmap
stale
Store
Tests
Transfer Engine
No milestone
No project
No assignees
1 participant
Notifications
Due date
No due date set.
Dependencies
No dependencies set.
Reference
kvcache-ai/Mooncake#163
Loading…
Add table
Add a link
Reference in a new issue
No description provided.
Delete branch "%!s()"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Originally created by @cicirori on GitHub (Jun 10, 2025).
Original GitHub issue: https://github.com/kvcache-ai/Mooncake/issues/467
hi, this is the data I've collected on LMCache's Mooncake backends. The test is a very direct and focused benchmark aimed at validating the end-to-end performance of these backends when integrated with LMCache and vLLM:
max_new_tokensset to 1—so the end-to-end performance essentially reflects the TTFT, which is depended by the backend's store/retrieve performance and implementation efficiency.Mooncake turned out to be unexpectedly slow:
After investigation, I’ve identified a few potential causes.
I’d like to know if this is expected behavior or if I’m using it incorrectly.
@cicirori commented on GitHub (Jun 10, 2025):
I'm running a llama 3.1 8B with 1 gpu,
LMCache config:
mooncache config:
@xiaguan commented on GitHub (Jun 11, 2025):
Could you try increasing LMCACHE_CHUNK_SIZE from 16 to 256? The current value is a bit too small for our case. We're not using 4MB pages, and based on our testing, a chunk size around 15MB works much better.
You can check the metrics on the master node to confirm this. Also, please make sure Mooncake is working correctly—LMCache logs should help with that.
@cicirori commented on GitHub (Jun 11, 2025):
@xiaguan Hi, thanks for your reply.
Ah, I missed that the test with chunksize 256 was done earlier. The results are slightly better, but not significantly.
@xiaguan commented on GitHub (Jun 11, 2025):
I used https://lmcache.ai/kv_cache_calculator.html to estimate that a chunk size of 256 results in approximately 32MB, while reducing it to 128 keeps it around 15MB, which seems to be the optimal value.
Moreover, you can enable the logs for this connector to observe the actual data size being transferred and the time consumed. This will allow you to calculate the bandwidth of mooncake, which theoretically should be close to the RDMA network card's bandwidth:
github.com/LMCache/LMCache@2a521e3325/lmcache/v1/storage_backend/connector/instrumented_connector.py.BTW, the performance metrics in the report are based on the use of the etcd as the transfer engine's metdata server. However, the current release does not include the etcd plugin. You need compile it with
-DUSE_ETCD. It will be bundled in the upcoming release.@cicirori commented on GitHub (Jun 11, 2025):
@xiaguan Thanks for your quick reply again!
After switching to etcd with a chunk size of 128, there was some improvement, but not significant.
Below is the debug output from the instrument connector:
The bandwidth doesn’t look ideal. In addition to these overheads, I noticed from the timeline that there are quite a few copies between CPUs and from CPU to GPU. These overheads combined are likely non-trivial as well.
etcd and mooncake_master launch cmd:
@xiaguan commented on GitHub (Jun 11, 2025):
The latency looks incorrect. Is the lmcache on a separate machine from the master, causing latency, or are they on the same machine? If on the same machine, RPC should be very fast (tens of microseconds). The bandwidth seems abnormal for an RDMA NIC; a 100Gbps card should complete operations within 2ms. The root cause is unclear. Could you test the RDMA NIC bandwidth or use the transfer engine bench? https://github.com/kvcache-ai/Mooncake/blob/main/mooncake-transfer-engine/example/transfer_engine_bench.cpp
@cicirori commented on GitHub (Jun 11, 2025):
yeah, they are on the same machine, here is the transfer engine bench result with default config.
didn't know if it is as excepted, not reached the nic speed limit, but much more better than instrument connector's outputs.
update: after adjusted(changed block size to 32k):
@cicirori commented on GitHub (Jun 11, 2025):
added some timing code in
get_bufferwith
chunk_size=128:with
chunk_size=16:Although
chunk_size=16avoids expensive memory operations, the actual performance is worse with this setting. I think this is partly due to the reduced transmission efficiency caused by smaller chunks, and partly because it significantly increases the overhead of integration with LMCache.The fixed overhead of the query operation is also relatively high. Not sure if this can be merged with the get call into a single invocation.
The integration with LMCache also introduces some CPU-to-CPU, CPU-to-GPU transfers, as well as overhead from Python itself, which further lowers overall performance. For example, in this function apart from the C++
mooncake_get_buffercall, there are also time-consuming CPU memory allocation and copy operations afterward. These also show up in the timing results from the instrument connector, so the current output from the instrument connector seems reasonable.@xiaguan commented on GitHub (Jun 12, 2025):
I'm working on the batch interface here: https://github.com/kvcache-ai/Mooncake/pull/455. Once our implementation is ready, I’ll submit a PR to lmcache to integrate this batch API.
In my tests, the batch interface can saturate the NIC bandwidth, so performance looks promising.
When the value size exceeds 16,777,200 bytes (kMaxSliceSize), it gets split up. In the end, since tensors need to be in contiguous memory, we have to stitch slices back together. But for a 15.6MB value, that copying shouldn't be happening—I'll dig into it a bit more. Maybe try lowering the value size to 14MB and see if it helps?
Also, exportSlices just allocates memory and does memcpy, but it's taking around 4ms, which seems a bit high—I should probably look into that too.
I'll share my test model and config with you shortly, so you can reproduce the performance more easily on your side.
@xiaguan commented on GitHub (Jun 12, 2025):
lmcache config
mooncake( i used main branch code)
vllm
how i bench
The results i get
@cicirori commented on GitHub (Jun 12, 2025):
that's nice! thanks for your great work and make it open sourced.
github.com/facebook/CacheLib@9005ef4224/cachelib/allocator/memory/Slab.h (L86)Have you made any changes to cachelib? According to the open source version it should be 4MB?
BTW I'm reproducing your results and would like to know on what GPU model you did the test~
@cicirori commented on GitHub (Jun 12, 2025):
tried to reproduce with H100
without lmcache:
with lmcache x mooncake:
@xiaguan commented on GitHub (Jun 12, 2025):
Just to give you a quick update on the current status and some performance notes:
To summarize:
That’s a quick snapshot of where things are at and the current perf-related work.
You could also join our slack https://join.slack.com/t/mooncake-project/shared_invite/zt-365h0e2tz-rfXTibSuGKIzik3GUYBJbg
@xiaguan commented on GitHub (Jun 13, 2025):
I think I found the reason why Mooncake is running slower.
For GDS and Local, their
exist()orcontains()interface just does a quick in-memory lookup (like checking a hashtable or dict), so it's super fast. But Mooncake calls an RPC to the master node instead — even though that RPC is pretty fast (around 100µs), it looks like the scheduler is sensitive to that extra latency.I did a quick hack where I made Mooncake use a local set for exist(), and that seemed to help.
Much better then previos bench.
We're planning to use the master's lease mechanism to build a client-side metadata cache to help reduce the impact of this issue.
Another idea we're considering is implementing something like batch_exists in the lmcache layer to better hide the network latency.
@cicirori commented on GitHub (Jun 13, 2025):
This is one of the reasons. I happened to benchmark this interface as well and confirmed the performance is indeed around 100μs, but I haven’t done deeper investigation yet.
I've made some optimizations on my side and saw significant improvements in my environment:
memcpy. RDMA is actually faster here. This logic doesn’t seem to exist on the main branch, but the commit I'm using still has it.I haven’t looked into optimizations for
queryandexistyet, but with the above changes, the performance in my environment improved ~7x. In some H100 cases, it's already faster than recomputation. I believe with further optimizations forqueryandexist, along with zero-copy on the GPU side, the performance of Mooncake Store X LMCache will be quite impressive. Thanks for open-sourcing this project!updated result from my original test:
Of course these numbers are very workload and environment dependent, just posting here to show some of the bottlenecks I see.
@xiaguan commented on GitHub (Jun 13, 2025):
Outstanding work! It's exciting to see Mooncake, as a distributed storage solution, delivering such excellent performance.
With my 100Gbps RDMA NIC, I’ve noticed that memcpy is actually faster than RDMA. Perhaps I should make this behavior configurable. I'm just curious—why is RDMA typically faster than memcpy? I'm wondering about the underlying reason.
Welcome to contribute to both Mooncake!
@cicirori commented on GitHub (Jun 13, 2025):
My NIC is 400Gbs, and this may be related to the experimental environment, my simple understanding is that memcpy will be subject to the current system load and some other interference, go RDMA only need to give two pointers, the transfer process bypasses the linux kernel stack also do not need to involve the CPU, the speed will be more stable.
Here is a very simple and naive memcpy_test result, it should be worse if run under real load:
@github-actions[bot] commented on GitHub (Jul 8, 2026):
This issue has had no activity for 90 days and will be closed in 7 days if there is no further activity. Please comment or react if it should stay open.
@github-actions[bot] commented on GitHub (Jul 16, 2026):
Closing due to 3 months of inactivity. If this is still relevant, please comment and we can reopen.