서버

최고 효율의 Proxy 서버를 찾아서(Node, Apache, Socks)

for2gles 2022. 11. 19. 19:03
반응형

인덱스

1. 프록시란

2. 프록시 서버가 필요하게 된 이유

3. NodeJS를 활용한 Proxy Server

4. Apache를 활용한 Proxy Server

5. Socks5를 활용한 Proxy Server

6. 스트레스 테스트 및 결과

프록시란 

 프록시(Proxy)는 "대리"의 의미로, 인터넷과 관련해서 쓰이는 경우, 특히 내부 네트워크에서 인터넷 접속을 할 때에, 빠른 액세스나 안전한 통신등을 확보하기 위한 중계서버를 "프록시 서버"라고 일컫는다. 클라이언트와 Web서버의 중간에 위치하고 있어, 대신 통신을 받아 주는 것이 프록시 서버이다. 

출처: https://engineer-mole.tistory.com/288

 

 

프록시 서버가 필요 하게 된 이유

모사의 API를 이용하다 보니 문제가 하나 있었다.

Response는 굉장히 빠른데, API Rule에 따라 데이터를 받기위해서는 요청해야 할 Request 또한 엄청 많았다.

사실 Request가 아무리 많아도 Response만 빠르게 빠르게 잘 return 된다면 concurrency를 잘 활용해서 처리할 수 있었다.

그러나 동시에 특정 숫자의 요청이 넘어가게 되니 Throttle 이 생기는 듯 했다.

IP 단위로 쓰로틀이 생기는것인지 확인해보기 위해 빠르게 Lightsail + Node를 활용해 Proxy 서버를 만들어 테스트를 해 보았고, 예상대로 IP 단위대로 쓰로틀이 형성되는 것 이었다.

 

이로서 Proxy 서버를 구축해야하는 임무가 생겼다.

이를 적용시키기 위해 세가지의 Proxy 서버 종류를 확인했고, 최적의 Proxy를 찾기위해 제작 및 스트레스 테스트를 진행 해 볼 것이다.

 

 

 

NodeJS를 활용한 Proxy Server

1. 기본 세팅(NodeJS 설치 및 pm2 설치는 생략한다.)

# Create Directory
$ mkdir proxy

# Enter to Directory
$ cd proxy

# Setting up NPM
$ npm init

# Install required packages
$ npm install express
$ npm install http-proxy

2.  index.js 파일 생성 및 코드 입력

const express = require('express');
const httpProxy = require('http-proxy');

const proxy = httpProxy.createProxyServer({});

const app = express();
app.all('*', function(req, res) {
proxy.web(req, res, { target: `${req._parsedUrl.protocol}//${req.hostname}` });
});
app.listen(3000);

3. pm2 를 사용하여 proxy 서버 실행

$ pm2 start --name proxy index.js

4. Proxy 사용 방법

const response = await axios.get('https://www.naver.com', {
	proxy: {
    	host: proxy_server_ip,
        port: proxy_server_port
    }
});

 

 

Apache를 활용한 Proxy Server

1. Apache 설정 변경 (필자는 Lightsail - Node.js 서버를 생성하여 설치되어있는 Apache를 활용하였다.)

1 - 1. proxy.conf 파일 생성 및 코드 입력

# Enter to Apache config directory
$ cd /opt/bitnami/apache/conf

# Get to vhosts directory
$ cd vhosts

# Create and Edit proxy.conf file
$ vi proxy.conf

 

 

 

<VirtualHost *:3001>
        ProxyRequests On
        SSLProxyEngine On
SSLProxyCheckPeerCN on
SSLProxyCheckPeerExpire on
<Proxy *>
</Proxy>
</VirtualHost>

1-2. httpd.conf 파일 수정 - Listen port 추가

# Get to Apache configure directory
$ ../

# Open the httpd.conf file
$ vi httpd.conf
# Using "/Listen" command, find the Listen 80
# Add Listen 3001
...
Listen 80
Listen 3001
...

2. Apache 재시작

$ sudo /opt/bitnami/ctlscript.sh restart apache

3. Proxy 사용 방법(NodeJS와 동일)

const response = await axios.get('https://www.naver.com', {
	proxy: {
    	host: proxy_server_ip,
        port: proxy_server_port
    }
});

 

 

Socks5를 활용한 Proxy Server

내 팀장은 Socks를 활용한 Proxy 통신이 가장 효율적이라고 생각했다.

실제로 우리 서비스에서 이미 사용을 하고있으며, Request 관련해서 Throttle과 같은 문제없이 사용하고 있었기 때문이었다.

 

