분산형 블룸 필터 설계 및 구현

블룸 필터 기초 개념

블룸 필터는 비트 배열과 해시 함수를 결합한 확률적 데이터 구조로, 원소 존재 여부를 효율적으로 판단합니다. 핵심 원리:

  • 크기 m의 비트 배열 초기화
  • k개의 해시 함수를 통해 원소를 k개의 비트 위치에 매핑
  • 삽입 시 해당 위치 비트를 1로 설정
  • 검색 시 모든 위치가 1인지 확인하여 존재 여부 판단

장점 및 한계

효율성 측면에서 다음과 같은 특징을 가집니다:

  • 메모리 절약: 원소 자체 대신 해시 값만 저장 가능
  • 고속 처리: 삽입/검색 모두 O(k) 시간 복잡도
  • 분산 확장성: 노드 간 분산 저장 가능
  • 단점: 오류 발생 가능성(정확도 감소), 삭제 지원 불가, 파라미터 최적화 어려움

실용적 적용 사례

다양한 시스템에서 활용되는 주요 용例:

  • 캐시 허브: 미존재 데이터 접근 방지
  • 이메일 필터링: 스팸 판별 최적화
  • 웹 스크래퍼: 중복 URL 제거
  • 데이터베이스: 중복 기록 방지
  • 분산 네트워크: 데이터 위치 검색 최적화

분산 블룸 필터 설계

Redis 기반 분산 구현을 위한 핵심 요소:

  • 비트 배열 분산 저장: 노드별 부하 균형
  • 해시 알고리즘: 동등 분포 보장
  • 일관성 해시: 노드 변화 시 데이터 재분배

구현 코드 예시


// 일관성 해시 관리 클래스
public class HashRing {
    private final Map nodeMap = new TreeMap<>();
    private final int virtualNodes;

    public HashRing(int virtualNodes) {
        this.virtualNodes = virtualNodes;
    }

    public void registerNode(String host, int port) {
        for (int i = 0; i < virtualNodes; i++) {
            String key = String.format("%s:%d:%d", host, port, i);
            nodeMap.put(hash(key), host + ":" + port);
        }
    }

    public String findNode(String key) {
        if (nodeMap.isEmpty()) return null;
        int hash = hash(key);
        if (!nodeMap.containsKey(hash)) {
            Map.Entry entry = nodeMap.tailMap(hash).firstEntry();
            return entry != null ? entry.getValue() : nodeMap.firstEntry().getValue();
        }
        return nodeMap.get(hash);
    }

    private int hash(String str) {
        return Math.abs(str.hashCode());
    }
}

// 분산 블룸 필터 클래스
public class DistributedBloom {
    private final HashRing hashRing;
    private final int bitSize;
    private final int hashCount;

    public DistributedBloom(int virtualNodes, int bitSize, int hashCount) {
        this.hashRing = new HashRing(virtualNodes);
        this.bitSize = bitSize;
        this.hashCount = hashCount;
    }

    public void add(String value) {
        int[] positions = computeHashPositions(value);
        String node = hashRing.findNode(value);
        try (Jedis jedis = new Jedis(node.split(":")[0], Integer.parseInt(node.split(":")[1]))) {
            for (int pos : positions) {
                jedis.setbit("bloom_key", pos, true);
            }
        }
    }

    public boolean check(String value) {
        int[] positions = computeHashPositions(value);
        String node = hashRing.findNode(value);
        try (Jedis jedis = new Jedis(node.split(":")[0], Integer.parseInt(node.split(":")[1]))) {
            for (int pos : positions) {
                if (!jedis.getbit("bloom_key", pos)) return false;
            }
        }
        return true;
    }

    private int[] computeHashPositions(String value) {
        int[] positions = new int[hashCount];
        for (int i = 0; i < hashCount; i++) {
            positions[i] = Math.abs(Murmur3.hash(value.getBytes()).asInt() % bitSize);
        }
        return positions;
    }
}

태그: Redis Bloom Filter Consistent Hashing Distributed Systems java

8월 10일 01:26에 게시됨