🔥 결론: 하나의 Java 프로세스 안에 있는 thread들을 전부 분리해서 확인할 수 있다

방법은 바로 이것:


✅ 1. Linux에서 Java 프로세스의 thread를 분리해서 보는 방법

명령어

 
top -H -p <java_pid>

예:

 
top -H -p 12345

그럼 하나의 Java 프로세스(PID=12345) 안에 있는 모든 thread(TID) 가 각각 CPU를 얼마나 쓰는지 나옵니다.

예:

 
PID %CPU COMMAND 12345 10.0 java <-- 전체 12347 280.0 java <-- 문제 쓰레드(스레드 ID) 12349 12.3 java 12351 5.6 java
  • 12347: 하나의 TID(thread ID)
  • 이게 CPU 280% 먹고 있음 → 문제 쓰레드

즉, Java 한 개 프로세스 안의 각 thread CPU 사용량을 분리해서 알 수 있음.


✅ 2. 문제 thread가 “Java 내부에서 어떤 함수”를 돌고 있는지도 확인 가능

이건 Java thread dump(jstack)를 사용합니다.


Step A. thread ID(TID)를 16진수로 변환

Java thread dump는 hex 값으로 thread를 표시함.

 
printf "%x\n" 12347

출력 예:

 
303b

Step B. jstack 실행

 
jstack 12345 > /tmp/stack.txt

Step C. thread ID(hex)로 검색

 
grep -n "0x303b" /tmp/stack.txt

그럼 이렇게 나옵니다:

 
"pool-1-thread-3" #32 prio=5 tid=0x00007fda900303b nid=0x303b runnable at com.myapp.service.OrderService.process(OrderService.java:182) at com.myapp.service.OrderService.runLoop(OrderService.java:155) at java.lang.Thread.run(Thread.java:748)

여기서:

  • nid=0x303b ← 이게 바로 문제 thread
  • process() 함수에서 CPU를 많이 먹고 있음
  • runLoop() 안에서 무한 loop가 돌고 있을 수 있음

이렇게 정확한 함수 이름 + 라인번호까지 알 수 있습니다.


🔥 추가: thread 이름까지 알 수 있음

Java에서는 thread를 만들 때 이름을 붙이면

 
new Thread(() -> {...}, "Worker-1").start();

jstack에서 이렇게 보입니다:

 
"Worker-1" #25 prio=5 ...

즉,

  • thread 이름
  • thread 상태
  • thread call stack
  • CPU 점유율
  • lock(JVM monitor) 보유 여부

전부 확인 가능.


🔥 추가: thread 목록 전체 보기

 
jcmd <pid> Thread.print

또는 자동으로 thread hierarchy 확인 가능.


🔥 결론 요약

하나의 Java 프로그램이라도 내부 thread들은 개별 TID를 가지므로
CPU 사용량, 함수 위치, thread 이름 등을 전부 분리해서 확인 가능하다.

✔ top -H -p PID → thread CPU 식별
✔ printf "%x" TID → hex 변환
✔ jstack PID → thread dump
✔ grep hex → problem thread 찾기
✔ 어떤 함수인지 100% 확인 가능


원하면 지금 사용 중인 Java 서버에서
문제가 되는 thread를 실시간으로 찾는 쉘 스크립트도 만들어줄게!

나의 말:

thread ID는 찾아도 어떤 코드인지 알수는 없는건가요?

ChatGPT의 말:

알 수 있습니다.
단순히 “thread ID 숫자만 보인다 → 코드 위치는 모른다”가 아니라,
thread ID(TID) → jstack → Java 함수명 + 파일명 + 라인번호까지 정확히 찾을 수 있습니다.

즉,

thread ID만 알면 “어떤 코드(어떤 함수)가 문제인지 100% 추적 가능합니다.”

아래를 보면 왜 가능한지 이해됩니다.


🔥 핵심 개념:

리눅스에서 보이는 thread ID(TID)는 JVM 내부 스레드의 nid(native thread id)와 1:1로 매핑됩니다.

예를 들어 top에서:

 
TID = 12347

라고 CPU를 많이 먹는 스레드가 보이면,

  • 이걸 HEX로 바꾸고
  • jstack에서 해당 TID를 검색하면
  • 그 스레드가 어떤 Java 코드(메소드) 를 실행 중인지 정확히 알 수 있습니다.

실제로 이렇게 나옵니다:


🚀 실전 예제 (이게 실제로 나오는 화면)

Step1 — CPU 많이 먹는 thread 찾기

 
top -H -p <java_pid>

