UBMS 기술 분석 보고서 5 / 7
7. 멀티스레드 안전성7.1 락 전략컴포넌트락 타입읽기쓰기UBMS::CacheManagershared_mutexshared_lock (동시 다중)unique_lock (배타적)UBMS::Chainmutex-addBlock/rollBack 직렬화UBMS::BlockCurrentatomic shared_ptr + mutexatomic load (락 없음)mutex 보호UBMS::BlockMetaFullCacheatomic shared_ptr + mutexatomic load (락 없음)COW 교체UBMS::BlockPoolatomic shared_ptr + mutexatomic load (락 없음)COW 교체UBMS::VolatileCacheshared_mutexshared_lockunique_lockUBMS::ConfirmedCacheshared_mutexshared_lockunique_lockUBMS::TxCurrentshared_mutexshared_lockunique_lockDBmutex모든 연산 직렬화모든 연산 직렬화7.2 TOCTOU 회피 설계취약한 설계 (분리 호출):Thread A: isSpentKey(key) → false (미소비)
--- 이 사이에 Thread B가 addBlock()으로 key 소비 ---
Thread A: addTx(key) → 이미 소비된 UTXO로 TX 생성 (이중 지불!)UBMS의 해결: 원자적 검사 함수checkDoubleSpendWithPool(address, key):
// CacheManager의 shared_lock이 이미 걸린 상태
// 1단계: 확정 원장 소비 확인
// TX풀 잔돈이면 통과, 아니면 거부
// 2단계: TX풀 소비 확인 (같은 주소)
// 이미 소비 예약되었으면 거부
// 3단계: 전역 크로스-주소 이중소비 확인
// 다른 주소의 TX가 이미 사용했으면 거부
// 전부 통과하면 미소비 확인 완료원자적 검사 함수 전체 목록:함수검사 범위용도checkDoubleSpendWithPool()확정 + TX풀 + 전역이중 지불 다단 검사isNotSpentKeyWithPool()확정 + TX풀 잔돈미소비 확인getUTXOWithPool()확정 + TX풀UTXO 통합 조회getInputWithPool()DB + volatile + TX풀입력 수집getBalanceAvailableWithPool()DB + volatile + TX풀사용 가능 잔액getStakeWithPool()DB + volatile + TX풀스테이크 통합 조회락 계층 설계 (교착 방지):UBMS::Chain::m_mutex (std::mutex, 배타적) ← addBlock/rollBack 직렬화
└→ UBMS::CacheManager::m_mutex (shared_mutex) ← 읽기/쓰기 분리
└→ UBMS::VolatileCache::m_mutex ← 내부 보호
└→ UBMS::ConfirmedCache::m_mutex ← 내부 보호
└→ UBMS::TxCurrent::m_mutex ← 내부 보호
규칙: 외부 → 내부 순서로만 취득, 역순 불가 (교착 원천 차단)7.3 락프리 읽기 패턴현재 블록, 블록 메타 전체캐시, 블록풀은 읽기 경로에서 잠금 없이 현재 상태의 스냅샷을 즉시 가져올 수 있도록 설계됨. 쓰기는 단일 경로로 제한하여 데이터 경합을 원천 차단하면서도, 읽기 쪽에 대기나 차단이 발생하지 않음.7.4 TX풀 이중 소비 방지 — 4단 충돌 검사isConflict_(reserved, tx):
검사 1: TX 내부 입력 중복
같은 TX 안에서 동일 UTXO를 두 번 참조하면 거부
검사 2: 주소별 예약 풀 이중 소비
같은 주소의 이전 TX가 이미 소비 예약한 UTXO면 거부
검사 3: 전역 크로스-주소 이중 소비
다른 주소의 TX가 이미 사용한 UTXO면 거부
→ m_globalSpentKeys (unordered_set, O(1) 조회)
검사 4: TX 내부 출력 인덱스 중복
같은 출력 인덱스를 두 번 생성하면 거부TX풀 예약 풀 (UtxoPool) 동작:applyReserveAdd_(tx):
output 중 자기 주소로 돌아오는 잔돈 → available에 추가
input → spent_keys + m_globalSpentKeys에 등록
효과:
A가 5 UBMS UTXO로 3 UBMS 전송 시
→ spent_keys: {원본 5 UBMS key}
→ available: {잔돈 2 UBMS key} ← 다음 TX에서 즉시 사용 가능블록 확정 후 TX풀 정리 (3단계):1) syncCurrentTx(confirmedTxList) → txid로 확정된 TX 제거
2) removeConflictingCurrentTx(spentKeys) → 충돌하는 미확정 TX 제거
3) cleanupCurrentTxByHeight(minHeight) → 너무 오래된 TX 제거8. 성능 분석이하 O() 표기는 시간 복잡도(Time Complexity)를 나타낸다. O(1)은 데이터 양과 무관하게 일정한 시간, O(N)은 데이터 양에 비례하는 시간을 의미.8.1 조회 성능연산경로비고잔액 조회DB(owner 인덱스) + volatile 필터링O(UTXO 개수)TX 존재 확인volatile(10블록) -> DB최신 TX는 메모리에서 즉시UTXO 소비 확인volatile spentKeys -> DBO(10) 최대최근 TX 조회volatile 역순 -> DBtxid 타임스탬프 정렬referral 조회ConfirmedCache 메모리O(1) 해시맵8.2 쓰기 성능연산비용비고블록 추가O(TX수 + UTXO수)volatile pushBackDB 커밋O(차분 크기)10블록마다 한 번, 배치 쓰기롤백O(1)volatile popBack, DB 건드리지 않음8.3 I/O 성능 — 실측 벤치마크측정 환경: AMD Ryzen 7 2700X (2018년 출시), 싱글스레드 (1 core), 3초 측정, localhost8년 전 CPU의 단일 코어만으로 측정한 수치. 동일 세대 Ryzen 9 3900X에서는 싱글코어 기준 30% 이상 향상 확인처리량 — 텍스트 프로토콜메시지 크기클라이언트처리량 (msg/s)송신수신32B11,195,7573,587,4333,587,27132B1010,132,69260,851,19230,398,077256B1883,1322,649,5812,649,396256B104,284,16527,230,56412,852,4961KB1801,8052,405,4162,405,4161KB101,628,3768,246,6304,885,1294KB1320,2681,299,084960,8064KB10205,1661,706,216615,498처리량 — 바이너리 프로토콜메시지 크기클라이언트처리량 (msg/s)송신수신32B11,431,7834,295,6704,295,34932B109,755,88574,314,91529,267,656256B11,231,1943,693,6943,693,584256B105,260,27231,169,94015,780,8171KB1627,7741,883,3221,883,3221KB101,709,7458,647,5785,129,2354KB1509,8161,687,9591,529,4494KB10447,8002,172,0841,343,400레이턴시 (64B echo, 1,000회 반복)지표값평균32.0 usp5032.0 usp9938.1 usmin28.1 usmax40.6 us연결 속도지표값연결 속도12,419 conn/s총 연결1,000건 / 0.08초실측 수치 요약위 벤치마크는 libubmsio_uring.so 자체 실측값이며, 타 라이브러리와의 동일 조건 비교 측정은 수행하지 않았다. 다만 싱글스레드에서 1KB 메시지 170만 msg/s, 32B 메시지 1,013만 msg/s, p99 레이턴시 38us는 io_uring의 커널 수준 최적화를 실용적으로 잘 활용한 결과이며, 공개된 epoll 기반 라이브러리(libevent, libuv, Boost.Asio 등)의 벤치마크 자료와 대조해도 상당히 높은 수치.주요 실측 수치:- 바이너리 1KB, 10클라이언트: 1,709,745 msg/s (싱글스레드)
- 텍스트 1KB, 10클라이언트: 1,628,376 msg/s (싱글스레드)
- 32B 소형 메시지, 10클라이언트: 10,132,692 msg/s
- p99 레이턴시: 38.1us (64B echo RTT)
- 연결 속도: 12,419 conn/s (1,000건/0.08초)
- 멀티코어 활용 시 추가 향상 확인 (사무실 장비에서 20%+ 향상)io_uring 자체의 커널 수준 최적화(SQE 배치 제출, 커널 측 폴링, 시스템콜 감소)가 처리량의 주된 원인이며, libubmsio_uring.so는 이 위에 multishot, zero-copy, provided buffers, backpressure를 조합하여 분산 인프라 노드에 적합한 네트워크 계층을 구성.벤치마크 바이너리(ubmsio_uring_benchmark)가 빌드 산출물에 포함되어 있으므로, 위 수치는 누구든 동일 환경에서 직접 재현할 수 있다.8.4 메모리 사용 추정VolatileCache ~50MB (10블록 x 5MB/블록)
ConfirmedCache ~10MB (referral tree + nodeInfo)
TxCurrent ~100MB (pending TX + 예약 풀)
BlockPool ~100MB (미확정 분기)
합계 ~260MB (정상 상태)
DB 수 GB ~ 수백 GB (블록 데이터)8.5 네트워크 최적화메시지 압축 zlib (평문 메시지)
메시지 중복 제거 메시지 ID 해싱 + 윈도우 기반 중복 추적
공개키 캐싱 LRU 방식 (PEM 파싱 비용 제거)
배치 전송 sendmsg 일괄 전송
100% 당첨! UBMS 무료 코인 참여 이벤트
간단한 참여 완료 시 이벤트 보상을 100% 전원 지급해 드립니다! UBMS 커뮤니티만을 위한 특별 혜택을 지금 바로 확인하세요.
이벤트 참여하고 무료코인 받기