sylar 고성능 서버 구현 가이드

프로젝트 개요 및 의존성 설정

환경 구축과 네트워크 설정

VS를 사용해 원격으로 Linux 서버에 연결하는 과정에서, 과거 물리 머신에서 설정했던 여러 구성이 그대로 남아 있었습니다. 하지만 단순히 따라 하기보다 각 단계의 필요성에 대해 고민하게 되었습니다.

gcc, gdb와 VSCode를 연동하여 사용하는 방법, 그리고 올바른 설치 절차를 익혔습니다. 네트워크 설정에서는 가상 머신의 세 가지 연결 방식(브리지, NAT, 호스트 전용)을 이해했습니다.

Linux 배포판이 업데이트되면서 Ubuntu, CentOS, RedHat, Kali 등에서 네트워크 설정 명령어가 달라졌습니다. 과거에는 ens33 파일을 수정하고 정적 라우팅을 추가한 뒤 네트워크를 재시작하는 방식이었지만, 현재는 netplan을 통해 보다 체계적으로 설정하게 되면서 문제 해결이 더 까다로워졌습니다.

IP 주소 범위(0~255)와 같은 기본적인 문제는 컴파일 오류로 나타났고, 엄격한 들여쓰기를 지키지 않으면 컴파일이 실패했습니다. 컴파일이 성공해도 ping이 안 되는 경우는 IP 충돌을 의심하여 DHCP로 전환한 후 자동 할당된 IP를 확인해 정적 설정에 반영했습니다. 외부 네트워크에 ping이 안 되지만 호스트에서 SSH 접속은 가능하다면 게이트웨이 문제일 가능성이 높아 다시 DHCP로 전환하고 route 명령어로 게이트웨이를 확인한 뒤 정적 라우팅을 올바르게 수정하여 문제를 해결했습니다.

로그 모듈 구축

log4cxx 설치 과정

Ubuntu 20.04에 Apache log4cxx를 설치하는 과정에서 여러 의존성 문제를 겪었습니다.

APR(Apache Portable Runtime) 라이브러리를 먼저 설치해야 합니다.

tar xzvf apr-1.6.3.tar.gz
cd apr-1.6.3
./configure --prefix=/usr/local/apr-1.6.3
sudo make
sudo make install

APR-util도 동일한 방식으로 설치합니다.

tar xzvf apr-util-1.6.1.tar.gz
cd apr-util-1.6.1
./configure --prefix=/usr/local/lib/apr-util-1.6.1 --with-apr=/usr/local/lib/apr-1.6.3
sudo make
sudo make install

설치 중 libexpat1-dev가 없어 발생하는 오류는 다음 명령으로 해결합니다.

sudo apt-get install libexpat1-dev

다음으로 log4cxx 자체를 설치합니다.

tar -xvf apache-log4cxx-0.11.0.tar.gz
cd apache-log4cxx-0.11.0
./configure --prefix=/usr/local/log4c-0.11.0 --with-apr=/usr/local/lib/apr-1.6.3 --with-apr-util=/usr/local/lib/apr-util-1.6.1
sudo make
sudo make install

이 과정에서 autoconf, automake, libtool 버전 문제가 발생했습니다. autoconf 2.65 이상이 필요하다는 오류가 나타나면 다음을 수행합니다.

wget ftp://ftp.gnu.org/gnu/autoconf/autoconf-2.69.tar.gz
wget https://ftp.gnu.org/gnu/m4/m4-1.4.6.tar.gz

autoconf와 m4를 설치한 후 automake와 libtool도 설치합니다.

tar -xvf automake-1.16.tar.gz
cd automake-1.16
./configure
make
sudo make install

tar -xvf libtool-2.4.6.tar.gz
cd libtool-2.4.6
./configure
make
sudo make install

libtool 버전 불일치(Version mismatch error)가 발생하면 autoreconf -fiv 명령을 실행하여 해결합니다.

이 모든 과정을 거친 후 log4cxx 설치가 완료됩니다.

로깅 표준과 log4j 취약점

log4j, logback, log4j2 등 여러 로깅 프레임워크가 서로 다른 인터페이스를 제공하기 때문에 SLF4J(Simple Logging Facade for Java) 같은 퍼사드 인터페이스가 필요합니다.

logback은 SLF4J를 기본 구현하지만 log4j는 그렇지 않으므로, log4j를 SLF4J 표준에 맞추려면 log4j-over-slf4j 의존성을 추가해야 합니다. 여러 구현체가 동시에 존재할 경우 클래스 로딩 순서에 따라 결정되므로, exclude 등을 사용해 의존성을 명확히 지정해야 합니다.

log4j의 JNDI 취약점(CVE-2021-44228)은 공격자가 악의적인 RMI 서버를 실행하고 log4j의 JNDI lookup 기능을 통해 서버 측에서 원격 객체를 로드하도록 조작합니다. 이로 인해 서버에서 임의의 코드가 실행되어 시스템이 손상될 수 있습니다. 이는 SQL 인젝션과 유사한 JNDI 인젝션 공격입니다.

sylar 로그 모듈 설계

log4cpp의 로그 레벨을 참고하여 다음과 같은 열거형을 정의합니다.

enum Level {
    FATAL  = 0,     
    ALERT  = 100,   
    CRIT   = 200,   
    ERROR  = 300,   
    WARN   = 400,   
    NOTICE = 500,   
    INFO   = 600,   
    DEBUG  = 700,   
    NOTSET = 800,   
};

핵심 클래스는 다음과 같습니다.

class LogFormatter;
class LogAppender;
class Logger;
class LogEvent;
class LogEventWrap;
class LogManager;

LogFormatter는 log4cpp의 PatternLayout 역할을 하며, 생성 시 지정된 패턴에 따라 로그 이벤트를 문자열로 포맷팅합니다.

LogAppender는 포맷된 로그를 특정 출력 대상(콘솔, 파일 등)으로 내보냅니다. 내부에 LogFormatter를 보유하며, log 메서드를 통해 로그를 처리합니다. StdoutLogAppenderFileLogAppender로 확장할 수 있습니다.

Logger는 여러 LogAppender와 로그 레벨을 포함합니다. log 메서드는 전달된 LogEvent의 레벨이 Logger의 레벨보다 높은 경우에만 Appender를 통해 로그를 출력합니다.

LogEvent는 로그 레벨, 파일명/라인 번호, 메시지, 스레드/코루틴 ID, 로거 이름 등 로그 발생 시점의 컨텍스트를 저장합니다.

LogEventWrap은 LogEvent와 Logger를 함께 묶어 매크로 사용을 간편하게 합니다. 소멸 시 Logger의 log 메서드를 호출하여 실제 로그를 출력합니다.

LogManager는 싱글톤 패턴으로 모든 Logger를 관리합니다. 기본 root Logger를 제공하여 초기 로깅을 보장합니다.

로그 모듈 동작 흐름

  1. LogFormatter, LogAppender, Logger를 초기화합니다.
  2. 매크로를 통해 스트림 방식 및 포맷 방식의 로그 인터페이스를 제공합니다. 로그를 기록할 때마다 LogEvent를 생성하고 Logger와 함께 LogEventWrap 객체로 감쌉니다.
  3. LogEventWrap 객체가 소멸되면서 Logger의 log 메서드를 호출하여 로그를 최종 출력합니다.

태그: sylar log4cxx APR Netplan SLF4J

6월 17일 20:05에 게시됨