Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
107 changes: 107 additions & 0 deletions site/bps/BP-38-bypass-journal-ledger.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,107 @@
---
title: "BP-38: bypass journal ledger"
issue: https://github.com/apache/bookkeeper/issues/1918
state: "Under Discussion"
release: "N/A"
---

### Motivation

To guarantee high durability, BK write journal before flush data to persistent device which will cause two write of data.
But we may not need this level of persistence under [scenarios](https://cwiki.apache.org/confluence/display/BOOKKEEPER/BP-14+Relax+durability) which prefer weak durability guarantee.
This proposal is aimed at providing bypass journal ledger, this feature includes these parts work:
- add new write flag `BYPASS_JOURNAL` to existing protocol

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

I assume BYPASS_JOURNAL is applicable only in the week durability case. We have that in the protocol, so can't BYPASS_JOURNAL be just a configuration parameter on bookie, which will used only (if enabled) on week durability case?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

When user create LedgerHandle, he/she can construct it with WriteFlag.BYPASS_JOURNAL

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

@jvrao I think we cannot have a bookie configuration parameter because the client must be aware of relaxed durability and advance LAC accordingly (like we do with DEFERRED_SYNC)

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

@jvrao If I remember this correctly, we were thinking of adding BYPASS_JOURNAL as a WriteFlag, no? Applications can decide whether to use journal or not.

- impl the newly write flag at the client side and server side

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Do you mean client visible API change ? or where exactly is this flag?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Yes. What I mean is extending WriteFlags, the user who wants using this feature only needs pass WriteFlags to the WriteHandle. looks like this:

newCreateLedgerOp()
                .withEnsembleSize(3)
                .withWriteQuorumSize(3)
                .withAckQuorumSize(3)
                .withPassword(PASSWORD)
                .withWriteFlags(WriteFlag.BYPASS_JOURNAL)
                .execute()

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

@ArvinDevel it would be good if you can put the example code in the BP.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

will do that


The usage will looks like this:
```java
WriteHandle writeHandle = newCreateLedgerOp()
.withEnsembleSize(3)
.withWriteQuorumSize(3)
.withAckQuorumSize(3)
.withPassword(PASSWORD)
.withWriteFlags(WriteFlag.BYPASS_JOURNAL)
.execute().get();
// append data as usual, but the lac won't advance
writeHandle.appendAsync(...);
// force to advance lac
writeHandle.force();
writeHandle.closeAsync();
```
The details of changes are listed in Section “[Proposed Changes](#proposed-changes)”.

### Public Interfaces

This feature will introduce new 'WRITE_FLAG' to enable single write storage impl.
Like `DEFERRED_SYNC`, when we construct `WriteHandle`, we can pass `BYPASS_JOURNAL`, then every `AddRequest` will carry this flag.
As for monitoring, we can add metrics to record the main time interval during the io path.
The detailed compatibility related stuff is in Section “[CDMP](#compatibility-deprecation-and-migration-plan)”.

### Proposed Changes

While the main approach is based on [`WRITE_FLAG` impl](https://github.com/apache/bookkeeper/pull/742),
the actual implementation is more tricky. In my opinion, there are three different solution:

1. Relax LAC protocol(rejected due to violate LAC protocol)

Modify server side code mostly and don't change legerHandle's LAC advance logic, if the write flag is `BYPASS_JOURNAL`, after write to `LegerStorage`(the data maybe in the memTable, or the buffer of File, or the os cache),

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

don't change legerHandle's LAC advance logic

I think we should use the DEFERRED_SYNC way of handling LAC, that is that a regular write will not advance LAC, but you need a "force" (like you state below).

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

The difficult is how to execute "force", leave to app or client lib, and how often to schedule force if WriteHandle is responsible for that. Do you have any ideas?

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

force() RPC may carry a flag on the wire which tells that the clients wants to fait for a flush of the memtable for the given ledger.
force() with DEFERRED_SINC -> wait for/force a write to the journal
force() with BYPASS_JOURNAL -> wait for/force a flush on the EntryLogger

It makes sense only in conjunction with "multiple entry loggers"/"one entry logger per ledger" feature.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

yes, but I'm more worried about that is the synchronized "force" applicable for bypass-journal weak durability. On the "deferred_sync" scenario, the consumer/ReadHandle can tolerant reading after "force" or close. If we still restrict the reader can only read up to the point where writer "force", will this limit the applied scenarios of bypass-journal weak durability?

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

I agree with @eolivelli. BYPASS_JOURNAL should have same LAC semantics as DEFERRED_SYNC. We only advanced LAC when force happen. force will carry the write flag and decide to force a write to the journal, or force a flush on ledger storage.

For bypass journal use cases, I think applications are usually when a ledger is closed/forced. So the above assumptions would make implementation easier.

bookie return result to the client directly.
This impl is like [disable syncData](https://github.com/apache/bookkeeper/issues/753), once all the replica fails, the BK cluster can't recovery from it.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

With this the above will be obsolete?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

The bookie level config syncData example is just used to compare. We still needs to modify server side to sense client's WriteFlag.BYPASS_JOURNAL option, and extend WriteFlag to give users this choice.

Note, the user shall know the weak durability for his use case when using this impl.

2. Extend `Force` API

Like `DEFERRED_SYNC`, the normal 'bypass-journal' operation don't advance LAC on the client.
Only advance LAC using `force` api. To support this new 'bypass-journal' option, we need theses changes:

- Add force interface to `LedgerDescriptor` and LedgerStorage

Used to flush the data on memTable to persistent device for specific ledger, and this make senses with "one entry logger per ledger" feature.
For general SortedLedgerStorage, this "force" operation may has some overhead due to flush data too early.

- Extend the force request

If the force request contains bypass journal option, execute force method of `LedgerDescriptor`, which will call LedgerStorage's force interface to flush received entries to persistent device.

In addition to these changes, we should consider who is responsible for the `force` execution? How often to schedule 'force'?
To simply the design and give more choices to apps, these choices are up to user.

3. Add NonPersistentLAC semantic to existing LAC protocol(rejected due to infeasible and complex)

To not violate LAC semantics like method 1, we can add `NonPersistentLAC` semantic, this includes these changes:

- Add persistent callback to LedgerStorage

Maintain non-persistent entry list and `maxPersistentEntryId` on `LedgerDescriptor`.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

I tried to have a 'maxPersistentEntryId' while working on DEFERRED_SYNC but actually it was not possible because if you use "LedgerHandleAdv" entries won't get to the bookie with a specific order, so you will have to keep track of holes.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

you're right, thanks


- Wire protocol changes

Add optional `maxPersistentEntryId` field to `AddResponse`. When the `AddRequest` has 'bypass-journal' option, the server get `maxPersistentEntryId` from `LedgerDescriptor` to construct response.

- Client side changes

Add `nonPersistentLAC` to WriteHandle. WriteHandle with 'bypass-journal' option updates the LAC using `maxPersistentEntryId`, and update `nonPersistentLAC` if receives enough ack.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

nonPersistentLAC is more like 'pendingAddsSequenceHead' that we introduced for DEFERRED_SYNC

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Yes, and I forgot to state something to complete nonPersistentLAC :

  • carry nonPersistentLAC to bookie, and LedgerDesciptor record it
  • extend readEntry of ReadHandle, so that it can read up to nonPersistentLAC

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Why persisting an non-persistent value ?
The value makes sense only on the client (writer), you won't ever read that value from bookies

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

What I want is relaxing the reader to read up to latest entry as early as possible.

For normal WriteHandle, the `nonPersistentLAC` is set to null to indicate to keep original LAC advance logic.

As we only introduce `BYPASS_JOURNAL` write flag to add request, it's better not change existing fencing logic. So fence operation shall falls into journal io path.

### Compatibility, Deprecation, and Migration Plan

As this new feature only add one ledger creating option and corresponding ledger implementation. It has no effect
on existing users. After this feature is implemented, user can use this function directly on new released version which includes this implementation.
When user use the latest client which has the `BYPASS_JOURNAL` write flag, but the bookie is old versions which can't do bypass-journal process,
the bookie will reject this type write. Old client has no chance to use this new write flag, and the new bookie can handle as usual.

### Test Plan

- unit tests for newly introduced write_flag and extended force at client side and server side
- end-to-end tests for the new Protocol request/response
- compat tests (client with this new writeflags will not be able to write on old bookies)

### Rejected Alternatives

To avoid two write of data, we can write the data to one log abstraction in the bookie, either by bypassing journal or
bypassing entryLog. If we choose bypassing entryLog, then we will do lots of work to enable rich read on journal,
which is more huge work compared with bypassing journal.


3 changes: 2 additions & 1 deletion site/community/bookkeeper_proposals.md
Original file line number Diff line number Diff line change
Expand Up @@ -85,7 +85,7 @@ using Google Doc.

This section lists all the _bookkeeper proposals_ made to BookKeeper.

*Next Proposal Number: 38*
*Next Proposal Number: 39*

### Inprogress

Expand All @@ -109,6 +109,7 @@ Proposal | State
[BP-35: 128 bits support](../../bps/BP-35-128-bits-support) | Accepted
[BP-36: Stats documentation annotation](../../bps/BP-36-stats-documentation-annotation) | Accepted
[BP-37: Improve configuration management for better documentation](../../bps/BP-37-conf-documentation) | Accepted
[BP-38: Bypass journal ledger](../../bps/BP-38-bypass-journal-ledger) | Draft

### Adopted

Expand Down