no image
HikariCP 커넥션 풀 최적화하기
🚀 느린 환경에서 HikariCP 커넥션 풀 최적화하기Spring + MySQL 시스템 속도를 확 끌어올리는 실전 가이드👋 들어가며Spring + HikariCP 조합은 빠르고 안정적이지만, 컴퓨터 성능이 낮거나 MySQL이 느린 환경에서는 오히려 문제가 더 자주 발생합니다.예를 들어:커넥션 타임아웃 에러가 자꾸 발생한다요청이 몰리면 시스템 전체가 느려진다CPU와 메모리 점유율이 갑자기 튄다MySQL이 죽어서 서비스 전체가 멈춘다이런 문제는 대부분 커넥션 풀 설정이 머신 스펙과 맞지 않아 발생하는 경우가 많습니다.이번 글에서는 느린 환경에서도 안정적으로 동작하는 HikariCP 최적화 설정을 단계별로 정리했습니다.🔍 문제 원인 분석: 왜 느린 환경에서 HikariCP가 문제를 일으킬까?HikariC..
2025.11.19
no image
JDBC 커넥션 풀 고갈 문제 해결기
🚨 문제 상황증상: 레거시로 프로그램에 JDBC 커넥션을 못 잡아서 애플리케이션이 간헐적으로 터짐환경: HikariCP 사용 중, MySQL max_connections = 10,000의문: 커넥션 풀도 있고 MySQL 설정도 충분한데 왜?🔍 원인 분석1. 스레드 수 vs 커넥션 풀 크기 불균형애플리케이션 스레드 구성:├─ 스케줄러 스레드: 15개├─ 비동기 스레드: 5-20개 ├─ SMS 워커 스레드: 3개└─ LED 스레드: 3-10개총 최대 48개 스레드HikariCP 커넥션 풀: 15개 ❌→ 스레드 수가 커넥션 풀보다 3배 많음!2. 1분 스케줄러의 대량 개별 UPDATE// 매 1분마다 2개 스케줄러 동시 실행@Scheduled(cron = "0 0/1 * * * *")public void..
2025.11.13
no image
가비아 DNS 쓰는 개발자의 SSL 자동갱신 좌충우돌기 (feat. Postfix + Naver SMTP)
1️⃣ 배경: 왜 메일 알림이 필요했는가?도메인 인증서(SSL)는 Let’s Encrypt로 무료 발급이 가능하지만,이번에 Wildcard 방식으로 만들 수밖에 없었다.특히 *.도메인 형태의 Wildcard 인증서는 DNS TXT 레코드를 직접 등록해야 하기 때문이다.(💡 보충 설명)일반 도메인(example.com, www.example.com)은 HTTP-01 인증 방식을 이용해 자동 갱신이 가능하다.즉, certbot renew를 크론(cron)에 등록해두면,서버가 자동으로 /.well-known/acme-challenge/ 경로에 임시 인증파일을 만들고Let’s Encrypt가 HTTP 요청으로 이를 확인해 인증을 갱신한다.그러나 Wildcard(*.example.com)의 경우,하위 도메인 전..
2025.10.26
no image
크림 kream 보관판매 매크로
🤖 BoPan Robot - 크림 보관판매 자동화 프로그램 안녕하세요! 크림 보관판매를 자동화해주는 프로그램입니다.📥 다운로드🖥️ Windows 사용자Windows 다운로드 https://drive.google.com/file/d/19RHsrWpviG9_udveEEnFrC7rbiZiT0Ix/view BoPan-Robot-Windows.zip drive.google.com 압축 해제 → BoPan Robot.exe 실행 → 바로 사용! ✅🍎 macOS 사용자macOS 다운로드 https://drive.google.com/file/d/1T5pcZV23mqKWHHm5YYaO7xbp0xU04oDW/view BoPan-Robot-macOS.zip drive.google.com압축 해제 후 터미널에서 한 번..
2025.07.28
no image
[2] Apache에서 Nginx로 갈아타기
💪 실전 마이그레이션 과정1단계: 기존 시스템 분석 및 측정bash# 기존 Apache 서버 정확한 측정echo "=== Apache 측정 $(date) ==="apache_mem=$(ps aux | grep httpd | grep -v grep | awk '{sum+=$6} END {print sum/1024}')apache_proc=$(ps aux | grep httpd | grep -v grep | wc -l)connections=$(netstat -an | grep :80 | grep ESTABLISHED | wc -l)echo "Apache Memory: ${apache_mem} MB"echo "Apache Processes: ${apache_proc}"echo "Active Connectio..
2025.07.05
no image
[1] Apache에서 Nginx로 갈아타기
🔥 서버를 옮기기전 했던 고민회사에서 운영하던 웹사이트 및 API 서버가 느려지기 시작했다. 비용 절약을 위해 하나의 서버에서 웹사이트와 백엔드 API를 함께 돌리고 있었는데, 트래픽이 증가하면서 문제가 표면화되었고,이번에 서버를 옮기는 과정에 (nhn 하드웨어서버 -> navercloud) 개선을 해보도록 하였다.문제 상황의 구체적 모습:웹사이트 응답 속도 저하: 특히 이미지와 정적 파일 로딩 지연API 서버 응답 지연: JSON 응답이 평소 200ms에서 2-3초까지 늘어남서버 리소스 경합: 웹사이트 트래픽 증가 시 API 성능도 함께 저하상호 영향: API 호출이 많아지면 웹사이트도 느려지는 악순환ㄴ메모리 사용량 모니터링으로 확인한 문제점:ApacheRAM: 7.7G total, 5.7G used..
2025.07.05
no image
Flutter 앱 아이콘 간단히 설정하기(flutter_launcher_icons 사용)
플러터 앱 출시를 위해선 앱 아이콘을 변경을 해주어야한다. 아니면 기본 flutter 아이콘으로 앱이 나오기 때문이다.이럴 때 유용하게 사용할 수 있는 라이브러리가 flutter_launcher_icons 이다! https://pub.dev/packages/flutter_launcher_icons flutter_launcher_icons | Dart packageA package which simplifies the task of updating your Flutter app's launcher icon.pub.dev 1. 설치터미널에 해당 명령어를 입력핵서 설치한다2. 설정1) pubspec.yaml 설정Flutter 프로젝트의 pubspec.yaml에 아래와 같이 설정합니다:dev_dependenci..
2025.01.30
no image
플러터 초기 실행시 AGP 버전 맞지 않을때 해결법
┌─ Flutter Fix ────────────────────────────────────────────────────────────────────────────────────┐ │ [!] This is likely due to a known bug in Android Gradle Plugin (AGP) versions less than 8.2.1, │ │ when │ │ 1. setting a value for SourceCompatibility and │ │ 2. using Java 21 or above. │ │ To fix this error, please upgrade your AGP version to at least 8.2.1. The version of AGP that │ │ your pr..
2025.01.30

🚀 느린 환경에서 HikariCP 커넥션 풀 최적화하기

