Fontes Fintech

저지연 트레이딩 시스템에서 Lock 경합이 중요한 이유 | Trading Engineering #8 본문

엔지니어링 : Engineerings

저지연 트레이딩 시스템에서 Lock 경합이 중요한 이유 | Trading Engineering #8

폰테스 핀테크 :: 금융거래의 안전한 미래 2026. 9. 10. 21:19

저지연 트레이딩 시스템에서 Lock 경합이 중요한 이유

Trading Engineering Series — 08

저지연 트레이딩 시스템에서는 데이터 전달 속도만큼 동기화(Synchronization)가 중요합니다.

여러 프로세스나 여러 CPU Core가 동일한 데이터를 처리해야 하는 상황에서는 데이터의 일관성을 유지하기 위해 Lock이나 Atomic Operation 등의 동기화 방법이 필요합니다.

하지만 동기화가 과도하게 사용되면 오히려 시스템의 latency가 증가할 수 있습니다.

특히 여러 실행 주체가 동일한 Lock을 기다리는 Lock Contention은 고성능 트레이딩 시스템에서 중요한 성능 저하 요인이 될 수 있습니다.


1. 왜 Lock이 필요한가?

여러 Thread가 하나의 데이터를 동시에 수정한다고 생각해 보겠습니다.

예를 들어 주문 수량을 관리하는 변수가 있다고 하면:

Thread A → Order Quantity
Thread B → Order Quantity

두 Thread가 동시에 값을 변경할 경우 예상하지 못한 결과가 발생할 수 있습니다.

따라서 공유 데이터에 접근할 때 하나의 실행 주체만 접근하도록 제한할 필요가 있습니다.

가장 일반적인 방법 중 하나가 Mutex Lock입니다.

개념적으로는:

Lock → Shared Data Access → Unlock

과 같은 구조입니다.

Lock은 데이터의 일관성을 유지하기 위한 중요한 도구입니다.

문제는 Lock 자체가 아니라 얼마나 많은 실행 주체가 얼마나 자주 Lock을 기다리느냐입니다.


2. 락 경합 (Lock Contention)이란?

여러 Thread가 동일한 Lock을 사용한다고 가정해 보겠습니다.

Thread A → Lock → Processing

Thread B → Waiting

Thread C → Waiting

Thread D → Waiting

Thread A가 Lock을 해제할 때까지 다른 Thread들은 기다려야 합니다.

이러한 경쟁 상황을 Lock Contention이라고 합니다.

특히 처리해야 할 작업이 짧은데 Lock을 기다리는 시간이 길다면 문제가 더욱 커집니다.

예를 들어 실제 데이터 처리는 수십 나노초 또는 수백 나노초 수준으로 끝나더라도 Lock을 획득하기 위해 더 긴 시간을 기다린다면, Lock이 전체 latency의 중요한 부분이 될 수 있습니다.


3. 왜 트레이딩 시스템에서 더 중요한가?

일반적인 애플리케이션에서는 수 마이크로초 또는 수 밀리초의 차이가 큰 문제가 아닐 수 있습니다.

하지만 고빈도 시장 데이터와 주문을 처리하는 시스템에서는 상황이 다릅니다.

예를 들어:

Market Data → Strategy → Signal → Risk Check → Order → FEP

이 과정에서 여러 단계가 서로 Lock을 기다린다면 전체 Critical Path가 길어질 수 있습니다.

특히 높은 빈도로 반복되는 작업에서는 작은 synchronization overhead도 누적될 수 있습니다.

따라서 저지연 시스템에서는 단순히 CPU 성능을 높이는 것보다 Lock을 기다리는 구조 자체를 줄이는 것이 중요할 수 있습니다.


4. Critical Path에서 Lock을 줄이기

모든 Lock을 제거해야 한다는 의미는 아닙니다.

중요한 것은 Latency-Critical Path에 불필요한 Lock이 있는지 확인하는 것입니다.

예를 들어 다음과 같은 구조가 있다고 생각해 보겠습니다.

Market Data

Lock

Strategy

Lock

Order Manager

Lock

FEP

각 단계에서 공유 데이터에 접근하기 위해 Lock을 기다려야 한다면 latency가 증가할 가능성이 있습니다.

따라서 중요한 데이터의 Ownership을 명확하게 하고, 공유 영역 자체를 줄이는 방식으로 구조를 개선할 수 있습니다.


5. Lock Scope를 작게 만들기

Lock을 완전히 제거할 수 없는 경우에는 Lock Scope를 줄이는 것도 중요한 방법입니다.

예를 들어:

Lock → 많은 작업 수행 → Unlock

보다는:

Lock → 필요한 데이터 수정 → Unlock

과 같이 Lock이 유지되는 시간을 최소화하는 것이 좋습니다.

특히 Lock을 획득한 상태에서:

  • 복잡한 계산
  • 네트워크 I/O
  • 파일 I/O
  • 불필요한 함수 호출
  • 긴 Loop

등을 수행하면 다른 Thread의 대기 시간이 증가할 수 있습니다.

저지연 시스템에서는 Lock 내부에서 수행하는 작업을 최대한 단순하게 유지하는 것이 중요합니다.


6. Single Writer 설계

Lock을 줄이는 대표적인 방법 중 하나는 Single Writer 구조입니다.

여러 Thread가 동일한 데이터를 수정하는 대신 하나의 Writer가 데이터를 관리하도록 합니다.

예를 들어:

Multiple Writers → Shared Data

구조에서는 데이터 변경을 조정하기 위한 Synchronization이 필요할 수 있습니다.

반면:

Single Writer → Shared Data → Multiple Readers

구조에서는 데이터의 Ownership을 명확하게 정의할 수 있습니다.

