728x90

- Backend (NestJS): 서버의 리소스 상태를 주기적으로 체크하고, 연결된 클라이언트들에게 WebSocket 이벤트를 Broadcasting 합니다.
- Frontend (NuxtJS): 소켓 서버에 접속하여 데이터를 수신하고, 이를 시각적인 UI로 렌더링합니다.
실시간으로 서버의 CPU, 메모리, 디스크 사용량을 모니터링하고 싶다면?
NestJS 백엔드와 Nuxt 3 프론트엔드를 WebSocket으로 연결해서 멋진 대시보드를 만들어보자!키워드NestJS, Nuxt3, WebSocket, Gateway, Socket.io, 서버 모니터링, 실시간 대시보드, CPU 사용량, 메모리 사용량, os 모듈, Chart.js목표
NestJS 백엔드와 Nuxt 3 프론트엔드를 WebSocket으로 연결해서 멋진 대시보드를 만들어보자!키워드NestJS, Nuxt3, WebSocket, Gateway, Socket.io, 서버 모니터링, 실시간 대시보드, CPU 사용량, 메모리 사용량, os 모듈, Chart.js목표
- NestJS에서 주기적으로 서버 상태(os 정보)를 수집
- WebSocket Gateway을 통해 실시간으로 클라이언트에게 브로드캐스트
- Nuxt 3에서 Socket.io-client로 연결하여 실시간 차트 업데이트
1. NestJS 백엔드 설정
# 프로젝트 생성
nest new server-monitoring-backend
cd server-monitoring-backend
npm install @nestjs/websockets @nestjs/platform-socket.io socket.io os
nest g gateway monitoring
// monitoring.gateway.ts
import { WebSocketGateway, WebSocketServer, OnGatewayInit } from '@nestjs/websockets';
import { Server } from 'socket.io';
import * as os from 'os';
@WebSocketGateway({
cors: {
origin: '*',
},
})
export class MonitoringGateway implements OnGatewayInit {
@WebSocketServer()
server: Server;
private interval: NodeJS.Timeout;
afterInit() {
// 2초마다 서버 상태 전송
this.interval = setInterval(() => {
const cpus = os.cpus();
const totalMem = os.totalmem();
const freeMem = os.freemem();
const loadAvg = os.loadavg()[0]; // 1분 평균 로드
// CPU 사용률 계산 (간단한 방법)
let totalIdle = 0, totalTick = 0;
cpus.forEach(cpu => {
for (const type in cpu.times) {
totalTick += cpu.times[type];
}
totalIdle += cpu.times.idle;
});
const idle = totalIdle / cpus.length;
const total = totalTick / cpus.length;
const cpuUsage = 100 - Math.round((100 * idle) / total);
this.server.emit('serverStats', {
cpu: cpuUsage,
memory: Math.round(((totalMem - freeMem) / totalMem) * 100),
loadAverage: loadAvg.toFixed(2),
uptime: os.uptime(),
timestamp: new Date().toISOString(),
});
}, 2000);
}
handleDisconnect() {
if (this.interval) clearInterval(this.interval);
}
}
// main.ts - CORS 허용
async function bootstrap() {
const app = await NestFactory.create(AppModule);
app.enableCors({
origin: '*',
});
await app.listen(3000);
}
서버 실행: npm run start:dev → http://localhost:30002.
2. Nuxt 3 프론트엔드 설정
npx nuxi@latest init server-monitoring-frontend
cd server-monitoring-frontend
npm install socket.io-client chart.js primevue primeicons
plugins/socket.client.ts
import { defineNuxtPlugin } from '#app';
import io from 'socket.io-client';
export default defineNuxtPlugin(() => {
const socket = io('http://localhost:3000', {
autoConnect: true,
reconnection: true,
});
return {
provide: {
socket,
},
};
});
pages/index.vue
<template>
<div class="container mx-auto p-8">
<h1 class="text-3xl font-bold mb-8">실시간 서버 헬스 모니터링</h1>
<div class="grid grid-cols-1 md:grid-cols-3 gap-6 mb-8">
<div class="bg-white rounded-lg shadow p-6">
<h3 class="text-lg font-semibold text-gray-700">CPU 사용량</h3>
<p class="text-4xl font-bold mt-2">{{ stats.cpu }}%</p>
</div>
<div class="bg-white rounded-lg shadow p-6">
<h3 class="text-lg font-semibold text-gray-700">메모리 사용량</h3>
<p class="text-4xl font-bold mt-2">{{ stats.memory }}%</p>
</div>
<div class="bg-white rounded-lg shadow p-6">
<h3 class="text-lg font-semibold text-gray-700">로드 평균</h3>
<p class="text-4xl font-bold mt-2">{{ stats.loadAverage }}</p>
</div>
</div>
<div class="bg-white rounded-lg shadow p-6">
<h2 class="text-2xl font-bold mb-4">실시간 차트</h2>
<canvas ref="chartRef"></canvas>
</div>
</div>
</template>
<script setup lang="ts">
const { $socket } = useNuxtApp();
const stats = ref({
cpu: 0,
memory: 0,
loadAverage: '0.00',
});
const chartRef = ref<HTMLCanvasElement | null>(null);
let chart: any = null;
const labels = ref<string[]>([]);
const cpuData = ref<number[]>([]);
const memoryData = ref<number[]>([]);
onMounted(() => {
$socket.on('serverStats', (data: any) => {
stats.value = data;
const time = new Date(data.timestamp).toLocaleTimeString();
labels.value.push(time);
cpuData.value.push(data.cpu);
memoryData.value.push(data.memory);
// 30개 데이터만 유지
if (labels.value.length > 30) {
labels.value.shift();
cpuData.value.shift();
memoryData.value.shift();
}
if (!chart && chartRef.value) {
const ctx = chartRef.value.getContext('2d');
chart = new Chart(ctx, {
type: 'line',
data: {
labels: labels.value,
datasets: [
{
label: 'CPU (%)',
data: cpuData.value,
borderColor: 'rgb(239, 68, 68)',
tension: 0.4,
},
{
label: 'Memory (%)',
data: memoryData.value,
borderColor: 'rgb(59, 130, 246)',
tension: 0.4,
},
],
},
options: {
responsive: true,
maintainAspectRatio: false,
},
});
} else {
chart?.update();
}
});
});
onUnmounted(() => {
$socket.off('serverStats');
});
</script>
<style scoped>
canvas {
height: 400px;
}
</style>
실행하기
# 백엔드
cd server-monitoring-backend
npm run start:dev
# 프론트엔드 (새 터미널)
cd server-monitoring-frontend
npm run dev
→ http://localhost:3000 접속하면 실시간으로 서버 상태가 업데이트되는 대시보드가 나타난다!
이렇게 간단하게 NestJS의 WebSocket Gateway과 Nuxt 3 + Socket.io-client만으로도 강력한 실시간 모니터링 시스템을 만들 수 있다.
추가로 Prometheus + Grafana를 붙이거나, 여러 서버를 모니터링하고 싶다면 gateway에 room 기능이나 DB 연동하면 확장도 쉽다.실시간 데이터의 재미를 느껴보고 싶다면 지금 바로 따라 만들어보자!
추가로 Prometheus + Grafana를 붙이거나, 여러 서버를 모니터링하고 싶다면 gateway에 room 기능이나 DB 연동하면 확장도 쉽다.실시간 데이터의 재미를 느껴보고 싶다면 지금 바로 따라 만들어보자!
728x90
'IT 일반,소식' 카테고리의 다른 글
| 🚢 부산항 9부두 지능형 항만 시스템 개발 계획 (MySQL, Nuxt.js, Nest.js 기반) (1) | 2025.12.07 |
|---|---|
| 🏢 빌딩 엘리베이터 시뮬레이션 개발계획(MySQL, Nuxt.js, Nest.js 기반) (0) | 2025.12.07 |
| AI는 일자리를 없애지 않는다 – 방직기 시대가 증명해준 250년 전 이야기, 그리고 지금 (0) | 2025.12.02 |
| MM/DD 입력 기준으로 기준일과 가장 가까운 연도 계산하기 (작년/금년/내년) (0) | 2025.11.25 |
| MTNS 배경 로고 인트로 (0) | 2025.10.23 |