Spring + MySQL 시스템 속도를 확 끌어올리는 실전 가이드


👋 들어가며

Spring + HikariCP 조합은 빠르고 안정적이지만, 컴퓨터 성능이 낮거나 MySQL이 느린 환경에서는 오히려 문제가 더 자주 발생합니다.

예를 들어:

  • 커넥션 타임아웃 에러가 자꾸 발생한다
  • 요청이 몰리면 시스템 전체가 느려진다
  • CPU와 메모리 점유율이 갑자기 튄다
  • MySQL이 죽어서 서비스 전체가 멈춘다

이런 문제는 대부분 커넥션 풀 설정이 머신 스펙과 맞지 않아 발생하는 경우가 많습니다.

이번 글에서는 느린 환경에서도 안정적으로 동작하는 HikariCP 최적화 설정을 단계별로 정리했습니다.


🔍 문제 원인 분석: 왜 느린 환경에서 HikariCP가 문제를 일으킬까?

HikariCP는 기본적으로 "고성능 서버"를 기준으로 설계된 풀입니다.
그래서 다음과 같은 증상이 나타나기 쉽습니다.

❗ 대표 문제들

문제 원인
Connection Timeout 커넥션 생성 속도가 느려 타임아웃 발생
커넥션 부족 Pool Size가 머신 성능 대비 무리함
메모리 부족 풀을 너무 크게 잡아 메모리 사용 폭증
MySQL 다운 커넥션 과다 생성으로 DB 과부하

즉, 문제의 핵심은 “풀 크기와 타임아웃이 머신 스펙과 맞지 않는다”는 것입니다.


🧩 HikariCP 주요 설정 이해하기

기존 문제가 발생하던 설정은 보통 이런 형태였습니다:

<property name="minimumIdle" value="10"/>
<property name="maximumPoolSize" value="50"/>
<property name="connectionTimeout" value="30000"/>
<property name="idleTimeout" value="600000"/>
<property name="maxLifetime" value="1800000"/>

설정값 영향 요약

설정 설명 너무 크면? 너무 작으면?
minimumIdle 유지할 최소 유휴 커넥션 메모리 낭비 커넥션 생성 지연
maximumPoolSize 최대 커넥션 수 MySQL 부하, 메모리 증가 처리량 감소
connectionTimeout 커넥션 기다리는 시간 응답 지연 Timeout 증가
idleTimeout 유휴 연결 정리 시간 불필요 메모리 점유 커넥션 재생성 비용 증가
maxLifetime 커넥션 유효 기간 교체 오버헤드 커넥션 누수 위험

🛠️ 단계별 최적화 방법

✅ 1단계: 타임아웃 조정 (느린 환경 필수)

기본 30초는 너무 짧습니다. 느린 컴퓨터에서는 DB 커넥션 자체가 느려 타임아웃이 쉽게 발생합니다.

<property name="connectionTimeout" value="60000"/>

또한 MySQL JDBC URL에도 timeout 옵션을 명시적으로 넣어줍니다.

jdbc:mysql://127.0.0.1:3306/enha?characterEncoding=UTF-8&useSSL=false&autoReconnect=true&socketTimeout=60000&connectTimeout=15000

📌 효과:

  • 커넥션 생성 중 타임아웃 발생 위험 감소
  • 느린 환경에서도 안정적으로 커넥션 확보

✅ 2단계: 시스템 성능에 맞게 Pool Size 줄이기

속도가 느린 환경에서 최대 50개 풀은 MySQL에게 과도한 압력입니다.

👉 동시 사용자 약 10명 기준 최적값:

<property name="minimumIdle" value="5"/>
<property name="maximumPoolSize" value="20"/>

📌 근거 계산

사용자 10명 × 1.5 커넥션 = 15개  
시스템용 = 1~2개  
기타 앱 = 2~3개  

총 20개 수준이 가장 안정적

✅ 3단계: 메모리 최적화

유휴 시간을 줄이고, 커넥션 수명을 짧게 해서 시스템 부담을 줄입니다.

<property name="idleTimeout" value="300000"/>     <!-- 5분 -->
<property name="maxLifetime" value="900000"/>     <!-- 15분 -->

📉 메모리 사용량 변화

설정 커넥션 수 메모리
기존 50개 약 150MB
최적화 20개 약 60MB
절감률 60% 절약

📊 MySQL 커넥션 모니터링 쿼리 모음

현재 커넥션 사용량

SELECT 
    VARIABLE_NAME, VARIABLE_VALUE
FROM INFORMATION_SCHEMA.GLOBAL_STATUS 
WHERE VARIABLE_NAME IN ('Threads_connected', 'Max_used_connections');

커넥션 에러 확인

SHOW STATUS LIKE 'Connection_errors%';
SHOW STATUS LIKE 'Aborted_connects';

호스트별 연결 상황

SELECT 
    SUBSTRING_INDEX(HOST, ':', 1) AS client,
    USER,
    COUNT(*) AS connections
FROM INFORMATION_SCHEMA.PROCESSLIST
GROUP BY client, user
ORDER BY connections DESC;

🎯 최종 추천 설정 (느린 PC/저사양 서버용)

<bean id="dataSource" class="com.zaxxer.hikari.HikariDataSource" destroy-method="close">
    <property name="driverClassName" value="com.mysql.jdbc.Driver"/>

    <!-- 본인 환경에 맞춰 DB 주소/스키마를 수정하세요 -->
    <property name="jdbcUrl" value="jdbc:mysql://DB_HOST:3306/DB_NAME?characterEncoding=UTF-8&useSSL=false&autoReconnect=true&socketTimeout=60000&connectTimeout=15000"/>

    <!-- 계정 정보는 환경변수 또는 설정파일에서 주입 -->
    <property name="username" value="${DB_USER}"/>
    <property name="password" value="${DB_PASSWORD}"/>

    <!-- 최적화된 HikariCP 설정 -->
    <property name="minimumIdle" value="5"/>
    <property name="maximumPoolSize" value="20"/>
    <property name="connectionTimeout" value="60000"/>
    <property name="idleTimeout" value="300000"/>
    <property name="maxLifetime" value="900000"/>
    <property name="leakDetectionThreshold" value="60000"/>

    <property name="validationTimeout" value="5000"/>
    <property name="poolName" value="enhaSR-OptimizedPool"/>
</bean>

📝 최적화 결과

지표 최적화 전 최적화 후 개선
메모리 사용량 150MB 60MB 60% 감소
커넥션 에러 잦음 거의 없음 95% 감소
평균 응답속도 2~3초 0.8~1.2초 60% 개선
시스템 안정성 불안정 매우 안정적 상승

💡 환경별 추천값

개발 환경 (1~2명)

minimumIdle = 2
maximumPoolSize = 8

스터디카페/소규모 운영 (5~10명)

minimumIdle = 5
maximumPoolSize = 20

중형 서비스 (20~50명)

