| 일 | 월 | 화 | 수 | 목 | 금 | 토 |
|---|---|---|---|---|---|---|
| 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 |
- 컴퓨터구조
- OS
- 백준
- 자료구조
- IT
- spring webflux
- 디자인 패턴
- Java
- mongoDB
- Ethereum
- 자바
- Road to Web3
- JavaScript
- react
- Galera Cluster
- Spring
- Heap
- 알고리즘
- Algorithm
- MySQL
- redis
- Data Structure
- 운영체제
- C
- design pattern
- JPA
- MSA
- 파이썬
- Blockchain
- 네트워크
- Today
- Total
시냅스
Road to Web3 (13) 이벤트 로그로 보는 온체인에서 오프체인 연동: 인덱싱과 캐싱이 왜 필요한가 본문
Road to Web3 (13) 이벤트 로그로 보는 온체인에서 오프체인 연동: 인덱싱과 캐싱이 왜 필요한가
ted k 2026. 1. 1. 11:59이 글은 Ethereum 및 EVM 계열을 기준으로 설명합니다.
이번 편의 목표는 한 문장입니다.
- 온체인 상태 변화의 흔적을 이벤트 로그로 읽고, 그걸 오프체인 시스템에 안전하게 반영하는 감각을 만든다
제가 처음 체인 기반 서비스를 바라봤을 때의 생각입니다.
- 체인에서 읽어오면 되지, 굳이 인덱서를 왜 운영하지
- 트랜잭션 해시만 알면 서비스 상태를 다 알 수 있지 않나
- 이벤트는 단순 로그라서 중요한 정보가 아니다
현실은 반대에 가깝습니다.
- 읽기 트래픽을 체인에 직접 때리면 운영이 깨진다
- 서비스 화면은 거의 항상 오프체인 머티리얼라이즈드 뷰가 된다
- 이벤트 로그는 온체인에서 오프체인으로 넘어오는 가장 실용적인 신호다
요약
| 개념 | web2 비유 | 온체인 의미 |
|---|---|---|
| 이벤트 로그 event | 감사 로그, CDC 스트림 | 상태 변경의 흔적, 인덱싱 원재료 |
| 인덱서 indexer | CDC 소비자, ETL 잡 | 블록과 로그를 읽어 DB로 적재 |
| 캐시 캐시DB | 머티리얼라이즈드 뷰, 리드 레플리카 | 빠른 조회, 비용 절감 |
| 커서 cursor | 오프셋 offset | 어디까지 처리했나 block 번호 |
| 재구성 reorg | 롤백, 리더 교체 | 확정 전이면 과거 블록이 바뀔 수 있음 |
| 멱등성 | idempotency key | 중복 이벤트에도 1번만 반영 |
1) 이벤트 로그는 무엇인가
EVM에서 컨트랙트는 실행 중 이벤트 로그를 남길 수 있습니다.
- e.g. : ERC20 Transfer, Approval
- e.g. : 주문 체결, 청구 완료, 정산 완료
이 로그는 블록에 포함된 트랜잭션의 실행 결과로 생성됩니다.
중요한 포인트
- 이벤트는 상태 그 자체가 아니다
- 하지만 상태 변경이 있었음을 알려주는 가장 읽기 쉬운 흔적이다
web2로 치면
- 트랜잭션 커밋 뒤에 남기는 audit log
- 또는 DB binlog 기반 CDC 이벤트
같은 역할입니다.
2) 왜 인덱싱이 필요할까
체인에서 데이터 읽기는 생각보다 비쌉니다.
- RPC는 외부 의존성이고 레이트리밋이 있다
- 같은 데이터를 반복 조회하면 비용과 지연이 늘어난다
- 화면용 쿼리는 조인과 정렬이 많은데, 체인은 그런 형태의 쿼리를 제공하지 않는다
그래서 서비스는 보통 이렇게 갑니다.
- 온체인 로그를 스트리밍으로 수집
- 오프체인 DB에 적재
- API는 DB에서 조회
- 체인은 진실 원천으로만 사용

