Skip to content

Conversation

@tarzanek
Copy link
Contributor

@tarzanek tarzanek commented Jun 20, 2019

NOTE:
the important classes to review are RESTInfo.java and RESTNodeProbe.java (do ignore jmx/api namespace, it's 1-1 copy from scylla-jmx)
this is WIP, so proof of concept as such, we wanted to avoid JMX layer in between

when reviewing RESTNodeProbe -
"super." means it is just fallback to old jmx layer in NodeProbe

-R for command line is used temporarily so I can easily switch between new and old probe

build-test, stress-build is removed in build.xml just for me to build faster

I added classes from jmx/api/ from https://github.com/scylladb/scylla-jmx repo - can we make a dependency on it so we don't duplicate stuff?

performance wise for my small test the result is the same, but now there is no jmx layer in between
(note that we still connect to jmx for fallback commands even if -R is used!)

and last warning - API client doesn't use command line hostname+port yet, so I know this code fails when run against remote host

@glommer
Copy link
Contributor

glommer commented Jun 20, 2019

@penberg please let us know what you think

@tarzanek
Copy link
Contributor Author

old:

[root@scylla scylla-tools-java]# time nodetool info
ID                     : 7dfdbd92-42d8-46bb-9e83-62bc83e5f694
Gossip active          : true
Thrift active          : true
Native Transport active: true
Load                   : 121.01 KB
Generation No          : 1560962206
Uptime (seconds)       : 71018
Heap Memory (MB)       : 23.06 / 247.50
Off Heap Memory (MB)   : 1.54
Data Center            : datacenter1
Rack                   : rack1
Exceptions             : 0
Key Cache              : entries 0, size 0 bytes, capacity 0 bytes, 0 hits, 0 requests, 0.000 recent hit rate, 0 save period in seconds
Row Cache              : entries 79, size 79 bytes, capacity 6.87 MiB, 189 hits, 508 requests, 0.372 recent hit rate, 0 save period in seconds
Counter Cache          : entries 0, size 0 bytes, capacity 0 bytes, 0 hits, 0 requests, 0.000 recent hit rate, 0 save period in seconds
Percent Repaired       : 0.0%
Token                  : (invoke with -T/--tokens to see all 256 tokens)

real    0m11.086s
user    0m6.432s
sys     0m0.353s

new:

[root@scylla scylla-tools-java]# time ./bin/nodetool -R info
ID                     : 7dfdbd92-42d8-46bb-9e83-62bc83e5f694
Gossip active          : true
Thrift active          : true
Native Transport active: true
Load                   : 121.01 KB
Generation No          : 1560962206
Uptime (seconds)       : 0
Heap Memory (MB)       : 0.00 / 0.00
Off Heap Memory (MB)   : 1.54
Data Center            : datacenter1
Rack                   : rack1
Exceptions             : 0
Key Cache              : entries 0, size 0 bytes, capacity 0 bytes, 0 hits, 0 requests, 0.000 recent hit rate, 0 save period in seconds
Row Cache              : entries 79, size 79 bytes, capacity 6.87 MiB, 187 hits, 506 requests, 0.370 recent hit rate, 0 save period in seconds
Counter Cache          : entries 0, size 0 bytes, capacity 0 bytes, 0 hits, 0 requests, 0.000 recent hit rate, 0 save period in seconds
Percent Repaired       : 0.0%
Token                  : (invoke with -T/--tokens to see all 256 tokens)

real    0m13.849s
user    0m10.807s
sys     0m2.043s

I tested with -T and it works well, too
uptime and heaps are 0 in new version due to #98

@penberg
Copy link
Contributor

penberg commented Jun 20, 2019

Some high-level comments:

The approach makes tons of sense, and it's something we have discussed internally before too.

We should indeed make the REST API parts of Scylla JMX available as a library for this effort. One option is to make a separate "scylla-api-java.git", which has the generally useful bits. @avikivity, what do you think?

List<Class<? extends Runnable>> commands = asList(
Help.class,
Info.class,
REST==true?RESTInfo.class:Info.class,
Copy link
Contributor

Choose a reason for hiding this comment

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

Perhaps it would be simpler to always have Info.class here and make that class internally switch between RESTInfo and JMXInfo?

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 is a good comment ... I wanted to avoid modifying Info class as we consume it from upstream - so if we will merge upstream, this approach(to modify loaded classes) should be easier to handle conflicts and we will know what should be ported where

Copy link
Contributor

Choose a reason for hiding this comment

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

Sure, it makes sense not to modify Info class directly, but what if we add a InfoWrapper class that we use here, which delegates to Info or RESTInfo?

@Option(type = OptionType.GLOBAL, name = {"-pwf", "--password-file"}, description = "Path to the JMX password file")
private String passwordFilePath = EMPTY;

@Option(type = OptionType.GLOBAL, name = {"-R"}, description = "Use REST instead of JMX")
Copy link
Contributor

Choose a reason for hiding this comment

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

Maybe elaborate more in the description. For example, something like this:

Use Scylla's REST API (when supported) instead of the Cassandra-compatible JMX protocol for operations

Copy link
Contributor Author

Choose a reason for hiding this comment

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

we actually want to get rid of this option :-)
I have it there to ease my testing and comparing if I miss functionality from old NodeProbe

Copy link
Contributor

Choose a reason for hiding this comment

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

I would like to keep the option (and have it disabled by default) for one or two releases. But we certainly can switch over to REST altogether once it's proven stable in production.

Copy link
Contributor

Choose a reason for hiding this comment

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

This will get confusing when we default to it.
Pekka, if you want an option here, I'd like to suggest something like --probe=[rest|jmx] or --proto so we can choose any, and not only an enable-style flag so we can switch between both

// } catch (UnknownHostException e) {
// e.printStackTrace(); //TODO fix DNS name lookup error
// }
// return client.getStringValue("/snitch/datacenter", queryParams, 10000);
Copy link
Contributor

Choose a reason for hiding this comment

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

I guess the commented out code will be removed from the final pull request.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

correct, this is a very early draft, so no cleanup was done

@tarzanek
Copy link
Contributor Author

I force pushed new update, hopefully it still keeps some history, seems comments are still here :-)
I got rid of -R
and added few jars that are needed for this code to work (I will need to check ALL of the jar dependencies to make sure it works 100%, since scylla-jmx is on mvn and this repo is on ant :-( )

@penberg
Copy link
Contributor

penberg commented Jun 20, 2019

Overall, the pull request makes sense to me. I think RESTNodeProbe can be simplified and cleaned up, and, as you also say, we need to figure out a way to eliminate APIClient duplication between JMX and this repository. Other than that, I think we can definitely go ahead with this approach.

@tarzanek
Copy link
Contributor Author

@haaawk @elcallio could give your insights on the approach too?
I basically have only one concern, which is data that should be cached (jmx now caches few things, I think snitch, datacenter and rack and few metrics for few seconds), will loose caching now, since nodetool will re-query it always.
(which could in the end prove more useful than jmx refreshing it always :-) )

