Skip to content

HBASE-27710 ByteBuff ref counting is too expensive for on-heap buffers - #5104

Merged
bbeaudreault merged 4 commits into
apache:masterfrom
HubSpot:HBASE-27710
Mar 17, 2023
Merged

HBASE-27710 ByteBuff ref counting is too expensive for on-heap buffers#5104
bbeaudreault merged 4 commits into
apache:masterfrom
HubSpot:HBASE-27710

Conversation

@bbeaudreault

Copy link
Copy Markdown
Contributor

This felt like the cleanest way to solve this case, but open to other opinions. Whether we need to checkRefCount is directly tied to whether we use NONE recycler.

A couple other options I considered:

  • Create a new inheritance hierarchy, i.e. OnHeapSingleByteBuff, etc. This felt like it'd only complicate an already complex system.
  • Update the SingleByteBuff and MultiByteBuff constructors to take a new boolean onHeap or boolean shouldCheckRefCount. This felt more error prone because it's too easy for someone to forget to pass the correct boolean value for the corresponding recycler.

I added a basic test to validate that we only call checkRefCount for non-NONE recyclers. Beyond that, I think our existing ample coverage should suffice? Let me know if you'd like to see a particular test.

Comment threadhbase-server/pom.xml Outdated
@Apache-HBase

This comment was marked as outdated.

@Apache-HBase

This comment was marked as outdated.

@Apache-HBase

This comment was marked as outdated.

@Apache-HBase

Copy link
Copy Markdown

🎊 +1 overall

VoteSubsystemRuntimeComment
+0 🆗reexec0m 24sDocker mode activated.
_ Prechecks _
+1 💚dupname0m 0sNo case conflicting files found.
+1 💚hbaseanti0m 0sPatch does not have any anti-patterns.
+1 💚@author0m 0sThe patch does not contain any @author tags.
_ master Compile Tests _
+0 🆗mvndep0m 13sMaven dependency ordering for branch
+1 💚mvninstall3m 53smaster passed
+1 💚compile3m 6smaster passed
+1 💚checkstyle0m 48smaster passed
+1 💚spotless0m 45sbranch has no errors when running spotless:check.
+1 💚spotbugs2m 2smaster passed
_ Patch Compile Tests _
+0 🆗mvndep0m 10sMaven dependency ordering for patch
+1 💚mvninstall3m 36sthe patch passed
+1 💚compile3m 8sthe patch passed
+1 💚javac3m 8sthe patch passed
+1 💚checkstyle0m 46sthe patch passed
+1 💚whitespace0m 0sThe patch has no whitespace issues.
+1 💚xml0m 1sThe patch has no ill-formed XML file.
+1 💚hadoopcheck14m 2sPatch does not cause any errors with Hadoop 3.2.4 3.3.4.
+1 💚spotless0m 42spatch has no errors when running spotless:check.
+1 💚spotbugs2m 13sthe patch passed
_ Other Tests _
+1 💚asflicense0m 16sThe patch does not generate ASF License warnings.
44m 34s
SubsystemReport/Notes
DockerClientAPI=1.42 ServerAPI=1.42 base: https://ci-hbase.apache.org/job/HBase-PreCommit-GitHub-PR/job/PR-5104/2/artifact/yetus-general-check/output/Dockerfile
GITHUB PR#5104
Optional Testsdupname asflicense javac spotbugs hadoopcheck hbaseanti spotless checkstyle compile xml
unameLinux ea0ff56bbf26 5.4.0-1097-aws #105~18.04.1-Ubuntu SMP Mon Feb 13 17:50:57 UTC 2023 x86_64 x86_64 x86_64 GNU/Linux
Build toolmaven
Personalitydev-support/hbase-personality.sh
git revisionmaster / c2b64e7
Default JavaEclipse Adoptium-11.0.17+8
Max. process+thread count84 (vs. ulimit of 30000)
modulesC: hbase-common hbase-server U: .
Console outputhttps://ci-hbase.apache.org/job/HBase-PreCommit-GitHub-PR/job/PR-5104/2/console
versionsgit=2.34.1 maven=3.8.6 spotbugs=4.7.3
Powered byApache Yetus 0.12.0 https://yetus.apache.org

This message was automatically generated.

@Apache-HBase

Copy link
Copy Markdown

🎊 +1 overall