minimumIdle = 10
maximumPoolSize = 50

📌 마무리

느린 환경에서 “많은 커넥션을 유지하려는 시도”는 오히려 MySQL을 죽이고 시스템을 더 느리게 만드는 지름길입니다.

✔️ 핵심은 적은 수의 안정적인 커넥션 유지
✔️ 타임아웃은 느린 환경을 고려해 충분히 늘리기
✔️ MySQL 상태는 주기적으로 모니터링하기

이 설정만 적용해도 대부분의 커넥션 문제가 해결되고
응답 속도, 안정성 모두 크게 개선됩니다.

 

🚨 문제 상황

  • 증상: 레거시로 프로그램에 JDBC 커넥션을 못 잡아서 애플리케이션이 간헐적으로 터짐
  • 환경: HikariCP 사용 중, MySQL max_connections = 10,000
  • 의문: 커넥션 풀도 있고 MySQL 설정도 충분한데 왜?

🔍 원인 분석

1. 스레드 수 vs 커넥션 풀 크기 불균형

애플리케이션 스레드 구성:
├─ 스케줄러 스레드: 15개
├─ 비동기 스레드: 5-20개  
├─ SMS 워커 스레드: 3개
└─ LED 스레드: 3-10개
총 최대 48개 스레드

HikariCP 커넥션 풀: 15개 ❌
→ 스레드 수가 커넥션 풀보다 3배 많음!

2. 1분 스케줄러의 대량 개별 UPDATE

// 매 1분마다 2개 스케줄러 동시 실행
@Scheduled(cron = "0 0/1 * * * *")
public void startMethod2() { /* 자동퇴실, 스터디룸 관리 */ }

@Scheduled(cron = "0 0/1 * * * *") 
public void startMethod3() { /* 자습실 시간 스케줄 */ }

커넥션 폭증 시나리오:

매 1분 정각:
├─ 자동퇴실 50명 × 개별 UPDATE = 50개 커넥션
├─ 스터디룸 20개 × 개별 UPDATE = 20개 커넥션
├─ 기타 조회/업데이트 = 30개 커넥션
└─ 일반 웹 요청 = 10개 커넥션
총 110개 커넥션 동시 사용! (풀 크기: 15개)

3. 불필요한 SMS DB 설정

<!-- 사용하지 않는 SMS DB (커넥션 풀 없음) -->
<bean id="dataSource2" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
    <!-- 매번 새 커넥션 생성/해제 → 성능 저하 -->
</bean>

🚀 해결 방안

1. HikariCP 커넥션 풀 최적화

<!-- 기존 설정 -->
<property name="minimumIdle" value="3"/>
<property name="maximumPoolSize" value="15"/>
<property name="idleTimeout" value="30000"/>      <!-- 30초 -->
<property name="maxLifetime" value="1200000"/>    <!-- 20분 -->

<!-- 개선된 설정 -->
<property name="minimumIdle" value="10"/>         <!-- 안정적 기본 연결 -->
<property name="maximumPoolSize" value="50"/>     <!-- 스레드 48개 대응 -->
<property name="idleTimeout" value="600000"/>     <!-- 10분 -->
<property name="maxLifetime" value="1800000"/>    <!-- 30분 -->
<property name="leakDetectionThreshold" value="60000"/> <!-- 1분, 빠른 감지 -->

2. 배치 업데이트 도입

기존 방식 (N+1 문제):

for(int i=0; i<list.size(); i++) {
    // 개별 UPDATE (매번 커넥션 사용)
    params.put("querykey", "seat_power_state_update");
    params.put("power_number", powerNumber);
    params.put("power_state", "0");
    comService.simpleUpdate(params);  // 커넥션 1개 사용
}

개선된 방식 (배치 처리):

List<String> powerNumbers = new ArrayList<String>();

for(int i=0; i<list.size(); i++) {
    // 데이터만 수집 (커넥션 사용 안 함)
    powerNumbers.add(powerNumber);
}

// 한 번에 배치 업데이트 (커넥션 1개만 사용)
comService.batchUpdateSeatPowerState(powerNumbers, "0");

배치 UPDATE 쿼리:

<update id="seat_power_state_batch_update">
    UPDATE xe_tbl_seat 
    SET power_state = #{power_state}
    WHERE power_number IN 
    <foreach collection="power_numbers" item="power_number" open="(" close=")" separator=",">
        #{power_number}
    </foreach>
</update>

3. 사용하지 않는 SMS DB 설정 제거

<!-- 제거된 설정들 -->
<bean id="dataSource2">...</bean>
<bean id="sqlSessionFactory2">...</bean>
<bean id="transactionManager2">...</bean>
<bean id="sqlSession2">...</bean>

📊 성능 개선 결과

커넥션 사용량 비교

시나리오 기존 개선 후 개선율
자동 퇴실 50명 50개 UPDATE 1개 UPDATE 98% 감소
스터디룸 20개 20개 UPDATE 1개 UPDATE 95% 감소
업무 마감 100좌석 100개 UPDATE 1개 UPDATE 99% 감소
1분 스케줄러 전체 170개 커넥션 20개 커넥션 88% 감소

실제 SQL 실행 비교

-- 기존: 100개 좌석 처리 시
UPDATE xe_tbl_seat SET power_state = '0' WHERE power_number = '1';
UPDATE xe_tbl_seat SET power_state = '0' WHERE power_number = '2';
-- ... 100번 반복

-- 개선: 100개 좌석 처리 시  
UPDATE xe_tbl_seat SET power_state = '0' 
WHERE power_number IN ('1','2','3',...,'100');

🛡️ 안전한 적용 전략

배치 적용 기준

적용 가능

  • 상태값이 명확하게 동일한 경우
  • 로직이 단순한 경우
  • 안전성이 보장되는 경우

적용 제외

  • 상태값이 동적으로 계산되는 경우
  • 복잡한 조건문이 있는 경우
  • 기존 로직 변경 위험이 있는 경우

적용된 4가지 케이스

  1. 자동 퇴실: 시간 만료 → 모두 OFF
  2. 스터디룸 퇴실: 예약 종료 → 모두 OFF
  3. 스터디룸 입실: 예약 시작 → 모두 ON ⭐
  4. 업무 마감: 운영 종료 → 모두 OFF

🎯 핵심 교훈

1. 스레드 수와 커넥션 풀 크기의 관계

  • 동시 실행 가능한 스레드 수 ≤ 커넥션 풀 크기
  • 스케줄러, 비동기 작업 등 모든 스레드 고려 필요

2. 배치 처리의 위력

  • N+1 문제 해결로 극적인 성능 향상
  • 안전한 부분만 선별 적용해도 큰 효과

3. 모니터링의 중요성

  • 커넥션 누수 감지 시간 단축 (5분 → 1분)
  • 배치 처리 결과 로깅으로 효과 측정

💡 결론

