2025년 3월 10일 월요일

Node.js 서버의 동시 접속 한도 및 설정

Node.js 서버의 동시 접속 한도

Node.js 서버의 동시 접속 한도는 기본 설정으로 특정 숫자가 정해져 있지 않지만, 여러 요소에 의해 제한됩니다:

  1. HTTP 서버 기본 설정:

    • Node.js의 HTTP/HTTPS 서버는 기본적으로 연결 수에 엄격한 제한을 두지 않음
    • Express 같은 프레임워크는 기본 설정으로 대기열에 5,000개의 요청을 가질 수 있음
  2. 운영체제 제한:

    • 가장 일반적인 제한 요소는 운영체제의 최대 동시 열린 파일(소켓) 수
    • Linux에서는 보통 ulimit -n으로 확인 가능하며, 기본값은 1,024
    • 이는 서버가 1,024개의 동시 연결을 처리할 수 있음을 의미
  3. Node.js 이벤트 루프:

    • Node.js는 단일 스레드 이벤트 루프 모델을 사용하므로, 처리 능력은 CPU 작업 부하와 I/O 작업의 효율성에 따라 달라짐
  4. 하드웨어 리소스:

    • 메모리, CPU, 네트워크 대역폭 등 서버의 하드웨어 자원도 제한 요소

프로덕션 환경에서 더 많은 동시 연결 처리 방법

// 서버 생성 시 최대 연결 수 증가
const server = http.createServer(app);
server.maxConnections = 10000;

// OS 파일 디스크립터 한도 증가 (Linux/Unix)
// $ ulimit -n 10000 (터미널에서 실행)

// Keep-Alive 타임아웃 설정
server.keepAliveTimeout = 5000; // 5초
        

실제로는 클러스터 모듈이나 PM2 같은 프로세스 매니저를 사용하여 여러 개의 Node.js 인스턴스를 실행하고, Nginx나 HAProxy 같은 로드 밸런서를 앞단에 두는 것이 일반적입니다.

멀티파트 업로드 시스템의 경우, 특히 SSE(Server-Sent Events)를 사용한 진행률 모니터링 때문에 일반적인 HTTP 요청보다 더 많은 리소스를 사용할 수 있으므로, 프로덕션 환경에서는 서버 설정을 적절히 조정하는 것이 중요합니다.

현재 구조라면 로드밸런서(LB)만 추가해도 기본적으로 정상 동작할 수 있지만 대용량 트래픽과 멀티파트 업로드를 효율적으로 처리하기 위해서는 몇 가지 추가 설정이 필요합니다.

로드밸런서 추가 시 고려사항

  1. Connection 수 조정:

    • Nginx의 경우 worker_connections 값을 조정 (기본값은 보통 512나 1024)
    • HAProxy의 경우 maxconn 값을 조정
  2. 세션 관리:

    • 멀티파트 업로드의 경우 각 청크가 같은 서버로 가야 함
    • 특히 uploadId를 기준으로 동일 사용자의 요청이 동일 서버로 라우팅되어야 함
  3. 타임아웃 설정:

    • 대용량 파일 업로드는 일반 요청보다 오래 걸리므로 타임아웃 설정 확인 필요
    • Nginx의 경우 client_body_timeout, proxy_read_timeout 등을 조정

Nginx 설정 예시

http {
  # 워커 프로세스당 최대 연결 수 증가
  worker_connections 10000;

  # 요청 본문 크기 제한 증가 (대용량 청크 허용)
  client_max_body_size 10M;

  # 타임아웃 설정 증가
  client_body_timeout 120s;
  proxy_connect_timeout 120s;
  proxy_send_timeout 120s;
  proxy_read_timeout 120s;

  # 업로드 ID 기반 세션 일관성 설정
  upstream app_servers {
    ip_hash; # 또는 더 나은 방법으로 sticky sessions 사용
    server app1.example.com:3000;
    server app2.example.com:3000;
    # 추가 서버...
  }

  # SSE 관련 설정 (진행률 모니터링용)
  server {
    # ...

    location /api/progress {
      proxy_pass http://app_servers;
      proxy_http_version 1.1;
      proxy_set_header Connection '';
      proxy_buffering off;
      proxy_cache off;
      proxy_read_timeout 24h; # SSE 연결 유지를 위한 긴 타임아웃
    }

    # 일반 API 엔드포인트
    location /api {
      proxy_pass http://app_servers;
      proxy_http_version 1.1;
      proxy_set_header X-Real-IP $remote_addr;
      proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
      proxy_set_header Host $host;
    }
  }
}
        