예:

 
12347 280% java ← 문제 스레드

Step2 — 10진수를 16진수(hex)로 변환

 
printf "%x\n" 12347

출력:

 
303b

Step3 — jstack 덤프 생성

 
jstack <java_pid> > dump.txt

Step4 — 문제 스레드 검색

 
grep -n "0x303b" dump.txt

🔥 실제로 보이는 결과

 
"pool-4-thread-1" #47 prio=5 os_prio=0 tid=0x00007fda900303b nid=0x303b runnable at com.company.payment.PaymentService.calculateFee(PaymentService.java:183) at com.company.payment.PaymentWorker.run(PaymentWorker.java:92) at java.lang.Thread.run(Thread.java:748)

즉, thread ID 하나만으로

  • 어떤 클래스인지
  • 어떤 메소드인지
  • 몇 번째 줄(line number)인지
    정확히 나온다.

여기서는:

  • calculateFee() 함수가 CPU를 폭주시키고 있음
  • 파일: PaymentService.java
  • 라인: 183

이 수준까지 바로 알 수 있습니다.


💡 정리하면

❗ thread ID 자체로는 코드 이름이 안 보이지만

❗ thread ID → jstack 검색을 하면

👉 스레드가 실행 중인 메소드
👉 메소드가 있는 클래스
👉 Java 파일 이름
👉 라인 번호
👉 Lock held 여부
👉 JVM 상태(runnable / waiting / blocked)

까지 전부 알 수 있습니다.


🎯 결론

thread ID만 알면 어떤 코드가 문제인지 100% 찾아낼 수 있습니다.
단순한 추론이 아니라, 실제 Java stack trace에 메소드/라인번호가 정확히 찍힙니다.

Posted by yongary
,

✅ 1. MongoDB 5.0 지원 종료 사실

MongoDB 5.0은 2024년 10월부로 End of Life(EOL) 입니다.
→ Security patch 포함 지원 없음, CVE 발생 시 패치 불가

현재 지원되는 LTS 버전은:

  • 6.0 LTS
  • 7.0 LTS

즉, 실질적 업그레이드 목표는:

 
5.0 → 6.0 → 7.0

(6.0을 LTS로 오래 운영해도 됨)

MongoDB는 메이저 버전 건너뛰기 업그레이드를 허용하지 않습니다.
5 → 7로 직접 업그레이드하면 ReplicaSet 자체가 깨집니다.


✅ 2. “서비스 중단 없이” 업그레이드할 수 있는 구조

현재 EC2 3대로 구동 중이라면 아마 아래 형태일 거예요:

 
Replica Set - Primary - Secondary - Secondary

이 구조에서는 롤링 업그레이드(Rolling Upgrade) 를 사용하면
서비스 중단 없이 업그레이드 가능합니다.


✅ 3. 정식 업그레이드 절차 (MongoDB 공식 절차 기반)

전체 플로우

 
1) Pre-check (호환성, 스토리지 엔진, Feature Compatibility Version) 2) Secondary 1대 업그레이드 3) Secondary 2대 업그레이드 4) Primary를 Step Down 후 업그레이드 5) FCV 변경 6) 클러스터 정상화 확인

아래에 실제 현장에서 쓰는 구체 절차를 적어볼게요.


🔥 4. 실제 상세 절차

Step 0 — 백업/스냅샷 생성

  • EC2 EBS Snapshot
  • 혹은 mongodump
    → 실패 시 즉각 롤백 가능하게

Step 1 — 사전 체크

mongo 콘솔에서:

 
db.adminCommand({ getParameter: 1, featureCompatibilityVersion: 1 })

FCV가 5.0이어야 정상.

또한:

 
rs.status() rs.conf()

오류 없는지 확인.


Step 2 — Secondary 한 대를 업그레이드

  1. Secondary 한 대를 선택
  2. mongod 종료
 
sudo systemctl stop mongod
  1. MongoDB 6.0 패키지 설치
    (amazon linux / ubuntu에 따라 다름 — 필요하면 상세 스크립트 제공 가능)
  2. 재기동
 
sudo systemctl start mongod
  1. 클러스터 정상 합류 확인
 
rs.status()
  1. oplog sync OK 확인

→ 이 서버가 6.0으로 잘 돌아가면 계속 진행.


Step 3 — 나머지 Secondary도 동일 절차로 업그레이드


Step 4 — Primary 업그레이드

Primary는 직접 Upgrade 하면 다운타임 위험 있으므로:

  1. Primary를 강제로 step down
 
