cassandra高级操作之JMX操作
前言
路漫漫其修远兮,吾将上下而求索!
github:https://github.com/youzhibing
码云(gitee):https://gitee.com/youzhibing
需求场景
项目中有这么个需求:统计集群中各个节点的数据量存储大小,不是记录数。
一开始有点无头绪,后面查看cassandra官方文档看到Monitoring章节,里面说到:Cassandra中的指标使用Dropwizard Metrics库进行管理。 这些指标可以通过JMX查询,也可以使用多个内置和第三方报告插件推送到外部监控系统(Jconsole)。那么数据量存储大小是不是也是cassandra的某项指标了? 带着疑问,我通过Jconsole看到了cassandra的一些指标(先启动cassandra, 运行 -> Jconsole),如下图
数据量存储大小就在叫org.apache.cassandra.db的MBean中,具体会在之后介绍。
JMX定义
引用JMX超详细解读中一段话:
JMX(Java Management Extensions)是一个为应用程序植入管理功能的框架。JMX是一套标准的代理和服务,实际上,用户可以在任何Java应用程序中使用这些代理和服务实现管理。这是官方文档上的定义,我看过很多次也无法很好的理解。
我个人的理解是JMX让程序有被管理的功能,例如你开发一个WEB网站,它是在24小时不间断运行,那么你肯定会对网站进行监控,如每天的UV、PV是多少;又或者在业务高峰的期间,你想对接口进行限流,就必须去修改接口并发的配置值。 应用场景:中间件软件WebLogic的管理页面就是基于JMX开发的,而JBoss则整个系统都基于JMX构架,另外包括cassandra中各项指标的管理。 对于一些参数的修改,网上有一段描述还是比较形象的: 1、程序初哥一般是写死在程序中,到要改变的时候就去修改代码,然后重新编译发布。 2、程序熟手则配置在文件中(JAVA一般都是properties文件),到要改变的时候只要修改配置文件,但还是必须重启系统,以便读取配置文件里最新的值。 3、程序好手则会写一段代码,把配置值缓存起来,系统在获取的时候,先看看配置文件有没有改动,如有改动则重新从配置里读取,否则从缓存里读取。 4、程序高手则懂得物为我所用,用JMX把需要配置的属性集中在一个类中,然后写一个MBean,再进行相关配置。另外JMX还提供了一个工具页,以方便我们对参数值进行修改。
给我的感觉,jmx server进行监听,jmx client进行请求的发送,以此达到通信的目的;cassandra的jmx server已经被cassandra实现,我们只需要实现jmx client,就能从cassandra进程中拿到我们需要的指标数据。
JMX Server
MBean接口定义
接口的命名规范为以具体的实现类为前缀(这个规范很重要),动态代理的过程中需要用到这点。
public interface HelloMBean
{
String getName();
void setName(String name); void print();
}
MBean接口实现
实现上面的接口:
public class Hello implements HelloMBean
{ private String name; @Override
public String getName()
{
return this.name;
} @Override
public void setName(String name)
{
this.name = name;
} @Override
public void print()
{
System.out.println("hello, print");
} }
jmx server实现
定义一个jmx server,并启动它
public class HelloService
{
private static final int RMI_PORT = 8099;
private static final String JMX_SERVER_NAME = "TestJMXServer";
private static final String USER_NAME = "hello";
private static final String PASS_WORD = "world"; public static void main(String[] args) throws Exception
{
HelloService service = new HelloService();
service.startJmxServer();
} private void startJmxServer() throws Exception
{
//MBeanServer mbs = MBeanServerFactory.createMBeanServer(jmxServerName);
MBeanServer mbs = this.getMBeanServer(); // 在本地主机上创建并输出一个注册实例,来接收特定端口的请求
LocateRegistry.createRegistry(RMI_PORT, null, RMISocketFactory.getDefaultSocketFactory()); JMXServiceURL url = new JMXServiceURL("service:jmx:rmi:///jndi/rmi://localhost:" + RMI_PORT + "/" + JMX_SERVER_NAME);
System.out.println("JMXServiceURL: " + url.toString()); Map<String, Object> env = this.putAuthenticator(); //JMXConnectorServer jmxConnServer = JMXConnectorServerFactory.newJMXConnectorServer(url, null, mbs); // 不加认证
JMXConnectorServer jmxConnServer = JMXConnectorServerFactory.newJMXConnectorServer(url, env, mbs); // 加认证
jmxConnServer.start();
} private MBeanServer getMBeanServer() throws Exception
{
MBeanServer mbs = ManagementFactory.getPlatformMBeanServer();
ObjectName objName = new ObjectName(JMX_SERVER_NAME + ":name=" + "hello");
mbs.registerMBean(new Hello(), objName);
return mbs;
} private Map<String, Object> putAuthenticator()
{
Map<String,Object> env = new HashMap<String,Object>();
JMXAuthenticator auth = createJMXAuthenticator();
env.put(JMXConnectorServer.AUTHENTICATOR, auth); env.put("com.sun.jndi.rmi.factory.socket", RMISocketFactory.getDefaultSocketFactory());
return env;
} private JMXAuthenticator createJMXAuthenticator()
{
return new JMXAuthenticator()
{
public Subject authenticate(Object credentials)
{
String[] sCredentials = (String[]) credentials;
if (null == sCredentials || sCredentials.length != 2)
{
throw new SecurityException("Authentication failed!");
}
String userName = sCredentials[0];
String password = sCredentials[1];
if (USER_NAME.equals(userName) && PASS_WORD.equals(password))
{
Set<JMXPrincipal> principals = new HashSet<JMXPrincipal>();
principals.add(new JMXPrincipal(userName));
return new Subject(true, principals, Collections.EMPTY_SET,
Collections.EMPTY_SET);
}
throw new SecurityException("Authentication failed!");
}
};
}
}
点下print按钮,你会发现控制台会打印:hello, print
cassandra的jmx server已经自己实现了,我们不需要实现它,我们需要实现的是调用它。
JMX client
这个是我们需要关注和实现的
client端接口定义
接口中定义的方法是我们需要调用的,方法名必须与server端暴露的方法一样,通过server端动态生成client端的实例,实例中的方法只包括client端接口中定义的方法(若server端暴露的是属性,那么直接在属性前加get,后面cassandra部分会讲到)
public interface HelloClientMBean
{
void print(); // 方法定义与server端暴露的方法一致
}
连接jmx server
public class HelloClient implements AutoCloseable
{
private static final String fmtUrl = "service:jmx:rmi:///jndi/rmi://[%s]:%d/TestJMXServer";
private static final String ssObjName = "TestJMXServer:name=hello";
private static final int defaultPort = 1099; // cassandra默认端口是7199
final String host;
final int port;
private String username;
private String password; private JMXConnector jmxc;
private MBeanServerConnection mbeanServerConn;
private HelloMBean hmProxy; /**
* Creates a connection using the specified JMX host, port, username, and password.
*
* @param host hostname or IP address of the JMX agent
* @param port TCP port of the remote JMX agent
* @throws IOException on connection failures
*/
public HelloClient(String host, int port, String username, String password) throws IOException
{
assert username != null && !username.isEmpty() && password != null && !password.isEmpty()
: "neither username nor password can be blank"; this.host = host;
this.port = port;
this.username = username;
this.password = password;
connect();
} /**
* Creates a connection using the specified JMX host and port.
*
* @param host hostname or IP address of the JMX agent
* @param port TCP port of the remote JMX agent
* @throws IOException on connection failures
*/
public HelloClient(String host, int port) throws IOException
{
this.host = host;
this.port = port;
connect();
} /**
* Creates a connection using the specified JMX host and default port.
*
* @param host hostname or IP address of the JMX agent
* @throws IOException on connection failures
*/
public HelloClient(String host) throws IOException
{
this.host = host;
this.port = defaultPort;
connect();
} /**
* Create a connection to the JMX agent and setup the M[X]Bean proxies.
*
* @throws IOException on connection failures
*/
private void connect() throws IOException
{
JMXServiceURL jmxUrl = new JMXServiceURL(String.format(fmtUrl, host, port));
Map<String,Object> env = new HashMap<String,Object>();
if (username != null)
{
String[] creds = { username, password };
env.put(JMXConnector.CREDENTIALS, creds);
} env.put("com.sun.jndi.rmi.factory.socket", getRMIClientSocketFactory()); jmxc = JMXConnectorFactory.connect(jmxUrl, env);
mbeanServerConn = jmxc.getMBeanServerConnection(); try
{
ObjectName name = new ObjectName(ssObjName);
hmProxy = JMX.newMBeanProxy(mbeanServerConn, name, HelloMBean.class);
}
catch (MalformedObjectNameException e)
{
throw new RuntimeException(
"Invalid ObjectName? Please report this as a bug.", e);
}
} private RMIClientSocketFactory getRMIClientSocketFactory() throws IOException
{
if (Boolean.parseBoolean(System.getProperty("ssl.enable")))
return new SslRMIClientSocketFactory();
else
return RMISocketFactory.getDefaultSocketFactory();
} public void print()
{
hmProxy.print();
} @Override
public void close() throws Exception
{
jmxc.close();
}
}
接口调用
public class JmxClient
{
public static void main(String[] args) throws Exception
{
HelloClient client = new HelloClient("localhost", 8099, "hello", "world");
client.print();
client.close();
} }
会在控制台打印:hello, print。
统计cassandra集群中各个节点的数据量存储大小
回到我们的项目需求,如何实现呢? 也分3步
client端接口定义
因为我们只关心数据量存储大小,所以我们只需要在接口定义一个方法
public interface StorageServiceMBean
{
/** Human-readable load value. Keys are IP addresses. */
public Map<String, String> getLoadMap(); // cassandra端暴露的是属性LoadMap,那么此方法名由get加LoadMap组成, 那么getLoad方法就可以获取LoadMap的值
}
连接jmx server
cassandra-env.sh配置文件中有cassandra的JMX默认端口:JMX_PORT="7199"
public class CassNodeProbe implements AutoCloseable
{
private static final String fmtUrl = "service:jmx:rmi:///jndi/rmi://[%s]:%d/jmxrmi";
private static final String ssObjName = "org.apache.cassandra.db:type=StorageService";
private static final int defaultPort = 7199;
final String host;
final int port;
private String username;
private String password; private JMXConnector jmxc;
private MBeanServerConnection mbeanServerConn;
private StorageServiceMBean ssProxy; /**
* Creates a NodeProbe using the specified JMX host, port, username, and password.
*
* @param host hostname or IP address of the JMX agent
* @param port TCP port of the remote JMX agent
* @throws IOException on connection failures
*/
public CassNodeProbe(String host, int port, String username, String password) throws IOException
{
assert username != null && !username.isEmpty() && password != null && !password.isEmpty()
: "neither username nor password can be blank"; this.host = host;
this.port = port;
this.username = username;
this.password = password;
connect();
} /**
* Creates a NodeProbe using the specified JMX host and port.
*
* @param host hostname or IP address of the JMX agent
* @param port TCP port of the remote JMX agent
* @throws IOException on connection failures
*/
public CassNodeProbe(String host, int port) throws IOException
{
this.host = host;
this.port = port;
connect();
} /**
* Creates a NodeProbe using the specified JMX host and default port.
*
* @param host hostname or IP address of the JMX agent
* @throws IOException on connection failures
*/
public CassNodeProbe(String host) throws IOException
{
this.host = host;
this.port = defaultPort;
connect();
} /**
* Create a connection to the JMX agent and setup the M[X]Bean proxies.
*
* @throws IOException on connection failures
*/
private void connect() throws IOException
{
JMXServiceURL jmxUrl = new JMXServiceURL(String.format(fmtUrl, host, port));
Map<String,Object> env = new HashMap<String,Object>();
if (username != null)
{
String[] creds = { username, password };
env.put(JMXConnector.CREDENTIALS, creds);
} env.put("com.sun.jndi.rmi.factory.socket", getRMIClientSocketFactory()); jmxc = JMXConnectorFactory.connect(jmxUrl, env);
mbeanServerConn = jmxc.getMBeanServerConnection(); try
{
ObjectName name = new ObjectName(ssObjName);
ssProxy = JMX.newMBeanProxy(mbeanServerConn, name, StorageServiceMBean.class);
}
catch (MalformedObjectNameException e)
{
throw new RuntimeException(
"Invalid ObjectName? Please report this as a bug.", e);
}
} private RMIClientSocketFactory getRMIClientSocketFactory() throws IOException
{
if (Boolean.parseBoolean(System.getProperty("ssl.enable")))
return new SslRMIClientSocketFactory();
else
return RMISocketFactory.getDefaultSocketFactory();
} public Map<String, String> getCassClusterStorage()
{
return ssProxy.getLoadMap();
} @Override
public void close() throws Exception
{
jmxc.close();
}
}
接口调用
public class JMXTest
{ public static void main(String[] args) throws Exception
{
CassNodeProbe prode = new CassNodeProbe("127.0.0.1");
Map<String, String> nodeStorages = prode.getCassClusterStorage();
System.out.println(nodeStorages);
prode.close();
} }
最后得到结果:{127.0.0.1=266.36 KB}
cassandra的jmx 认证访问我就不做演示了,大家自己去实现。
cassandra-all
cassandra给我们提供了工具jar,也就是cassandra jmx client实现,jmx server暴露的在这个工具jar中都有对应的请求方式;
如若大家用到的很少则可以自己实现,而不需要用cassandra-all,当然我们可以拷贝cassandra-all中我们需要的代码到我们的工程中,那么我们就可以不用引用此jar,但是又满足了我们的需求
<dependency>
<groupId>org.apache.cassandra</groupId>
<artifactId>cassandra-all</artifactId>
<version>2.1.14</version>
</dependency>
参考
http://www.cnblogs.com/FlyAway2013/p/jmx.html
http://www.cnblogs.com/dongguacai/p/5900507.html
cassandra高级操作之JMX操作的更多相关文章
- 第一百七十一节,jQuery,高级事件,模拟操作,命名空间,事件委托,on、off 和 one
jQuery,高级事件,模拟操作,命名空间,事件委托,on.off 和 one 学习要点: 1.模拟操作 2.命名空间 3.事件委托 4.on.off 和 one jQuery 不但封装了大量常用的事 ...
- 【如何让代码变“高级”(二)】-这样操作值得一波666(Java Stream)(这么有趣)
[如何让代码变“高级”(二)]-这样操作值得一波666(Java Stream)(这么有趣) 开发中的代码 在开发中的代码是不是很常见这样的代码: 这样的? for循环取元素取值 List<Us ...
- Laravel框架数据库CURD操作、连贯操作
这篇文章主要介绍了Laravel框架数据库CURD操作.连贯操作.链式操作总结,本文包含大量数据库操作常用方法,需要的朋友可以参考下 一.Selects 检索表中的所有行 $users = DB::t ...
- Laravel框架数据库CURD操作、连贯操作总结
这篇文章主要介绍了Laravel框架数据库CURD操作.连贯操作.链式操作总结,本文包含大量数据库操作常用方法,需要的朋友可以参考下 一.Selects 检索表中的所有行 复制代码代码如下: $use ...
- MySQL(一) -- MySQL学习路线、数据库的基础、关系型数据库、关键字说明、SQL、MySQL数据库、MySQL服务器对象、SQL的基本操作、库操作、表操作、数据操作、中文数据问题、 校对集问题、web乱码问题
1 MySQL学习路线 基础阶段:MySQL数据库的基本操作(增删改查),以及一些高级操作(视图.触发器.函数.存储过程等). 优化阶段:如何提高数据库的效率,如索引,分表等. 部署阶段:如何搭建真实 ...
- Django(八)上:Model操作和Form操作
↑↑↑点上面的”+”号展开目录 Model和Form以及ModelForm简介 Model操作: 创建数据库表结构 操作数据库表 做一部分的验证 Form操作: 数据验证(强大) ModelForm ...
- Day23-Model操作和Form操作-转载
参考出处: http://blog.csdn.net/fgf00/article/details/54614706 Model和Form以及ModelForm简介 Model操作: 创建数据库表结构 ...
- jquery实现点击展开列表同时隐藏其他列表 js 对象操作 对象原型操作 把一个对象A赋值给另一个对象B 并且对象B 修改 不会影响 A对象
这篇文章主要介绍了jquery实现点击展开列表同时隐藏其他列表的方法,涉及jquery鼠标事件及节点的遍历与属性操作技巧,具有一定参考借鉴价值,需要的朋友可以参考下 本文实例讲述了jquery实现点击 ...
- IDEA04 工具窗口管理、各种跳转、高效定位、行操作、列操作、live template、postfix、alt enter、重构、git使用
1 工具窗口管理 所有的窗口都是在view -> tools windows 下面的,这些窗口可以放在IDEA的上下左右各个位置:右键某个窗口后选择move to 即可进行位置调整 2 跳转 2 ...
随机推荐
- 读书笔记 effective c++ Item 18 使接口容易被正确使用,不容易被误用
1. 什么样的接口才是好的接口 C++中充斥着接口:函数接口,类接口,模板接口.每个接口都是客户同你的代码进行交互的一种方法.假设你正在面对的是一些“讲道理”的人员,这些客户尝试把工作做好,他们希望能 ...
- 纪中集训 Day 5
不知不觉已经day 5了啊 今天早上醒来,觉得要AK的节奏,结果就立flag了 - - 30分QAQ 其实第一题应该得想得到的,还有T2也能够解决的(话说后来看别人的代码写的好赞啊QAQ) 然后下午就 ...
- 使用splice实现高效的代理服务器
很多网络应用场景下, 当原设备与目标设备无法直接建立连接时,这时就需要一台代理服务器进行中转.代理服务器只需要将来自源设备的报文 原封不动的转发给目标设备,而并不需要知道报文的具体内容.在这种情况下, ...
- 如何在网上得到你想要的图片,如logo
比如我们想得到网页:http://www.ahnu.edu.cn/里的安徽师范大学logo,可以这样做: 1.Ctrl+U,便进入了网页源代码页,也可以鼠标右键点"查看网页源代码" ...
- 【CNMP系列】CentOS7.0下安装MySql5.6服务
接上一回的话,CentOS7.0下安装好了Nginx服务,对于我们的CNMP,我们可以开始我们的M啦,就是传统意义上的MySql服务 MySql简介 MySQL是一个关系型数据库管理系统,由瑞典MyS ...
- Java显式锁学习总结之六:Condition源码分析
概述 先来回顾一下java中的等待/通知机制 我们有时会遇到这样的场景:线程A执行到某个点的时候,因为某个条件condition不满足,需要线程A暂停:等到线程B修改了条件condition,使con ...
- table标签中thead、tbody、tfoot的作用
为了让大表格(table)在下载的时候可以分段的显示,就是说在浏览器解析HTML时,table是作为一个整体解释的,使用tbody可以优化显示.如果表格很长,用tbody分段,可以一部分一部分地显示, ...
- Python拉勾爬虫——以深圳地区数据分析师为例
拉勾因其结构化的数据比较多因此过去常常被爬,所以在其多次改版之下变得难爬.不过只要清楚它的原理,依然比较好爬.其机制主要就是AJAX异步加载JSON数据,所以至少在搜索页面里翻页url不会变化,而且数 ...
- 自定义 Layout布局 UICollectionViewLayout
from: http://www.tuicool.com/articles/vuyIriN 当我们使用系统自带的UICollectionViewFlowLayout无法实现我们的布局时,我们就可以 ...
- canvas的beginPath和closePath分析总结,包括多段弧的情况
参考博文: Html5 canvas画图教程17:论beginPath的重要性 先看两个例子 例1: <canvas id="myCanvas" width="30 ...