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
Revise document for handling exceptions for Two-phase Commit Transactions #934
Revise document for handling exceptions for Two-phase Commit Transactions #934
Conversation
7151c8b
to
b69b3d5
Compare
b69b3d5
to
ee57bae
Compare
// transaction as committed | ||
AtomicReference<Exception> exception = new AtomicReference<>(); | ||
boolean anyMatch = | ||
Stream.of(transaction1, transaction2) |
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.
With this error handling, I think the commits can be executed in parallel as follows
Stream.of(transaction1, transaction2)
.parallel()
.anyMatch(
...
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.
Ah, sorry. I found the parallel version code in the next section below.
This code is the sequential version, right? If so, please ignore my comment. But it might be good to mention sequential execution or something here?
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.
I think that has already been mentioned here:
https://github.com/scalar-labs/scalardb/pull/934/files#diff-2677f880f1a9e512f31cce8e12950863ddffd4be49408d310d72d4d73e6122b9R306
What do you think?
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.
Looks good!
} catch (Exception e) { | ||
// Rollback the transaction | ||
if (transaction1 != null) { | ||
transaction1.rollback(); |
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.
Wrapping this with try-catch would be safer just in case if rollback()
could throw any exception.
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.
Fixed in 635b41d. Thanks.
} | ||
|
||
// Otherwise, throw the first exception | ||
throw exceptions.get(0); |
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.
[minor] This is a very corner case (and unexpected usage), but this line would throw NPE ArrayIndexOutOfBoundsException if transactions
is empty?
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.
Ah, that's a very unexpected usage. We could add validation or an assertion to this method, but I think it might be too verbose since it's a sample code. What do you think?
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.
Yeah, I think it's okay to go with current simple one 👍
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.
It looks good, thanks. I left two suggestions.
Co-authored-by: Vincent Guilpain <vincent.guilpain@scalar-labs.com>
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.
LGTM, thank you!
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.
I've added some comments and suggestions. PTAL!
Requests in the same gRPC connection always go to the same server in L3/L4 load balancing. | ||
When using an L7 load balancer, since requests in the same gRPC connection do not necessarily go to the same server, you need to use cookies or similar for routing requests to correct server. | ||
For example, when you use [Envoy](https://www.envoyproxy.io/), you can use session affinity (sticky session) for gRPC. | ||
Or you can also use [Bidirectional streaming RPC in gRPC](https://grpc.io/docs/what-is-grpc/core-concepts/#bidirectional-streaming-rpc) since the L7 load balancer distributes requests in the same stream to the same server. |
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.
Or you can also use [Bidirectional streaming RPC in gRPC](https://grpc.io/docs/what-is-grpc/core-concepts/#bidirectional-streaming-rpc) since the L7 load balancer distributes requests in the same stream to the same server. | |
Alternatively, you can use [bidirectional streaming RPC in gRPC](https://grpc.io/docs/what-is-grpc/core-concepts/#bidirectional-streaming-rpc) since the L7 load balancer distributes requests in the same stream to the same server. |
|
||
Typically, you use a server-side (proxy) load balancer with HTTP/1.1. | ||
When using an L3/L4 load balancer, you can use the same HTTP connection to send requests in a transaction, which guarantees the requests go to the same server. | ||
When using an L7 load balancer, since requests in the same HTTP connection do not necessarily go to the same server, you need to use cookies or similar for routing requests to correct server. |
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 using an L7 load balancer, since requests in the same HTTP connection do not necessarily go to the same server, you need to use cookies or similar for routing requests to correct server. | |
When using an L7 load balancer, since requests in the same HTTP connection don't necessarily go to the same server, you need to use cookies or similar method to route requests to the correct server. |
Co-authored-by: Josh Wong <joshua.wong@scalar-labs.com>
Co-authored-by: Josh Wong <joshua.wong@scalar-labs.com>
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.
LGTM! 👍
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.
LGTM! Thank you!🙇♂️
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.
Overall, looking good! Thank you!
And, sorry for the late review.
I left some comments and suggestions.
Also, I think the name Two-phase Commit Transactions
might be misleading since readers would think normal transactions don't employ the two-phase commit protocol.
Let's discuss this offline.
@@ -5,6 +5,21 @@ With Two-phase Commit Transactions, you can execute a transaction that spans mul | |||
|
|||
This document briefly explains how to execute Two-phase Commit Transactions in ScalarDB. | |||
|
|||
## Overview | |||
|
|||
ScalarDB transactions normally execute in a single transaction manager instance. |
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.
ScalarDB transactions normally execute in a single transaction manager instance. | |
ScalarDB normally executes transactions in a single transaction manager instance with a one-phase commit interface, which we call normal transactions. |
I think we should define normal transactions
here because it is referred to in the following sentence.
Also, we should probably note about interfaces.
Maybe, it might be more clear to say something like this since normal transactions don't sound like doing two-phase commits.
Although ScalarDB employs a variant of the two-phase commit protocol, ScalarDB normally executes transactions in a single transaction manager instance with a one-phase commit interface, which we call normal transactions.
Also, it might be helpful to have a diagram like this.
https://speakerdeck.com/scalar/scalar-db-universal-transaction-manager?slide=27
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.
I applied the suggestion in 0db8458.
Also, it might be helpful to have a diagram like this.
https://speakerdeck.com/scalar/scalar-db-universal-transaction-manager?slide=27
Regarding this, let's do in another PR.
Two-phase commit transactions are basically executed by multiple processes/applications (a coordinator and participants). | ||
However, in this example code, you can see multiple transaction managers (`transactionManager1` and `transactionManager2`) in a single process. | ||
|
||
The following example code shows how to handle exceptions in Two-phase Commit Transactions: |
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 we have anything to be noted in particular?
(like, If we don't follow the following guide on how to handle exceptions properly, you may face anomalies...)
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.
Fixed in 272d88b. Can you please check it?
When using an L3/L4 load balancer, you can use the same HTTP connection to send requests in a transaction, which guarantees the requests go to the same server. | ||
When using an L7 load balancer, since requests in the same HTTP connection don't necessarily go to the same server, you need to use cookies or similar method to route requests to the correct server. | ||
You can use session affinity (sticky session) in that case. | ||
|
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.
Should we introduce ScalarDB Cluster a bit?
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.
Yes, we should. Let's do that in another PR. Thanks.
Co-authored-by: Hiroyuki Yamada <mogwaing@gmail.com> Co-authored-by: Josh Wong <joshua.wong@scalar-labs.com>
@feeblefakie As discussed, let's rephrase the terms |
@brfrn169 Just one note about the following:
If |
I might be missing something and sorry in advance if this is a silly comment. If |
Ah, I missed #934 (comment). Got the point. ( |
@josh-wong Thank you for the input. Let's proceed with the lowercase notation. |
@komamitsu Yes, we should clarify that while ScalarDB uses a variant of the two-phase commit protocol (Consensus Commit), it offers two types of interfaces: |
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.
LGTM! Thank you!
[skip ci] Change `two-phase commit transactions` to `transactions with a two-phase commit interface` as noted in #934 (comment).
[skip ci] Change `two-phase commit transactions` to `transactions with a two-phase commit interface` as noted in scalar-labs/scalardb#934 (comment).
This PR revises the document for handling exceptions for Two-phase Commit Transactions. Please take a look!