-
Notifications
You must be signed in to change notification settings - Fork 3.3k
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
HBASE-23296 Add CompositeBucketCache to support tiered BC #868
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -25,6 +25,7 @@ | |
|
||
import org.apache.hadoop.conf.Configuration; | ||
import org.apache.hadoop.hbase.HConstants; | ||
import org.apache.hadoop.hbase.io.hfile.BlockCache.CacheLevel; | ||
import org.apache.hadoop.hbase.io.hfile.bucket.BucketCache; | ||
import org.apache.hadoop.hbase.io.util.MemorySizeUtil; | ||
import org.apache.hadoop.hbase.util.ReflectionUtils; | ||
|
@@ -64,6 +65,8 @@ public final class BlockCacheFactory { | |
|
||
public static final String BUCKET_CACHE_WRITER_QUEUE_KEY = "hbase.bucketcache.writer.queuelength"; | ||
|
||
public static final String BUCKET_CACHE_COMPOSITE_KEY = "hbase.bucketcache.composite.enabled"; | ||
|
||
/** | ||
* A comma-delimited array of values for use as bucket sizes. | ||
*/ | ||
|
@@ -110,29 +113,35 @@ public static BlockCache createBlockCache(Configuration conf) { | |
+ "we will remove the deprecated config.", DEPRECATED_BLOCKCACHE_BLOCKSIZE_KEY, | ||
BLOCKCACHE_BLOCKSIZE_KEY); | ||
} | ||
FirstLevelBlockCache l1Cache = createFirstLevelCache(conf); | ||
BlockCache l1Cache = createFirstLevelCache(conf); | ||
if (l1Cache == null) { | ||
return null; | ||
} | ||
boolean useExternal = conf.getBoolean(EXTERNAL_BLOCKCACHE_KEY, EXTERNAL_BLOCKCACHE_DEFAULT); | ||
if (useExternal) { | ||
BlockCache l2CacheInstance = createExternalBlockcache(conf); | ||
return l2CacheInstance == null ? | ||
l1Cache : | ||
new InclusiveCombinedBlockCache(l1Cache, l2CacheInstance); | ||
if (conf.getBoolean(EXTERNAL_BLOCKCACHE_KEY, EXTERNAL_BLOCKCACHE_DEFAULT)) { | ||
BlockCache l2Cache = createExternalBlockcache(conf); | ||
return l2Cache == null ? l1Cache : new InclusiveCombinedBlockCache( | ||
(FirstLevelBlockCache)l1Cache, l2Cache); | ||
} else { | ||
// otherwise use the bucket cache. | ||
BucketCache bucketCache = createBucketCache(conf); | ||
if (!conf.getBoolean("hbase.bucketcache.combinedcache.enabled", true)) { | ||
// Non combined mode is off from 2.0 | ||
LOG.warn( | ||
"From HBase 2.0 onwards only combined mode of LRU cache and bucket cache is available"); | ||
BucketCache l2Cache = createBucketCache(conf, CacheLevel.L2); | ||
if (conf.getBoolean(BUCKET_CACHE_COMPOSITE_KEY, false)) { | ||
return l2Cache == null ? l1Cache : new CompositeBucketCache((BucketCache)l1Cache, l2Cache); | ||
} else { | ||
if (!conf.getBoolean("hbase.bucketcache.combinedcache.enabled", true)) { | ||
// Non combined mode is off from 2.0 | ||
LOG.warn("From HBase 2.0 onwards only combined mode of LRU cache and bucket" | ||
+ " cache is available"); | ||
} | ||
return l2Cache == null ? l1Cache : new CombinedBlockCache( | ||
(FirstLevelBlockCache)l1Cache, l2Cache); | ||
} | ||
return bucketCache == null ? l1Cache : new CombinedBlockCache(l1Cache, bucketCache); | ||
} | ||
} | ||
|
||
private static FirstLevelBlockCache createFirstLevelCache(final Configuration c) { | ||
private static BlockCache createFirstLevelCache(final Configuration c) { | ||
if (c.getBoolean(BUCKET_CACHE_COMPOSITE_KEY, false)) { | ||
return createBucketCache(c, CacheLevel.L1); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. So L1 can be offheap - I mean the engine type and L2 is a seperate bucket cache and so it can be on file also? If both has to be offheap - we should recommend the memory usage part also. Say how much % will be good for L1 and how much for L2. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. We have exposed some conf key for each level's BucketCache (see CompositeBucketCache), such as the ioengine and cacheSize. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Yes. I saw it now. The bucket cache's hash map was considered to take significant space and was optimized by some JIRA by @anoopsjohn . So now with this tiered cache it may be having some more impact. But all those for later just saying. Will take a closer look at the patch. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
That's great! is there any JIRA to track with? looking forward on it. |
||
} | ||
final long cacheSize = MemorySizeUtil.getOnHeapCacheSize(c); | ||
if (cacheSize < 0) { | ||
return null; | ||
|
@@ -200,28 +209,48 @@ private static BlockCache createExternalBlockcache(Configuration c) { | |
|
||
} | ||
|
||
private static BucketCache createBucketCache(Configuration c) { | ||
// Check for L2. ioengine name must be non-null. | ||
String bucketCacheIOEngineName = c.get(BUCKET_CACHE_IOENGINE_KEY, null); | ||
private static BucketCache createBucketCache(Configuration c, CacheLevel level) { | ||
// Check for ioengine name must be non-null. | ||
String bucketCacheIOEngineName; | ||
int writerThreads; | ||
int writerQueueLen; | ||
String persistentPath; | ||
switch(level) { | ||
case L1: | ||
bucketCacheIOEngineName = c.get(CompositeBucketCache.IOENGINE_L1, null); | ||
writerThreads = c.getInt(CompositeBucketCache.WRITER_THREADS_L1, | ||
DEFAULT_BUCKET_CACHE_WRITER_THREADS); | ||
writerQueueLen = c.getInt(CompositeBucketCache.WRITER_QUEUE_LENGTH_L1, | ||
DEFAULT_BUCKET_CACHE_WRITER_QUEUE); | ||
persistentPath = c.get(CompositeBucketCache.PERSISTENT_PATH_L1); | ||
break; | ||
case L2: | ||
default: | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. We need to LOG that we are creating both L1 and L2 caches as bucket cache. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Add some log like this: |
||
bucketCacheIOEngineName = c.get(CompositeBucketCache.IOENGINE_L2, | ||
c.get(BUCKET_CACHE_IOENGINE_KEY, null)); | ||
writerThreads = c.getInt(CompositeBucketCache.WRITER_THREADS_L2, | ||
c.getInt(BUCKET_CACHE_WRITER_THREADS_KEY, DEFAULT_BUCKET_CACHE_WRITER_THREADS)); | ||
writerQueueLen = c.getInt(CompositeBucketCache.WRITER_QUEUE_LENGTH_L2, | ||
c.getInt(BUCKET_CACHE_WRITER_QUEUE_KEY, DEFAULT_BUCKET_CACHE_WRITER_QUEUE)); | ||
persistentPath = c.get(CompositeBucketCache.PERSISTENT_PATH_L2, | ||
c.get(BUCKET_CACHE_PERSISTENT_PATH_KEY)); | ||
break; | ||
} | ||
if (bucketCacheIOEngineName == null || bucketCacheIOEngineName.length() <= 0) { | ||
return null; | ||
} | ||
|
||
int blockSize = c.getInt(BLOCKCACHE_BLOCKSIZE_KEY, HConstants.DEFAULT_BLOCKSIZE); | ||
final long bucketCacheSize = MemorySizeUtil.getBucketCacheSize(c); | ||
final long bucketCacheSize = MemorySizeUtil.getBucketCacheSize(c, level); | ||
if (bucketCacheSize <= 0) { | ||
throw new IllegalStateException("bucketCacheSize <= 0; Check " + | ||
BUCKET_CACHE_SIZE_KEY + " setting and/or server java heap size"); | ||
} | ||
|
||
if (c.get("hbase.bucketcache.percentage.in.combinedcache") != null) { | ||
LOG.warn("Configuration 'hbase.bucketcache.percentage.in.combinedcache' is no longer " | ||
+ "respected. See comments in http://hbase.apache.org/book.html#_changes_of_note"); | ||
} | ||
int writerThreads = c.getInt(BUCKET_CACHE_WRITER_THREADS_KEY, | ||
DEFAULT_BUCKET_CACHE_WRITER_THREADS); | ||
int writerQueueLen = c.getInt(BUCKET_CACHE_WRITER_QUEUE_KEY, | ||
DEFAULT_BUCKET_CACHE_WRITER_QUEUE); | ||
String persistentPath = c.get(BUCKET_CACHE_PERSISTENT_PATH_KEY); | ||
String[] configuredBucketSizes = c.getStrings(BUCKET_CACHE_BUCKETS_KEY); | ||
int [] bucketSizes = null; | ||
if (configuredBucketSizes != null) { | ||
|
@@ -248,7 +277,7 @@ private static BucketCache createBucketCache(Configuration c) { | |
// Bucket cache logs its stats on creation internal to the constructor. | ||
bucketCache = new BucketCache(bucketCacheIOEngineName, | ||
bucketCacheSize, blockSize, bucketSizes, writerThreads, writerQueueLen, persistentPath, | ||
ioErrorsTolerationDuration, c); | ||
ioErrorsTolerationDuration, level, c); | ||
} catch (IOException ioex) { | ||
LOG.error("Can't instantiate bucket cache", ioex); throw new RuntimeException(ioex); | ||
} | ||
|
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.
When we have on heap cache and a BucketCache, or 2 Bucket Cache are we making it like L1 and L2 really now? That the caching of all blocks starts with L1 and L2 is victim handler for the eviction? I think no. If so better to avoid the term L1 and L2 IMHO. We have done that as part of some work and removed this. Not getting other naming also. Suggestions?
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.
Do you think it's better to naming L1 as metaCache, L2 as dataCache?