
{"id":1762,"date":"2015-05-23T15:34:22","date_gmt":"2015-05-23T15:34:22","guid":{"rendered":"http:\/\/www.codergears.com\/Blog\/?p=1762"},"modified":"2015-05-23T15:34:22","modified_gmt":"2015-05-23T15:34:22","slug":"enforce-the-single-responsibility-principle-cassandra-nodetool-case-study","status":"publish","type":"post","link":"https:\/\/codergears.com\/Blog\/?p=1762","title":{"rendered":"Enforce the Single Responsibility Principle: Cassandra nodetool case study"},"content":{"rendered":"<p style=\"color: #555555;\">Let&#8217;s start with the single responsibility principle from wikipedia:<\/p>\n<blockquote>\n<p style=\"color: #555555;\">In object-oriented programming, the single responsibility principle states that every class should have responsibility over a single part of the functionality provided by the software, and that responsibility should be entirely encapsulated by the class. All its servicesshould be narrowly aligned with that responsibility.<\/p>\n<\/blockquote>\n<p><!--more--><\/p>\n<p style=\"color: #555555;\">Enforce the single responsibility priniciple makes your code more readable and maintainable. In this article the goal is to go inside the Cassandra\u00a0<a style=\"color: #2970a6;\" href=\"http:\/\/wiki.apache.org\/cassandra\/NodeTool\">nodetool<\/a>, and see how we can enforce this princple. For that we use\u00a0<a style=\"color: #2970a6;\" href=\"http:\/\/www.jarchitect.com\/\">JArchitect\u00a0<\/a>to understand how the nodetool works internally.<\/p>\n<p style=\"color: #555555;\">Relational database management systems are the most commonly used system to store and use data, but for extremely large amounts of data, this kind of system doesn\u2019t scale up properly.<\/p>\n<p style=\"color: #555555;\">The concept of\u00a0<a style=\"color: #2970a6;\" href=\"http:\/\/en.wikipedia.org\/wiki\/NoSQL\">\u201cNoSQL\u201d<\/a>(Not Only SQL) has been spreading due to the growing demand for relational database alternatives. The biggest motivation behind NoSQL is scalability. NoSQL solutions can offer a way to store and use extremely large amounts of data, but with less overhead, less work, better performance, and less downtime.<br \/>\n<span id=\"more-1024\"><\/span><br \/>\n<a style=\"color: #2970a6;\" href=\"http:\/\/cassandra.apache.org\/\">Apache Cassandra<\/a>\u00a0implements the \u201cNoSQL\u201d concept. It was developed at Facebook to power their Inbox Search feature, and it became an Apache open source project. Twitter, Digg, Reddit and quite a few others started using it<\/p>\n<p style=\"color: #555555;\">Cassandra exposes a number of management operations via Java Management Extensions (JMX). Java Management Extensions (JMX) is a Java technology that supplies tools for managing and monitoring Java applications and services. Any statistic or operation that a Java application has exposed as an MBean can then be monitored or manipulated using JMX.<\/p>\n<p style=\"color: #555555;\">The nodetool utility is a command line interface for Cassandra. You can use it to help manage a cluster. It\u2019s used like this<\/p>\n<blockquote><p>nodetool -h HOSTNAME [-p JMX_PORT] COMMAND<\/p><\/blockquote>\n<p style=\"color: #555555;\">Here are some available commands:<\/p>\n<pre style=\"color: #555555;\">  ring                   - Print informations on the token ring\r\n  join                   - Join the ring\r\n  info                   - Print node informations (uptime, load, ...)\r\n  cfstats                - Print statistics on column families\r\n  clearsnapshot          - Remove all existing snapshots\r\n  version                - Print cassandra version\r\n  tpstats                - Print usage statistics of thread pools\r\n  drain                  - Drain the node (stop accepting writes and flush all column families)\r\n<\/pre>\n<p style=\"color: #555555;\">Let&#8217;s first discover the major nodetool components and how they work internally.<\/p>\n<p style=\"color: #555555;\">The nodetool classes exist in the org.apache.cassandra.tools package, and the entry class is NodeCmd.<\/p>\n<h3 style=\"font-weight: bold; color: #555555;\">NodeCmd<\/h3>\n<p style=\"color: #555555;\">To understand the role of this class let\u2019s search for methods called by the main method from the NodeCmd class by executing the following CQLinq query:<\/p>\n<pre style=\"color: #555555;\">from m in Methods where m.IsUsedBy (\"org.apache.cassandra.tools.NodeCmd.main(String[])\")\r\nselect new { m, m.NbBCInstructions }\r\n<\/pre>\n<p style=\"color: #555555;\"><a style=\"color: #2970a6;\" href=\"https:\/\/javadepend.files.wordpress.com\/2014\/01\/cassandra1.png\"><img decoding=\"async\" class=\"aligncenter size-full wp-image-1025\" src=\"https:\/\/javadepend.files.wordpress.com\/2014\/01\/cassandra1.png?w=595\" alt=\"cassandra1\" \/><\/a><\/p>\n<p style=\"color: #555555;\">To treat commands, the main method uses the Apache Commons CLI library which provides an API for parsing command line options. It\u2019s also able to print help messages of all the options available.<\/p>\n<p style=\"color: #555555;\">For each command the NodeCmd switch to the appropriate method to do the job. For that the NodeCmd collaborates with the NodeProbe class.<\/p>\n<h3 style=\"font-weight: bold; color: #555555;\">NodeProbe<\/h3>\n<p style=\"color: #555555;\">Let\u2019s discover how NodeProbe achieve its task, for that we can search for all types used by it.<\/p>\n<pre style=\"color: #555555;\">from t in Types where t.IsUsedBy (\"org.apache.cassandra.tools.NodeProbe\")\r\nselect new { t }\r\n<\/pre>\n<p style=\"color: #555555;\"><a style=\"color: #2970a6;\" href=\"https:\/\/javadepend.files.wordpress.com\/2014\/01\/cassandra2.png\"><img decoding=\"async\" class=\"aligncenter size-full wp-image-1026\" src=\"https:\/\/javadepend.files.wordpress.com\/2014\/01\/cassandra2.png?w=595\" alt=\"cassandra2\" \/><\/a><\/p>\n<p style=\"color: #555555;\">The NodeProbe class uses mainly the management beans; it acts as a facade and redirects each command to the appropriate JMX bean.<\/p>\n<p style=\"color: #555555;\">Here is the list of all Cassandra JMX beans:<\/p>\n<pre style=\"color: #555555;\">from t in Types\r\nwhere t.NameLike (@\"mbean\\i\") &amp;&amp; t.IsInterface \r\nselect  t\r\n<\/pre>\n<p style=\"color: #555555;\"><a style=\"color: #2970a6;\" href=\"https:\/\/javadepend.files.wordpress.com\/2014\/01\/cassandra3.png\"><img decoding=\"async\" class=\"aligncenter size-full wp-image-1027\" src=\"https:\/\/javadepend.files.wordpress.com\/2014\/01\/cassandra3.png?w=595\" alt=\"cassandra3\" \/><\/a><\/p>\n<p style=\"color: #555555;\">Many managed beans are available which gives the possibility to create tools exploiting their capabilities, to help administrators monitor and manage the Cassandra cluster.<\/p>\n<p style=\"color: #555555;\">The idea of such tools is to interact with the JMX beans and invoke some of their methods, for that we need to create a JMX proxy by invoking JMX.newMBeanProxy.<\/p>\n<p style=\"color: #555555;\">Let\u2019s search for methods which create a JMX proxy.<\/p>\n<pre style=\"color: #555555;\">from m in Methods where m.IsUsing (\"javax.management.JMX.newMBeanProxy(MBeanServerConnection,ObjectName,Class)\")\r\nselect new { m, m.NbBCInstructions }\r\n<\/pre>\n<p style=\"color: #555555;\"><a style=\"color: #2970a6;\" href=\"https:\/\/javadepend.files.wordpress.com\/2014\/01\/cassandra4.png\"><img decoding=\"async\" class=\"aligncenter size-full wp-image-1028\" src=\"https:\/\/javadepend.files.wordpress.com\/2014\/01\/cassandra4.png?w=595\" alt=\"cassandra4\" \/><\/a><\/p>\n<p style=\"color: #555555;\">The NodeProbe which acts as a facade create these proxies, we can take as example the connect method which is invoked to create these proxies, and discover some methods invoked by it.<\/p>\n<p style=\"color: #555555;\"><a style=\"color: #2970a6;\" href=\"https:\/\/javadepend.files.wordpress.com\/2014\/01\/cassandra5.png\"><img decoding=\"async\" class=\"aligncenter size-full wp-image-1029\" src=\"https:\/\/javadepend.files.wordpress.com\/2014\/01\/cassandra5.png?w=595\" alt=\"cassandra5\" \/><\/a><\/p>\n<p style=\"color: #555555;\">After the creation of proxies, all the commands will be just a redirection, for example let\u2019s search for methods used by NodeProbe.forceRemoveCompletion.<\/p>\n<pre style=\"color: #555555;\">from m in Methods where m.IsUsedBy (\"org.apache.cassandra.tools.NodeProbe.forceRemoveCompletion()\")\r\nselect new { m, m.NbBCInstructions }\r\n<\/pre>\n<p style=\"color: #555555;\"><a style=\"color: #2970a6;\" href=\"https:\/\/javadepend.files.wordpress.com\/2014\/01\/cassandra6.png\"><img decoding=\"async\" class=\"aligncenter size-full wp-image-1030\" src=\"https:\/\/javadepend.files.wordpress.com\/2014\/01\/cassandra6.png?w=595\" alt=\"cassandra6\" \/><\/a><\/p>\n<p style=\"color: #555555;\">Only the StorageServiceMBean.forceRemoveCompletion is used, all the logic of the treatment is in the server side. TheStorageServiceMBean is implemented by the StorageService class and here are all methods used by the StoageService. forceRemoveCompletion method:<\/p>\n<p style=\"color: #555555;\"><a style=\"color: #2970a6;\" href=\"https:\/\/javadepend.files.wordpress.com\/2014\/01\/cassandra7.png\"><img decoding=\"async\" class=\"aligncenter size-full wp-image-1031\" src=\"https:\/\/javadepend.files.wordpress.com\/2014\/01\/cassandra7.png?w=595\" alt=\"cassandra7\" \/><\/a><\/p>\n<h3 style=\"font-weight: bold; color: #555555;\">Refactor to enforce the responsibility principle<\/h3>\n<p style=\"color: #555555;\">We discovered that NodeCmd parse the command line options and delegate the job to the NodeProbe class which is just a facade to the JMX beans, but what about NodeCmd class, it uses any JMX beans directly?<\/p>\n<p style=\"color: #555555;\">The NodeCmd uses the EndpointSnitchInfoMBean JMX bean, and here are all the methods using this bean.<\/p>\n<pre style=\"color: #555555;\">from m in Methods where m.IsUsing (\"org.apache.cassandra.locator.EndpointSnitchInfoMBean\")\r\nselect new { m, m.NbBCInstructions }\r\n<\/pre>\n<p style=\"color: #555555;\"><a style=\"color: #2970a6;\" href=\"https:\/\/javadepend.files.wordpress.com\/2014\/01\/cassandra9.png\"><img decoding=\"async\" class=\"aligncenter size-full wp-image-1034\" src=\"https:\/\/javadepend.files.wordpress.com\/2014\/01\/cassandra9.png?w=595\" alt=\"cassandra9\" \/><\/a><\/p>\n<p style=\"color: #555555;\">Both NodeCmd and NodeProbe use it, the NodeCmd doesn\u2019t have the proxy but ask it from the NodeProbe class as shown in this dependency graph:<\/p>\n<p style=\"color: #555555;\"><a style=\"color: #2970a6;\" href=\"https:\/\/javadepend.files.wordpress.com\/2014\/01\/cassandra10.png\"><img decoding=\"async\" class=\"aligncenter size-full wp-image-1033\" src=\"https:\/\/javadepend.files.wordpress.com\/2014\/01\/cassandra10.png?w=595\" alt=\"cassandra10\" \/><\/a><\/p>\n<p style=\"color: #555555;\">To enforce the single responsibility principle it&#8217;s better to refactor the nodetool and let only NodeProbe redirect commands to the JMX proxies, and acts as the only facade to the management capabilities, and the responsibility of the NodeCmd will be only the parsing of the command line and redirect to the NodeProbe class.<\/p>\n<p>&nbsp;<\/p>\n","protected":false},"excerpt":{"rendered":"<p>Let&#8217;s start with the single responsibility principle from wikipedia: In object-oriented programming, the single responsibility principle states that every class should have responsibility over a single part of the functionality provided by the software, and that responsibility should be entirely encapsulated by the class. All its servicesshould be narrowly aligned with that responsibility.<\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[],"tags":[],"class_list":["post-1762","post","type-post","status-publish","format-standard","hentry"],"_links":{"self":[{"href":"https:\/\/codergears.com\/Blog\/index.php?rest_route=\/wp\/v2\/posts\/1762","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/codergears.com\/Blog\/index.php?rest_route=\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/codergears.com\/Blog\/index.php?rest_route=\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/codergears.com\/Blog\/index.php?rest_route=\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/codergears.com\/Blog\/index.php?rest_route=%2Fwp%2Fv2%2Fcomments&post=1762"}],"version-history":[{"count":6,"href":"https:\/\/codergears.com\/Blog\/index.php?rest_route=\/wp\/v2\/posts\/1762\/revisions"}],"predecessor-version":[{"id":1768,"href":"https:\/\/codergears.com\/Blog\/index.php?rest_route=\/wp\/v2\/posts\/1762\/revisions\/1768"}],"wp:attachment":[{"href":"https:\/\/codergears.com\/Blog\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=1762"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/codergears.com\/Blog\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=1762"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/codergears.com\/Blog\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=1762"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}