| 일 | 월 | 화 | 수 | 목 | 금 | 토 |
|---|---|---|---|---|---|---|
| 1 | 2 | 3 | ||||
| 4 | 5 | 6 | 7 | 8 | 9 | 10 |
| 11 | 12 | 13 | 14 | 15 | 16 | 17 |
| 18 | 19 | 20 | 21 | 22 | 23 | 24 |
| 25 | 26 | 27 | 28 | 29 | 30 | 31 |
- 데이터베이스
- Effective Java
- 스프링핵심원리
- 카카오
- 티스토리챌린지
- 자바
- 오블완
- 엘라스틱서치
- springboot
- effectivejava
- kubernetes
- 자바스크립트
- Kotlin
- Spring
- JavaScript
- Effective Java 3
- java
- 클린아키텍처
- 스프링
- 알고리즘
- ElasticSearch
- 김영한
- 이펙티브자바
- Sort
- 이펙티브 자바
- 알고리즘정렬
- 스프링 핵심원리
- 스프링부트
- 예제로 배우는 스프링 입문
- k8s
- Today
- Total
목록컴퓨터 공학 (35)
Kim-Baek 개발자 이야기
서버 한 대로는 한계였다Court Alarm이 2년째 운영되면서 사용자가 급증했다.월간 활성 사용자: 10만 명일일 예약: 5,000건동시 접속: 1,000명MySQL 서버 하나로 버티고 있었는데, 점점 한계가 보이기 시작했다.CPU: 90% (쿼리 처리)메모리: 85% (버퍼 풀)디스크 I/O: 포화 (읽기/쓰기)응답 시간: 2초 (평소 50ms)특히 새벽 6시, 예약 오픈 시간에는 서버가 거의 죽었다.두 가지 선택지가 있었다:1. Scale-Up (수직 확장)서버 스펙 업그레이드CPU, RAM, SSD 증설한계: 비용 급증, 물리적 한계2. Scale-Out (수평 확장)서버 추가읽기/쓰기 분산무한 확장 가능당연히 Scale-Out을 선택했다. 그리고 두 가지 기법을 적용했다:Replication: ..
같은 쿼리가 다른 결과를 보여줬다예약 통계를 보여주는 대시보드를 만들고 있었다.@Transactionalfun getStatistics(userId: Long): Statistics { // 1. 총 예약 수 val totalCount = reservationRepository .countByUserId(userId) // 2. 예약 목록 val reservations = reservationRepository .findByUserId(userId) return Statistics( totalCount = totalCount, reservations = reservations )}이상한 현상:totalCoun..
실수로 테이블을 날렸다금요일 오후 4시, 배포를 준비하고 있었다.-- 개발 DB에서 테스트 데이터 삭제하려고DELETE FROM test_reservations WHERE created_at 실행 버튼을 눌렀다. 1초 후, 끔찍한 메시지가 보였다.Query OK, 450,234 rows affected45만 건? 테스트 데이터는 100건인데...급하게 확인해보니 운영 DB에 접속되어 있었다. 실수로 운영 DB의 예약 데이터를 삭제한 것이다.SELECT COUNT(*) FROM reservations;-- 50,000 (원래 500,000)45만 건의 예약이 사라졌다.심장이 멎는 것 같았다. 하지만 다행히 백업과 바이너리 로그가 있었다.# 1. 새벽 2시 백업 복원mysql 30분 후, 모든 데이터가 복구..
MySQL로는 처리할 수 없었다Court Alarm이 2년째 운영되면서 새로운 기능을 추가하기로 했다. 실시간 채팅이었다.사용자들이 코트를 예약하면서 서로 메시지를 주고받고, 매칭을 할 수 있게 하는 것이었다. 간단해 보였다.-- 채팅 메시지 테이블CREATE TABLE chat_messages ( id BIGINT PRIMARY KEY AUTO_INCREMENT, room_id BIGINT NOT NULL, user_id BIGINT NOT NULL, message TEXT NOT NULL, created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP, INDEX idx_room_created (room_id, created_at));베타 테스트를..
데이터가 사라졌다금요일 밤 11시, 장애 알림이 울렸다."DB 서버 응답 없음"Court Alarm의 모든 예약 데이터가 저장된 MySQL 서버가 다운됐다. 급하게 서버에 접속했다.mysql -u root -p# ERROR 2002 (HY000): Can't connect to local MySQL serverMySQL이 죽어있었다. 재시작을 시도했다.systemctl start mysql# Job for mysql.service failed로그를 확인했다.tail -f /var/log/mysql/error.log[ERROR] InnoDB: Corruption detected in tablespace reservations[ERROR] InnoDB: Database page corruption[ERROR..
서버가 80%의 시간을 놀고 있었다Court Alarm API 서버의 모니터링 대시보드를 보고 있었다. 이상한 점이 있었다.CPU 사용률: 20%메모리 사용률: 40%응답 시간: 평균 2초동시 접속자: 500명리소스는 충분한데 응답이 느렸다. 뭔가 이상했다.스레드 덤프를 떠서 분석했다.jstack | grep "WAITING\|BLOCKED" | wc -l# 결과: 190 (전체 200 스레드 중)190개 스레드가 대기 중이었다! 무엇을 기다리고 있을까?"http-nio-8080-exec-42" #42 waiting on condition at java.net.SocketInputStream.socketRead0(Native Method) at java.net.SocketInputStream.rea..
100만 개 파일을 저장했더니 서버가 느려졌다Court Alarm이 1년쯤 운영되면서 사용자들의 프로필 사진이 쌓이기 시작했다. 처음엔 몇 백 개였는데, 어느새 10만 개, 50만 개, 그리고 100만 개를 넘어섰다.그런데 이상한 일이 생겼다. 파일을 저장하거나 읽는 속도가 점점 느려지는 것이었다.// 프로필 사진 저장val file = File("/data/profile-images/${userId}.jpg")file.writeBytes(imageData) // 처음엔 10ms → 지금은 500ms?!왜 똑같은 작업이 50배나 느려진 걸까?서버 스펙은 그대로였다. CPU도, 메모리도, 디스크도 여유가 있었다. 문제는 파일 시스템에 있었다. 하나의 디렉토리에 100만 개 파일을 저장하면서 파일 시스템의..
서버가 10,000개 연결을 처리하는 방법Court Alarm이 성장하면서 동시 접속자가 급증했다. 처음엔 100명, 그 다음 1,000명, 그리고 어느 날 10,000명이 동시에 접속했다.서버가 버텨낼 수 있을까? 놀랍게도 서버는 문제없이 동작했다. CPU 사용률 40%, 메모리 사용률 60%. 여유가 있었다.어떻게 서버 한 대가 10,000개의 동시 연결을 처리할까?답은 운영체제의 네트워크 스택에 있었다. 운영체제는 네트워크 연결을 효율적으로 관리하는 정교한 메커니즘을 가지고 있다. 소켓, 버퍼, 인터럽트, I/O 다중화...5년 차가 되어서도 이 부분이 가장 어려웠다. 하지만 실제 성능 문제를 해결하면서 운영체제의 네트워크 처리를 제대로 이해하게 됐다.소켓(Socket)이란 무엇인가기본 개념소켓은 ..
예약이 두 번 되는 버그Court Alarm을 출시하고 일주일 후, 황당한 버그 리포트가 들어왔다."같은 시간대에 예약이 2개 잡혔어요. 코트는 하나인데..."처음엔 믿기지 않았다. 예약 전에 분명히 중복 체크를 하는 코드가 있었다. 하지만 로그를 확인해보니 정말로 같은 시간대에 2명의 예약이 동시에 들어가 있었다.[2024-01-05 10:23:45.123] 사용자A: 14시 코트 예약 시도[2024-01-05 10:23:45.125] 사용자B: 14시 코트 예약 시도[2024-01-05 10:23:45.234] 사용자A: 예약 성공[2024-01-05 10:23:45.236] 사용자B: 예약 성공두 요청이 거의 동시에 들어왔다. 둘 다 "예약 없음"을 확인하고, 둘 다 예약을 진행했다. 전형적인 Ra..
서버가 느려지는 이유를 찾아서월요일 오전, Court Alarm 서버의 응답 속도가 점점 느려지고 있었다.배포 직후에는 평균 응답시간 200ms였는데, 2일이 지나니 2초, 3일째는 5초, 그리고 금요일엔 거의 응답이 없었다. 서버를 재시작하면 다시 빨라졌지만, 며칠 지나면 또 느려졌다.모니터링 그래프를 보니 메모리 사용량이 계속 증가하고 있었다. 시작할 때 500MB였던 메모리가 일주일 후엔 3.8GB(전체 4GB 중)를 사용하고 있었다. 전형적인 메모리 누수(Memory Leak) 증상이었다.5년차가 되어서도 메모리 관리는 여전히 어려웠다. 하지만 이번 경험을 통해 Heap과 Stack의 차이를 머리가 아닌 손으로 이해하게 됐다.메모리 구조의 기본메모리는 왜 영역을 나눌까프로그램이 실행되면 운영체제는..
프로세스와 스레드 - 경력 5년차 개발자의 실전 경험새벽 3시에 울린 장애 알림새벽 3시, 장애 알림이 울렸다."API 서버 응답 없음. 모든 요청 타임아웃."급하게 서버에 접속해서 확인해보니 CPU 사용률은 20%인데, 스레드 200개가 전부 BLOCKED 상태였다. 5년 차가 되어서야 깨달았다. 프로세스와 스레드의 차이를 '아는 것'과 '제대로 사용하는 것'은 완전히 다른 문제라는 것을.이 글에서는 경력 개발자 면접에서 단골로 나오는 "프로세스와 스레드"를 기본 개념부터 실무 적용까지 상세하게 정리해보려고 한다.프로세스란 무엇인가프로세스의 정의프로세스(Process)는 실행 중인 프로그램을 의미한다. 좀 더 정확히 말하면, 디스크에 저장된 실행 파일(예: .exe, .jar)이 메모리에 올라가서 실행..
📌 MongoDB에서 Time Series 기능을 사용하지 않고 일반 컬렉션을 활용하는 것과의 차이점MongoDB에서 Time Series Collection을 사용하지 않고, 일반 컬렉션에 시간 데이터를 저장하여 쿼리하는 방법도 가능합니다. 하지만 두 방식에는 성능, 저장 공간 효율성, 쿼리 최적화 측면에서 차이가 있습니다.1️⃣ Time Series Collection vs 일반 컬렉션의 차이점 정리비교 항목 Time Series Collection 사용 일반 MongoDB Collection 사용저장 구조시간 기반 자동 최적화된 저장JSON 문서 개별 저장인덱싱timestamp 필드 자동 인덱싱수동으로 timestamp 필드에 인덱스 추가 필요읽기(Read) 성능시간 기반 데이터 검색에 최적화일반..
MongoDB Time Series Collection (몽고DB 시계열 컬렉션)란?MongoDB는 5.0 버전부터 **Time Series Collection(시계열 컬렉션)**을 제공하여 시계열 데이터(시간 기반 데이터)를 효율적으로 저장, 인덱싱, 분석할 수 있도록 지원합니다.💡 MongoDB의 Time Series Collection은 일반 컬렉션과 다르게 데이터를 시간 중심으로 최적화하여 저장하는 기능을 제공하며, 기존 RDBMS 기반의 Time Series DB와 차별화된 유연성을 갖습니다.1️⃣ MongoDB Time Series Collection의 특징✅ 시계열 데이터 최적화데이터를 자동으로 압축 및 그룹핑하여 저장 공간을 절약읽기 및 분석 성능 향상✅ 자동화된 시계열 인덱싱시간(tim..
📌 Time Series DB (시계열 데이터베이스)란?**Time Series Database(시계열 데이터베이스, TSDB)**는 **시간(time)**에 따라 변하는 데이터를 저장하고 관리하는 특화된 데이터베이스입니다.이러한 데이터베이스는 센서 데이터, 주식 시장 데이터, 서버 로그, IoT 기기 데이터, 모니터링 시스템 등의 데이터를 다룰 때 많이 사용됩니다.1️⃣ Time Series DB의 특징✅ 시간(Time)이 가장 중요한 요소 → 데이터는 시간 순서대로 저장됨✅ 읽기(Read)가 많고 쓰기(Write)도 많음 → 데이터가 계속 추가되며 빠른 검색이 필요함✅ 압축(Compression) 및 보관(Retention) 기능 필요 → 데이터가 매우 많아지므로 저장 공간을 효율적으로 관리해야 함..
이 글을 읽으면: Spring Data MongoDB의 Audit 기능으로 '누가, 언제' 데이터를 생성/수정했는지 자동으로 추적하는 방법을 배울 수 있습니다. 실무에서 바로 적용 가능한 코드와 함께 자주 발생하는 문제 해결법까지 다룹니다.📌 목차왜 Audit이 필요한가? - 실무 사례MongoDB Audit 기본 개념실전 코드 구현 - 단계별 가이드트러블슈팅 - 자주 겪는 문제들실무 활용 팁1. 왜 Audit이 필요한가? - 실무 사례😫 실무에서 겪은 문제프로젝트를 운영하다 보면 이런 상황이 자주 발생합니다:상황 1: 데이터 변경 이력 추적 불가PM: "이 사용자 정보, 누가 언제 수정했어요?"개발자: "...로그를 뒤져봐야 알 것 같습니다"PM: "😡"상황 2: 버그 원인 파악 어려움- 어제까지..
이 글을 읽으면: API 문서 작성의 고통에서 벗어날 수 있습니다. OpenAPI(Swagger)를 사용하여 코드만 작성하면 자동으로 문서가 생성되고, 프론트엔드 개발자와의 협업도 10배 쉬워집니다. Spring Boot 실전 예제와 함께 배워보세요.📌 목차왜 API 문서 자동화가 필요한가?OpenAPI란? Swagger와의 차이Spring Boot에 적용하기 - 단계별 가이드Controller와 DTO 문서화Swagger UI 활용법실무 활용 팁트러블슈팅1. 왜 API 문서 자동화가 필요한가?😫 실무에서 겪는 API 문서의 고통상황 1: 끝없는 Postman Collection 관리개발자: "API 스펙이 바뀌었는데, Postman Collection도 수정해야 하나..."프론트엔드: "어? 저는 ..
디자인 패턴 중, 비지터 패턴에 대해서 강의를 듣고 정리해보았다. 위의 다이어그램이 비지터 패턴의 다이어그램이다. 중요한 것은 Element( 자료구조 ) 는 변화하지 않는다는 것과 vistor ( 서비스 로직 ) 가 추가되는 기능을 가진다는 것이다. 비지터 패턴은 일반적으로 프로그래밍을 하는 과정에서 생각하는 것과는 약간 다른데, 아래와 같다고 보면 된다. 일반적 : 방문자는 “구매” 라는 기능을 가지고 가게에 간다. 버거킹에 가면 “햄버거”를 사고, 피자헛에 가면 “피자"를 산다. 비지터패턴 : 가게에 방문자가 들어간다. 가게가 방문자에게 자신의 정보를 주고, 방문자는 정보에 따라 “버거킹의 햄버거 구매”, “피자헛의 피자 구매” 라는 기능을 호출한다. 코드 예시를 통해서 살펴보도록 하자. 비지터 패..
POST post 메서드는 기존에 알고있던대로 등록에 관한 내용이다. http 메세지로 넘어온 엔티티를 새로운 자원으로 등록한다. 새로운 자원으로 등록하지않을 수도있는데 이런 경우엔 200(ok)이나 204(no content) response code로 응답한다. 새로운 자원으로 만들어진 경우에는 201(created) response code로 응답하며 신규 생성된 자원의 위치를 헤더에 포함해야한다. 무슨 말이냐하면 예를들어 게시판에 새로 게시물을 등록하면 이를 따라갈수있는 위치를 응답 헤더에 넣어야한다는 의미다. 201 created Location: /board/2 PUT post와 가장 큰차이는 put 메서드는 자원의 식별자를 이미 알고있는 상태여야한다는 점이다. put 메서드는 식별자의 자원을..
- 웹 서버 (Web Server) 클라이언트가 서버에 페이지 요청을 하면 요청을 받아 정적 컨텐츠(.html, .png, .css등)를 제공하는 서버 클라이언트에서 요청이 올 때 가장 앞에서 요청에 대한 처리를 한다. 클라이언트의 요청을 기다리고 요청에 대한 데이터를 만들어서 응답하는 역할 (정적 데이터) CASE 정적 컨텐츠를 요청(request)했나? 1. 정적 컨텐츠구나! 내가 제공해줄게 => .html, .png 등 응답(response) 2. 정적 컨텐츠가 아니구나.. 웹서버에서 간단히 처리 못하겠군. WAS에게 처리를 부탁해야겠다! => 결국 WAS가 처리해준 컨텐츠를 받은 웹서버는 응답(response)을 해줌 대표 : Apache, nginx - WAS (Web Application Se..
"브라우저에 도메인을 입력하면 → DNS서버에 IP주소를 요청 → 수신한 IP주소에 해당하는 웹서버에 접속" 1. 로컬PC의 hosts파일 확인 ( 브라우저에 캐싱되어 있는지 먼저 확인하자 ) 로컬PC의 C:\Windows\System32\drivers\etc 경로(윈도우 설치 경로에 따라 조금 차이가 있을 수 있음)에는 hosts라는 파일이 있다. 이 파일을 메모장으로 열어보면, IP주소와 도메인 주소를 설정할 수가 있다. 이 파일은 PC의 자체 DNS역할을 하며, 브라우저는 가장 먼저 이 파일을 확인하여 입력한 도메인의 매핑정보가 존재하는지 확인한다. 2. DHCP&ARP 대부분 가정집에서는 DHCP로 인터넷 접속을 하고 있을 것이다. DHCP는 Dynamic Host Configuration Pro..