3) 이벤트만 믿으면 안 되고, 상태와 함께 봐야 한다
이벤트는 편하지만, 이벤트만 보면 위험한 이유가 있습니다.
- 컨트랙트가 이벤트를 안 찍을 수도 있다
- 이벤트는 설계 실수로 누락될 수 있다
- 컨트랙트 업그레이드나 버그로 이벤트 형태가 바뀔 수 있다
- reorg로 이벤트가 사라질 수 있다
그래서 안전한 패턴은 이렇습니다.
- 이벤트는 트리거 신호
- 중요한 값은 상태 조회 call로 재검증
- 최종 스냅샷은 DB에 커밋
web2로 비유하면
- CDC 이벤트를 보고 로컬 뷰를 갱신하되
- 가끔 원본 DB를 다시 읽어 리컨실리에이션을 돌리는 감각입니다
4) 인덱서 기본 구조: 커서와 재처리
인덱서는 결국 이런 루프입니다.
1) lastProcessedBlock 커서를 저장한다
2) 다음 블록부터 차례로 로그를 읽는다
3) 로그를 DB에 반영한다
4) 커서를 업데이트한다
여기서 핵심은 두 가지입니다.
- 멱등성: 같은 로그를 여러 번 봐도 결과는 1번만 반영
- 재처리: 장애가 나면 커서부터 다시 시작
web2로 비유하면
- 카프카 컨슈머 오프셋 관리와 거의 동일합니다
5) reorg 대응: 확정 정책을 인덱서에 넣어야 한다
확정 전 블록은 바뀔 수 있습니다.
그래서 인덱서는 보통 확정 깊이를 둡니다.
- tip 최신 블록까지 바로 반영하지 않는다
- tip - k 까지만 확정 처리한다
- tip 근처는 임시 테이블이나 pending 상태로 둔다
이렇게 하면 reorg가 나도
- 임시 영역만 되돌리면 되고
- 확정 영역은 안정적으로 유지됩니다

추가 팁
- 인덱서 DB에는 blockHash도 저장한다
- 다음 폴링 때 같은 blockNumber의 blockHash가 달라지면 reorg로 판단한다
- reorg 구간을 롤백하고 다시 적재한다
이 절차는 web2의 리더 교체 후 로그 롤백과 닮았습니다.
6) 캐싱은 왜 필요한가
인덱싱만으로도 화면이 나오긴 합니다.
하지만 캐싱이 없으면 곧 이런 문제가 옵니다.
- 같은 지갑 히스토리 조회가 폭주한다
- 인기 토큰 트랜잭션 조회가 폭주한다
- 이벤트 인덱스 쿼리가 병목이 된다
그래서 보통 2단 캐시 구조가 됩니다.
- DB 자체가 1차 머티리얼라이즈드 뷰
- Redis 같은 캐시가 2차 가속
web2에서
- 리드 레플리카 + Redis 캐시
를 놓는 것과 같은 그림입니다.
7) 체크리스트
1) 이벤트는 진실이 아니라 흔적이다
2) 이벤트는 트리거, 중요한 값은 상태 조회로 재검증한다
3) 인덱서는 커서 기반으로 단방향 재처리 가능해야 한다
4) 멱등성 키는 txHash + logIndex 또는 blockNumber + logIndex 조합을 쓴다
5) 블록 해시를 저장해 reorg를 감지한다
6) 확정 깊이 k를 두고 tip 근처는 임시 영역으로 둔다
7) 장애 시 커서부터 재시작해도 중복 반영이 없어야 한다
8) RPC 레이트리밋과 장애 모델을 전제로 재시도와 백오프를 넣는다
9) 이벤트 스키마 변경과 컨트랙트 업그레이드를 대비해 버전 필드를 둔다
10) 화면용 쿼리는 온체인에서 하지 말고 오프체인 뷰로 만든다
11) 캐시는 조회 폭주를 막는 보험이다
12) 운영 메트릭은 처리 지연, reorg 롤백 횟수, 누락률을 본다
결론
- 이벤트 로그는 온체인에서 오프체인으로 넘어오는 가장 실용적인 신호다
- 인덱서는 커서, 멱등성, 재처리, reorg 완충이 핵심이다
- 캐시는 비용과 지연을 줄이는 제품 필수 구성이다
.
'Road To Web3 > Blockchain' 카테고리의 다른 글
| Road to Web3 (15) 배치 정산 모델: 빠른 UX 오프체인 + 강한 신뢰 온체인의 타협 (0) | 2026.01.01 |
|---|---|
| Road to Web3 (14) L2 롤업 구조: 시퀀서, 소프트 확정 vs L1 하드 확정 (0) | 2026.01.01 |
| Road to Web3 (12) 블록체인 동시성: 락 대신 전역 직렬화 + nonce 조건부 커밋 (0) | 2026.01.01 |
| Road to Web3 (11) 실패하는 트랜잭션도 비용이 든다: revert와 운영비 (0) | 2026.01.01 |
| Road to Web3 (10) 스마트컨트랙트는 DB 트랜잭션 함수다 (0) | 2025.12.29 |