"스레드 수를 고려한 커넥션 풀 크기 조정 + 선별적 배치 업데이트 적용"

  • 스케줄러 실행 횟수는 그대로 유지
  • 커넥션 사용량만 88% 감소
  • 기존 기능 완전 보존
  • 안정성과 성능 두 마리 토끼 모두 확보

결과: 커넥션 풀 고갈 문제 해결된거같으나 경과를 지켜봐야할꺼같다..

1️⃣ 배경: 왜 메일 알림이 필요했는가?

도메인 인증서(SSL)는 Let’s Encrypt로 무료 발급이 가능하지만,
이번에 Wildcard 방식으로 만들 수밖에 없었다.
특히 *.도메인 형태의 Wildcard 인증서DNS TXT 레코드를 직접 등록해야 하기 때문이다.

(💡 보충 설명)
일반 도메인(example.com, www.example.com)은 HTTP-01 인증 방식을 이용해 자동 갱신이 가능하다.
즉, certbot renew를 크론(cron)에 등록해두면,
서버가 자동으로 /.well-known/acme-challenge/ 경로에 임시 인증파일을 만들고
Let’s Encrypt가 HTTP 요청으로 이를 확인해 인증을 갱신한다.

그러나 Wildcard(*.example.com)의 경우,
하위 도메인 전체(aaa.example.com, bbb.example.com 등)에 대한 권한을 증명해야 하기 때문에
HTTP 방식만으로는 “도메인 전체의 소유자임”을 확인할 수 없다.
그래서 Let’s Encrypt는 DNS-01 방식, 즉 “DNS에 TXT 레코드로 인증값을 등록하는 방법”만 허용한다.


내가 사용하는 가비아(Gabia)DNS API를 제공하지 않기 때문에,
Certbot이 자동으로 TXT 레코드를 추가할 수 없다.
(이 부분 때문에 가비아를 쓰는 걸 조금 후회 중... 😅
AWS Route 53, Cloudflare, Google Cloud DNS 등은
API를 통해 TXT 레코드를 자동 등록할 수 있어 Wildcard 자동갱신이 가능하다.)


즉, 매번 아래 명령을 직접 실행해야 한다 👇

sudo certbot certonly --manual --preferred-challenges dns \
  -d example.com -d '*.example.com'

그리고 DNS TXT 두 개를 수동으로 등록해야 한다.

이 과정 자체는 어렵지 않지만,
👉 인증서 유효기간(90일)을 깜빡하면 사이트가 “보안 연결 실패”로 중단된다.
그래서 만료 30일 전 메일로 자동 알림이 오도록 설정해두었다.

 


2️⃣ 환경 요약

항목 내용

OS Rocky Linux 9
인증서 Let’s Encrypt (Wildcard)
DNS 가비아 (API 미지원)
메일 전송 Postfix + s-nail + Naver SMTP (465 SSL)
알림 스크립트 /root/check-ssl.sh (cron 자동 실행)

3️⃣ 메일 발송 실패 이유와 해결

초기엔 s-nail로 메일을 보내려 했지만 실패했습니다.

문제 로그

550 5.7.2 Your email has been blocked because the sender is unauthenticated.

이는 Postfix가 단순 로컬 송신(unauthenticated)이라서
네이버 SMTP 인증이 안 된 상태였기 때문입니다.

✅ 해결 과정 요약

가비아 DNS 환경에서 Let’s Encrypt Wildcard 인증서 만료 알림 메일을 보내기 위해
로컬 서버(Postfix)가 네이버 SMTP 서버를 통해 인증 발송하도록 설정했습니다.


1️⃣ Postfix 및 메일 유틸 설치

sudo dnf install -y postfix s-nail
sudo systemctl enable --now postfix
  • postfix: 메일 전송(MTA) 서버
  • s-nail: 간단한 CLI 메일 발송 도구
  • enable --now: 부팅 시 자동 실행 + 즉시 시작

2️⃣ SMTP 인증 설정 (/etc/postfix/main.cf)

inet_interfaces = 127.0.0.1
inet_protocols = ipv4
relayhost = [smtp.naver.com]:465

smtp_use_tls = yes
smtp_tls_security_level = encrypt
smtp_sasl_auth_enable = yes
smtp_sasl_password_maps = hash:/etc/postfix/sasl_passwd
smtp_sasl_security_options = noanonymous
smtp_generic_maps = hash:/etc/postfix/generic

📌

  • relayhost: 네이버 SMTP 서버 지정
  • smtp_sasl_password_maps: 계정/비밀번호 저장 위치
  • smtp_generic_maps: 로컬 root 주소를 네이버 메일 주소로 변환

3️⃣ SMTP 비밀번호 파일 설정

sudo nano /etc/postfix/sasl_passwd
[smtp.naver.com]:465 example@naver.com:애플리케이션비밀번호

 

sudo postmap /etc/postfix/sasl_passwd
sudo chmod 600 /etc/postfix/sasl_passwd /etc/postfix/sasl_passwd.db

💡

  • 일반 비밀번호는 사용 불가
    네이버 2단계 인증 활성화 후 앱 비밀번호를 생성해야 함. (중요!!)
  • postmap: Postfix가 읽을 수 있는 해시 DB로 변환.
  • chmod 600: 파일 권한 제한(보안 때문에!)

4️⃣ 메일 주소 변환 설정

sudo nano /etc/postfix/generic
root@xxx-web-01.example.kr  example@naver.com
sudo postmap /etc/postfix/generic

📌
로컬에서 root@xxx.example.kr 로 발송되는 메일을
외부에서는 example@naver.com 으로 보이게 변환.


5️⃣ Postfix 재시작

sudo systemctl restart postfix

6️⃣ 테스트 메일 발송

echo "테스트 메일입니다." | s-nail -s "Postfix → Naver OK?" -r example@naver.com example@naver.com

이후 로그 확인 👇

sudo tail -n 50 /var/log/maillog

정상이라면 다음 메시지가 보입니다:

250 2.0.0 OK ... - nsmtp

🎉 SMTP 인증 성공!
이제 서버가 네이버 SMTP를 통해 정상적으로 인증된 메일을 발송할 수 있습니다.

 

이제 테스트 성공했으니 해당 관련해서 크론에서 실행 되도록 스크립트를 만들어 보자!


4️⃣ SSL 만료 알림 스크립트

/root/check-ssl.sh

#!/usr/bin/env bash
EMAIL="example@naver.com"
CERT="/etc/letsencrypt/live/example.kr/fullchain.pem"
THRESHOLD=30  # 만료 30일 이하부터 알림

if [[ ! -f "$CERT" ]]; then
  echo "⚠️ 인증서 파일을 찾을 수 없습니다: $CERT" |
  s-nail -s "[SSL 경고] example.kr 인증서 파일 없음" "$EMAIL"
  exit 1
fi

EXPIRE_RAW=$(openssl x509 -in "$CERT" -noout -enddate | cut -d= -f2)
EXPIRE_TS=$(date -d "$EXPIRE_RAW" +%s)
NOW_TS=$(date +%s)
DAYS_LEFT=$(( (EXPIRE_TS - NOW_TS) / 86400 ))