@elcallio
Copy link
Contributor

@tarzanek I am generally for this, though we have not done this earlier because (apparently?) there are customers relying on JMX supprt (not for nodetool, but third party stuff).
However, I really feel you need to make scylla-jmx-rest-api junk a proper dependency, not just copied binaries. As suggested above, a library split and git submodule is one approach. Another is to use the maven-copy code in build.xml and extend it to pick scylla libraries and dependencies as well. This is probably the simpler approach right now. (We should add maven repo functionality to our jenkins so versioned scylla-jmx can be copied from there).

@tarzanek
Copy link
Contributor Author

piotr [2:57 PM]
flag shouldn't be binary
but rather take value of communication method
not -use-rest

but -protocol=rest
-protocol=jmx

@elcallio
Copy link
Contributor

Btw, before we can even think of making nodetool REST-only, the REST api needs to support HTTPS/TLS. JMX connectivity can be secured on Java level, and scylla-jmx to localhost w.o. security is probably fine, but for remote client to REST api, both SSL + auth is really needed.

@glommer
Copy link
Contributor

glommer commented Jun 25, 2019

@tarzanek I am generally for this, though we have not done this earlier because (apparently?) there are customers relying on JMX supprt (not for nodetool, but third party stuff).
However, I really feel you need to make scylla-jmx-rest-api junk a proper dependency, not just copied binaries. As suggested above, a library split and git submodule is one approach. Another is to use the maven-copy code in build.xml and extend it to pick scylla libraries and dependencies as well. This is probably the simpler approach right now. (We should add maven repo functionality to our jenkins so versioned scylla-jmx can be copied from there).

