nodejs 获取 Kafka JMX监控信息

Kafka JMX监控信息

kafka 启用jmx

# ./bin/kafka-run-class.sh
# IP4配置 -Djava.rmi.server.hostname=本机ip4
# JMX settings
if [ -z "$KAFKA_JMX_OPTS" ]; then
  KAFKA_JMX_OPTS="-Dcom.sun.management.jmxremote=true -Dcom.sun.management.jmxremote.authenticate=false -Dcom.sun.management.jmxremote.ssl=false -Djava.rmi.server.hostname=本机ip4 -Djava.net.preferIPv4Stack=true"
fi
# ./bin/kafka-run-class.sh
# 设置 JMX 以进行客户机认证
# 控制该认证的属性为
# com.sun.management.jmxremote.authenticate,必须将其设置为 true。该认证由下列两个其他属性和配置文件进行管理:
# com.sun.management.jmxremote.access.file:此属性指定文件的位置,该文件包含有关访问用户角色和相关联的许可权的信息。
# com.sun.management.jmxremote.password.file:此属性指定文件的位置,该文件包含每个角色的密码。
# 可使用名为 jmxremote.access 和 jmxremote.password 的两个样本文件作为用户角色和密码

if [ -z "$KAFKA_JMX_OPTS" ]; then
  KAFKA_JMX_OPTS="-Dcom.sun.management.jmxremote=true -Dcom.sun.management.jmxremote.authenticate=true -Dcom.sun.management.jmxremote.access.file=./jmx_access.txt -Dcom.sun.management.jmxremote.access.file=./jmx_password.txt -Dcom.sun.management.jmxremote.ssl=false -Djava.rmi.server.hostname=本机ip4 -Djava.net.preferIPv4Stack=true"
fi

# ./jmx_access.txt
 jmxremote.access=admin
 
# ./jmx_password.txt
 jmxremote.password=kafka
# 配置 JMX 端口
# ./bin/kafka-server-start.sh
if [ "x$KAFKA_HEAP_OPTS" = "x" ]; then
    export JMX_PORT=9988
fi
 
# ./bin/kafka-console-producer.sh
if [ "x$KAFKA_HEAP_OPTS" = "x" ]; then
    export JMX_PORT=9989
fi
 
# ./bin/kafka-console-consumer.sh
if [ "x$KAFKA_HEAP_OPTS" = "x" ]; then
    export JMX_PORT=9987
fi
#启动生产者,以监控kafka.producer指标
 bin/kafka-console-producer.sh --bootstrap-server 127.0.0.1:9092 --topic topicName
 
#启动消费者,以监控kafka.consumer指标
 bin/kafka-console-consumer.sh --bootstrap-server 127.0.0.1:9092 --topic topicName
 # kafka 停止
 # 停止时注意顺序 kafka > zookeeper
 sudo systemctl stop zookeeper 
 sudo systemctl stop kafka 
 
 # 或
 
 kafka/bin/kafka-server-stop.sh -daemon  kafka/kafka/config/server.properties
 # kafka 启动
 # 启动时注意顺序 zookeeper > kafka
 sudo systemctl start zookeeper 
 sudo systemctl start kafka 
 
 # 或
 
 kafka/bin/kafka-server-start.sh -daemon  kafka/kafka/config/server.properties

验证当前服务器的kafka是否开启JMX

sudo ./kafka/bin/kafka-run-class.sh kafka.tools.JmxTool --jmx-url service:jmx:rmi:///jndi/rmi://127.0.0.1:9988/jmxrmi --object-name kafka.server:type=BrokerTopicMetrics,name=BytesInPerSec

用到的cjmx jar包

cjmxGitHub


kafka用到的 mbeans 官网mbeabs

cjmx

java -cp $JAVA_HOME/lib/tools.jar:cjmx_2.12-2.8.1-app.jar cjmx.Main  "remote-connect 127.0.0.1:9999" "mbeans 'java.lang:type=OperatingSystem' select OpenFileDescriptorCount"

example

java.lang:type=OperatingSystem
------------------------------
  OpenFileDescriptorCount = 204

cjmx

java -cp $JAVA_HOME/lib/tools.jar:cjmx_2.12-2.8.1-app.jar cjmx.Main  "remote-connect 127.0.0.1:9999" "mbeans 'java.lang:type=OperatingSystem' select *"

example

