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包
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:*'});