-
Notifications
You must be signed in to change notification settings - Fork 0
9주차 일지 김규원
티켓 재고 수량을 관리하는데 모든 커넥션들이 하나의 row 에 대한 비관락을 기다려서 성능이 떨어지는 이슈가 발생했습니다. 그렇기 때문에 팀원분들의 아이디어로 락을 분산시키기로 했습니다.
이렇게 하면 클라이언트가 서로를 기다릴 일이 없습니다. 그렇게 해서 저희는 플로우가 다음과 같이 바꼈습니다.
- 티켓 재고 중 판매 안된 재고 하나 가져오기
- 가져온 티켓재고를 판매 완료로 상태 업데이트
이때 민지님이 제안해주신 아이디어로 limit 1 skip locked
를 쓰게되었습니다. 이렇게 하면 이미 잠겨있는 행을 제외하고 바로 반환이 가능하였습니다.
MySQL 저장 프로시저의 성능 이슈:
쿼리 최적화: MySQL은 저장 프로시저 내의 쿼리를 개별적으로 최적화하며, 프로시저 전체를 최적화하지 않습니다.
캐싱 제한: MySQL은 저장 프로시저 결과를 효과적으로 캐싱하지 못합니다.
파싱 오버헤드: 매번 실행 시 프로시저를 다시 파싱해야 합니다.
메모리 관리: 복잡한 프로시저는 메모리 사용량이 증가할 수 있습니다.
MSSQL 저장 프로시저의 성능:
쿼리 플랜 캐싱: MSSQL은 저장 프로시저의 실행 계획을 캐싱하여 재사용합니다.
최적화: 전체 프로시저를 대상으로 최적화를 수행합니다.
컴파일: 처음 실행 시 컴파일되어 이후 실행 시 빠르게 처리됩니다.
네트워크 트래픽 감소: 클라이언트-서버 간 통신을 줄여 성능을 향상시킵니다.
결론적으로, MSSQL의 저장 프로시저가 MySQL보다 일반적으로 더 나은 성능을 보입니다.
-
작동 원리:
- 외부 테이블(outer table)에서 행을 하나씩 읽습니다.
- 각 외부 행에 대해, 내부 테이블(inner table)의 모든 행을 스캔하여 조인 조건을 만족하는 행을 찾습니다.
- 조건을 만족하는 행들을 결과 집합에 추가합니다.
-
성능 특성:
- 시간 복잡도: O(n * m), 여기서 n과 m은 각 테이블의 행 수입니다.
- 작은 테이블에 효과적이지만, 큰 테이블에서는 비효율적일 수 있습니다.
-
최적화 기법:
- 작은 테이블을 외부 테이블로 선택
- 내부 테이블에 적절한 인덱스 사용
- 조인 버퍼 크기 조정
-
사용 시나리오:
- 작은 데이터셋
- 높은 선택도(selectivity)를 가진 조인 조건
- 내부 테이블에 효율적인 인덱스가 있는 경우
-
MySQL에서의 구현: MySQL은 기본적으로 Nested Loop Join을 사용하며, 필요에 따라 다른 알고리즘으로 전환합니다.
-
작동 원리:
- 빌드 단계: 작은 테이블(빌드 테이블)의 조인 키에 대한 해시 테이블을 메모리에 생성합니다.
- 프로브 단계: 큰 테이블(프로브 테이블)을 스캔하면서 각 행의 조인 키에 대한 해시값을 계산하고, 해시 테이블에서 일치하는 항목을 찾습니다.
-
성능 특성:
- 시간 복잡도: O(n + m), 여기서 n과 m은 각 테이블의 행 수입니다.
- 대용량 데이터셋에 효과적이지만, 해시 테이블 생성에 초기 오버헤드가 있습니다.
-
최적화 기법:
- 작은 테이블을 빌드 테이블로 선택
- 해시 함수 최적화
- 메모리 관리 (해시 테이블이 메모리에 완전히 들어가지 않을 경우 Grace Hash Join 사용)
-
사용 시나리오:
- 대용량 데이터셋
- 동등 조인 조건
- 인덱스가 없거나 비효율적인 경우
-
MySQL에서의 구현: MySQL 8.0.18 버전부터 Hash Join이 도입되었으며, 특정 조건에서 자동으로 선택됩니다.
-
작동 원리:
- 정렬 단계: 두 테이블을 조인 키에 따라 정렬합니다.
- 병합 단계: 정렬된 두 테이블을 동시에 스캔하면서 일치하는 행을 찾아 결과 집합에 추가합니다.
-
성능 특성:
- 시간 복잡도: O(n log n + m log m), 여기서 n과 m은 각 테이블의 행 수입니다.
- 정렬에 초기 비용이 들지만, 한 번 정렬되면 효율적으로 병합할 수 있습니다.
-
최적화 기법:
- 이미 정렬된 데이터 활용 (예: 인덱스가 조인 키에 맞게 정렬된 경우)
- 정렬 알고리즘 최적화
- 병합 과정에서의 버퍼 관리
-
사용 시나리오:
- 대용량 정렬된 데이터셋
- 범위 조인 조건
- 조인 결과가 정렬되어야 하는 경우
-
MySQL에서의 구현: MySQL은 특정 조건에서 Merge Join을 사용할 수 있지만, 주로 인덱스를 활용한 Nested Loop Join으로 구현됩니다.
기획을 줄이게 되면서 팀원분의 작업 일부를 날리게 되었습니다. 처음부터 기획을 줄이자고 설득을 강하게 했었어야 됐는데 그렇지 못한 제 자신이 아쉬웠습니다. 그리고 지금 대기열 로직을 확정시키지 못하고 있음이 아쉽습니다. 최대한 고민 많이 해보고 구현하고 있었는데 예외 상황이 있어서 갈아엎는 상황이 계속 발생하고 있습니다. 비즈니스적으로 처리할 예외사항들이 너무 많아서 힘드네요.. 웹소켓, 메세지큐 쓰면 모든게 해결되는 상황인데 성능 이슈, 또는 인프라 비용 이슈 때문에 못쓰고 있습니다. 역시 돈 많이 들인 서버가 제일 좋은거 같아요.