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

Shard awareness extension for Scylla #1206

Closed
wants to merge 3 commits into from
Closed

Shard awareness extension for Scylla #1206

wants to merge 3 commits into from

Conversation

dahankzter
Copy link
Contributor

This PR brings shard awareness to the token aware policy for Scylla servers version 2.3 or later.

This is done by implementing the Scylla protocol extension mechanism as as defined by:
https://github.com/scylladb/scylla/blob/master/docs/protocol-extensions.md
The impact for Scylla users is significant improvement in performance while still maintaining the original performance for Cassandra users.
Both latency and throughput are greatly improved but especially latency can see an order of magnitude improvement.

No config is needed for the user to benefit from this patch, the driver will discover the sharding support on its own.

conn_test.go Outdated
@@ -828,14 +828,19 @@ func TestFrameHeaderObserver(t *testing.T) {

frames := observer.getFrames()

if len(frames) != 2 {
if len(frames) != 3 {
t.Fatalf("Expected to receive 2 frames, instead received %d", len(frames))
Copy link

Choose a reason for hiding this comment

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

Do you need to adjust this message now also from 2 frames into 3 frames?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

The protocol specifies an additional options query to discover the sharding info which cannot be statically read once since it's a runtime connection property. See the Conn::startup method. Afaik the test then needs to be accommodated. Is this the wrong way to verify this? If there is a better please let me know I am open to suggestions.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Ouch @JvGinkel I read your message too loosely it seems.
I will correct the message. Good catch!

Copy link
Contributor

@alourie alourie left a comment

Choose a reason for hiding this comment

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

So, there are a few nits with the code itself, but I have some reservations about merging all of it in the current form. The issue is clearly with the fact that it's an addition to include a different SERVER project's properties. I'm definitely not against supporting multiple endpoints, but something in the way it is organised now rubs me the wrong way.

I would probably ask for 2 separate PRs: one for the refactored connPicker implementation, and another for scylla support. But I would like to see the Scylla support as clearly separated, like maybe using "backends" module, so that main thing is used as a common base (which is, clearly, C*), and then additional backends (like Scylla) do their additional/different implementations.

CC @Zariel

type DefaultConnPicker struct {
conns []*Conn
pos uint32
size int
Copy link
Contributor

@alourie alourie Oct 8, 2018

Choose a reason for hiding this comment

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

I'd use an unsigned int variant for the size.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

It's very viral. This property is threaded through the code and it makes sense to have them as uint but perhaps not in this patch?

}

func NewDefaultConnPicker(size int) *DefaultConnPicker {
return &DefaultConnPicker{
Copy link
Contributor

Choose a reason for hiding this comment

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

check for size to be non-zero to avoid errors?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I can check it here and return an error. If so what do we do then, panic or default to something?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

There is no real infrastructure available to handle errors in this. It all relies on the config defaulting to 2. We can change the assumptions but I'd rather not in a patch that is about something else.

What do you think?

Copy link
Contributor

Choose a reason for hiding this comment

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

I think panic here is fine.

connpicker.go Outdated

for i, candidate := range p.conns {
if candidate == conn {
p.conns[i] = conn
Copy link
Contributor

Choose a reason for hiding this comment

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

p.conns[i] == nil?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

p.conns[i] = nil perhaps? I think we should maybe eve resize it what do you think?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I have set it to nil now. We can change it if you prefer but the rest of the code works guards against nil.

Copy link
Contributor

Choose a reason for hiding this comment

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

nah, nil is fine. That's exactly what I meant :-)

}

func (p *DefaultConnPicker) Pick(token) *Conn {
pos := int(atomic.AddUint32(&p.pos, 1) - 1)
Copy link
Contributor

Choose a reason for hiding this comment

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

Not sure the initial reason for this, but would you mind just reading atomically directly?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

This keeps track of the current position in the conns list. I think it was always like this to step to the next connection in one atomic go.

Copy link
Contributor

Choose a reason for hiding this comment

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

right, ok

policies.go Outdated
}

func (host selectedHost) Info() *HostInfo {
return (*HostInfo)(host.info)
Copy link
Contributor

Choose a reason for hiding this comment

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

probably no need to cast here

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Ah, thx!

@dahankzter
Copy link
Contributor Author

About your major comment @alourie I would also want to isolate and modularize it more but when we implemented this we saw now real option without major refactoring which felt very invasive for such a relatively small patch. It depends of course on what you mean with this backends module? A factory struct that knows how to instantiate backends?

I will try to address your minor issues asap, thanks for noticing. Nitpicks accumulate so it's good to catch them early!

@alourie
Copy link
Contributor

alourie commented Oct 8, 2018

@dahankzter I don't know what's the best way to implement backends, for now, would need to wait until @Zariel has an opinion. Maybe in the next major API change.

But splitting this into 2 PRs should not be complicated, no? The connection picker and the Scylla's implementation are quite separate, so I'd assume it would be possible to do.

@dahankzter
Copy link
Contributor Author

We can probably split them up but the assignment of the picker to use is dynamic so at some point the code will blend.

There are basically 2 reasons for the code being as is today.

  1. Make as small an impact as possible on the core code.
  2. Make the usage for users as small as possible. They only need to update the driver now for it to kick in.

That's it really we can make any sort of bootstrapping otherwise if we don't want 2.
Maybe there even is a way to implement it more isolated that we haven't thought of and while we prefer no-config for end users we are not married to the idea. We want to be pragmatic about it and a config option can work fine as well. We just need to tell users to enable it.

@mmatczuk
Copy link
Contributor

mmatczuk commented Oct 9, 2018

Hi @alourie,
I have fixed the code to limit scope of Scylla related stuff as much possible. It's split into multiple commits and two PRs. Please find the gocql generic changes in #1210 and Scylla specific changes in #1211 (note the dependency).

cc @dahankzter

dahankzter and others added 3 commits October 10, 2018 09:24
This is an extension to tokenAwareHostPolicy supported by the Scylla 2.3
and onwards. It allows the driver to select a connection to shard on a host
based on token. The protocol extension spec is available at [1].

[1] https://github.com/scylladb/scylla/blob/master/docs/protocol-extensions.md

Co-authored-by: Michał Matczuk <[email protected]>
@dahankzter
Copy link
Contributor Author

Lets work off of #1210 and #1211 instead.

@dahankzter dahankzter closed this Oct 10, 2018
@alourie
Copy link
Contributor

alourie commented Oct 10, 2018

👍

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.

4 participants