if (( DAYS_LEFT <= THRESHOLD )); then
  SUBJECT="⚠️ example.kr SSL ${DAYS_LEFT}일 후 만료 예정"
  BODY=$(cat <<EOF
도메인: example.kr (*.enhasys.kr)
인증서 경로: $CERT
만료일: $EXPIRE_RAW (D-${DAYS_LEFT})

✅ 조치 방법:
1. 가비아 DNS에 TXT 2개 추가
2. 아래 명령으로 갱신 실행

sudo certbot certonly --manual --preferred-challenges dns \
  -d example.kr -d '*.example.kr'

EOF
)
  echo "$BODY" | s-nail -s "$SUBJECT" "$EMAIL"
fi

5️⃣ 크론 설정

crontab -e
0 3 * * * certbot renew --quiet
0 9 * * * /root/check-ssl.sh
  • 오전 3시: 자동 갱신 시도 (일반 도메인용) (와일드 카드가 아닌 도메인들은 이렇게 직접 자동 갱신이 되도록 해놨다.)
  • 오전 9시: example.kr 만료일 체크 후 메일 발송

✅ 결과

  • 이제 example.kr 와일드카드 인증서만 수동 갱신하면 됨
  • 나머지 도메인(example1.co.kr, example2.co.kr)은 자동 갱신됨
  • 만료 30일 전 자동 메일 도착으로 깜빡할 일이 없음

📎 결론

  • Postfix 설정
  • SASL 인증
  • 가비아 API 부재 대응
  • crontab 자동화
    까지 해야하는 과정이었다.
  • (즉 DNS는 꼭 API 있는걸로 사용하시길  @@)

동작 gif

🤖 BoPan Robot - 크림 보관판매 자동화 프로그램 

안녕하세요! 크림 보관판매를 자동화해주는 프로그램입니다.


📥 다운로드

🖥️ Windows 사용자

Windows 다운로드

 

https://drive.google.com/file/d/19RHsrWpviG9_udveEEnFrC7rbiZiT0Ix/view

 

BoPan-Robot-Windows.zip

 

drive.google.com

 

  • 압축 해제 → BoPan Robot.exe 실행 → 바로 사용!

🍎 macOS 사용자

macOS 다운로드

 

https://drive.google.com/file/d/1T5pcZV23mqKWHHm5YYaO7xbp0xU04oDW/view

 

BoPan-Robot-macOS.zip

 

drive.google.com

  • 압축 해제 후 터미널에서 한 번만 실행:
    xattr -rd com.apple.quarantine "/Users/사용자명/Downloads/BoPan Robot.app"
  • 이후 BoPan Robot.app 더블클릭 → 정상 실행!

🎯 간단 사용법

1️⃣ 로그인

  • 우측 상단 로그인 버튼 클릭
  • 크림 계정 정보 입력

2️⃣ 상품 검색

  • 제품명 입력 후 검색 버튼
  • 원하는 상품 선택

3️⃣ 자동화 시작

  • 상세정보 버튼 클릭
  • 사이즈 확인 후 🤖로봇시작 클릭
  • 자동으로 보관판매 신청 완료! 🚀

4️⃣ 모니터링

  • 로그창에서 진행상황 실시간 확인
  • 🛑로봇중지 버튼으로 언제든 중지 가능

⚠️ 주의사항

  • 무료 프로그램입니다
  • 안전한 프로그램이지만 보안 프로그램에서 경고 발생 가능
  • 미서명 앱으로 인한 정상적인 보안 알림
  • ⚠️ 사용은 본인 책임하에 이용해주세요

🔧 문제 해결

자주 묻는 질문

  • 로그인 안됨: 계정정보 재확인
  • 검색 안됨: 다른 제품명으로 재시도
  • 앱 실행 안됨: 보안설정에서 실행 허용

macOS 사용자 추가 도움

보안 경고가 계속 나타나면:

  1. 시스템 환경설정보안 및 개인정보 보호
  2. 일반 탭에서 "BoPan Robot 열기 허용" 클릭

💬 사용 후기 & 지원

2025년 7월 27일 기준 작동 잘됨

댓글로 잘 되는지 적어주시면 몇분 나중 추가 권한 드리겠습니다! 🎁

 

 

문의 및 지원

  • 💬 댓글로 문의해주세요!
  • 🐛 버그 신고 환영합니다
  • 💡 개선 아이디어 제안해주세요

💪 실전 마이그레이션 과정

1단계: 기존 시스템 분석 및 측정

bash

# 기존 Apache 서버 정확한 측정
echo "=== Apache 측정 $(date) ==="
apache_mem=$(ps aux | grep httpd | grep -v grep | awk '{sum+=$6} END {print sum/1024}')
apache_proc=$(ps aux | grep httpd | grep -v grep | wc -l)
connections=$(netstat -an | grep :80 | grep ESTABLISHED | wc -l)

echo "Apache Memory: ${apache_mem} MB"
echo "Apache Processes: ${apache_proc}"
echo "Active Connections: ${connections}"

# 성능 벤치마크 측정
ab -n 1000 -c 10 https://example.co.kr/

측정 결과 (Before):

  • 초당 처리 요청: 45 requests/sec
  • 평균 응답 시간: 220ms
  • Apache 메모리 사용량: 186MB (11개 프로세스)
  • 시스템 전체 메모리 사용률: 74%
  • 스왑 사용률: 85% (심각한 상태)

2단계: Naver Cloud에 Nginx 환경 구축

bash

# CentOS 7 환경에서 Nginx 설치
yum install -y nginx

# 기본 설정 최적화
vi /etc/nginx/nginx.conf

글로벌 최적화 설정:

nginx

# worker 프로세스 최적화
worker_processes auto;
worker_connections 1024;

# 압축 설정
gzip on;
gzip_vary on;
gzip_min_length 1000;
gzip_types text/plain text/css application/json application/javascript text/xml application/xml;

# 보안 헤더
add_header X-Frame-Options DENY;
add_header X-Content-Type-Options nosniff;
add_header X-XSS-Protection "1; mode=block";

3단계: 도메인별 설정 분리 - 웹사이트 vs API 최적화

웹사이트(example.co.kr) 설정 - 정적 파일 최적화:

nginx

# /etc/nginx/conf.d/website.conf
server {
    listen 80;
    server_name example.co.kr www.example.co.kr;
    return 301 https://$server_name$request_uri;
}

server {
    listen 443 ssl http2;
    server_name example.co.kr www.example.co.kr;

    # SSL 설정
    ssl_certificate /etc/letsencrypt/live/example.co.kr/fullchain.pem;
    ssl_certificate_key /etc/letsencrypt/live/example.co.kr/privkey.pem;

    # 정적 파일 직접 처리 (핵심 개선점!)
    location ~* \.(jpg|jpeg|png|gif|ico|css|js|woff|woff2)$ {
        root /var/www/html;
        expires 1y;
        add_header Cache-Control "public, immutable";
        access_log off;
    }

    # 동적 요청만 백엔드로
    location / {
        proxy_pass http://127.0.0.1:8081;
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header X-Forwarded-Proto $scheme;
    }
}

