전체 글 (39) 썸네일형 리스트형 InnoDB의 Lock 관리 매커니즘 1. 배경 InnoDB에서는 여러 트랜잭션이 동시에 동일한 데이터를 변경할 때 일관성을 보장하기 위해 Lock을 사용한다하나의 트랜잭션이 특정 Record를 변경하고 있다면 다른 트랜잭션이 동일한 Record를 동시에 변경할 수 없도록 Lock을 획득한다-- Transaction ASTART TRANSACTION;UPDATE memberSET name = 'A'WHERE id = 1; 그렇다면 특정 Record에 어떤 트랜잭션이 Lock을 획득하고 있으며,다른 트랜잭션이 해당 Lock을 기다리고 있다는 정보는 InnoDB 내부에서 어떻게 관리될까? 단순하게 생각하면 Record 내부에 Lock 상태를 함께 저장하는 방법을 떠올릴 수도 있다 하지만 하나의 Record에는 여러 트랜잭션의 Lock 요청이 존.. TTS-Bot: Triton Ensemble 고정 화자 TTS 추론 파이프라인 구성 (1) 1. 배경 이번 프로젝트는 MLOps와 AI Model Serving에 대한 이해를 높이고,백엔드 개발자로서 AI 서비스와 연결되는 기술 스택을 직접 다뤄보기 위해 시작했다 현재 계획은 아래와 같다 Triton 기반 추론 파이프라인 구성 Triton 기반 서빙을 통한 성능 튜닝gRPC를 통한 WAS와 Triton 간 통신WebFlux 기반 스트림 비동기 처리Voice Cloning을 통한 Speaker Embedding 저장 및 활용(이 글은 프로젝트를 진행하며 작성하는 것이기에, 계획이 수정될 수 있다) 특히 ONNX나 Model의 Input/Output Tensor, 전/후처리, GPU 기반 추론 등을 실제로 구성하면서AI Serving 환경에서 각 컴포넌트가 어떤 역할을 담당하는지 이해하고자 했다 .. CUDA Warp Divergence의 동작 원리와 Independent Thread Scheduling 1. 배경 GPU는 수많은 스레드를 병렬로 실행함으로써 높은 처리량을 얻는다 CUDA에서 스레드는 개별적으로 작성되지만 GPU에서는 Warp를 기본 단위로 명령어를 실행한다NVIDIA GPU의 Warp는 32개의 스레드로 구성되며, SIMT 방식에 따라 Warp에 속한 스레드들이 동일한 명령을 수행한다 예를 들어 다음과 같이 각 스레드가 배열의 서로 다른 원소를 계산한다고 해보자__global__ void add(int* data) { int tid = threadIndex.x; data[tid] += 1;} 각 스레드가 접근하는 데이터는 다르지만 수행하는 명령어는 동일하기 때문에,하나의 Warp에 속한 스레드들을 효율적으로 병렬 실행할 수 있다 그렇다면 다음과 같이 각 스레드마다 서로 다른 .. Java의 Hash 자료구조 동작 원리와 안전한 Hash Key 설계 1. 배경 Java에서 HashMap 이나 HashSet 을 사용하다 보면,객체의 equals() 와 hashCode() 를 함께 재정의해야 한다는 설명을 접한다 두 객체가 같은지를 판단하는 것은 equals() 의 역할이다그렇다면 hashCode() 는 왜 필요하며, 두 메서드가 함께 재정의되지 않으면 어떤 문제가 발생할까? 이번 글에서는 Java의 HashMap 을 중심으로 다음 내용을 살펴보고자 한다 equals() 와 hashCode() 가 함께 사용되는 이유해시값을 Bucket의 위치로 변환하는 방식Hash 충돌과 Bucket 내부 구조Load Factor와 Resize 과정Record와 VO를 안전한 Hash Key로 사용하는 방법 2. equals()와 hashCode()는 .. LongAdder는 어떻게 CAS 경쟁을 분산할까? 1. 배경 이전 글에서는 AtomicLong 이 volatile 수준의 메모리 의미와 CAS를 결합해 원자적인 값 변경을 제공하는 과정을 살펴보았다 AtomicLong 은 별도의 Lock으로 임계 영역 전체를 보호하지 않고도 여러 스레드에서 하나의 값만 안전하게 갱신할 수 있다 하지만 여러 스레드의 갱신이 하나의 값에 집중되면 CAS 실패와 재시도가 반복될 수 있다이때 먼저 갱신에 성공한 스레드를 제외한 나머지 스레드는 현재 값을 다시 읽고 연산을 재시도해야 한다 그렇다면 하나의 값에 집중된 갱신을 여러 위치로 나누어 경쟁을 줄일 수는 없을까?Java는 이러한 상황을 위해 LongAdder 를 제공한다private final LongAdder counter = new LongAdder();publi.. AtomicLong은 어떻게 Lock-Free를 달성했을까? 1. 배경 여러 스레드에서 하나의 카운터를 증가시켜야 할 때 흔히 AtomicLong 을 사용한다private final AtomicLong counter = new AtomicLong();public void increment() { counter.incrementAndGet();} 사용법 자체는 어렵지 않다하지만 내부 동작을 생각하면 몇 가지 의문이 생긴다 synchronized 를 사용하지 않고 어떻게 원자성을 보장할까?여러 스레드가 동시에 값을 변경하려 할 때 어떤 스레드가 성공할까? volatile 은 이 과정에서 어떤 역할을 할까?CPU 레지스터와 캐시는 왜 동시성 문제에 등장할까?CAS(Compare-And-Set) 방식도 경쟁이 심해지면 오버헤드가 생기는데 그 이유는 뭘까?이번.. InnoDB에서 Covering Index를 사용해도 테이블 접근이 발생하는 이유 1. 배경 Covering Index는 쿼리에서 필요로 하는 모든 컬럼을 Index가 포함하고 있는 경우를 의미한다 일반적으로 Covering Index를 사용하면 실제 테이블의 Row를 다시 읽지 않고,Index만으로 조회를 완료할 수 있기 때문에 성능을 개선할 수 있다고 설명한다 하지만 InnoDB의 MVCC 동작을 살펴보던 중 필요한 컬럼이 모두 Secondary Index에 포함돼 있더라도Clustered Index를 다시 조회할 수 있다는 내용을 확인했다 Covering Index는 실제 Row에 대한 접근을 생략하기 위한 방법인데,왜 다시 Clustered Index를 읽어야 할까? 이를 이해하기 위해서 먼저 InnoDB가 Clustered Index와 Secondary Index를 어떻게 구.. ZSET은 어떻게 빠른 정렬 조회를 구현했을까? 1. 배경 Redis의 ZSET 자료구조는 어떤 형태를 가질까?처음에는 ZSET이 내부적으로 Red-Black Tree와 같은 균형 트리로 구성되지 않을까 생각했다 ZSET은 Member와 Score를 함께 저장하고,score를 기준으로 한 정렬된 조회를 제공한다 특정 score 범위에 해당하는 원소를 찾거나 정렬 순서상 일부 구간을 조회할 수 있다는 점은C++의 std::map 에서 제공하는 lower_bound , upper_bound 와도 잘 어울려보였다 하지만 곧 한 가지 의문이 생겼다 Red-Black Tree 하나만으로도 key 기반 조회는 가능하다예를 들어 Member를 기준으로 Tree를 구성하면 특정 Member의 Score를 O(log N)에 찾을 수 있다 하지만 ZSET은 Mem.. 이전 1 2 3 4 5 다음