java.lang:type=OperatingSystem
------------------------------
  OpenFileDescriptorCount = 204
  MaxFileDescriptorCount = 10240
  CommittedVirtualMemorySize = 38951071744
  TotalSwapSpaceSize = 2147483648
  FreeSwapSpaceSize = 1399324672
  ProcessCpuTime = 245404940000
  FreeMemorySize = 15626240
  TotalMemorySize = 17179869184
  CpuLoad = 0.1593305251962664
  ProcessCpuLoad = 3.06505964565591E-4
  FreePhysicalMemorySize = 15233024
  TotalPhysicalMemorySize = 17179869184
  SystemCpuLoad = 0.0
  Name = Mac OS X
  Version = 12.1
  AvailableProcessors = 12
  Arch = x86_64
  SystemLoadAverage = 2.95849609375
  ObjectName = java.lang:type=OperatingSystem

cjmx

java -cp $JAVA_HOME/lib/tools.jar:cjmx_2.12-2.8.1-app.jar cjmx.Main  "remote-connect 127.0.0.1:9999" "mbeans 'java.lang:type=OperatingSystem' select *" |grep OpenFileDescriptorCount|cut -f 4 -w

example

0.0

Node /index.js

const path = require('path');
const { exec } = require("child_process");

function KafkaStats (_options) {
  var options = _options || {};
  this.host = options.host || '127.0.0.1';
  this.normal_port = options.normal_port || '9988';
  this.producer_port = options.producer_port || '9989';
  this.consumer_port = options.consumer_port || '9987';
  this.username = options.username || '';
  this.password = options.password || '';
};

// let grep = "|grep OneMinuteRate|cut -f 4 -w"
// exec(`${jmx_cmd} "${mbeans}" ${grep}`,null, (err, stdout, stderr) => {
//     if(err){
//         console.error(err)
//     } else if(stdout) {
//         console.log(stdout)
//     }
// })

KafkaStats.prototype.queryMBeans = async function queryMBeans(params) {

  let jmx_jar = 'cjmx_2.12-2.8.1-app.jar';
  let jmx_path = 'java -cp $JAVA_HOME/lib/tools.jar:' + jmx_jar + ' cjmx.Main';
  let jmx_format = 'format text';

  let MBeans = params.mbeans.split(',').map( r => `"mbeans '${r.replace(/&/g, ',')}' select *"`);
  let fields = params.fields ? params.fields.split(',') : [];
  let kafkaMBeans = { 
      producer: MBeans.filter( r =>  r && r.includes('kafka.producer')),
      consumer: MBeans.filter( r =>  r && r.includes('kafka.consumer')),
      normal: MBeans.filter( r =>  r && !r.includes('kafka.consumer') && !r.includes('kafka.producer')),
    };

  let result = {};
  await Object.keys(kafkaMBeans).reduce(async (memo, key) => {
    await memo;
    if( kafkaMBeans[key].length) {
      let jmx_remoteConnect = 'remote-connect ' + this.host + ':' + this[key + '_port'];
      let cmd = this.username ? `${jmx_path} "${jmx_remoteConnect} ${this.username}" ${this.password}` : `${jmx_path} "${jmx_remoteConnect}" "${jmx_format}"`;
      let ret = await KafkaStats.prototype.queryJmx(`${cmd} ${kafkaMBeans[key].join(' ')}`,fields);
      result = Object.assign(result,ret.data);
    }
  },0)
  console.log(result)
  return Promise.resolve(result);
}

KafkaStats.prototype.queryJmx = function queryJmx (jmx_cmd,fields = []) {
  return new Promise((resolve, reject) => {
    let child = exec(jmx_cmd,{ timeout: 5000 }, (err, stdout, stderr) => {
      let result = {};
      if(err){
        reject({data:result, err})
      } else if(stderr){
        reject({data:result, err:stderr})
      } else if(stdout) {
        stdout = stdout.split('MBeans\n');
        stdout[1] && stdout[1].split('\n\n')
        .map(r => r.split('\n'))
        .forEach(r => {
          let key = r[0] && r[0].trim();
          let values = r.splice(2);
          if(key) {
            !result[key] && (result[key] = {});
            values.forEach( r => {
              r = r.split(' = ');
              let r_key = r[0] && r[0].trim();
              let r_val = r[1];
              r_val = !isNaN(r_val) ? Number(r_val) : r_val ;
              if(key && (!fields.length || fields.some( field => field === r_key))) {
                result[key][r_key] = r_val;
              }
            })
          }
        })
      }
      resolve({data:result});
    });

    if(this.username) {
      child.stdin.write(this.password+'\n');
      child.stdin.end();
    }
  });
}

new KafkaStats({}).queryMBeans({mbeans:'kafka.consumer:*'});

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值