이 친구를 활용하는 방법은 두가지가 있는 것 같다.

1. Socks5 서버를 실행시켜주는것

2. SSH 커넥션을 통해 Socks5를 사용하는것

 

현재 우리회사의 경우에는 Docker Swarm을 활용하여 Docker Instanse가 십여개이다.

이 경우에 모든 Docker Instance에 SSH Connection을 뚫는것은 아닌 것 같다고 생각했다.

이에 따라 프록시 서버로 활용할 서버에서 Socks5 서버를 실행시켜주는 방식으로 진행하기로  했다.

 

서버는 Dante라는 서버로 하였고, 세팅은 아래의 Docs를 참고하였다.

1. 기본 세팅

https://www.digitalocean.com/community/tutorials/how-to-set-up-dante-proxy-on-ubuntu-20-04

 

How to Set Up Dante Proxy for Private Connections on Ubuntu 20.04 | DigitalOcean

 

www.digitalocean.com

 

2. Proxy 사용 방법

2-1 socks-proxy-agent module 설치 - 이친구는 다른 Proxy와 다르게 agent 모듈이 필요하다.

$ npm install socks-proxy-agent

2-2 axios에서 사용 방법

const { SocksProxyAgent } = require('socks-proxy-agent');
const response = await axios.get('https://www.naver.com', {
    httpsAgent: new SocksProxyAgent(`socks5://proxy_test:test1234@${proxy_host}:${proxy_port}/`),
});

 

 

스트레스 테스트 및 결과

Proxy 서버를 활용할 때 문제가 발생한다면 동시 요청량이 많을 때 발생할 것 이라고 생각했다.

또한 각각의 요청이 1초 ~ 3초의 시간이 걸린다고 할 때를 테스트하였다.

 

이에 따라 원하는 시간 후에 Response를 보내줄 수 있는 페이지를 하나 만들었다.

기존에 사용하고있는 내 호스팅을 사용하였고 CodeIgniter(PHP) 를 활용하여 간단하게 만들었다.

	/**
	 * 타임아웃테스트
	 */
	public function timeout()
	{
        $second = $this->input->get('s');
        sleep($second);
	}

https://주소/timeout?s=5

위의 주소로 요청하게되면 5초 후에 200 response를 return 해주었다.

 

테스트 조건

- Lightsail 1vCore 1GB $5짜리 서버

 

테스트 방법

1. n * 100 개의 Request를 동시에 보내고, 이런 Request를 5회 진행한다.

2. 걸리는 시간은 1초로 테스트한다.

 

테스트 코드

더보기

 

const axios = require('axios');
const { SocksProxyAgent } = require('socks-proxy-agent');

async function test() {
  console.time('checking');
  try {
    const host = '3.36.103.81';
    const port = 1080;
    const howMany = 700;
    for (let r = 0; r < 5; r += 1) {
      console.log(`${r} start`, new Date());
      const requests = [];
      for (let i = 0; i < howMany; i += 1) {
          const request = axios.default.get('https://주소/timeout', {
          params: {
            s: 1,
          },
          proxy: {
            host: 'host',
            port: 3001,
          },
          // httpsAgent: new SocksProxyAgent(`socks5://proxy_test:test1234@${host}:${port}/`),
        });
        requests.push(request);
      }
      await Promise.all(requests);
      console.log(`${r} end`, new Date());
    }

    console.timeEnd('checking');
    return true;
  } catch (error) {
    console.timeEnd('checking');
    console.log(error.response);
    throw error;
  }
}

test();

 

테스트 결과

- NodeJS

동시 400개의 Request도 버티지 못하고 Error 내뿜음

- Apache

동시 700개의 Request를 진행할 때 약 38초가 걸림

- Socks5

동시 700개의 Request를 진행할 때 약 2분이 걸림

 

Apache 프로세스가 가장 빨랐다.. 나는 암호화 통신 없이 진행된다고 하는 Socks5가 가장 빠를줄 알았다.

하지만 결과는 Apache가 더 빨랐다.

 

이 결과에는 Apache worker 수정이나 Socks5 session max 수정이 들어가지 않았다.

이후에 Socks5 Dante 서버 세팅에 Session.max 문제인가 싶어 5000으로 입력 해 보았지만 속도는 동일했다.

아마 CPU사용량이 아파치에 비해서 비효율적이지 않을까 싶었다.

 

이 내용을 내일모레 팀장한테 공유해줘야지..

반응형