Sonntag, 20. Oktober 2019

How to Monitor Kafka with AppDynamics

This article is about the monitoring of a Kafka installation with AppDynamics. I will look in to the instrumentation with the JavaAgent 4.5 and MachineAgent 4.5. All this on a local Notebook installation. Maybe I will look in to an Opensift setup later.

A good source for Kafka knowledge for the beginners can be found here: http://cloudurable.com/blog/kafka-tutorial-kafka-from-command-line/index.html

What we need:
1. Kafka & Zookeeper
2. AppDynamics Controler (SAAS)
3. AppDynamics Java Agent and Machine Agent

Kafka was downloaded from https://kafka.apache.org/downloads. At the time of writing 2.3.0 was the latest version and used for this article. I installed it according to the tutorial of Clousurable mentioned above.

For AppDynamics I have registered the 15 days evaluation license. From my newly created account I downloaded the Machine Agent and Java Agent 4.5.X. Both where unziped to the home folder of my Fedora 29.

Configuration


1. Kafka


To enable JMX I have added this line export JMX_PORT=9988 just above the last line in kafka-server-start.sh located in the Kafka bin folder.

To support the AppDynamics Java Agent I have added $APPD_OPTS to the section #Launch mode of the shell script kafka-run.calss.sh located in the bin folder of Kafka. So it looks like this:

exec $JAVA $APPD_OPTS $KAFKA_HEAP_OPTS $KAFK_.........

Location is important. It must be the first argument after $JAVA.

2. AppDynamics


For AppDynamics we have two sections. The Java Agent and the Machine Agent. Let us start with the Java Agent.

2.1 AppDynamics Java Agent


I have unpacked the ZIP  AppServerAgent-4.5.15.27926.zip to /home/juerg/AppDynamics_JavaAgenet. Configuration of the agent takes place in /conf/controler-info.xml. Here the controler-info.xml. I used. Beside the conroler-info.xml. The someof the fields I passed via -D parameter in $APPD_OPTS to Kafka. I placed this in ~/.bash_profile. The export looks like this:

export APPD_OPTS=" -javaagent:/home/juerg/AppDynamics_JavaAgenet/javaagent.jar -Dappdynamics.agent.logs.dir=/tmp/logs -Dappdynamics.agent.uniqueHostId=$HOSTNAME -Dappdynamics.agent.reuse.nodeName=true -Dappdynamics.jvm.shutdown.mark.node.as.histical=true -Dappdynamics.agent.reuse.nodeName.prefix=Kafka-Broker- -Dappdynamics.agent.tierName=Kafka-Broker -Dappdynamics.agent.log4j2.disabled=true"

Here some Screenshots from AppDynamics UI:



2.2 Machine Agent


Like the Java Agent I unziped the Machine Agent to my home folder. To start it as a stand alone agent I have created a simple shell script:

agent-start.sh
#!/bin/bash
./bin/machine-agent -p /tmp/pidfile -Dappdynamics.agent.uniqueHostId=$HOSTNAME -Dappdynamics.agent.reuse.nodeName=true -D appdynamics.jvm.shutdown.mark.node.as.histical=true -Dappdynamics.agent.reuse.nodeName.prefix=Kafka-Broker- -Dappdynamics.agent.tierName=Kafka-Broker -Dappdynamics.agent.log4j2.disabled=true -Dappdynamics.agent.maxMetrics=5000

As you can see the tier and node name are the same in Machine and Java agent. This will in AppDynamics UI then been aggregated in the same place.

Here some Screenshots from AppDynamics UI:



Samstag, 19. Oktober 2019

ESP32 misst Fluglärm

Nach dem erfolgreichen Bau eines Feinstaubsensors (https://luftdaten.info/feinstaubsensor-bauen/) ist die Idee entstanden das Konzept für das Messen des Fluglärms zu übertragen. Die Stärke des Feinstaubsensors SDS011 ist seine serielle Schnittstelle. Diese ermögliche den Anschluss des Sensors mit nur 4 Leitungen und ist somit auch für weniger erfahrene leicht nachzubauen.

Nach einiger Recherche habe ich bei Ali Express den HH_06.03 gefunden. Dieser ist hier beschrieben https://zhzh.xyz/2019/07/10/iot/esp32micropythonhh06uart/. Das enthaltene MicroPython Script:

from machine import UART 
uart = UART(1, 115200)
uart.init(115200, bits=8, parity=None, stop=1)
print(uart)
frameHeader = b'\xbb\xaa\x01' 
while True:
    if frameHeader == uart.read(3):
          frameDataLowPosition = uart.read( 1 )
          frameDataHighPosition = uart.read( 1 )
          frameCheck = uart.read( 1 )
          frameDataLowPosition = int.from_bytes(frameDataLowPosition, 'big' )
          frameDataHighPosition = int.from_bytes(frameDataHighPosition, 'big' )
    
          frameCheck = int.from_bytes(frameCheck, 'big' )
          if ((frameDataLowPosition+frameDataHighPosition+ 187 + 170 + 1 )& 0xFF ) == frameCheck:
             db = (frameDataHighPosition<< 8 | frameDataLowPosition)* 0.1
             print(db)     

lässt sich auf dem ESP32 leicht testen. Der Sensor liefert alle 500ms den gemessenen db(A) Wert.

Ich bin aktuell mit Windows unterwegs. Da sieht die Übertragung der Firmware für MicroPython so aus:
esptool.py --chip esp32 --port com4 --baud 460800 write_flash -z 0x1000 esp32-20191011-v1.11-422-g98c2eabaf.bin

Ich verwende Thonny als IDE.

Im nächsten Schritt übertrage ich den Code nun nach Arduino.

Die ersten Tests führten zu Bootschleifen. Dies lag an der Verwendung von serial1. Hier eine Erklärung: https://www.az-delivery.com/blogs/azdelivery-blog-fur-arduino-und-raspberry-pi/esp-32-lora-alle-seriellen-schnittstellen-nutzen. Die Verwendung von serial2 löst das Problem.

Mit dem Logik-Analyser habe ich mir mal das gelieferte Signal angesehen un kann die Angaben der o.g. chinesischen Web-Seite bestätigen. Alle 500ms wird ein Werte-Paket mit \xbb\xaa\x01 als Starts Sequenz  gesendet.


Wenn ich keinen Weg finde nach den drei Start-Zeichen zu suchen, so wie in Python, dann ist das hier ein Ansatz https://stackoverflow.com/questions/33662818/arduino-serial-read-and-parse-hex.

Nah dem ich die erwarteten Daten auf serial2 des ESP32 nicht erhalten habe, habe ich mal SoftwareSerial ausprobiert. Siehe da swSer.begin(115200, 18, 19, SWSERIAL_8N1, false, 95, 11);
hat auf Anhieb geklappt.

23:16:39.369 ->  <Arduino is ready>
23:16:40.022 -> This just in ... BB
23:16:40.022 -> This just in ... AA
23:16:40.057 -> This just in ... 1
23:16:40.090 -> This just in ... 14
23:16:40.090 -> This just in ... 5
23:16:40.124 -> This just in ... 7F
23:16:40.492 -> This just in ... BB
23:16:40.526 -> This just in ... AA
23:16:40.560 -> This just in ... 1
23:16:40.560 -> This just in ... 59
23:16:40.594 -> This just in ... 3
23:16:40.627 -> This just in ... C2

Nun kann es weitergehen. Erste Code-Schnipsel funktionieren und liefern Daten. Es gibt immer mahl wieder Lücken in der Werteverarbeitung. Grund??