API 서버(api.example.co.kr) 설정 - 성능과 응답 최적화:

nginx

# /etc/nginx/conf.d/api.conf
server {
    listen 80;
    server_name api.example.co.kr;
    return 301 https://$server_name$request_uri;
}

server {
    listen 443 ssl http2;
    server_name api.example.co.kr;

    # 같은 SSL 인증서 사용 (관리 효율성)
    ssl_certificate /etc/letsencrypt/live/example.co.kr/fullchain.pem;
    ssl_certificate_key /etc/letsencrypt/live/example.co.kr/privkey.pem;

    # API 전용 최적화 설정
    location / {
        proxy_pass http://127.0.0.1:8085;
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header X-Forwarded-Proto $scheme;

        # API 응답 최적화
        proxy_buffering off;
        proxy_cache_bypass 1;
        proxy_read_timeout 30s;

        # CORS 설정
        add_header Access-Control-Allow-Origin *;
        add_header Access-Control-Allow-Methods "GET, POST, PUT, DELETE, OPTIONS";
        add_header Access-Control-Allow-Headers "Content-Type, Authorization";
    }
}

4단계: SSL 인증서 통합 관리

기존 문제점: 각 도메인별 개별 인증서로 관리 복잡성 증가

해결방법: 멀티도메인 인증서로 통합

bash

# 4개 도메인을 하나의 인증서로 관리
certbot certonly --webroot -w /var/www/html \
  -d example.co.kr -d www.example.co.kr \
  -d api.example.co.kr -d www.api.example.co.kr

# 자동 갱신 설정
crontab -e
0 2 * * 1 certbot renew --quiet && systemctl reload nginx

5단계: 무중단 마이그레이션 실행

DNS 기반 점진적 전환:

  1. 새 서버에서 완전한 테스트 완료
  2. DNS TTL을 300초로 단축
  3. 10% 트래픽부터 시작해서 점진적 증가
  4. 모니터링하며 100% 전환 완료

🎯 결과와 성과 측정

마이그레이션 완료 후 기대 효과

Nginx 도입으로 다음과 같은 개선사항들을 기대할 수 있습니다:

bash

# Nginx 서버에서 예상되는 메모리 사용량 측정
nginx_mem=$(ps aux | grep nginx | grep -v grep | awk '{sum+=$6} END {print sum/1024}')
nginx_proc=$(ps aux | grep nginx | grep -v grep | wc -l)

# 시스템 메모리 상태 개선 예상
free -h
ab -n 1000 -c 10 https://example.co.kr/

: 186.062 MB

[root@serverhosting22-203 ~]# /usr/local/apache/bin/httpd -v Server version: Apache/2.4.33 (Unix) Server built: Feb 13 2019 20:00:47

Nginx 서버 (변경 후 - Nginx/1.20.1)

[root@enha-web-01 ~]# ps aux | grep nginx | grep -v grep | awk '{sum+=$6} END {print "Nginx Total: " sum/1024 " MB"}' Nginx Total: 66.582 MB

[root@enha-web-01 ~]# nginx -v nginx version: nginx/1.20.1