rs.stepDown()

→ 다른 Secondary가 Primary가 됨
서비스 중단 없음

  1. 기존 Primary 서버를 mongod stop
  2. MongoDB 6.0 설치 후 start

Step 5 — FeatureCompatibilityVersion 변경

모든 노드가 6.0에서 정상적으로 올라온 뒤:

 
db.adminCommand({ setFeatureCompatibilityVersion: "6.0" })

Step 6 — 정상 동작 확인

  • rs.status()
  • replication lag 확인
  • 애플리케이션 write/read 정상 동작 확인
  • op log 증가 확인
  • mongod.log 에 error 없는지

🔁 6. (선택) 6.0 → 7.0 업그레이드

같은 방식으로 “롤링 업그레이드” 하면 됩니다.

 
5.0 → 6.0 → 안정화 후 → 7.0

바로 7.0까지 갈 필요 없으면 6.0 LTS 유지해도 안전합니다.


⚠️ “바로 5.x → 7.x or 5.x → 5.9.x” 하면 안 되는 이유

  • MongoDB는 메이저 버전 건너뛰기 허용 안함
  • WiredTiger 스토리지 메타데이터가 다름
  • FCV 매커니즘 때문에 클러스터 자체가 올라오지 않음
  • 5.9는 정식 릴리즈가 아님 (개발 프리뷰)

🧩 추가 고려사항 (실무에서 꼭 필요)

✔︎ 바뀌는 parameter / deprecated 기능

  • setParameter, replication.enableMajorityReadConcern 같은 값의 호환성 체크

✔︎ Driver 버전 업데이트

Node/Java/Python에서 MongoDB Driver도 버전 호환 필요

  • 6.x 이상에서는 5.x 드라이버가 deprecated 되는 경우 있음

✔︎ Monitoring (CloudWatch/Datadog/Prometheus)

업그레이드 후 connection pool 동작이 달라질 수 있음


🎯 최종 요약

MongoDB 5.0 → 6.0 롤링 업그레이드 절차

  1. Snapshot/백업 생성
  2. FCV 확인
  3. Secondary 1 업그레이드 → 정상 확인
  4. Secondary 2 업그레이드
  5. Primary stepDown → 업그레이드
  6. 6.0 전체 업 후 FCV 6.0 설정
  7. 정상 동작 확인
  8. (선택) 같은 방식으로 7.0까지 업그레이드 가능

👉 서비스 중단 없음 (Zero downtime 유지 가능)
👉 메이저는 반드시 계단식 업그레이드 (5 → 6 → 7)

Posted by yongary
,

AWS EC2 환경에서 데이터베이스(PostgreSQL, MySQL 등)는 보통 보안상의 이유로 퍼블릭 접근을 막고 VPC 내부에서만 접근 가능하도록 구성합니다.
이때, 개발자나 운영 담당자가 사내 네트워크(로컬 PC)에서 안전하게 DB에 접속하려면 SSH 포트포워딩(터널링) 방식을 활용하는 것이 가장 간편하고 안전한 방법입니다.


1️⃣ 준비사항

항목설명
EC2 인스턴스 DB가 설치되어 있는 서버 (또는 DB에 접근 가능한 Bastion 서버)
PEM 키 파일 AWS EC2 접속용 개인키 (예: mykey.pem)
보안그룹 EC2의 SSH(22번 포트)는 회사 IP만 허용되어 있어야 함
DB 클라이언트 psql, DBeaver, TablePlus 등 DB 접속 도구

2️⃣ SSH 포트포워딩 원리

SSH 클라이언트가 로컬 포트EC2 서버 포트 사이에 암호화된 통신 터널을 생성합니다.

 
[로컬 PC] ←(암호화 터널:SSH)→ [EC2 서버][DB 서버(Localhost:5432)]

즉, 로컬 PC에서 localhost:5433 으로 접속하면, 실제로는 EC2의 localhost:5432 (PostgreSQL 등)에 접속하는 효과가 납니다.


3️⃣ 실행 명령 예시 (PostgreSQL 기준)

 
ssh -i ~/mykey.pem -L 5433:localhost:5432 ec2-user@<EC2_Public_IP>
옵션설명
-i ~/mykey.pem 개인키 경로 지정
-L 5433:localhost:5432 로컬의 5433 포트를 EC2 내부의 5432 포트로 연결
ec2-user@<EC2_Public_IP> 접속 대상 EC2의 사용자와 공인 IP