VoteSubsystemRuntimeComment
+0 🆗reexec0m 25sDocker mode activated.
-0 ⚠️yetus0m 3sUnprocessed flag(s): --brief-report-file --spotbugs-strict-precheck --whitespace-eol-ignore-list --whitespace-tabs-ignore-list --quick-hadoopcheck
_ Prechecks _
_ master Compile Tests _
+0 🆗mvndep0m 10sMaven dependency ordering for branch
+1 💚mvninstall3m 22smaster passed
+1 💚compile1m 24smaster passed
+1 💚shadedjars5m 8sbranch has no errors when building our shaded downstream artifacts.
+1 💚javadoc0m 40smaster passed
_ Patch Compile Tests _
+0 🆗mvndep0m 12sMaven dependency ordering for patch
+1 💚mvninstall3m 52sthe patch passed
+1 💚compile1m 4sthe patch passed
+1 💚javac1m 4sthe patch passed
+1 💚shadedjars5m 6spatch has no errors when building our shaded downstream artifacts.
+1 💚javadoc0m 37sthe patch passed
_ Other Tests _
+1 💚unit2m 28shbase-common in the patch passed.
+1 💚unit206m 12shbase-server in the patch passed.
234m 54s
SubsystemReport/Notes
DockerClientAPI=1.42 ServerAPI=1.42 base: https://ci-hbase.apache.org/job/HBase-PreCommit-GitHub-PR/job/PR-5104/2/artifact/yetus-jdk11-hadoop3-check/output/Dockerfile
GITHUB PR#5104
Optional Testsjavac javadoc unit shadedjars compile
unameLinux 178808e9bed2 5.4.0-1097-aws #105~18.04.1-Ubuntu SMP Mon Feb 13 17:50:57 UTC 2023 x86_64 x86_64 x86_64 GNU/Linux
Build toolmaven
Personalitydev-support/hbase-personality.sh
git revisionmaster / c2b64e7
Default JavaEclipse Adoptium-11.0.17+8
Test Resultshttps://ci-hbase.apache.org/job/HBase-PreCommit-GitHub-PR/job/PR-5104/2/testReport/
Max. process+thread count2408 (vs. ulimit of 30000)
modulesC: hbase-common hbase-server U: .
Console outputhttps://ci-hbase.apache.org/job/HBase-PreCommit-GitHub-PR/job/PR-5104/2/console
versionsgit=2.34.1 maven=3.8.6
Powered byApache Yetus 0.12.0 https://yetus.apache.org

This message was automatically generated.

@Apache-HBase

Copy link
Copy Markdown

🎊 +1 overall

VoteSubsystemRuntimeComment
+0 🆗reexec1m 2sDocker mode activated.
-0 ⚠️yetus0m 3sUnprocessed flag(s): --brief-report-file --spotbugs-strict-precheck --whitespace-eol-ignore-list --whitespace-tabs-ignore-list --quick-hadoopcheck
_ Prechecks _
_ master Compile Tests _
+0 🆗mvndep0m 11sMaven dependency ordering for branch
+1 💚mvninstall2m 48smaster passed
+1 💚compile0m 58smaster passed
+1 💚shadedjars4m 17sbranch has no errors when building our shaded downstream artifacts.
+1 💚javadoc0m 38smaster passed
_ Patch Compile Tests _
+0 🆗mvndep0m 13sMaven dependency ordering for patch
+1 💚mvninstall2m 50sthe patch passed
+1 💚compile0m 58sthe patch passed
+1 💚javac0m 58sthe patch passed
+1 💚shadedjars4m 17spatch has no errors when building our shaded downstream artifacts.
+1 💚javadoc0m 38sthe patch passed
_ Other Tests _
+1 💚unit1m 53shbase-common in the patch passed.
+1 💚unit224m 18shbase-server in the patch passed.
249m 46s
SubsystemReport/Notes
DockerClientAPI=1.42 ServerAPI=1.42 base: https://ci-hbase.apache.org/job/HBase-PreCommit-GitHub-PR/job/PR-5104/2/artifact/yetus-jdk8-hadoop3-check/output/Dockerfile
GITHUB PR#5104
Optional Testsjavac javadoc unit shadedjars compile
unameLinux 1c8c92624138 5.4.0-137-generic #154-Ubuntu SMP Thu Jan 5 17:03:22 UTC 2023 x86_64 x86_64 x86_64 GNU/Linux
Build toolmaven
Personalitydev-support/hbase-personality.sh
git revisionmaster / c2b64e7
Default JavaTemurin-1.8.0_352-b08
Test Resultshttps://ci-hbase.apache.org/job/HBase-PreCommit-GitHub-PR/job/PR-5104/2/testReport/
Max. process+thread count2405 (vs. ulimit of 30000)
modulesC: hbase-common hbase-server U: .
Console outputhttps://ci-hbase.apache.org/job/HBase-PreCommit-GitHub-PR/job/PR-5104/2/console
versionsgit=2.34.1 maven=3.8.6
Powered byApache Yetus 0.12.0 https://yetus.apache.org

This message was automatically generated.

@bbeaudreault

Copy link
Copy Markdown
ContributorAuthor

@Apache9 thank you very much for the review. I had an idea this morning, and wonder if you have any opinion.

Currently we do this:

protectedvoidcheckRefCount() {
ObjectUtil.checkPositive(refCnt(), REFERENCE_COUNT_NAME);
}

Calling refCnt() goes down the expensive path of getting the real refCnt numeric value.

I think what we really care about is "has this buffer been recycled". In which case, what if we added a volatile boolean to our RefCnt class which gets set to true when the Recycler is called? We don't care about synchronization since it always goes from false to true. The above method could become:

