🚀 자바 스레드와 분산처리 완벽 가이드¶
클라우드 엔지니어를 꿈꾸는 자바 초보자를 위한 친절한 안내서
📚 목차¶
🧵 스레드란 무엇인가?¶
스레드(Thread)는 프로그램 안에서 동시에 여러 가지 일을 할 수 있게 해주는 기술입니다.
🏠 실생활 비유로 이해하기¶
집에서 요리하는 상황을 생각해보세요:
graph TD
A[엄마 혼자 요리하기] --> B[밥 짓기 30분]
B --> C[반찬 만들기 20분]
C --> D[국 끓이기 15분]
D --> E[총 65분 소요]
F[가족이 함께 요리하기] --> G[엄마: 밥 짓기 30분]
F --> H[아빠: 반찬 만들기 20분]
F --> I[언니: 국 끓이기 15분]
G --> J[총 30분 소요!]
H --> J
I --> J
- 싱글 스레드: 엄마 혼자 모든 요리를 순서대로 (65분)
- 멀티 스레드: 가족이 함께 동시에 요리하기 (30분)
🎯 왜 스레드가 중요한가?¶
1️⃣ 성능 향상¶
- 여러 작업을 동시에 처리하여 시간 단축
- CPU를 효율적으로 사용
2️⃣ 사용자 경험 개선¶
- 앱이 멈추지 않고 부드럽게 동작
- 파일 다운로드 중에도 다른 기능 사용 가능
3️⃣ 서버 처리 능력 증대¶
- 많은 사용자의 요청을 동시에 처리
- 웹 서비스의 응답 속도 향상
🌟 스레드 실생활 예제¶
📱 카카오톡 메신저 예제¶
graph LR
A[카카오톡 앱] --> B[메시지 받기 스레드]
A --> C[메시지 보내기 스레드]
A --> D[화면 업데이트 스레드]
A --> E[알림 처리 스레드]
B --> F[친구 메시지 실시간 수신]
C --> G[내 메시지 서버로 전송]
D --> H[채팅창 스크롤, 애니메이션]
E --> I[푸시 알림, 소리]
만약 스레드가 없다면? - 메시지를 보내는 동안 새 메시지 받기 불가능 - 화면이 멈춰서 스크롤도 안 됨 - 매우 불편한 사용자 경험!
💻 자바에서 스레드 사용하기¶
기본 스레드 생성 방법¶
// 방법 1: Thread 클래스 상속
class MyThread extends Thread {
public void run() {
System.out.println("새로운 스레드에서 실행 중!");
}
}
// 방법 2: Runnable 인터페이스 구현 (추천)
class MyTask implements Runnable {
public void run() {
System.out.println("작업 실행 중!");
}
}
// 사용법
public class ThreadExample {
public static void main(String[] args) {
// 방법 1 사용
MyThread thread1 = new MyThread();
thread1.start();
// 방법 2 사용
Thread thread2 = new Thread(new MyTask());
thread2.start();
}
}
🍕 피자 주문 처리 시스템 예제¶
class PizzaOrderProcessor implements Runnable {
private String customerName;
public PizzaOrderProcessor(String name) {
this.customerName = name;
}
public void run() {
System.out.println(customerName + "님의 주문 처리 시작");
try {
Thread.sleep(3000); // 피자 만드는 시간 (3초)
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(customerName + "님의 피자 완성!");
}
}
public class PizzaShop {
public static void main(String[] args) {
// 동시에 여러 주문 처리
Thread order1 = new Thread(new PizzaOrderProcessor("김철수"));
Thread order2 = new Thread(new PizzaOrderProcessor("이영희"));
Thread order3 = new Thread(new PizzaOrderProcessor("박민수"));
order1.start();
order2.start();
order3.start();
// 3개 주문이 동시에 처리됨!
}
}
🌐 분산처리와 Redis¶
분산처리란?¶
하나의 큰 일을 여러 컴퓨터가 나누어서 처리하는 것입니다.
graph TD
A[대용량 데이터 처리 작업] --> B[서버 1]
A --> C[서버 2]
A --> D[서버 3]
A --> E[서버 4]
B --> F[결과 1]
C --> G[결과 2]
D --> H[결과 3]
E --> I[결과 4]
F --> J[최종 결과 통합]
G --> J
H --> J
I --> J
🏪 편의점 체인점 비유¶
graph LR
A[CU 본사] --> B[강남점]
A --> C[홍대점]
A --> D[신촌점]
B --> E[재고 관리]
C --> F[매출 관리]
D --> G[고객 관리]
E --> H[Redis 중앙 데이터베이스]
F --> H
G --> H
- 본사 = 메인 서버
- 각 지점 = 분산된 서버들
- Redis = 모든 지점이 공유하는 중앙 창고
📊 Redis를 활용한 분산처리¶
Redis란?¶
- Remote Dictionary Server
- 메모리에 데이터를 저장하는 고속 데이터베이스
- 여러 서버가 공유할 수 있는 중앙 저장소 역할
실무에서의 활용 예¶
sequenceDiagram
participant U as 사용자
participant S1 as 서버1
participant S2 as 서버2
participant R as Redis
U->>S1: 로그인 요청
S1->>R: 세션 정보 저장
R-->>S1: 저장 완료
S1-->>U: 로그인 성공
U->>S2: 다른 페이지 요청
S2->>R: 세션 정보 조회
R-->>S2: 세션 정보 전달
S2-->>U: 인증된 사용자로 응답
🛒 쇼핑몰 장바구니 시스템 예제¶
// Redis를 활용한 장바구니 관리
public class ShoppingCartService {
private RedisTemplate<String, Object> redisTemplate;
// 장바구니에 상품 추가
public void addToCart(String userId, String productId, int quantity) {
String key = "cart:" + userId;
redisTemplate.opsForHash().put(key, productId, quantity);
// 24시간 후 자동 삭제
redisTemplate.expire(key, 24, TimeUnit.HOURS);
}
// 장바구니 조회
public Map<String, Integer> getCart(String userId) {
String key = "cart:" + userId;
return redisTemplate.opsForHash().entries(key);
}
}
장점: - 🚀 빠른 속도: 메모리에서 데이터 처리 - 🔄 서버 간 공유: 어느 서버에 접속해도 같은 장바구니 - ⏰ 자동 만료: 불필요한 데이터 자동 정리
☁️ 클라우드 환경에서의 활용¶
마이크로서비스 아키텍처¶
graph TB
subgraph "사용자"
U[모바일 앱/웹]
end
subgraph "로드 밸런서"
LB[Load Balancer]
end
subgraph "마이크로서비스들"
US[사용자 서비스]
PS[상품 서비스]
OS[주문 서비스]
CS[결제 서비스]
end
subgraph "공유 자원"
R[Redis Cluster]
DB[(Database)]
end
U --> LB
LB --> US
LB --> PS
LB --> OS
LB --> CS
US --> R
PS --> R
OS --> R
CS --> R
US --> DB
PS --> DB
OS --> DB
CS --> DB
실무 활용 시나리오¶
1️⃣ 세션 클러스터링¶
// 여러 서버가 사용자 로그인 상태 공유
@Service
public class SessionService {
public void createSession(String userId, String sessionId) {
// Redis에 세션 정보 저장
redisTemplate.opsForValue().set(
"session:" + sessionId,
userId,
30, TimeUnit.MINUTES
);
}
}
2️⃣ 캐싱으로 성능 향상¶
@Service
public class ProductService {
@Cacheable(value = "products", key = "#productId")
public Product getProduct(Long productId) {
// 첫 번째 요청시에만 DB 조회
// 이후 요청은 Redis에서 빠르게 응답
return productRepository.findById(productId);
}
}
3️⃣ 분산 락으로 동시성 제어¶
@Service
public class InventoryService {
public boolean purchaseProduct(Long productId, int quantity) {
// 재고 차감시 동시성 문제 해결
String lockKey = "lock:product:" + productId;
try (RLock lock = redisson.getLock(lockKey)) {
if (lock.tryLock(5, TimeUnit.SECONDS)) {
// 안전하게 재고 차감 처리
return processInventory(productId, quantity);
}
return false;
}
}
}
🎯 클라우드 엔지니어로서 알아야 할 핵심 포인트¶
1️⃣ 확장성 (Scalability)¶
graph LR
A[사용자 증가] --> B[서버 부하 증가]
B --> C[새로운 서버 추가]
C --> D[Redis로 상태 공유]
D --> E[부하 분산 완료]
2️⃣ 고가용성 (High Availability)¶
graph TD
A[마스터 Redis] --> B[슬레이브 Redis 1]
A --> C[슬레이브 Redis 2]
D[마스터 장애 발생] --> E[자동 페일오버]
E --> F[슬레이브가 마스터로 승격]
F --> G[서비스 중단 없음]
3️⃣ 모니터링과 로깅¶
@Component
public class PerformanceMonitor {
@EventListener
public void logSlowQueries(SlowQueryEvent event) {
// 느린 쿼리 감지 및 알림
if (event.getExecutionTime() > 1000) {
log.warn("Slow query detected: {} ms",
event.getExecutionTime());
}
}
}
📝 정리 및 다음 단계¶
✅ 오늘 배운 것들¶
- 스레드: 동시에 여러 작업을 처리하는 기술
- 분산처리: 여러 서버가 협력하여 큰 작업 처리
- Redis: 고속 메모리 데이터베이스로 서버 간 데이터 공유
- 클라우드 활용: 확장 가능하고 안정적인 시스템 구축
🚀 다음 학습 추천¶
- Spring Boot로 REST API 만들기
- Docker로 애플리케이션 컨테이너화
- Kubernetes로 컨테이너 오케스트레이션
- AWS/GCP/Azure 클라우드 서비스 활용
- 모니터링 도구 (Prometheus, Grafana) 학습
💡 실습 프로젝트 아이디어¶
- 간단한 채팅 애플리케이션 (WebSocket + Redis)
- 쇼핑몰 장바구니 시스템 (Spring Boot + Redis)
- 파일 업로드/다운로드 시스템 (멀티스레드 활용)
🎉 마무리¶
클라우드 엔지니어의 길은 처음엔 복잡해 보이지만, 하나씩 차근차근 배워나가면 충분히 달성할 수 있습니다!
기억하세요:
- 🧵 스레드로 동시 처리 능력 향상
- 🌐 분산처리로 확장 가능한 시스템 구축
- 📊 Redis로 고성능 데이터 공유
- ☁️ 클라우드로 안정적인 인프라 운영
화이팅! 💪