링크 1. Overview & IDEA - HW monitoring 2. Problem & PoC 3. DATA Design 4. Publisher 5. Database & logger 6. Visualization 7. ToBeContinue…?
Problem
자 그럼 문제가 뭐냐? AWS에는 우선 모니터링 시스템이 있다!
AWS CloudWatch라는 놈인데 여러대도 가능하고 물론 시각화도 더 좋고 분명 좋은 점이 많다.
하지만 문제는 돈을 내야한다는 점이지… 학생인 나는 한달에 40만원 용돈 받으면서 aws쓰면서도 돈이 나가는데 이거까지 달고 쓰면 내 통장은 텅장이 되겠지…그럼 어케하냐? 내가 그냥 만들면 된다는 거지. 해서 팀을 구성한다.
- Publisher : 임우찬
- Broker : 이종근
- Consumer : 금종현
요렇게 맡고 초기에 내가 publisher를 조금씩 만지면서 그림을 그리기 시작한다.
Architecture
생각은 간단했다. 우리가 게임을 할때도 cpu, gpu이런걸 보기위해서 이런게 있다. 윈도우에서 ctrl + shift + esc를 누르면 나오는 창인데 요런게 한대가 아니라 여러대로 나타나서 각 컴퓨터가 동작하고 있는 상황을 알고 갑자기 cpu의 사용량이 뛴다면 바로 나에게 알려주면 몇분이 지나서 알게 되는게 아니라 바로 알려주면 되니까 당연히 손실이 적지 않을까 하는 생각이 드는 것이라고 생각했다!
조건은 아래와 같다
- N대의 AWS컴퓨터를 모니터링 한다.
- 실시간으로 AWS 컴퓨터를 추가 할 수도 있다.
- 시각화가 가능해야한다.
그렇다면 내가 배운 아이디어는 중앙에 데이터 허브를 두고 여러대의 컴퓨터에 현재 상황을 받을 수 있다면 좀 더 scaliable할 것이다! 여러방법이 있지만 데이터 허브를 두겠다는 생각은 2개정도에 이유가 있다.
- 만약 단일 서버에서 데이터를 받아들이는 구조라고 하면 http 통신이나 socket을 이용해서 연결을 해야되는게 단점이되는데, 이런 상황에서는 computing을 하라고 aws를 쓰는데 데이터를 넘겨주겠다고 계속 리소스를 낭비하는 꼴이된다고 생각했다 해서 단절된 pub/sub구조를 사용하고 연결을 최소화하는게 좋겠다는 생각이었다.
- 실시간으로 컴퓨터가 추가되면 클라이언트 서버구조에서는 데이터를 감당할 수 없을 것 같았다. 이후에 구현에서도 보겠지만 1초에 1개의 데이터만 들어와도 하루면 엄청나게 많은 데이터가 들어오고 컴퓨터가 늘어남에 따라 선형적으로 데이터의 적제 속도가 늘어나게 될 것이다. 이러한 처리량을 감당하고 후에 다른 사용자가 생기더라도 안정적으로 모니터링을 할 수 있게 하기 위해서는 KAFKA나 Kensis같은 데이터 허브가 필요하다고 생각했다. (키네시스는 돈드니까 제외)
좋다! 이후에 구조는 아래와 같이 간단하다 사실 간단하지 않았다 뒤에 보면 참 많은 일이 있었지만 이때는 그냥 요렇게 생각했다!
```
Node1 \
Node2 - > KAFKA -> visualization
Node3 /
하지만 이걸로 팀원을 설득시킬 수는 없다. 내가 하자고 했으니 내가 작게나마 시작을 해봐야지! PoC를 하기 시작한다.
PoC (Proof of Concept) & Publisher
일딴 컴퓨터에서 어떻게 하면 메모리와 이런 것들을 잡아올 수 있는 지 확인을 해보자. 우선 내 컴퓨터는 MAC인데 터미널에서 아래 명령어를 치게 되면 현재 컴퓨터의 상태를 1초마다 나타내 준다.
top -b -n 1
물론 이렇게 하지 않아도 JAVA에서 프로그램에 정보를 잡아오는 코드도 있다.
com.sun.management.OperatingSystemMXBean
요런 라이브러리를 써도 괜찮은데 궁극적인 목표는 process까지 넘겨서 어떤 작업이 현재 가장 많은 리소스를 사용하는까지 보고싶어서 (이 부분이 뒤에가서 애매해졌는데 우선은 cpu,mem,disk r/w만 정리했다) 해당 라이브러리 보다 top명령어를 parsing하는 걸 publisher로 쓰기로 했다. 해당 프로그래밍은 우찬이가 수고해 줬다. 물론 문제는 몇개 있었다.
- OS가 다르면 다른 명령어를 사용해야한다
- 윈도우나 리눅스는 또 다른 명령러를 사용하고 형식도 다르다. 이때문에 ubuntu에서만 우선 진행하는 것으로 정리했다.
- 파싱문제
- 띄어쓰기를 기준으로 하다보니 갑자기 type문제가 날때가 있었다. 알고보니 Google Chorome같은 이름에 띄어쓰기가 문제였으므로 이를 해결하는데 시간이 조금 걸렸다. 아래는 해당 코드다 필요한 정보만을 parsing하므로 이를 이제 KAFKA에 연결해 주면 된다.
// parsing "TOP COMMAND"
int staringPoint=0;
while (true) {
if (staringPoint == 0) {
staringPoint++;
continue; }
String sendOutStr = ""; // the output string to be sent to kafka broker
String temp;
Process p;
int lineNumber;
// TOP COMMAND HANDLER
try {
lineNumber = 0;
p = Runtime.getRuntime().exec("top -b -n 1");
BufferedReader br = new BufferedReader(new InputStreamReader(p.getInputStream()));
while ((temp = br.readLine()) != null) {
if (lineNumber < 2) {
lineNumber++;
continue; }
String[] temp_str = temp.split("\\s+");
// PARSING
if (lineNumber == 2) { // parsing CPU
System.out.println(Arrays.toString(temp_str));
cpuDetail = new TotalCpuDetail(Float.parseFloat(temp_str[1]), Float.parseFloat(temp_str[3]));
System.out.println(cpuDetail.toString());
} else if (lineNumber == 3) { // parsing PhysMem
memDetail = new TotalMemDetail(Float.parseFloat(temp_str[7]), Float.parseFloat(temp_str[5]));
} else if (lineNumber > 6) { // parsing ProcessDetail;
if (Float.parseFloat(temp_str[9]) >= 1.0 ) {
TopProcessDetail topProcessDetail = new TopProcessDetail(Integer.parseInt(temp_str[1]), temp_str[12], Float.parseFloat(temp_str[9]), temp_str[11], Float.parseFloat(temp_str[10]), temp_str[8]);
topRateProcess.add(topProcessDetail);
}
}
lineNumber++;
}
p.waitFor();
p.destroy();
} catch (Exception e) {
throw new RuntimeException(e);
}
// DF COMMAND HANDLER FOR DISK INFO
try {
p = Runtime.getRuntime().exec("df -h");
BufferedReader br = new BufferedReader(new InputStreamReader(p.getInputStream()));
br.readLine(); // firstline like "Filesystem/Size/Used/Avail/Use%/Mounted on"
String[] tempDisk = br.readLine().split("\\s+");
String readDisk = tempDisk[2].substring(0, tempDisk[2].length()-1);
String writeDisk = tempDisk[3].substring(0, tempDisk[3].length()-1);
diskDetail = new TotalDiskDetail(Float.parseFloat(readDisk), Float.parseFloat(writeDisk));
p.waitFor();
p.destroy();
} catch (Exception e) {
throw new RuntimeException(e);
}
일딴 너무 기니까 다음으로!
->다음편3. DATA Design에서 계속