Skip to content
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

Support runtime chunk deduplication #1507

Open
wants to merge 5 commits into
base: master
Choose a base branch
from

Conversation

jiangliu
Copy link
Collaborator

@jiangliu jiangliu commented Dec 7, 2023

Details

This PR enhances nydusd to support runtime chunk deduplication. It works in this way:

  1. Use a sqlite database to record information about decompressed/plaintext chunks available on local node.
  2. When a chunk is not ready in the uncompressed data blob file, query the sqlite database whether a chunk with the same chunk digest is available. If a chunk with the same chunk digest exists, copy the decompressed from the source data blob file to the target data blob by using copy_file_range().
  3. Otherwise download the compressed chunk from remote, uncompress it and write to the target data blob, and add a record for the chunk to the database.

So there are two types of chunk deduplication:

  1. saving network bandwidth when the chunk is available on local node, because we don't need to download compressed chunk data from remote.
  2. saving local disk space if the underlying filesystem supports reference. If the filesystem storing data blob files supports reference, copy_file_range() will optimize to use reference instead of data copy, thus reduce local storage consuption.

Types of changes

What types of changes does your PullRequest introduce? Put an x in all the boxes that apply:

  • Bug fix (non-breaking change which fixes an issue)
  • New feature (non-breaking change which adds functionality)
  • Breaking change (fix or feature that would cause existing functionality to change)
  • Documentation Update (if none of the other choices apply)

Checklist

Go over all the following points, and put an x in all the boxes that apply.

  • I have updated the documentation accordingly.
  • I have added tests to cover my changes.

@jiangliu jiangliu requested a review from a team as a code owner December 7, 2023 02:10
@jiangliu jiangliu requested review from liubogithub, luodw and changweige and removed request for a team December 7, 2023 02:10
@jiangliu jiangliu force-pushed the runtime-chunk-dedup branch 4 times, most recently from 7cc1aa1 to ac55d88 Compare December 7, 2023 05:13
Copy link

codecov bot commented Dec 7, 2023

Codecov Report

Merging #1507 (7d287c9) into master (06755fe) will increase coverage by 0.02%.
The diff coverage is 66.51%.

Additional details and impacted files

Impacted file tree graph

@@            Coverage Diff             @@
##           master    #1507      +/-   ##
==========================================
+ Coverage   62.72%   62.74%   +0.02%     
==========================================
  Files         129      129              
  Lines       44153    44360     +207     
  Branches    44153    44360     +207     
==========================================
+ Hits        27695    27834     +139     
- Misses      15087    15144      +57     
- Partials     1371     1382      +11     
Files Coverage Δ
storage/src/cache/dedup/db.rs 79.09% <100.00%> (+0.08%) ⬆️
storage/src/cache/mod.rs 57.84% <ø> (ø)
utils/src/digest.rs 91.53% <0.00%> (-0.53%) ⬇️
storage/src/cache/filecache/mod.rs 67.58% <66.66%> (+0.08%) ⬆️
storage/src/cache/fscache/mod.rs 75.92% <63.63%> (-0.47%) ⬇️
storage/src/utils.rs 93.59% <78.94%> (-2.30%) ⬇️
storage/src/cache/cachedfile.rs 33.14% <0.00%> (-0.44%) ⬇️
src/bin/nydusd/main.rs 0.18% <0.00%> (-0.01%) ⬇️
storage/src/cache/dedup/mod.rs 72.72% <82.75%> (+72.72%) ⬆️

... and 1 file with indirect coverage changes

@jiangliu jiangliu force-pushed the runtime-chunk-dedup branch 4 times, most recently from bc4403c to 946d8a0 Compare December 7, 2023 06:50
@jiangliu jiangliu force-pushed the runtime-chunk-dedup branch 2 times, most recently from 13de7e8 to 40415e5 Compare December 8, 2023 04:17
@jiangliu jiangliu force-pushed the runtime-chunk-dedup branch 3 times, most recently from 5403291 to 1c695cf Compare December 11, 2023 10:51
Copy link
Contributor

@ccx1024cc ccx1024cc left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

NICE. LGTM.
copy_file_range is triggered in tests. It's effective.

Add helper copy_file_range() which:
- avoid copy data into userspace
- may support reflink on xfs etc

Signed-off-by: Jiang Liu <[email protected]>
Implement CasManager to support chunk dedup at runtime.
The manager provides to major interfaces:
- add chunk data to the CAS database
- check whether a chunk exists in CAS database and copy it to blob file
  by copy_file_range() if the chunk exists.

Signed-off-by: Jiang Liu <[email protected]>
Enable chunk deduplication for file cache. It works in this way:
- When a chunk is not in blob cache file yet, inquery CAS database
  whether other blob data files have the required chunk. If there's
  duplicated data chunk in other data files, copy the chunk data
  into current blob cache file by using copy_file_range().
- After downloading a data chunk from remote, save file/offset/chunk-id
  into CAS database, so it can be reused later.

Signed-off-by: Jiang Liu <[email protected]>
Add smoking test case for chunk dedup.

Signed-off-by: Jiang Liu <[email protected]>
Add documentation for cas.

Signed-off-by: Jiang Liu <[email protected]>
docs/data-deduplication.md Show resolved Hide resolved

// Verify lower layer mounted by nydusd
ctx.Env.BootstrapPath = lowerBootstrap
tool.Verify(t, ctx, lowerLayer.FileTree)
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We may need a way to check if the CAS works.

@@ -240,9 +240,16 @@ impl FileCacheEntry {
};
let blob_compressed_size = Self::get_blob_size(&reader, &blob_info)?;

// Turn off chunk deduplication in case of tarfs.
let cas_mgr = if is_tarfs {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe give a warnning message about conflict feature here.

@@ -208,11 +209,18 @@ impl FileCacheEntry {
} else {
reader.clone()
};
// Turn off chunk deduplication in case of cache data encryption is enabled or is tarfs.
let cas_mgr = if mgr.cache_encrypted || mgr.cache_raw_data || is_tarfs {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe give a warn message about conflict feature here.

If a record with the same chunk digest already exists, it will be reused.
We call such a system as CAS (Content Addressable Storage).

## Chunk Deduplication by Using CAS as L2 Cache
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This still seems to be an experimental feature, do we still need to consider the cas.db record recycling?

@jonoirwinrsa
Copy link

Hi all, I tried out this feature and it seems to work as expected. Is there something preventing it from being merged?

@imeoer
Copy link
Collaborator

imeoer commented May 29, 2024

Hi all, I tried out this feature and it seems to work as expected. Is there something preventing it from being merged?

cc @jiangliu any updates we can continue? :)

Sign up for free to 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.

None yet

5 participants