이렇게 하면 불필요한 Lock을 줄이고 데이터 흐름을 단순하게 만들 수 있습니다.

물론 모든 데이터에 Single Writer 구조가 적합한 것은 아닙니다.

데이터의 특성과 처리 방식에 따라 적절한 구조를 선택해야 합니다.


7. Ring Buffer와 Synchronization

앞선 7편에서 살펴본 Shared Memory와 Ring Buffer 역시 Lock 최소화와 밀접한 관계가 있습니다.

예를 들어 Single Producer / Single Consumer Ring Buffer 구조를 사용할 경우 Producer와 Consumer의 역할을 명확하게 분리할 수 있습니다.

Producer

Ring Buffer

Consumer

데이터의 Ownership과 읽기/쓰기 위치를 명확하게 관리하면 복잡한 Lock 구조를 피할 수 있습니다.

이러한 설계는 고속으로 발생하는 Market Data나 Trading Signal을 처리하는 데 유용할 수 있습니다.


8. Atomic Operation은 Lock의 대안인가?

경우에 따라 Atomic Operation을 활용하면 Mutex와 같은 무거운 동기화 구조를 줄일 수 있습니다.

예를 들어 단순한 상태 값이나 Counter 등을 관리하는 경우 Atomic Operation이 적합할 수 있습니다.

하지만 Atomic Operation 역시 비용이 없는 것은 아닙니다.

CPU Core 간 데이터 공유가 발생하면 Cache Coherence와 Memory Ordering 등의 문제가 영향을 줄 수 있습니다.

따라서:

Mutex → 느림

Atomic → 항상 빠름

이라고 단순하게 생각해서는 안 됩니다.

중요한 것은 데이터의 접근 패턴과 실제 병목 지점입니다.


9. False Sharing도 고려해야 한다

멀티코어 환경에서는 False Sharing도 성능에 영향을 줄 수 있습니다.

서로 다른 Thread가 서로 다른 변수를 사용하고 있더라도, 해당 변수들이 같은 CPU Cache Line에 위치하면 Core 간 Cache synchronization이 빈번하게 발생할 수 있습니다.

예를 들어:

Thread A → Variable A

Thread B → Variable B

논리적으로는 서로 다른 데이터이지만 물리적으로 같은 Cache Line에 위치한다면 불필요한 Cache traffic이 발생할 수 있습니다.

따라서 저지연 시스템에서는 단순히 Lock의 개수만 줄이는 것이 아니라 메모리 구조와 CPU Cache 동작까지 고려해야 합니다.


10. Lock-Free가 항상 정답은 아니다

저지연 시스템을 이야기하다 보면 흔히 Lock-Free라는 표현을 접하게 됩니다.

하지만 Lock-Free 구조가 항상 더 좋은 것은 아닙니다.

Lock을 제거하는 대신:

  • 알고리즘 복잡도 증가
  • 디버깅 어려움
  • 메모리 ordering 문제
  • 데이터 일관성 문제
  • 장애 상황 분석의 어려움

등이 발생할 수 있습니다.

특히 금융 시스템에서는 단순한 성능보다 정확성과 안정성이 훨씬 중요한 경우도 많습니다.

따라서 목표는 무조건 Lock을 제거하는 것이 아니라:

필요한 Synchronization은 유지하면서 불필요한 대기 시간을 줄이는 것

입니다.


11. 어떻게 최적화할 것인가?

Lock 문제를 해결하기 위해서는 먼저 실제 병목을 측정해야 합니다.

예를 들어 다음과 같은 항목을 확인할 수 있습니다.

  • Lock 획득 시간
  • Lock 대기 시간
  • Lock 보유 시간
  • Thread별 처리량
  • Context Switch
  • CPU Cache 관련 성능
  • Critical Path latency

이를 통해 실제로 시스템의 latency를 증가시키는 지점을 찾아야 합니다.

그 이후:

Measure → Identify → Redesign → Benchmark

과정을 반복하는 것이 중요합니다.


12. FontesFintech의 접근 방식

FontesFintech는 저지연 트레이딩 시스템을 설계할 때 Lock을 얼마나 사용했는가보다 왜 Lock이 필요한가를 먼저 살펴봅니다.

주요 설계 방향은 다음과 같습니다.

  • Critical Path의 Lock 최소화
  • Lock Scope 최소화
  • Data Ownership 명확화
  • Single Writer 구조 검토
  • Shared Memory 활용
  • Ring Buffer 활용
  • 적절한 Atomic Operation 사용
  • 불필요한 공유 데이터 최소화
  • CPU Cache 효율성 고려
  • 실제 Latency 측정 및 Benchmark

성능을 높이기 위해 무조건 복잡한 기술을 적용하는 것이 아니라, 실제 시스템의 데이터 흐름과 병목을 분석하여 필요한 부분을 최적화하는 것이 중요합니다.


Conclusion

저지연 트레이딩 시스템에서 Synchronization은 성능과 안정성을 동시에 결정하는 중요한 요소입니다.

Lock은 데이터의 정확성을 지키기 위해 필요하지만, 과도한 Lock은 불필요한 대기 시간을 만들 수 있습니다.

따라서 중요한 것은:

Less Contention
Smaller Critical Sections
Clear Data Ownership
Efficient Synchronization

입니다.

그리고 가장 중요한 원칙은 하나입니다.

Do not optimize what you cannot measure.

실제 latency-critical path를 측정하고 병목을 확인한 뒤, 필요한 부분의 Synchronization 구조를 개선해야 합니다.

좋은 저지연 시스템은 Lock이 없는 시스템이 아니라,

필요한 곳에는 정확하게 동기화하고, 불필요한 곳에서는 기다리지 않는 시스템입니다.