-
Notifications
You must be signed in to change notification settings - Fork 462
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
JAMES-3740 Compact primitive collections for UID <-> MSN mapping #942
Conversation
https://issues.apache.org/jira/browse/JAMES-3740 it would be good to have also a mapDB based alternative! |
This PR gives an instant boost to memory storage and as such is definitly an improvment. We would benefit from having customization of UidMsnConverter, and optional implementations of it (memory? MapDB ? Range based?). The enhancements delivered by this PR could well be backing the default memory implementation. Hence I propose to merge this. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Sorry missed that PR. Just a small typo comment :)
protocols/imap/src/main/java/org/apache/james/imap/processor/base/UidMsnConverter.java
Outdated
Show resolved
Hide resolved
This reduces HEAP memory consumption of this use case by a factor 3.
This is the nominal use case, in the absent of concurrent message operation on the mailbox. Sorting the resulting list 'in place' allows to avoid usage of tree like structures that enforces a copy and require temporary allocations of entry. This shows: - x2.5 performance enhancements - Dramatically reduces heap pressure upon UidMsnConverter::addAll
5fd53bb
to
662ed2e
Compare
Just a tiny rebase... |
This reduces HEAP memory consumption of this use case by a factor 6.
What is UID <-> MSN mapping ?
In IMAP RFC-3501 there is two ways one addresses a message:
We then need:
We do store the list of UIDs, sorted, in RAM and perform binarysearches to resolve those.
What is the impact on heap?
Each uid is wrapped in a MessageUID object. This object wrapping comes with an overhead of at least 12 bytes in addition to the 8 bytes payload (long). Quick benchmarks shows it's actually worse: 10 million uids did take up to 275 MB.
Now, from let's take a classical production deployment I get:
So for a small scale deployment, we are already "consuming" ~300 MB of memory just for the UID <-> mapping.
Scaling to 1.000 users on a single James instance we clearly see that HEAP consumption will start being a problem (~3GB) without even speaking of target of 10.000 users per James I do have in mind.
It's worth mentioning that IMAP being statefull, and UID <-> MSN mapping attached to a selected mailbox, such a mapping is long lived:
Temporary fix ?
We can get rid of the object boxing in UidMsnConverter by using primitive type collections for instance provided by fastutils project.
The same bench was down to 84MB.
Also, we could get things more compact by using an INT representation of UIDs. (Those are most of the case below 2 billions, to be above this there need to be more than 2 billion emails transiting through one's mailbox which is highly unlikely). A fallback to "long" storage can be setted up if a UID above 2 billion is observed.
This such a compact int storage we are down to 46MB.
So taking the prior mentioned numbers we could expect a 1.000 people deployment to require ~400 MB and a larger scale 10.000 people deployment on a single James to consume up to 4GB. Not that enjoyable but definitly more manageable.
Please note that primitive collections are more GC friendly as their elements are manages together, as a single object (backing array).
What other mail servers do
I found references to Dovecote, which does a similar algorithm compared to us: binary search on a list of uids. The noticeable difference is that this list of UIDs is held on disk and not in memory as we do.
References: https://doc.dovecot.org/developer_manual/design/indexes/mail_index_api/?highlight=time
Of course, such a solution would be attractive... We could imagine keeping the last 1.000 uids in memory, which would most of the time be the ones used for MSN resolution and locate the rest on-disk, use them only when needed and thus dramatically reduce heap pressure.
Making UidMsnConverter an interface with a backing factory would enable different implementation to co-exist and allow some experimentation ;-)