나는 최근에 nodejs 모니터링에 대해 배우고 있습니다. 모니터링의 간단한 버전을 작성하는 방법을 배울 에너지는 없지만 여전히 이러한 지표를 얻는 방법을 배울 수는 없습니다. 국내 인터넷에는 이 내용에 대한 소개가 너무 적다는 점.. 서버노드 지식포인트도 정리하고 있어서 이 글에서 정리해보도록 하겠습니다.)
이 글의 일부 지표에는 문제가 있을 수 있습니다. 실제로 이러한 데이터를 정리하여 모니터링 라이브러리에 작성하여 자신의 중소 규모 프로젝트에 사용할 수 있습니다. 그러면 프론트엔드 리액트에는 비즈차트, g2 등의 도구가 있고, 프론트엔드가 스스로 큰 화면의 데이터를 그립니다. esay 모니터가 수집한 데이터 차원은 우리만큼 포괄적이지 않다고 생각합니다.
서버의 성능 병목 현상은 일반적으로
둘 다 어느 정도 시스템의 사용량을 반영할 수 있습니다.
CPU 사용량은 실행 중인 프로그램이 차지하는 CPU 리소스로, 특정 시점에 컴퓨터가 프로그램을 실행하는 방식을 나타냅니다. 사용률이 높을수록 현재 컴퓨터에서 많은 프로그램을 실행하고 있음을 의미하며 그 반대의 경우도 마찬가지입니다. 사용량 수준은 CPU 성능과 직접적인 관련이 있습니다. 먼저 CPU 사용량을 얻기 위한 코드를 이해하는 데 도움이 되는 관련 API와 일부 용어 설명을 이해하겠습니다.
os.cpus()
각 논리적 CPU 코어에 대한 정보가 포함된 객체 배열을 반환합니다.
model: CPU 코어의 모델을 지정하는 문자열입니다.
속도: CPU 코어의 속도를 MHz 단위로 지정하는 숫자입니다.
times: 다음 속성을 포함하는 객체:
참고: nice
값은 POSIX에만 해당됩니다. Windows 운영 체제에서 nice
값은 모든 프로세서에 대해 항상 0입니다.
유저와 나이스필드를 보시면 어떤 학생들은 장점에 대해 헷갈려하시는 분들이 계시는데, 저도 마찬가지여서 그 의미에 대해 세심하게 문의해 주셨으니 계속 진행해주시기 바랍니다.
user는 CPU가 사용자 모드 에서 실행되는 시간의 비율을 나타냅니다.
응용 프로그램 프로세스 실행은 사용자 모드 와 커널 모드 로 구분됩니다. CPU는 사용자 모드에서 응용 프로그램 프로세스의 자체 코드 논리(일반적으로 일부 논리 또는 수치 계산 )를 실행합니다. CPU는 일반적으로 응답으로 커널 모드에서 프로세스에 의해 시작된 시스템 호출을 실행합니다. 프로세스의 리소스 요청에 .
사용자 공간 프로그램은 커널의 일부가 아닌 모든 프로세스입니다. 셸, 컴파일러, 데이터베이스, 웹 서버 및 데스크톱 관련 프로그램은 모두 사용자 공간 프로세스입니다. 프로세서가 유휴 상태가 아닌 경우 대부분의 CPU 시간이 사용자 공간 프로세스를 실행하는 데 소비되는 것이 정상입니다.
Nice는 낮은 우선순위 사용자 모드 에서 CPU가 실행되는 시간의 비율을 나타냅니다. 낮은 우선순위는 프로세스의 nice 값이 0보다 작다는 것을 의미합니다.
사용자는 CPU가 커널 모드 에서 실행되는 시간의 비율을 나타냅니다.
일반적으로 애플리케이션 프로세스가 많은 수의 시스템 호출을 시작하지 않는 한 커널 모드 CPU 사용량은 너무 높아서는 안됩니다. 너무 높으면 IO 작업이 잦아지는 등 시스템 호출에 시간이 오래 걸린다는 뜻이다.
유휴는 CPU가 수행할 작업이 없는 유휴 상태에 있는 시간의 비율을 나타냅니다.
irq는 CPU가 하드웨어 인터럽트를 처리하는 시간의 비율을 나타냅니다.
네트워크 카드 인터럽트 는 일반적인 예입니다. 네트워크 카드는 데이터 패킷을 수신한 후 하드웨어 인터럽트를 통해 CPU에 처리를 알립니다. 시스템 네트워크 트래픽이 매우 많으면 irq 사용량이 크게 증가할 수 있습니다.
사용자 상태가 70% 미만, 커널 상태가 35% 미만, 전체 상태가 70% 미만이면 정상 상태로 간주할 수 있습니다.
다음 예에서는 Node.js에서 os.cpus() 메서드를 사용하는 방법을 보여줍니다.
예 1:
// Node.js 프로그램을 보여줍니다. //os.cpus() 메소드 // os 모듈 할당 const os = require('os'); // os.cpus() 값 인쇄 console.log(os.cpus());
출력:
[ { 모델:'Intel(R) Core(TM) i5-7200U CPU @ 2.50GHz', 속도: 2712, 타임스: { 사용자:900000, nice:0, sys:940265, 유휴:11928546, irq:147046 } }, { 모델:'Intel(R) Core(TM) i5-7200U CPU @ 2.50GHz', 속도: 2712, 타임스: { 사용자:860875, nice:0, sys:507093, 유휴:12400500, irq:27062 } }, { 모델:'Intel(R) Core(TM) i5-7200U CPU @ 2.50GHz', 속도: 2712, 타임스: { 사용자:1273421, nice:0, sys:618765, 유휴:11876281, irq:13125 } }, { 모델:'Intel(R) Core(TM) i5-7200U CPU @ 2.50GHz', 속도: 2712, 타임스: { user:943921, nice:0, sys:460109, idle:12364453, irq:12437 } } ]
다음은 CPU 사용률을 구하는 방법에 대한 코드입니다.
const os = require('os'); const sleep = ms => new Promise(resolve => setTimeout(resolve, ms)); 클래스 OSUtils { 생성자() { this.cpuUsageMSDefault = 1000; //CPU 사용률 기본 기간} /** * 일정 시간 동안의 CPU 사용률 구하기* @param { Number } Options.ms [시간 간격, 기본값은 1000ms, 1초] * @param { Boolean } Options.percentage [true(백분율 결과로 반환됨) false] * @returns { 약속 } */ 비동기 getCPUUsage(옵션={}) { const that = this; let { cpuUsageMS, 백분율 } = 옵션; cpuUsageMS = cpuUsageMS || that.cpuUsageMSDefault; const t1 = that._getCPUInfo(); // t1 시점의 CPU 정보 wait sleep(cpuUsageMS); const t2 = that._getCPUInfo(); // t2 시점의 CPU 정보 const idle = t2.idle - t1.idle; const 총계 = t2.total - t1.total; 사용량 = 1 - 유휴 / 총계로 설정합니다. if (백분율) 사용량 = (사용량 * 100.0).toFixed(2) + "%"; 반환 사용량; } /** * CPU 순간 시간 정보 가져오기 * @returns { Object } CPU 정보 * user <number> 사용자 모드에서 CPU가 소비한 밀리초 수입니다. * nice <number> CPU가 nice 모드에서 소비하는 시간(밀리초)입니다. * sys <number> CPU가 시스템 모드에서 소비한 시간(밀리초)입니다. * 유휴 <숫자> CPU가 유휴 모드에서 소비한 시간(밀리초)입니다. * irq <number> CPU가 인터럽트 요청 모드에서 소비한 시간(밀리초)입니다. */ _getCPUInfo() { const CPUs = os.cpus(); user = 0, nice = 0, sys = 0, 유휴 = 0, irq = 0, total = 0으로 설정합니다. for(cpu를 CPU에 넣음) { const 시간 = cpus[cpu].times; 사용자 += times.user; 좋은 += 시간.좋은; sys += times.sys; 유휴 += times.idle; irq += times.irq; } 전체 += 사용자 + nice + sys + 유휴 + irq; 반품 { 사용자, 시스템, 게으른, 총, } } } const cpuUsage = new OSUtils().getCPUUsage({ 백분율: true }); console.log('cpuUsage: ', cpuUsage.then(data=>console.log(data))); // 내 컴퓨터의
. CPU 로드(loadavg)는 이해하기 쉽고 특정 값을 나타냅니다. CPU 시간을 점유하는 프로세스 수와 CPU 시간을 기다리는 프로세스 수는 로드 평균입니다. 여기서 CPU 시간을 기다리는 프로세스는 대기 상태의 프로세스를 제외하고 깨어나기를 기다리는 프로세스를 의미합니다.
그 전에 노드 APIos.loadavg()
가 1분, 5분, 15분 평균 로드를 포함하는 배열을 반환하는 방법
을 배워야 합니다
.로드 평균은 운영 체제에서 계산하고 소수로 표시되는 시스템 활동의 측정값입니다.
로드 평균은 Unix에만 적용되는 개념입니다. Windows에서 반환 값은 항상 [0, 0, 0]
이는 운영 체제의 현재 사용률을 설명하는 데 사용됩니다. 이는 CPU가 사용하고 사용하기 위해 대기하는 평균 작업 수로 간단히 이해할 수 있습니다. 단위 시간당 CPU. CPU 부하가 너무 높다는 것은 프로세스가 너무 많다는 것을 의미합니다. Node에서는 자금성 모듈을 사용하여 새 프로세스를 반복적으로 시작하는 데 반영될 수 있습니다.
const os = require('os'); //CPU 스레드 수 const length = os.cpus().length; //싱글 코어 CPU의 평균 로드는 1분, 5분, 15분의 평균 로드를 포함하는 배열을 반환합니다. os.loadavg().map(load => 로드 / 길이)
먼저 API를 설명하겠습니다. 그렇지 않으면 읽을 수 없습니다. 메모리 표시기를 얻기 위한 코드인
이 함수는 4개의 매개변수를 반환하며, 의미와 차이점은 다음과 같습니다.
다음 코드를 사용하여 하위 프로세스의 메모리 사용량을 인쇄하면 rss가 top 명령의 RES와 대략 동일하다는 것을 알 수 있습니다. 또한, 메인 프로세스의 메모리는 33M에 불과해 자식 프로세스의 메모리보다 작으며, 메모리 사용량이 독립적으로 계산되는 것을 볼 수 있습니다.
var showMem = 함수(){ var mem = process.memoryUsage(); var 형식 = 함수(바이트){ return (바이트 / 1024 / 1024).toFixed(2) + 'MB'; }; console.log('프로세스: heapTotal' + format(mem.heapTotal) + ' heapUsed ' + format(mem.heapUsed) + ' rss ' + format(mem.rss) + ' external:' + format(mem.external) ); console.log('------------------- --- ---------------'); };
Node의 경우 메모리 누수가 발생하면 해결이 쉽지 않습니다. 메모리가 증가하기만 하고 떨어지지 않는 것으로 모니터링되면 메모리 누수 문제가 있는 것입니다. 정상적인 메모리 사용량은 증가하거나 감소해야 합니다. 액세스가 크면 증가하고, 액세스가 감소하면 감소합니다.
const os = require('os'); // 현재 Node 프로세스의 메모리 사용량을 확인합니다. const { rss, heapUsed, heapTotal } = process.memoryUsage(); // 시스템 여유 메모리 가져오기 const systemFree = os.freemem(); // 전체 시스템 메모리를 가져옵니다. const systemTotal = os.totalmem(); 모듈.수출 = { 메모리: () => { 반품 { system: 1 - systemFree / systemTotal, // 시스템 메모리 사용량 힙: heapUsed / headTotal, // 현재 노드 프로세스 메모리 사용량 node: rss / systemTotal, // 시스템 메모리의 현재 노드 프로세스 메모리 사용량 비율} } }
디스크 모니터링은 주로 디스크 사용량을 모니터링합니다. 잦은 로그 작성으로 인해 디스크 공간이 점차 소모됩니다. 디스크가 충분하지 않으면 시스템에 다양한 문제가 발생합니다. 디스크 사용량의 상한을 설정하세요. 디스크 사용량이 경고 값을 초과하면 서버 관리자가 로그를 정리하거나 디스크를 정리해야 합니다.
다음 코드는 Easy Monitor 3.0을 참조합니다.
const { execSync } = require('child_process'); const 결과 = execSync('df -P', { 인코딩: 'utf8'}) const 라인 = result.split('n'); const 메트릭 = {}; 라인.forEach(라인 => { if (line.startsWith('/')) { const match = line.match(/(d+)%s+(/.*$)/); if (일치) { const rate = parsInt(match[1] || 0); const mount = match[2]; if (!mounted.startsWith('/Volumes/') && !mounted.startsWith('/private/')) { 측정항목[마운트] = 속도; } } } }); console.log(metric)
I/O 로드는 주로 디스크 I/O를 나타냅니다. 이는 디스크의 읽기 및 쓰기 상황을 반영하며 주로 네트워크 서비스용으로 작성된 애플리케이션의 경우 I/O 로드가 너무 높을 가능성은 없습니다. 많은 읽기의 I/O 압력은 데이터베이스에서 발생합니다. .
I/O 표시기를 얻으려면 iostat라는 Linux 명령을 이해해야 합니다. 설치되어 있지 않은 경우 이 명령이 I/O 표시기iostat -dx를
반영할 수 있는 이유를 살펴보겠습니다.
속성 설명
rrqm/s: 초당 병합 읽기 작업 수입니다. 즉, rmerge/s(장치에 대한 읽기 요청이 초당 병합되는 횟수이며, 파일 시스템은 동일한 블록을 읽기 위해 요청을 병합합니다) wrqm/s: 초당 병합 쓰기 작업 수입니다. 즉, wmerge/s(장치에 대한 쓰기 요청이 초당 병합되는 횟수)입니다. r/s: 초당 완료된 I/O 장치 읽기 수입니다. 그건 rio/s입니다 w/s: 초당 완료된 I/O 장치에 대한 쓰기 수입니다. 그게 wio/s야 rsec/s: 초당 읽은 섹터 수입니다. RSect/s입니다. wsec/s: 초당 작성된 섹터 수입니다. 즉, wsect/s rkB/s: 초당 K바이트를 읽습니다. 각 섹터 크기가 512바이트이므로 RSect/s의 절반입니다. wkB/s: 초당 쓴 K 바이트 수입니다. wsect/s의 절반입니다. avgrq-sz: 장치 I/O 작업당 평균 데이터 크기(섹터)입니다. avgqu-sz: 평균 I/O 대기열 길이입니다. 대기: 각 장치 I/O 작업의 평균 대기 시간(밀리초)입니다. svctm: 각 장치 I/O 작업의 평균 처리 시간(밀리초)입니다. %util: I/O 작업에 사용되는 1초의 비율, 즉 IO에서 소비하는 CPU의 비율입니다.
%
util이 100%에 가까우 면 I/O 작업이 너무 많다는 의미입니다. /O 요청이 생성되었습니다. I/O 시스템이 완전히 로드되었으며 이 디스크에 병목 현상이 있을 수 있습니다.
Wait가 svctm보다 훨씬 크다면 I/O 대기열이 너무 길어지고 애플리케이션의 응답 시간이 느려진다는 의미입니다. 응답 시간이 사용자가 허용할 수 있는 범위를 초과하는 경우 더 빠른 디스크 교체를 고려할 수 있습니다. 커널 엘리베이터 알고리즘을 조정하고 애플리케이션을 최적화하거나 CPU를 업그레이드합니다.
Nodejs의 페이지 응답 시간을 모니터링합니다. 솔루션은 Liao Xuefeng 선생님의 블로그 기사에서 선택되었습니다.
최근에는 Nodejs의 성능을 모니터링하고 싶습니다. 로그를 기록하고 분석하는 것은 너무 번거롭습니다. 가장 간단한 방법은 각 HTTP 요청의 처리 시간을 기록하고 이를 HTTP 응답 헤더에 직접 반환하는 것입니다.
HTTP 요청 시간을 기록하는 것은 매우 간단합니다. 이는 요청을 수신할 때 타임스탬프를 기록하고, 요청에 응답할 때 다른 타임스탬프를 기록하는 것을 의미합니다. 두 타임스탬프의 차이는 처리 시간입니다.
그러나 res.send() 코드는 다양한 js 파일에 분산되어 있으므로 모든 URL 처리 기능을 변경할 수는 없습니다.
올바른 아이디어는 이를 달성하기 위해 미들웨어를 사용하는 것입니다. 하지만 Nodejs에는 res.send()를 가로채는 방법이 없습니다. 어떻게 깨뜨릴 수 있을까요?
사실, 우리의 생각을 약간 바꾸고 전통적인 OOP 방법을 버리고 res.send()를 함수 객체로 보는 한, 먼저 원래 처리 함수인 res.send를 저장한 다음 res.send를 우리의 함수로 바꿀 수 있습니다. 자체 처리 기능:
app.use (function (req, res, next) { //기록 시작 시간: var exec_start_at = Date.now(); //원래 처리 함수를 저장합니다. var _send = res.send; // 자체 핸들러 함수를 바인딩합니다. res.send = 함수() { //헤더 보내기: res.set('X-Execution-Time', String(Date.now() - exec_start_at)); // 원래 처리 함수를 호출합니다. return _send.apply(res, 인수); }; 다음(); });
단 몇 줄의 코드만으로 타임스탬프가 완료됩니다.
res.render()가 내부적으로 res.send()를 호출하므로 res.render() 메서드를 처리할 필요가 없습니다.
apply() 함수를 호출할 때 res 객체를 전달하는 것이 중요합니다. 그렇지 않으면 원래 처리 함수의 this가 정의되지 않음을 가리키며 이로 인해 직접 오류가 발생합니다.
측정된 홈페이지 응답 시간 9밀리초
용어집:
QPS: 초당 쿼리 수는 서버가 응답할 수 있는 쿼리 수인 "초당 쿼리 속도"를 의미합니다. 초당 은 특정 쿼리 서버가 지정된 기간 내에 처리하는 트래픽 양을 측정한 것입니다.
인터넷에서 도메인 이름 시스템 서버 역할을 하는 시스템의 성능은 초당 쿼리 속도로 측정되는 경우가 많습니다.
TPS: TransactionsPerSecond의 약어로 초당 트랜잭션 수를 나타냅니다. 소프트웨어 테스트 결과를 측정하는 단위입니다. 트랜잭션은 클라이언트가 서버에 요청을 보내고 서버가 응답하는 프로세스를 말합니다. 클라이언트는 요청을 보낼 때 타이밍을 시작하고 서버의 응답을 받으면 종료되어 사용된 시간과 완료된 트랜잭션 수를 계산합니다.
QPS 대 TPS: QPS는 기본적으로 TPS와 유사하지만 차이점은 페이지 방문이 TPS를 형성하지만 페이지 요청이 서버에 여러 요청을 생성할 수 있으며 서버는 이러한 요청을 "QPS"로 계산할 수 있다는 것입니다. 예를 들어, 페이지에 액세스하면 서버에 두 번 액세스하게 되며 한 번의 액세스는 "T"와 두 개의 "Q"를 생성합니다.
응답 시간: 응답 데이터를 수신할 때 처음부터 끝까지 요청을 실행하는 데 걸리는 총 시간, 즉 요청을 시작한 클라이언트부터 서버 응답 결과를 수신할 때까지의 시간입니다.
응답 시간 RT(Response-time)는 시스템의 가장 중요한 지표 중 하나이며, 그 수치는 시스템의 속도를 직접적으로 반영합니다.
동시성 수는 시스템이 동시에 처리할 수 있는 요청 수를 의미하며 이는 시스템의 로드 용량도 반영합니다.
시스템의 처리량(압력 견딜 수 있는 용량)은 요청, 외부 인터페이스, IO 등의 CPU 소비와 밀접한 관련이 있습니다. 단일 요청의 CPU 소비가 높을수록 외부 시스템 인터페이스와 IO 속도는 느려지고 시스템 처리량 용량은 낮아지며, 그 반대의 경우도 마찬가지입니다.
시스템 처리량의 몇 가지 중요한 매개변수: QPS(TPS), 동시성 수 및 응답 시간.
QPS(TPS): (Query Per Second) 초당 요청/트랜잭션 수
동시성: 시스템이 동시에 처리하는 요청/트랜잭션 수
응답 시간: 일반적으로
위의 의미를 이해한 후 평균 응답 시간을 계산합니다. 세 가지 요소 간의 관계:
예제를 통해 위의 개념을 이해해 보겠습니다. 80/20 법칙에 따르면 일일 방문자의 80%가 20%의 시간에 집중되어 있는 경우, 이 20%의 시간을 피크타임이라고 합니다.
1, 하루 300w PV는 단일 시스템에 얼마나 많은 QPS가 필요합니까?
(3000000 * 0.8) / (86400 * 0.2) = 139 (QPS)
2. 기계의 QPS가 58이라면, 이를 지원하려면 몇 대의 기계가 필요합니까?
139 / 58 = 3
이쯤 되면 일반 중소규모 프로젝트의 프론트엔드 아키텍처를 하고 자체적으로 노드 서비스를 배포해 보면 ppt 보고를 위해 클러스터를 구성하는데 몇 대의 머신이 필요한지 알 수 있을 것입니다. PV로 대략적인 값을 계산할 수 있습니다.
스트레스 테스트를 이해해야 합니다(qps를 얻으려면 스트레스 테스트에 의존해야 합니다). ab 명령을 예로 들어 보겠습니다.
명령 형식:
ab [options] [http://]hostname[:port]/path
공통
-n 요청 총 요청 수 -c 동시성 동시성 수 -t timelimit 요청의 시간 초과 시간으로 간주할 수 있는 테스트의 최대 시간(초) -p postfile POST가 필요한 데이터가 포함된
파일
-T content-type POST 데이터에서 사용되는 콘텐츠 유형 헤더 정보 코드 복사