分布式系统监控:通过JMX看对象模型的优势

发表于2016-04-13
评论0 7.8k浏览
  摘要:JMX以对象模型构造了简易的远程编程接口和扩展框架,对比传统的命令、信号提供了更多的语意支持和更好的底层通信封装。

 

  在Java的圈子里面,任何一个技术产品,一般会先公开一系列的接口定义,然后推出对这个接口的一系列实现软件,这种做法,是一个对软件开发非常有益的进步。因为这让使用这些的程序员,仅仅学习一份接口的定义,就能完成自己想要的功能,至于选择不同的实现软件,完全无需修改代码。比如JDK中的java.sql.*,就让JAVA程序员无需去学习各家SQL数据不同的API写法;javax.servlet.*规定了JAVA的Web应用程序的使用接口,使用者可以按照这个接口编写程序,在Apache Tomcat、Caucho Resin、Weblogic、甚至是Google App Engine上无需修改的运行。同样,JMX也是这样的一种技术,他带有一系列的编程接口定义,以及在JDK中实现的一套运行代码。


  那么,JMX到底是什么东西呢?它其实是Java Management eXtensions的缩写。大家在运营实际项目的过程中,特别是服务器端项目,往往都会有这种经验:盯着自己写的那个 Java进程,心里在想,它到底在什么?为什么用了这么长的时间?于是我们常常会想用JDK自带的诊断工具jmap或者jstack来一探究竟,但是又很担心影响性能。所以那些有经验的程序员,在编写程序的时候,往往会预先嵌入一些程序,专门用来反馈程序的运行状态。这些后门有时候简单的只是打一下日志,又有时候会是一些不断统计的运行时数据,比如在线连接数、请求的平均消耗时长……。但是这些代码,不同的程序员有不同的做法,记录的数据也是五花八门,由于这些功能实际上往往缺乏文档(这些基本上是技术需求,少有产品人员参与),如果要交接给其他程序员,一般都很难掌握。因此就时常会出现这种情况,一个程序出问题,当前的维护人员查了半天没找出原因,找来原作者后,他翻了翻日志就发现了原因。这种事情的原因就是,我们的系统对于“监控”功能缺乏规划,没有规范或者框架所导致的。而JMX,正是一套用于监控JAVA程序运行时状况的规范。


  很多时候我们查看监控数据,都是在简陋的字符命令行界面查询日志,但是如果我们使用了JMX就不同了,按这个规范编写的监控数据,能很简单的通过网络传递,并绘制到图形程序上,甚至JDK就自带了一个这样的监控界面程序:jconsole。我们在大型的分布式系统运营的时候,不可能一个个服务器去查看监控数据,一般都需要通过网络把监控数据集中处理,通过图形来显示。有很多系统都是程序员自己去预埋监控代码、编写监控数据的网络收发模块,然后再编写运维监控的集中处理界面。这种监控在不同的应用里面,往往各自都有一套,实际上这些代码中,有很多功能是重复的。JMX为这种通过网络搜集监控数据的功能,提供了一套良好的接口定义和底层网络实现。


  我们在运营一些游戏服务器、聊天服务器这类在线服务系统的时候,往往需要对这些在线服务进程发送一些特殊命令,比如踢某个用户下线、封某个IP禁止访问,或者其他很多业务相关的功能。然而,在Linux下,对于运行时进程进行控制的手段,是非常有限的,比较常用的有发送信号,预埋共享内存消息队列服务,通过socket通信端口插入特殊控制包这几种。然而,信号的个数有限,单独使用能表达的含义太少;使用共享内存、socket来对进程控制,编程复杂度又大大的提升。所以很多游戏服务器开发团队,都会开发一个叫GM系统的后门系统,提供给客服或运营人员使用,用socket或者共享内存发送“管理命令”到目标进程,执行预定的管理逻辑。不过如果你开发了多个这样的系统,可能你会对反复的写GM系统非常厌烦。能不能有一种更通用而简单的方法,来写这种“后门”系统呢?JMX正是这样的一种框架:它不但可以用来输出监控数据,还可以作为操作的入口,对运行中的程序执行各种自定义的逻辑命令。
 
  上面说了很多JMX的功能,其实核心只有三个:数据监视、控制命令、网络传输。一个需要展示的数据,会通过:数据搜集代码、网络传输代码、显示绘制代码三个部分。一个需要产生操作的控制命令,会通过:显示预设命令操作并绘制面板界面、网络命令传输、预设命令执行三个部分。因此JMX对这三个层次的功能,进行了定义和实现:
  1. Resources层,这部分包含了一系列Java Interface定义,用户按照这些接口编写的代码,就能成为JMX资源,嵌入到JAVA进程中,随时提供服务
  2. JMX核心层,这部分是JDK实现的代码,它为Resources接口的实现者对象,提供注册、发现、远程调用的功能,同时也包含了网络传输的功能。
  3. Management System层,这一层主要是用户自己编写的监控程序。由于JDK提供了JMX的实现,因此JAVA程序能很方便的通过“JMX核心”对“Resources层”的对象通过网络操作,比如读取这些对象的属性、执行某些预定的方法。
  在JMX中,Resources对象被称为MBean对象,这种对象需要符合MBean的一些形式。而JMX核心由两个子层次实现:Agent Level代理层,由JDK中的MBean Server类实现,主要提供对MBean的各种管理; Connector Level连接层,主要负责网络部分功能,实现一个MBean对象在网络上传输。
  这部分JDK实现了一些,比如RMI Adapter使用的是JAVA RMI的远程调用连接,又或者HTTP Adapter使用标准HTTML协议传递MBean对象。但是也可以通过继承Connector的接口自己实现,比如你可以建立SNMP协议的Adapter,或者用UDP协议来传输……。MBean对象、MBean Server、各种Connector Adapter,都是在一个JAVA Server进程中运行,在此之外,我们针对各种Adapter,编写各种通过网络来操控MBean的监控界面程序,这些程序统称为Remote Manager程序,其中有JDK提供的标准JMX Manager程序,这个程序使用的JDK自带的RMI Adapter;也可以直接使用Web浏览器访问HTTP Adapter提供的数据等等。


  JMX的核心接口是MBean形式,。由于Java有反射的能力,所以编写MBean无需继承任何预定的接口,而仅仅是要符合几个约定即可:
  (1) 接口名字以MBean结尾
  (2) 属性符合JavaBean规范,带getter或者setter方法
  (3) 方法是public void的
  只要一个Interface符合以上的约定,其实现者对象,就能成为一个MBean对象,被MBean Server所接受,其中带getter/setter方法会被认为是用以监视、修改的变量属性,而public void的方法则可以被直接远程调用以产生控制命令。MBean对象可以是任何功能的代码,比如这个对象中包含了对在线用户的统计数据,对恶意用户的踢下线、封IP功能等等……

  一旦我们编写好一个MBean接口和它的实现类,我们就能在任意的Java进程中插入代码,向MBeanServer注册这个MBean对象,注意注册时可以输入一个字符串作为这个对象的“名字”,MBeanServer可以利用这个“名字”在显示界面(Remote Manager)程序那里,用来做筛选、树状显示、标签等任何功能。比如JDK自带的JMX Manager就使用形式如:”myapp:type=webserver, name=Port 8080”的字符串,用来展示myapp/webserver/Port 8080的树状对象。

  JDK自带的 JConsole软件,能连接到任何一个本地的JAVA进程或远程网络JAVA进程。我们能看到你注册的MBean的对象,以及好多JDK自己注册的MBean对象。这些对象以ObjectName字符串的“名字:type=…, name=…”的格式放在树里面供检索。任何一个对象都可以在Attribute页对其属性进行读写,对于方法还可以在Operations页进行按钮操作。

  JMX协议,对于被管理的“后门对象”而言,就是一个接口的约定形式——MBean形式。这个形式非常简单,只有三条规则,很容易实现。这个接口的三类约定方法,最后会被塑造成三种监控行为接口:属性(读、写);调用;监听(这个刚才的例子没有提及)。然而,如果你已经写了一大堆监控代码,回头想接入到MBean这个规范里面,JMX也贴心的提供了方案:DynamicMBean接口。你的监控代码需要实现这个接口,然后通过Object getAttribute(String attribute) 这个方法返回你所有的属性对象;通过MBeanInfo getMBeanInfo()返回对于这个监控对象的MBean信息,比如名字什么的。
 
  当然我们不可能仅仅靠JConsole就能管理任何的服务进程,所以我们常常要自己编写很多RemoteManager系统。我们可以通过实现一系列“Manager接口”来实现:
  JMXServiceURL – 支持多种协议的JMX连接
  JMXConnector – 实现JMX连接
  MBeanServerConnection – 提供具体MBeanServer
  NotificationListener – 接收MBean的通知和属性变化
  MX.newMBeanProxy() – 构造一个远程MBean对象的本地代理对象,用以直接操作MBean对像
  通过ObjectName来定位:”type=… name=…”
  通过MBean接口来调用方法

  现在越来越多的软件,都自带了 Web协议的MBeanServer功能,可以直接通过浏览器来做监控,比如Tomcat/JBoss/ZooKeeper等等。现在市场上,也有很多企业,专门利用那些软件中的MBean,编写各种漂亮、好用的MBeanServer/Remote Manager来赚钱。


  我们可以对比一下JMX和其他监控系统的思路的差别:
  (1)一般监控系统只有对某些数据进行内部采样统计,然后提供读取功能;JMX提供了基于属性的读、写两个能力;同时还有监听器的能力,可以自动一直的搜集采样数据。
  (2)一般监控系统使用类似命令行命令的方式进行操控,而JMX提供了基于方法函数的控制操作接口,还有“通知“的模型接口。
  (3)一般的监控系统其网络通信协议五花八门,而JMX提供了标准的JAVA RMI实现,同时也可以扩展HTTP和其他任何的协议。
  (4)一般的监控系统的操作界面程序,需要专门针对某个业务系统去开发,非常繁琐和重复;而JMX采用反射方法,可以开发通用的监控系统界面,也可以使用叫Proxy的接口,定制专用的界面。

  总体来说,JMX所有的功能,都是装载一个标准化的盒子里面。而这个盒子的基础,正是面向对象的思路:
  (1)对象具备属性和方法,匹配成监控系统中的“属性”和“操作”
  (2)使用Connector接口来集成多种不同的监控通信协议
  (3)MBean对象约定和Manager接口提供了对监控系统的基本约束,也提供了巨大的自定扩展
空间
  (4)MBean Server完成了监控系统的主体功能,而各种接口规范了监控系统的细节差别。


  因此,以监控系统这种需求多变的业务领域来看,利用面向对象的思想,是能提供非常好的解决方案。即便是我们以前很习惯用Linux命令、信号、脚本这些运维工具来监控服务器系统,现在看到JMX这种高度规范化的监控框架,也应该认真考虑拥抱面向对象的软件思想吧!

  本文作者个人技术公众号:handa1740168 欢迎关注后和作者交流!

  感谢大家的阅读,如觉得此文对你有那么一丁点的作用,麻烦动动手指转发或分享至朋友圈。如有不同意见,欢迎后台留言探讨。


如社区发表内容存在侵权行为,您可以点击这里查看侵权投诉指引