HAProxy 설정 예시

global
  maxconn 10000

defaults
  timeout connect 10s
  timeout client 30m # 클라이언트 타임아웃 증가
  timeout server 30m # 서버 타임아웃 증가

frontend http-in
  bind *:80
  default_backend app_servers

backend app_servers
  balance source # IP 기반 세션 고정
  option http-server-close
  server app1 app1.example.com:3000 check
  server app2 app2.example.com:3000 check
  # 추가 서버...
        

Node.js 서버에서도 고려할 점

로드밸런서를 추가하더라도 Node.js 서버 자체에서도 다음 설정을 확인해야 합니다:

// app.js 또는 서버 설정 파일
const server = http.createServer(app);

// 연결 시간 제한 증가
server.keepAliveTimeout = 60000; // 60초
server.headersTimeout = 65000; // 65초

// Express나 다른 미들웨어 설정
app.use(express.json());
app.use(express.urlencoded({ extended: true }));
        

현재 코드에서는 SSE를 사용한 업로드 진행 모니터링이 있으므로, 특히 이 부분이 로드밸런서를 통해 제대로 작동하는지 확인하는 것이 중요합니다. 로드밸런서는 SSE 연결을 장시간 유지할 수 있도록 설정해야 합니다.

로드밸런서만 추가해도 기본적인 동작은 가능하지만, 효율적인 운영을 위해서는 로드밸런서와 Node.js 서버 모두에서 연결 수, 타임아웃, 세션 지속성 등의 설정을 적절히 조정해야 합니다.

타임아웃 설정시 일관성이 필요합니다. SSE 연결이 제대로 유지되려면 Node.js 서버의 타임아웃도 로드밸런서의 타임아웃과 일치하거나 그보다 길어야 합니다.

// Node.js 서버 설정
const server = http.createServer(app);

// SSE 연결을 위한 긴 타임아웃 설정
server.keepAliveTimeout = 86400000; // 24시간 (밀리초 단위)
server.headersTimeout = 86460000; // 약간 더 길게 설정 (24시간 + 1분)
        

현재 구조에서는 다음과 같은 타임아웃 설정이 일관성 있게 적용되어야 합니다:

  1. 로드밸런서(Nginx/HAProxy): 24시간 타임아웃
  2. Node.js 서버: 24시간 타임아웃
  3. 업로드 상태 관리: 코드에서 expiresIn: 6 * 60 * 60 (6시간)으로 설정되어 있음

특히 uploadStateService에서는 비활성 상태에 대한 타임아웃이 6시간으로 설정되어 있는데, 이 시간도 일관성 있게 조정하는 것이 좋습니다.

리소스 관리 측면에서는 실제 사용 패턴에 따라 이 타임아웃 값을 조정해야 합니다. 대부분의 업로드가 몇 시간 내에 완료된다면, 24시간보다 짧게 설정하는 것이 리소스 낭비를 줄일 수 있습니다.

2013년 4월 3일 수요일

CUBRID 설치


환경 : CentOS release 5.8 (Final) / 2.6.18-308.20.1.el5

일단 홈페이지 다운로드 페이지로 접속한다
http://www.cubrid.com/zbxe/download

현재 날짜 기준으로 CUBRID-9.1.0.0212-linux.x86_64.sh 이 최신 버전

적당한 곳에 다운로드를 하고 설치할 그룹과 계정을 생성한다 (여기서는 cubrid/cubrid 로 사용)

