본문 바로가기

전체 글

Redis 기반 Token bucket 벤치마크 기록 개요여러 플랫폼에서 공개하는 API들은 서버 자원을 보호하기 위해 Rate Limiting을 적용한다.클라이언트는 응답 헤더에 담긴 남은 토큰 개수나 다음 요청 가능 시점을 확인하고, 이를 근거로 리소스 접근 여부를 판단하게 된다.문제는 이러한 정보를 알기 위해서는 결국 API를 직접 호출해야 한다는 건데, 만약 접근이 불가능한 상태라면, 다수의 클라이언트가 동일하게 실패 응답을 받기 위해 반복적으로 리소스를 호출하는 비효율이 발생한다. 이를 줄이기 위해 캐싱이나 서킷브레이커(circuit breaker)를 활용할 수 있지만,캐시는 관리가 까다롭고(e.g. 캐시 무효화 전략의 복잡성, TTL 설정), 서킷은 RPS 제한이 초 단위로 걸려 있는 경우 너무 자주 열리고 닫혀 비효율적일 수 있다.그렇다면, .. 더보기
Fly.io 분산 시스템 챌린지(Maelstrom) 기록-5 #5: Kafka-Style Log(https://fly.io/dist-sys/5a/, https://fly.io/dist-sys/5b/)N개의 노드로 이뤄진 클러스터 환경에서 노드 간 로그 엔트리를 동기화하는 챌린지다.kafka의 ISR을 떠올려 Strong Leader 방식으로 구현해도 되지만, 이전에 이야기했듯이 리더 선출, 그룹 관리, 합의 등의 복잡한 추가 처리가 필요하므로 다른 방식으로 해결해보자. 이번 챌린지에서는 maelstrom에서 제공해주는 lin-kv 서비스를 이용한다.Redis 같은 외부 key-value 스토어라고 간단하게 생각해도 된다.* java 언어에서 lin-kv와 통신하려면 dest: lin-kv로 요청을 보내고, handler 에서 응답(e.g. read_ok)을 받아 .. 더보기
Fly.io 분산 시스템 챌린지(Maelstrom) 기록-4 #4: Grow-Only Counter(https://fly.io/dist-sys/4)N개의 노드로 이뤄진 클러스터 환경에서 Grow-Only Counter를 구현하는 챌린지다.모든 노드가 동일한 값을 갖기 위해선 어떻게 해야할까? 내가 생각한 방법은 두 가지다. 1. Strong Leader클러스터를 대표하는 노드가 모든 쓰기 요청을 처리하는 방식이다. 읽기 요청은 stale read가 허용되는 환경이냐에 따라 리더 노드에서 처리할 지, 다른 레플리카 노드에서도 처리 가능한 지를 결정해주면 된다.이번 챌린지에서는 eventually consistent 상태를 유지해주면 되므로, stale read가 허용되는 환경이라고 할 수 있다.다만 이 방식을 선택하려면 리더 선출 방식(e.g. 선거) 및 그룹 관리.. 더보기
Fly.io 분산 시스템 챌린지(Maelstrom) 기록-3 #3: Broadcast(https://fly.io/dist-sys/3a, https://fly.io/dist-sys/3b)N개의 노드로 이뤄진 클러스터 환경에서 gossip을 이용해 노드 간 데이터를 동기화하는 챌린지다.gossip을 전송하기 위해 각 노드는 자신의 인접 노드를 관리한다. (partial membership)네트워크 단절(partition) 상황은 발생하지 않는다는 전제가 있으므로, gossip 처리 시 오류가 발생하는 경우는 고려하지 않았다. RPC(클라이언트 요청)는 3가지 유형이 존재한다.1. broadcastmessage 저장 요청이다. 클라이언트는 한 노드에만 요청하므로, 클러스터 내 노드가 모두 인지하기 위해선 gossip을 전파해야 한다.인접한 노드와 gossip을 주고 받.. 더보기
Fly.io 분산 시스템 챌린지(Maelstrom) 기록-2 #2: Unique ID Generation(https://fly.io/dist-sys/2)N개의 노드로 이뤄진 클러스터 환경에서 유일한 ID를 생성해내는 챌린지다.--node-count 3테스트 실행 시점에 위 옵션을 넣어주면 maelstrom 에서 JVM 프로세스를 노드 개수만큼 띄워준다. 유일한 ID를 생성하기 위해서는 로컬에서 CAS를 지원하는 클래스를 사용할 수 있다. (e.g. AtomicLong)분산 환경에서는 각 노드가 로컬 ID의 변경 이벤트를 공유하지 않기 때문에, ID가 반드시 중복될 수 있다. 간단한 해결법은, ID를 어느 노드에서 생성했는지 식별자를 추가해주면 된다.분산 환경에서 식별자 생성의 대표적인 예로 Snowflake ID를 떠올릴 수 있다.https://en.wikiped.. 더보기
Fly.io 분산 시스템 챌린지(Maelstrom) 기록-1 #0: Getting Ready1. 설치(https://cljdoc.org/d/maelstrom/maelstrom/0.2.0/doc/getting-ready)Java: JDK 17Graphviz: brew install graphvizgnuplot: brew install gnuplotmaelstrom: https://github.com/jepsen-io/maelstrom/releases/tag/v0.2.4 Release 0.2.4 · jepsen-io/maelstromThis is a small release. it includes the latest version of Jepsen (0.3.7), and fixes a bug in Knossos which occurred when errors happ.. 더보기
Reactor Sink 트러블 슈팅 기록 배경최근에 기존 배치 작업이 정상적으로 처리되고 있지 않은 것 같다는 이슈가 제보됐는데, 확인해 보니 실제로 몇몇 데이터가 누락된(처리되지 않은) 상태였습니다. 데이터 원천 서버에서 REST API 를 통해서는 값이 조회됐는데, 같은 데이터를 참조하는 배치 작업에서는 해당 데이터가 어째선지 처리되지 않았습니다. 더 이상했던 점은 문제가 계속해서 발생하는 것이 아닌, 때때로 발생했다는 점이었습니다. 어떤 문제가 있었는지, 배치의 구조와 함께 이야기해 보겠습니다.배치의 데이터 처리 방식은 위 구조와 같습니다.데이터가 있는 서버와 배치가 실행되는 app 은 gRPC bi-stream 통신을 이용해 데이터를 주고받으며, client observer 의 onNext 에서 Sink 에 데이터를 전송해 줍니다. Si.. 더보기