apache / apache/lucene

Improve LruQueryCache's concurrency [LUCENE-9038]

Open
#10,081 13 comments 0 reactions 0 assignees View on GitHub
legacy-jira-priority:Major type:enhancement
Dominant language
Java
Stars
3.6k
Forks
1.4k
Avg merge
2d 11h
Merged PRs (30d)
88

Description

[LRUQueryCache](https://github.com/apache/lucene-solr/blob/master/lucene/core/src/java/org/apache/lucene/search/LRUQueryCache.java) appears to play a central role in Lucene's performance. There are many issues discussing its performance, such as #8290, #8292, #9075, #9260, and #10045. It appears that the cache's overhead can be just as much of a benefit as a liability, causing various workarounds and complexity.

When reviewing the discussions and code, the following issues are concerning:
1. The cache is guarded by a single lock for all reads and writes.
1. All computations are performed outside of the any locking to avoid penalizing other callers. This doesn't handle the cache stampedes meaning that multiple threads may cache miss, compute the value, and try to store it. That redundant work becomes expensive under load and can be mitigated with \~ per-key locks.
1. The cache queries the entry to see if it's even worth caching. At first glance one assumes that is so that inexpensive entries don't bang on the lock or thrash the LRU. However, this is also used to indicate data dependencies for uncachable items (per JIRA), which perhaps shouldn't be invoking the cache.
1. The cache lookup is skipped if the global lock is held and the value is computed, but not stored. This means a busy lock reduces performance across all usages and the cache's effectiveness degrades. This is not counted in the miss rate, giving a false impression.
1. An attempt was made to perform computations asynchronously, due to their heavy cost on tail latencies. That work was reverted due to test failures and is being worked on.
1. An [in-progress change](https://github.com/apache/lucene-solr/pull/940) tries to avoid LRU thrashing due to large, infrequently used items being cached.
1. The cache is tightly intertwined with business logic, making it hard to tease apart core algorithms and data structures from the usage scenarios.

It seems that more and more items skip being cached because of concurrency and hit rate performance, causing special case fixes based on knowledge of the external code flows. Since the developers are experts on search, not caching, it seems justified to evaluate if an off-the-shelf library would be more helpful in terms of developer time, code complexity, and performance. Solr has already introduced [Caffeine](https://github.com/ben-manes/caffeine) in [SOLR-8241](https://issues.apache.org/jira/browse/SOLR-8241) and [SOLR-13817](https://issues.apache.org/jira/browse/SOLR-13817).

The proposal is to replace the internals `LruQueryCache` so that external usages are not affected in terms of the API. However, like in `SolrCache`, a difference is that Caffeine only bounds by either the number of entries or an accumulated size (e.g. bytes), but not both constraints. This likely is an acceptable divergence in how the configuration is honored.

cc @sigram, @dsmiley

---
Migrated from [LUCENE-9038](https://issues.apache.org/jira/browse/LUCENE-9038) by Ben Manes, updated Nov 26 2019
Attachments: [cache.patch](https://apache.github.io/lucene-jira-archive/attachments/LUCENE-9038/cache.patch) (versions: 2), [CaffeineQueryCache.java](https://apache.github.io/lucene-jira-archive/attachments/LUCENE-9038/CaffeineQueryCache.java)

Contributor guide

Open the contributing guide

Research direction

Start with lucene/core/src/java/org/apache/lucene/search/LRUQueryCache.java and review the attached CaffeineQueryCache.java and cache.patch. Compare the current locking, caching constraints, and external API usage before evaluating the proposed replacement. Done means the internals have improved concurrency without changing external usage or the honored configuration beyond the stated constraint divergence.

Written by the indexing model from the issue text.

Assessment

Tech stack
java
Domain
backend, search
Issue type
Refactor
Difficulty
5/5
Estimated time
Over a week
Activity status
Quiet
Clarity
Needs clarification
Newbie friendliness
30/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.