//// in RefCnt.java//privatevolatilebooleanrecycled;
publicbooleanisRecycled() {
returnrecycled;
}
@Overrideprotectedfinalvoiddeallocate() {
this.recycler.free();
this.recycled = true; // of noteif (leak != null) {
this.leak.close(this);
}
}
//// In ByteBuff.java//protectedvoidcheckRefCount() {
Preconditions.checkState(!refCnt.isRecycled(), "ByteBuff has been recycled");
}

Of course we'd also rename the method. I plugged this into our test case and it performs similarly to this PR. The benefit of this approach is it might also speed up off-heap usages while still providing protection.

@Apache9

Copy link
Copy Markdown
Contributor

What you proposed is the trick in netty's CompositeByteBuf, where they introduce a freed flag to indicate whether the ByteBuf is still valid.

And for AbstractReferenceCountedByteBuf, the code is like this

 @Override
boolean isAccessible() {
// Try to do non-volatile read for performance as the ensureAccessible() is racy anyway and only provide
// a best-effort guard.
return updater.isLiveNonVolatile(this);
}

But seems we do not have access to the updater field so I think we could go with your current approach. The down side is we will add one more boolean for each ByteBuff but should be OK?

@bbeaudreault

bbeaudreault commented Mar 16, 2023

Copy link
Copy Markdown
ContributorAuthor

I downloaded jol-core and ran ClassLayout on RefCnt... On my platform, 24 bytes without the boolean, 32 bytes with. Not insubstantial. Despite a boolean being just 1 byte, we lose 3 bytes on internal alignment and then another 4 bytes on external/class alignment.

So it's effectively like adding a long... I guess most ByteBufferAllocators are configured in the 10s of thousands, so not a huge issue there. RefCnt is also used in BucketCache where imagine this will only matter for very large bucket cache sizes? We give 75gb to bucket cache in some cases, which equals 2-5M blocks. That'd be 40mb of space for us, which might be worth the performance tradeoff. If someone uses TB of file cache (i.e. when using object store like s3 for main storage), then it might be a lot more.

This solution is equivalent in performance to my original memory-free solution for on-heap, which is where we noticed the regression. The potential benefit is for off-heap, which I don't have performance numbers on.

For my company's case, I'd be fine to add the Boolean. For the more general case, it might make sense to only add the boolean if we can back it up with benchmarks. In that case, it might make sense to do that in a separate jira so we can solve the specific regression here first.

Let me know if that changes your opinion at all before I merge this as-is.

@Apache9

Copy link
Copy Markdown
Contributor

Just commit it as is for now, can open another issue for improvement performance for off heap ByteBuff.

@bbeaudreault

Copy link
Copy Markdown
ContributorAuthor

Agreed, thanks for discussing and review.

I had another idea that we could null out the recycler after calling it, so isAccessible would be a null check on that existing reference, rather than a new boolean field check. This would not take any additional memory. But can investigate these options in another issue.

This reverts commit 9a727d1.
@bbeaudreault
bbeaudreault merged commit 1673762 into apache:masterMar 17, 2023
@bbeaudreault
bbeaudreault deleted the HBASE-27710 branch March 17, 2023 12:05
@Apache-HBase

Copy link
Copy Markdown

💔 -1 overall

VoteSubsystemRuntimeComment
+0 🆗reexec0m 0sDocker mode activated.
-1 ❌patch0m 3s#5104 does not apply to master. Rebase required? Wrong Branch? See https://yetus.apache.org/documentation/in-progress/precommit-patchnames for help.
SubsystemReport/Notes
GITHUB PR#5104
Console outputhttps://ci-hbase.apache.org/job/HBase-PreCommit-GitHub-PR/job/PR-5104/3/console
versionsgit=2.17.1
Powered byApache Yetus 0.12.0 https://yetus.apache.org

This message was automatically generated.

@Apache-HBase

Copy link
Copy Markdown

💔 -1 overall

VoteSubsystemRuntimeComment
+0 🆗reexec0m 0sDocker mode activated.
-1 ❌patch0m 2s#5104 does not apply to master. Rebase required? Wrong Branch? See https://yetus.apache.org/documentation/in-progress/precommit-patchnames for help.
SubsystemReport/Notes
GITHUB PR#5104
Console outputhttps://ci-hbase.apache.org/job/HBase-PreCommit-GitHub-PR/job/PR-5104/3/console
versionsgit=2.25.1
Powered byApache Yetus 0.12.0 https://yetus.apache.org

This message was automatically generated.

@Apache-HBase

Copy link
Copy Markdown

💔 -1 overall

VoteSubsystemRuntimeComment
+0 🆗reexec0m 0sDocker mode activated.
-1 ❌patch0m 3s#5104 does not apply to master. Rebase required? Wrong Branch? See https://yetus.apache.org/documentation/in-progress/precommit-patchnames for help.
SubsystemReport/Notes
GITHUB PR#5104
Console outputhttps://ci-hbase.apache.org/job/HBase-PreCommit-GitHub-PR/job/PR-5104/3/console
versionsgit=2.25.1
Powered byApache Yetus 0.12.0 https://yetus.apache.org

This message was automatically generated.

bbeaudreault added a commit to HubSpot/hbase that referenced this pull request Mar 17, 2023
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants

@bbeaudreault@Apache-HBase@Apache9