그리고 다운로드 받은 파일을 cubrid 계정으로 그냥 실행
cubrid>$ sh CUBRID-9.1.0.0212-linux.x86_64.sh

위에서부터 차례대로

라이센스에 동의하냐?
기본 디렉토리에 설치할꺼냐?
CUBRID는 같은 버전끼리 호환된다. 알아들었냐?

그리고 위의 메세지가 나오면 설치가 성공적으로 끝난거다

설치가 끝난 후 다음 명령어를 실행한다
cubrid>$ . /home/cubrid/.cubrid.sh
CUBRID관련 환경정보 설정이므로 설치 후 한번만 실행하면 된다

모든 설치 및 설정이 완료되면 다음과 같이 구동 및 확인을 한다


웹매니저는 서버 설치시 자동 설치되니 방화벽 확인후 https://localhost:8282/ 로 접속을 하면 된다


일단 간단하게나마 설치를 했으니 매니저, 쿼리 브라우저를 설치하여 테스트를 해본다

테스트의 결론은..

큐브리드에 입사하고 싶다...... 하지만 능력이...ㅜㅜ



2013년 3월 28일 목요일

linux에 java 설치

환경 : CentOS release 5.5 (Final)

처음 centos를 설치하면 기본적으로 openjdk가 설치되어 있다
하지만 개발 환경이 sunjdk라면 해당 jdk를 따로 설치해야된다

일단 oracle 다운로드 페이지에서 설치파일을 다운로드 받자
http://www.oracle.com/technetwork/java/javase/downloads/index.html

현재시간으로 javase6의 가장 최신버전을 다운로드 받았다

1. 실행파일로 모드 변경
# chmod 755 jdk-6u41-linux-x64.bin 

2. java 설치
# ./jdk-6u41-linux-x64.bin 

3. 적당한 위치로 이동
# mv jdk1.6.0_41/ /usr/local/

4. 현재 java 버전 확인
# java -version

5. 현재 java 위치 확인
# which java

6. java 링크 경로 확인
# la -l /usr/bin/java (5번결과)

7. 기존링크 끊어주고 새로운 버전 링크지정
# unlink /usr/bin/java
# ln -s /usr/local/jdk1.6.0_41/bin/java /usr/bin/java (5번결과)

8. 최종확인
# ls -l /usr/bin/java
# java -version

9. symbolic link 관리
# cd /etc
# update-alternatives --install "/usr/bin/java" "java" "/usr/local/jdk1.6.0_41/bin/java" 1
# update-alternatives --config java
# java -version

9번과정은 안해도 되는건데 혹시나 8번까지 완료를 하고 나서도 java version이 openjdk로 인식할 경우 해주면 된다

2013년 3월 11일 월요일

centos에서 yum으로 mysql5.5 설치하기


환경 : CentOS release 5.8 (Final)


CentOS 5.x 에서 yum으로 설치할수 있는 mysql은 5.0.x 이다.

yum으로 mysql 5.5 버전을 설치하기 위해서는 다음 순서대로 실행하면 된다.


1. mysql 중지

service mysqld stop 

2. yum repository 추가

rpm -Uvh http://repo.webtatic.com/yum/centos/5/latest.rpm 

3. 기존 mysql 삭제

yum remove mysql mysql-* 

4. libmysqlclient15 설치

yum install libmysqlclient15 --enablerepo=webtatic 

5. mysql 5.5 설치

yum install mysql55 mysql55-server --enablerepo=webtatic 

6. mysql 시작

service mysqld start

7. 테이블 upgrade
mysql_upgrade -u root -p

처음엔 최신버전인 5.6을 설치하려고 mysql56을 했지만 실패
그냥 5.5 설치했다





2013년 3월 8일 금요일

jetty embedded + spring + spring-security + spring-data-jpa + mysql

환경
org.eclipse.jetty : 8.1.8.v20121106
org.springframework : 3.2.0.RELEASE
org.springframework.data : 1.2.0.RELEASE
org.springsecurity : 3.1.3.RELEASE
mysql : 5.5.28