Some background here: Indeed we won't be able to retire scylla-jmx by doing this, since there are other consumers (even when we finish the conversion). However we're seeing scylla-jmx slow down nodetool in some queries, and even the people who need no other API are paying the price. The goal, at least at first, is to convert nodetool, and then be able to disable scylla-jmx (or just leave it there, running doing nothing) for the customers who don't need it.

@tarzanek tarzanek changed the title WIP - use REST for nodetool info use REST for nodetool info Jul 12, 2019
@tarzanek
Copy link
Contributor Author

I addressed all the comments, however I lack a proper packaging test (so far I was running this from my workspace dir and only tried the artifact target)

@tarzanek
Copy link
Contributor Author

@tarzanek
Copy link
Contributor Author

tarzanek commented Jul 12, 2019

ok, packaging tests failed after packaging, I lack host and port support for REST, fixing now,
rebuilding http://jenkins.scylladb.com/view/master/job/scylla-master/job/manual-and-scheduled-tests/job/byo_build_tests_dtest/442/

@Option(type = OptionType.GLOBAL, name = {"-p", "--port"}, description = "Remote jmx agent port number")
private String port = "7199";

@Option(type = OptionType.GLOBAL, name = {"-o", "--restport"}, description = "Remote Scylla REST port number")
Copy link
Contributor

Choose a reason for hiding this comment

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

nitpicking short and long version should at least attempt to be similar

@Option(type = OptionType.GLOBAL, name = {"-pwf", "--password-file"}, description = "Path to the JMX password file")
private String passwordFilePath = EMPTY;

@Option(type = OptionType.GLOBAL, name = {"-r", "--protocol"}, description = "Use rest(default, only for what is ported) or jmx(legacy) protocol")
Copy link
Contributor

Choose a reason for hiding this comment

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

nitpicking again, the -r is not a great short version of --protocol

* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
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 we should add a scylla clause

Copy link
Contributor

Choose a reason for hiding this comment

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

A general comment, why do we need to replace the Info class at all?

If we replace the probe part, the rest should be transparent, right?
This way it will be easier to follow upstream changes

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 problem is that the probe methods use mxbeans for DAOs, so this is to get rid of mxbeans in REST part completely without changing much of original classes
obviously this creates later an update problem if we will sync with upstream(but the problem will be there anyways), but it will get us rid of mxbeans and merges with upstream should be easier to sync with modified classes(that use the mxbeans methods from probe)

/**
* REST client operations for Scylla.
*/
public class RESTNodeProbe extends NodeProbe
Copy link
Contributor

Choose a reason for hiding this comment

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

For testing during the transition phase, we can use an empty RESTNodeProbe and gradually add override methods.
What we don't override will be taken from NodeProbe

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 am calling super() now to parent jmx so fallback is to jmx where not implemented.
Are you suggesting to just return empty values instead?

@amnonh
Copy link
Contributor

amnonh commented Jul 24, 2019

an alternative (I'm not sure what the code impact would be) to create a fake jmx implementation layer, add the scylla-jmx classes inside the nodetool so nodeprobe would use it directly.

We can probably do that by changing the getter function on NodeProbe

@tarzanek
Copy link
Contributor Author

tarzanek commented Jul 26, 2019

an alternative (I'm not sure what the code impact would be) to create a fake jmx implementation layer, add the scylla-jmx classes inside the nodetool so nodeprobe would use it directly.

We can probably do that by changing the getter function on NodeProbe

interesting - so all the jmx mxbean code building would happen in one jvm - which is actually what we want to get rid of (it grows too much and is too slow)
how it would however happen in one JVM is a question, I can try if I will have spare time, but until then current approach seems just more obvious (unless somewhere the mxbean caching has better response than querying REST API layer) - I still expect the jmx to be just too slow

@amnonh
Copy link
Contributor

amnonh commented Jul 26, 2019 via email

@tarzanek
Copy link
Contributor Author

closing in favour of #121

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.

5 participants