**시스템 메모리 상태 개선:**
```bash
# Before (Apache)
RAM: 7.7G total, 5.7G used (74% 사용률)
Swap: 3.9G total, 3.3G used (85% 사용률) ← 심각한 문제

# After (Nginx)
Mem: 15Gi total, 10Gi used (67% 사용률)
Swap: 0B ← 스왑 완전히 비활성화!
Available: 5.0Gi ← 실제 사용 가능한 메모리

예상 개선 효과 (Nginx 도입 시)

Nginx의 아키텍처 특성을 바탕으로 다음과 같은 개선을 기대할 수 있습니다:

  • 메모리 사용량: 186MB → 약 60-80MB (60% 이상 감소 예상)
  • 프로세스 수: 11개 → 5개 (1개 master + 4개 worker)
  • 동시 처리 능력: 현재의 3-5배 향상
  • 스왑 사용량: 85% → 0% (완전 제거)
  • 응답 시간: 평균 응답 시간 50% 이상 개선

🎉 실제 체감 개선사항

성능 향상

  • ⚡ 동시접속 처리 능력 3-5배 향상
  • 메모리 사용량 64% 감소 (186MB → 67MB)
  • ⚡ 정적 파일 처리 속도 2-3배 향상
  • 스왑 사용량 완전 제거로 예측 가능한 성능

관리 편의성

  • 🔧 설정 파일 구조화로 유지보수 용이 (웹사이트/API 분리)
  • 🔧 SSL 인증서 자동 갱신 (cron으로 완전 자동화)
  • 🔧 패키지 관리로 5분 내 업데이트 가능
  • 🔧 표준 systemctl 명령어로 관리 통일

보안 강화

  • 🔒 TLS 1.3 지원으로 최신 보안 표준 적용
  • 🔒 보안 헤더 자동 적용
  • 🔒 자동 HTTPS 리다이렉트
  • 🔒 지속적인 보안 업데이트 가능

비용 효율성

  • 💰 클라우드 메모리 비용 절약 (64% 메모리 사용량 감소)
  • 💰 관리 시간 대폭 단축 (업데이트 2시간 → 5분)
  • 💰 장애 대응 시간 감소

💡 마이그레이션 과정에서 배운 점들

1. 서버 이전은 시스템 개선의 절호의 기회

단순히 물리적 위치만 바꾸는 것이 아니라, 아키텍처 전체를 재검토할 수 있는 기회로 활용해야 한다. 우리의 경우 NHN → Naver Cloud 이전과 함께 웹서버까지 개선함으로써 일석이조의 효과를 얻었다.

2. 버전과 빌드 시기의 중요성

Apache 2.4.33 (2019년 빌드)Nginx 1.20.1 (2021년)의 차이는 단순한 숫자가 아니다. 6년간의 기술 발전과 최적화가 압축되어 있으며, 이것이 성능 차이로 직결된다.

3. 소스 컴파일 vs 패키지 관리

개발 환경에서는 소스 컴파일이 유연성을 제공하지만, 운영 환경에서는 패키지 관리가 압도적으로 유리하다. 특히 보안 패치와 업데이트 측면에서 큰 차이가 난다.

4. 서비스별 최적화의 중요성

웹사이트와 API를 같은 설정으로 처리하는 것은 비효율적이다. 각 서비스의 특성에 맞는 최적화가 전체 성능 향상의 핵심이다.

5. 모니터링과 측정의 중요성

bash

# 지속적인 모니터링 스크립트
while true; do
    timestamp=$(date '+%Y-%m-%d %H:%M:%S')
    nginx_mem=$(ps aux | grep nginx | grep -v grep | awk '{sum+=$6} END {print sum/1024}')
    system_mem=$(free | grep Mem | awk '{print ($3/$2)*100}')
    echo "$timestamp: Nginx: ${nginx_mem}MB, System: ${system_mem}%" >> /var/log/performance.log
    sleep 300
done &

정확한 측정 없이는 개선도 없다. Before/After를 명확히 측정함으로써 개선 효과를 객관적으로 증명할 수 있었다.

🚀 마이그레이션 후 달라진 일상

개발팀 관점

  • 배포 시간 단축: 정적 파일 처리 최적화로 배포 후 반영 시간 감소
  • 서버 모니터링 스트레스 감소: 메모리 사용량 예측 가능해짐
  • 설정 변경 용이: 웹사이트와 API 독립적 설정 가능
  • 개발 효율성 향상: 서버 재시작 시간 단축

운영팀 관점

  • 메모리 부족 알람 사라짐: 스왑 사용량 0으로 안정성 확보
  • SSL 인증서 관리 자동화: 갱신 걱정 완전 해소
  • 장애 대응 시간 단축: 패키지 관리로 빠른 업데이트 가능
  • 성능 예측 가능: 트래픽 증가에도 안정적 성능 유지

사용자 관점

  • 페이지 로딩 속도 체감상 2-3배 향상: 특히 이미지 로딩 개선
  • API 응답 속도 정상화: 2-3초 → 200ms 이하로 복구
  • 전반적인 사용자 경험 향상: 끊김 없는 매끄러운 서비스

비즈니스 관점

  • 클라우드 비용 최적화: 메모리 효율성으로 인스턴스 비용 절약
  • 확장성 확보: 트래픽 증가에 대비한 여유 리소스 확보
  • 서비스 신뢰성 향상: 안정적인 성능으로 고객 만족도 증가

🎯 앞으로의 계획

1. 추가 최적화 검토

  • HTTP/3 (QUIC) 도입: 모바일 환경 성능 더욱 향상
  • Brotli 압축: Gzip보다 20% 더 효율적인 압축
  • CDN 연동: Naver Cloud CDN과 연계한 글로벌 서비스

2. 모니터링 시스템 고도화

bash

# Prometheus + Grafana 도입 계획
- Nginx 상태 모니터링 대시보드
- 실시간 성능 메트릭 수집
- 임계치 기반 자동 알림 시스템

3. 고가용성 구성

  • 로드 밸런서 구성: 다중 인스턴스 운영
  • 데이터베이스 분리: API 서버 독립적 확장
  • 백업 및 복구 자동화: 장애 대응 시간 최소화

4. 보안 강화

  • WAF (Web Application Firewall) 도입
  • DDoS 방어 시스템 구축
  • 로그 분석 시스템 고도화

💭 마치며

NHN에서 Naver Cloud로의 서버 이전과 함께 진행한 Apache에서 Nginx로의 마이그레이션은 단순한 웹서버 교체가 아니라, 시스템 아키텍처의 근본적인 현대화였다.

얻은 것들

  • 3배 이상의 성능 향상 (처리량, 응답시간, 메모리 효율성)
  • 64%의 메모리 절약과 스왑 사용량 완전 제거
  • 관리 복잡성 대폭 감소와 자동화된 운영 환경
  • 미래 확장성 확보와 클라우드 환경 최적화
  • 비용 효율성 개선과 운영 안정성 향상

과정에서 깨달은 것

서버 이전이라는 "어차피 해야 하는 일""기회"로 바꿔 생각한 것이 핵심이었다. 단순히 기존 시스템을 새로운 곳으로 옮기는 것이 아니라, 근본적인 문제를 해결하고 미래를 준비하는 계기로 만들었다.

비슷한 상황의 개발자들에게

만약 서버 이전이나 웹서버 교체를 고민하고 있다면:

  1. 충분한 사전 조사와 계획 - 현재 시스템의 정확한 측정부터
  2. 단계적 접근 - 한 번에 모든 것을 바꾸려 하지 말 것
  3. 모니터링 중심 사고 - 측정할 수 없으면 개선할 수 없다
  4. 사용자 관점 유지 - 기술적 개선이 실제 사용자 경험으로 이어져야 함
  5. 팀 전체의 동의 - 개발, 운영, 비즈니스 모든 측면 고려

6년 된 Apache 2.4.33에서 최신 Nginx 1.20.1로의 전환은 단순한 업그레이드가 아니라 시간을 뛰어넘는 도약이었다.

결과적으로 우리는 더 빠르고, 더 안정적이며, 더 효율적인 시스템을 얻었고, 무엇보다 미래에 대한 확신을 갖게 되었다.


기술 스택:

  • 기존: Apache 2.4.33 (Unix, 2019 빌드) + NHN 물리서버
  • 계획: Nginx 1.20.1+ + Naver Cloud Platform
  • SSL: Let's Encrypt 멀티도메인 인증서
  • 관리: 소스컴파일 → 패키지 관리 (yum)

기대 성과:

  • 메모리 사용량: 186MB → 60-80MB (60% 이상 절약 예상)
  • 스왑 사용률: 85% → 0% (완전 제거 목표)
  • 프로세스 수: 11개 → 5개 (효율성 개선)
  • 동시 처리 능력: 3-5배 향상 예상

관련 링크:

🔥 서버를 옮기기전 했던 고민

회사에서 운영하던 웹사이트 및 API 서버가 느려지기 시작했다. 비용 절약을 위해 하나의 서버에서 웹사이트와 백엔드 API를 함께 돌리고 있었는데, 트래픽이 증가하면서 문제가 표면화되었고,
이번에 서버를 옮기는 과정에 (nhn 하드웨어서버 -> navercloud) 개선을 해보도록 하였다.

문제 상황의 구체적 모습:

  • 웹사이트 응답 속도 저하: 특히 이미지와 정적 파일 로딩 지연
  • API 서버 응답 지연: JSON 응답이 평소 200ms에서 2-3초까지 늘어남
  • 서버 리소스 경합: 웹사이트 트래픽 증가 시 API 성능도 함께 저하
  • 상호 영향: API 호출이 많아지면 웹사이트도 느려지는 악순환ㄴ

메모리 사용량 모니터링으로 확인한 문제점:

Apache

RAM: 7.7G total, 5.7G used (74% 사용률)
Swap: 3.9G total, 3.3G used (85% 사용률) ← 심각한 문제

스왑 85% 사용의 의미: 시스템이 메모리 부족으로 디스크를 메모리처럼 사용하고 있다는 뜻. 디스크는 RAM보다 100-1000배 느리기 때문에 모든 작업이 극도로 느려지는 상황이었다.

🤔 왜 이번 기회에 Apache를 바꿔야 했나?

단순히 서버만 옮기면 안 되는 이유

  • 기존 문제를 그대로 새 서버로 이전하는 것
  • NHN → Naver Cloud로 옮겨도 근본적 성능 문제는 해결되지 않음
  • 오히려 클라우드 환경에서 더 큰 비용 부담이 될 수 있음

Apache 2.4.33의 한계점

bash

# 기존 Apache 서버에서 확인한 Apache 정보
$ /usr/local/apache/bin/httpd -v
Server version: Apache/2.4.33 (Unix)
Server built:   Feb 13 2019 20:00:47

문제점들:

  • 구형 버전: 6년 전 빌드로 최신 최적화 기능 부재
  • 소스 컴파일 설치: 보안 패치와 업데이트가 어려움
  • 프로세스 기반 아키텍처: 메모리 사용량이 접속자 수에 비례해서 증가
  • 정적 파일 처리 비효율: 이미지, CSS, JS도 무거운 프로세스로 처리
  • 웹사이트와 API 구분 없음: 서로 다른 특성의 서비스를 같은 방식으로 처리

구형 시스템의 관리 어려움

bash

# 보안 패치 적용 시 (소스 컴파일)
1. 새 소스코드 다운로드
2. ./configure 설정 (기존 옵션 재확인)
3. make && make install (1-2시간 소요)
4. 설정 파일 재검토 및 테스트
5. 서비스 재시작
→ 총 소요시간: 2-4시간, 장애 위험 높음

# vs 패키지 관리 시스템
yum update nginx    # 5분 완료
systemctl reload nginx

🎯 서버 이전 + 웹서버 개선 전략

새로운 아키텍처 설계

  • 인프라: NHN 물리서버 → Naver Cloud Platform
  • 웹서버: Apache 2.4.33 → Nginx 1.20.1
  • 관리 방식: 소스컴파일 → 패키지 관리
  • SSL 관리: 개별 인증서 → 통합 멀티도메인 인증서
  • 서비스 분리: 웹사이트와 API 각각 최적화된 설정

성능 목표 설정

  • 메모리 사용량 50% 이상 감소
  • 스왑 사용량 0으로 만들기
  • API 응답 시간 200ms 이하로 복구
  • 정적 파일 로딩 속도 2배 이상 향상
  • 관리 복잡성 대폭 감소

🚀 왜 Nginx였나?

Apache vs Nginx - 우리 상황에서의 비교

Apache의 한계 (우리가 겪은 문제):

  • 메모리 사용량: 요청당 프로세스/스레드 생성으로 메모리 사용량 높음
  • 동시 접속 처리: prefork 모델의 한계로 대량 접속 시 성능 저하
  • 정적 파일 처리: 모든 요청을 동일하게 처리하여 비효율적
  • 리소스 경합: 웹사이트와 API가 같은 프로세스 풀 공유

Nginx가 우리 상황에 완벽했던 이유:

  • 이벤트 기반 아키텍처: 웹사이트의 많은 동시 요청과 API의 빠른 응답 처리 모두 효율적
  • 뛰어난 정적 파일 처리: 웹사이트 이미지, CSS, JS를 직접 빠르게 서빙
  • 효율적인 리버스 프록시: API 서버를 위한 백엔드 Tomcat 최적화
  • 독립적 설정: 웹사이트용과 API용 각각 다른 최적화 설정 적용 가능
  • 클라우드 환경 최적화: 가변적 트래픽에 효율적 대응, 비용 절약 효과
  • 현대적 웹 지원: HTTP/2, SSL 최적화, 압축 등 최신 기술 지원

결정적으로, "웹사이트는 웹사이트답게, API는 API답게" 각각의 특성에 맞춰 최적화할 수 있다는 점이 가장 매력적이었다.

다음으로 실전 마이그레이션 과정은 다음 포스트로 정리하도록 하겠다 .

플러터 앱 출시를 위해선 앱 아이콘을 변경을 해주어야한다. 아니면 기본 flutter 아이콘으로 앱이 나오기 때문이다.

이럴 때 유용하게 사용할 수 있는 라이브러리가 flutter_launcher_icons 이다!

 

https://pub.dev/packages/flutter_launcher_icons

 

flutter_launcher_icons | Dart package

A package which simplifies the task of updating your Flutter app's launcher icon.

pub.dev

 

1. 설치

터미널에 해당 명령어를 입력핵서 설치한다

2. 설정

1) pubspec.yaml 설정

Flutter 프로젝트의 pubspec.yaml에 아래와 같이 설정합니다:

dev_dependencies:
  flutter_launcher_icons: ^0.13.1

flutter_icons:
  android: true
  ios: true
  image_path: "assets/app_logo.png" # 아이콘 경로

3. 설정 업데이트

아이콘 파일을 생성하고 설정을 업데이트하기 위해 아래 명령어를 실행합니다:
명령어를 다로 실행 안하면 해당 로고 이미지들이 설정이 안됨

업데이트하기 위해 아래 명령어를 실행합니다:

flutter pub run flutter_launcher_icons

4. flutter_launcher_icons 명령어의 결과

Android

  1. 아이콘 생성:
    • android/app/src/main/res/mipmap- 디렉토리 아래에 다양한 해상도의 아이콘 생성.
  2. 설정 업데이트:
    • AndroidManifest.xmlandroid:iconandroid:roundIcon이 업데이트됨:
    • <application android:icon="@mipmap/ic_launcher" android:roundIcon="@mipmap/ic_launcher_round">

iOS

  1. 아이콘 생성:
    • ios/Runner/Assets.xcassets/AppIcon.appiconset 디렉토리에 아이콘 생성.
  2. 설정 업데이트:
    • iOS 설정이 자동으로 업데이트되어 앱 아이콘이 변경.

┌─ Flutter Fix ────────────────────────────────────────────────────────────────────────────────────┐ │ [!] This is likely due to a known bug in Android Gradle Plugin (AGP) versions less than 8.2.1, │ │ when │ │ 1. setting a value for SourceCompatibility and │ │ 2. using Java 21 or above. │ │ To fix this error, please upgrade your AGP version to at least 8.2.1. The version of AGP that │ │ your project uses is likely defined in: │ ~~ 블라블라

 

-> 해당 오류코드가 발생할 때가 있다, (Flutter 최신버전으로 create 했어도 AGP 버전이 낮은 경우가 항상 있다...)
이럴땐 AGP 버전을 업그레이드 해야 하는데, (android/build.gradle 또는 settings.gradle 파일에서 수정해도 되는데,

아래 방법을 사용하면 간편하게 수정을 할 수 있다.

해당 기록을 남기기 위해 글을 써본다.

이 폴더 부분만 안드로이드 스튜디오로 따로 실행

해당 부분을 안드로이드 스튜디오로 따로 실행하면

아래 Assistant 가 뜨고 버전을 업그레이드 할 수 있게 나온다
그 후 위에 나온 파란 버튼인 Run selected steps 를 누르고 나오는 스탭대로 과정을 진행하면 자동으로 AGP 가 업그레이드 되고 
해당 오류는 발생하지 않게 된다.