✅ 이 명령을 실행한 터미널은 SSH 세션이 열린 상태로 유지되어야 합니다.
세션이 끊기면 포트포워딩도 함께 종료됩니다.


4️⃣ DB 클라이언트에서 접속

SSH 터널이 열린 상태에서 DB 클라이언트를 다음과 같이 설정합니다.

항목값
Host localhost
Port 5433
User postgres (또는 DB 계정명)
Password DB 비밀번호
Database 접속할 DB명 (예: appdb, vwstest 등)

5️⃣ 연결 확인

터미널에서 직접 psql로 접속해도 됩니다.

 
psql -h localhost -p 5433 -U postgres -d vwstest

정상적으로 접속되면, 포트포워딩이 성공적으로 작동하고 있는 것입니다.


6️⃣ 보안 팁

  • PEM 키는 외부 유출이 절대 금지이며, 파일 권한을 600으로 설정하세요.
  •  
    chmod 600 ~/mykey.pem
  • DB 보안그룹에서는 외부 접근(0.0.0.0/0) 을 모두 차단하고,
    EC2 내부 또는 Bastion 서버 IP 만 허용하세요.
  • 필요 시 autossh 나 ProxyCommand 를 이용해 포트포워딩 자동화를 설정할 수 있습니다.

✨ 마무리

이 방식은 별도의 VPN 없이도 AWS EC2의 SSH 터널을 활용하여
DB에 암호화된 통신 경로로 접속할 수 있는 안전한 방법입니다.
공용망을 통하지 않고 내부적으로만 접근이 가능하므로,
보안성과 편의성을 모두 확보할 수 있습니다.

Posted by yongary
,

AWS를 처음 사용할 때 가장 많이 하는 실수 중 하나가 바로 EC2 인스턴스 접속을 무조건 SSH 키페어로 해야 한다고 생각하는 것이야.
하지만 실제로는 **AWS Systems Manager(SSM)**을 이용하면 키페어 없이도 브라우저에서 바로 접속할 수 있고, 보안도 더 강력해져.

아래에서 SSM을 활용한 접속 과정과 필수 설정을 정리


1. SSM 접속의 장점

  • 키페어 분실 위험 없음
  • 22번 포트(SSH)를 열 필요가 없음 → 보안 강화
  • IAM 기반 권한 관리로 더 안전한 접근 제어
  • 브라우저 기반 Session Manager로 편하게 접속

2. SSM 사용 조건 정리

EC2가 SSM을 쓰려면 다음 3가지가 반드시 필요

① SSM Agent

  • Amazon Linux 2, Ubuntu 최신 버전은 기본 설치됨
  • 만약 설치 안 되어 있다면 아래 명령어로 가능
  •  
    sudo yum install amazon-ssm-agent -y sudo systemctl enable amazon-ssm-agent sudo systemctl start amazon-ssm-agent

② IAM Role 부착

EC2에 아래 정책을 가진 Role을 연결해야 함

  • AmazonSSMManagedInstanceCore

(콘솔 → EC2 → 인스턴스 선택 → 보안 → IAM Role 연결)

③ 네트워크 조건

  • 인터넷이 있거나
  • SSM용 VPC 엔드포인트가 존재해야 함

프라이빗 서브넷에서도 SSM 엔드포인트만 연결되어 있으면 접속 가능!


3. EC2를 SSM으로 접속하는 법

  1. AWS 콘솔 → Systems Manager → Session Manager
  2. “세션 시작” 클릭
  3. 인스턴스 선택 → Connect
  4. 브라우저 터미널이 열리면 끝

특별히 SSH 키도, 퍼블릭 IP도 필요 없다.


4. SSM 사용 시 자주 발생하는 오류 해결

🔸 1) 인스턴스 목록에 EC2가 안 보임

  • IAM Role에 AmazonSSMManagedInstanceCore 빠짐
  • SSM Agent가 실행 안 됨
  • 프라이빗 서브넷에 엔드포인트 없음

🔸 2) "세션 시작 실패"

  • CloudWatch Logs 권한 부족
  • SSM Agent 버전 오래됨
  • 보안그룹/라우팅으로 인해 SSM 서비스 접근 불가

🎯 5. SSM은 어떤 상황에서 쓰면 좋을까?

  • 운영 서버 SSH 차단하고 싶은 경우
  • 실습 환경에서 학생/팀원에게 개별 키 제공하기 싫을 때
  • Bastion 없이 내부 서버 접속해야 할 때
  • 로그 & 명령 실행을 중앙에서 관리하고 싶을 때
