로드 밸런서란 무엇일까?
로드 밸런서에 대한 개념은 위의 이미지를 보는 것과 같이 이해할 수 있지만,
WAS(Web Application Server)가 한 대라고 가정해보면 서버 한 대 분량의 부하(Load)만 받을 수 있습니다.
하지만, 사용자가 늘어서 서버를 두대를 사용해야할 경우는 어떻게 해야할까?
그 경우에 바로 보통 위처럼 Nginx를 앞에 두고 서버를 Nginx에 연결하는 방식으로 만들게 된다. 즉, Nginx는 요청을 받아 WAS에 중계해주는 역할을 하게 됩니다.
그러면 Load(부하)가 균형있게(Balance) 들어가게 되는데 이것을 로드 밸런서라고 부릅니다.
먼저 nginx.conf를 보면 다음과 같습니다.
보는 것과 같이 http안에 직접 만들어도 되지만, 아래를 보면 etc/nginx/sites-enabled
를 include하여 가져오는 것을 볼 수 있습니다.
저는 그래서 /etc/nginx/sites-enabled
에 있는 default
파일을 수정하여 설정해보도록 하겠습니다.
cd /etc/nginx/sites-enabled
sudo vi default
위와 같이 입력한 후, default
파일 안에 아래와 같이 입력해줍니다.
upstream [업스트림 이름] {
<로드밸런스 타입: defulat는 round-robin>
server <host1>:<port1>;
...
server <host2>:<port2>;
}
server {
listen 80;
location / {
proxy_pass http://[업스트림 이름]
}
}
저는 아래와 같이 작성하였습니다.
upstream myserver {
server localhost:8000;
server localhost:8001;
}
server {
listen 80;
location / {
proxy_pass http://myserver
}
}
upstream
은 강의 상류를 의미합니다. 즉, 위에서 아래로 뿌려주는 것을 의미합니다. (반대로는 downstream이 있습니다.)
즉, 여러군데로 뿌려주는 것을 upstream이라고 합니다.
위에서는 해당 nginx가 여러 서버에 배분해주므로 upstream 서버라고 부를 수도 있습니다.
로드밸런스느 부하(Load)를, 접속자를 분산하여 고루고루 보내주는데 이 때, 어떻게 분배할지에 대해 규칙을 알아야하는데요.
규칙은 아무것도 적지 않는다면,
Round-Robin
의 방식으로 동작합니다.
즉, 균등하게 분배한다는 뜻입니다.
위에서 본 것과 같이 다시 보게되면 아래와 같습니다.
server {
listen 80;
location / {
proxy_pass http://[업스트림 이름];
}
}
위와 같이 서버의 location에서 로드밸런싱할 url을 선택하면 됩니다.
그 후, proxy_pass를 붙여주면 됩니다.
아래 이미지를 보시면 부하 분산에 대해 콘솔을 확인하여 테스트를 진행하였습니다.
각 포트를 나누어준 서버에 대해 아래와 같이 pm2를 이용하여 start를 해주세요.
포트가 다른 총 두개의 파일을 실행시켜주어야 합니다.
pm2 start [파일이름.js]
// ex) pm2 start nodejs/index.js
// ex) pm2 start nodejs8001/index.js
제가 설정한 파일의 내용은 아래와 같으며, [public ip]/hello
로 접속하였습니다.
// nodejs/index.js
const http = require('http');
const port = process.env.PORT || 8000
const server = http.createServer((req, res) => {
if (req.method !== 'GET') {
res.end(`{"error": "${http.STATUS_CODES[405]}"}`)
} else {
if (req.url === '/') {
console.log("/");
res.end(`<h1>Hello World</h1>`)
}
if (req.url === '/hello') {
// console.log("hello");
res.end(`<h1>Hello</h1>`);
console.log('---------------------------------------------------',port);
}
}
res.end(`{"error": "${http.STATUS_CODES[404]}"}`)
})
server.listen(port, () => {
console.log(`Server listening on port ${port}`);
})
// nodejs8001/index.js
const http = require('http');
const port = process.env.PORT || 8001
const server = http.createServer((req, res) => {
if (req.method !== 'GET') {
res.end(`{"error": "${http.STATUS_CODES[405]}"}`)
} else {
if (req.url === '/') {
console.log("/");
res.end(`<h1>Hello World</h1>`)
}
if (req.url === '/hello') {
// console.log("hello");
res.end(`<h1>Hello</h1>`);
console.log('---------------------------------------------------',port);
}
}
res.end(`{"error": "${http.STATUS_CODES[404]}"}`)
})
server.listen(port, () => {
console.log(`Server listening on port ${port}`);
})
2개의 포트 모두 다 start를 하셨다면, pm2 list
를 입력해보시면 아래와 같은 화면을 보실 수 있습니다.
아래와 같이 모니터링을 하기 위한 명령어는 아래와 같습니다.
pm2 monit
log를 확인하기 위해서는 왼쪽에 있는 탭을 방향키로 접근하여 Enter를 누르면 log를 확인할 수 있습니다.
(저는 두 개의 터미널을 각각 켰습니다.)
보시는 것과 같이 우리는 아무것도 적지 않았기 때문에, default 값인 round-robin 방식으로 진행됩니다.
저는 8000번 포트와 8001번 포트를 지정하였는데,8000번 포트
와8001번 포트
모두 균일하게 콘솔이 찍히는 모습을 볼 수 있습니다.
round-robin(디폴트)
- 그냥 돌아가면서 분배.
hash
- 해시한 값으로 분배한다 쓰려면 hash <키> 형태로 쓴다. ex)hash $remote_addr <- 이는 ip_hash와 같다.
ip_hash
- 아이피로 해싱해서 분배.
random
- 랜덤으로 분배.
least_conn
- 연결수가 가장 적은 서버를 선택해서 분배, 근데 가중치를 고려.
least_time
- 연결수가 가자 적으면서 평균 응답시간이 가장 적은 쪽을 선택해서 분배.
또한 아래와 같이 Parameter 값을 줄 수도 있다.
upstream [업스트림 이름] {
server <host1>:<port1> weight=2;
...
server <host2>:<port2>;
}
server {
listen 80;
location / {
proxy_pass http://[업스트림 이름];
}
}
위의 경우 weight로 가중치를 줄 수 있는데 규칙은 유지하되 2배더 많이 사용한다는 뜻입니다.
예시는 아래와 같습니다.
저는 8000번 포트에 대해 weight를 2주었습니다. 아래 보시는 것과 같이8000번 포트
에 대해 2번 더 요청이 되는 것을 확인할 수 있습니다.
weight
- 가중치를 둬서 더많이 가게 한다.
max_conns
- 최대 연결 한계를 정한다.
max_fails
- 최대 실패 한계를 정한다. 최대 실패횟수에 도달하면 서버가 죽은것으로 간주한다.
fail_timeout
- 시간을 정한다. 이 시간을 넘어서도 응답하지 않으면 서버가 죽은것으로 간주한다.
backup
- 이 서버는 백업서버로 간주하고 다른 메인 서버가 죽었을때 동작한다. load balancing methods가 hash나 random일때는 무의미
down
- 표시한 서버는 사용치 않는다.
자세한 설명은 아래를 참고해주세요!
http://nginx.org/en/docs/stream/ngx_stream_upstream_module.html