STORY
web.xml, spring.xml 및 각종 config.xml을 없애고 java code 및 java annotation 으로 처리하는것이 최종 목적.
그와 함께 tomcat 대신 jetty를 임베디드 시켜 application 실행시키듯이 main method로 서버실행.
부가적으로 인증은 spring-security를 사용하고 db접근은 spring-data-jpa를 이용하였다

TEST
1. database-context.xml에서 db 설정을 한다 
   - database schema만 생성시켜 놓는다
   - 테이블이 없다면 서버 실행시 테이블을 자동생성 시킴
2. com.dorothy.jetty.Main - main을 실행시킨다
3. test user 정보를 db에 생성시킨다
4. restAPI를 호출한다
POST /test/{pathVar} HTTP 1.1
Host: localhost:8000
Authorization : access_id:access_key
5. log를 확인한다

TODO
처음부터 최종목표대로 NoXML로 하고 싶었지만 은근 애를 먹었다
그래서 일단은 xml설정으로 테스트를 시작하였다
이 소스를 가지고 NoXML로 바꿔나가야겠다

PS.
아 근데 구글블로그는 파일 첨부가 안되는거였군.....ㅡㅡ;;;
일단은 구글드라이브에..

한글 포함된 url 전송


환경
CentOS release 5.8 (Final)
apache-tomcat-7.0.35

현상
개발환경을 모두 utf-8로 맞추고 개발을 했지만 아무리 GET으로 api를 호출해도 한글만큼은 깨지는것이였다
물론 클라이언트에서는 utf-8로 인코딩후 요청

GET /list/?objectPath=/%ED%95%9C%EA%B8%80/ HTTP 1.1

서버는 아래처럼 spring을 사용했기 때문에 당연히 spring에서 처리해주는걸로 기대했지만 그게 아니였다 ㅡㅡ;;

org.springframework-version : 3.2.0.RELEASE
org.springframework.data-version : 1.2.0.RELEASE
org.springsecurity-version : 3.1.3.RELEASE

해결방법
처음엔 받아온 값을 utf-8로 변환시켰었다

String str = new String(value.getBytes("8859_1"), "utf-8");

당연히 잘되었음

하지만 먼가 소스상의 지저분함을 느꼈었고 다른 해결책을 알아보았다
당연히 간단한 방법이 있었음

tomcat의 server.xml에 설정만 해주면 되었다

<Connector port="8080" protocol="HTTP/1.1"
               connectionTimeout="20000"
               redirectPort="8443" URIEncoding="UTF-8" />

결론
한글은 위대하다

2013년 2월 4일 월요일

ORA-01652

*** 2008/10/13 16:20 작성한 내용 ***


ORA-01652 : unable to extend temp segment by 128 in table space TEMP
메세지가 출력된다면....

주로 두가지 원인때문인데

temp tablespace를 구성하는 data file의 size가 작은 경우랑
temp tablespace의 max extents에 도달한 경우이다...


첫번째 원인인 경우 일단 temp tablespace의 tempfile크기를 확인한다

SQL>SELECT * FROM DBA_TEMPFILES
2 WHERE TABLESPACE_NAME = 'TEMP';

확인 후 tablespace 공간을 세가지중 한가지 방법으로 추가한다
 
SQL>ALTER TABLESPACE TEMP ADD TEMPFILE'/ORADATA/TEMP02.DBF' SIZE 100M; or
SQL>ALTER DATABASE TEMPFILE'/ORADTA/TEMP01.DBF' AUTOEXTENT ON; or
SQL>ALTER DATABASE TEMPFILE"/ORADATA/TEMP01.DBF" RESIZE 100M;
 
두번째 원인인 경우 v$sort_segment를 확인해서 현재 할당된 크기가 얼마인지 확인한다
그리고 할당할 수 있는 최대 extent의 크기가 얼마인지 확인한다
 
SQL>SELECT max(blocks), max(bytes)
2 FROM DBA_FREE_SPACE
3 WHERE tablespace_name = 'TEMP';