Posted by yongary
,

대폰 브라우저에서 캐시삭제 하면 localStorage삭제 되나요? 아니면 데이터삭제까지 해야하나요?

 

휴대폰 브라우저에서 캐시 삭제 localStorage 삭제는 별개입니다.

캐시 삭제만 하는 경우

  • localStorage는 삭제되지 않습니다
  • 이미지, CSS, JS 파일 등 캐시된 리소스만 삭제됩니다
  • 웹사이트의 로그인 상태나 설정값은 그대로 유지됩니다

localStorage를 삭제하려면

브라우저마다 다르지만, 일반적으로:

Chrome (Android)

  • "사이트 데이터 삭제" 또는 "쿠키 및 사이트 데이터" 옵션을 선택해야 합니다

Safari (iOS)

  • "방문 기록 및 웹사이트 데이터 지우기"를 선택하면 localStorage도 함께 삭제됩니다
  • 또는 설정 > Safari > 고급 > 웹사이트 데이터에서 개별 삭제 가능

Samsung Internet / 기타

  • "쿠키 및 사이트 데이터" 또는 "저장된 데이터" 항목을 선택해야 합니다

요약

단순 캐시 삭제로는 localStorage가 유지되므로, localStorage를 삭제하려면 "사이트 데이터" 또는 "쿠키 및 사이트 데이터" 항목까지 함께 삭제해야 합니다.

어떤 브라우저를 사용하시나요? 구체적인 방법을 알려드릴 수 있습니다.

Posted by yongary
,

🧱 1️⃣ 새로운 VPC 생성

  1. AWS Management Console → VPC 서비스로 이동
    검색창에 “VPC” 입력 → “VPCs” 메뉴 클릭
  2. [Create VPC] 버튼 클릭
  3. 설정 예시
    • VPC only 선택
    • Name tag: my-new-vpc
    • IPv4 CIDR block: 10.1.0.0/16 (기존 VPC와 겹치지 않게)
    • IPv6 CIDR: 비활성화(필요시만)
    • Tenancy: Default (Dedicated 필요 없으면)
  4. [Create VPC] 클릭

✅ 결과: my-new-vpc라는 완전히 독립된 VPC가 만들어집니다.


🌐 2️⃣ 서브넷 / 인터넷 게이트웨이 / 라우팅 세팅

VPC만 있으면 EC2가 외부통신 불가이므로, 기본 네트워킹 요소를 만들어야 합니다.

  1. Subnet 생성
    • VPC 대시보드 → “Subnets” → [Create subnet]
    • VPC: my-new-vpc
    • Subnet name: my-new-public-subnet
    • Availability Zone: ap-northeast-2a (또는 원하는 AZ)
    • IPv4 CIDR block: 10.1.1.0/24
    • Create subnet
  2. Internet Gateway 생성
    • 왼쪽 메뉴 “Internet Gateways” → [Create internet gateway]
    • Name tag: my-new-igw
    • Create → Attach to VPC → my-new-vpc
  3. Route Table 수정
    • “Route tables” → my-new-vpc에 자동생성된 테이블 선택
    • Routes 탭 → Edit routes → Add route
      • Destination: 0.0.0.0/0
      • Target: 방금 만든 my-new-igw
    • Save changes
    • “Subnet associations” 탭 → Edit → my-new-public-subnet 연결

✅ 결과: my-new-public-subnet은 인터넷 연결 가능한 퍼블릭 서브넷이 됨.


💻 3️⃣ 새 EC2 인스턴스 생성 (이 VPC 안에)

  1. EC2 → Instances → [Launch instances]
  2. 이름: my-new-server
  3. AMI 선택: Amazon Linux / Ubuntu 등
  4. 인스턴스 유형: t3.micro 등
  5. Key pair:
    • “Create new key pair” 클릭
    • Name: my-new-keypair
    • Type: RSA (또는 ED25519)
    • Format: .pem (Windows PuTTY면 .ppk 선택)
    • [Create key pair] → 자동으로 다운로드됨 (my-new-keypair.pem)
  6. Network settings:
    • VPC: my-new-vpc
    • Subnet: my-new-public-subnet
    • Auto-assign public IP: Enable
    • Security group: 새로 생성 (예: SSH(22), HTTP(80), HTTPS(443))
  7. Launch instance

✅ 결과: 완전히 독립된 VPC + 서브넷 + 키쌍 환경에 EC2 인스턴스 생성 완료

Posted by yongary
,