블룸필터의 의미와 카산드라에서 블룸필터를 어떻게 구현했는지 체크한다.
1. 블룸 필터 (Bloom Filter)
블룸 필터는 data 파일의 키값을 모아, 주어진 정보가 있는지 없는지 알려주는 확률 기반의 필터이다. 블룸필터 를 통해서 data가 있는지 빨리 확인할 수 있다. 상식선에서 잘 생각했을 때, 데이터가 없는데 있다는 것는 괜찮지만, 데이터가 있다고 해놓고서는 없는 것은 없다 라는 개념으로 보면 된다. 전자는 false positives, 후자는 false negatives 이다. 아래 내용이 바로 그런 예라고 보면 된다.
(false positives : 참이 아닌데, 실제로는 참이다, false negatives : 참인데, 실제로는 거짓이다.)
(http://en.wikipedia.org/wiki/Bloom_filter 참조)
블룸 필터를 사용하면 일종의 키가 있는지 없는지에 대한 빠른 확인이 가능하다. (전문용어로 to save IO when performing a key lookup) 이렇게 함으로서 disk access를 조금이나다 적게 해서 속도를 높일 수 있다. 캐쉬는 아니지만, 캐쉬 처럼 비슷한 개념이 있다고 말할 수 있다.
블룸 필터는 두가지를 제공한다. 하나는 추가하는 add(), 하나는 존재하는지에 대한 isExist() 이다. add() 할 때, key를 hash 알고리즘을 이용해서 여러 개의 hash 값을 나누고, 버킷이라는 저장장소에 저장한다. 그래서 isExist할때 그 버킷를 활용해서 있는지를 확인한다. 확률상 없는데, 있다고 나오지 않도록 적절하게 잡는 알고리즘이 최상의 알고리즘이라 할 수 있을 것 이다.
(http://en.wikipedia.org/wiki/Bloom_filter 참조)
자세한 내용은 아래 내용을 참조하면 쉽게 이해할 수 있다.
Programming Game Gen 의 블룸필터 챕터
http://mindori.egloos.com/1699170
http://blog.naver.com/PostView.nhn?blogId=cra2yboy&logNo=90122287288
2. 카산드라의 실제 소스 확인
카산드라 1.0.5 에서 bloom filter 를 사용하는 곳 (모두 org.apache.cassandra.io.sstable 패키지)은 다음과 같다.
- SSTable 생성시 (Index 용으로 활용) (SSTableWriter의 inner class IndexWriter)
public final BloomFilter bf; bf = BloomFilter.getFilter(keyCount, 15); |
- SSTable을 읽을 때 (SSTableReader)
private Filter bf; bf = LegacyBloomFilter.getFilter(estimatedKeys, 15); |
false positive 확률을 파라미터는 15 정도로 해서 잘 넘기고 있다.
BloomFilter의 getFilter() 메서드의 원형은 다음과 같다.
/** |
# 저장
Filter.db 파일에 블룸필터를 저장한다. (Componen , SSTable 클래스 참조)
bloom filter를 저장할 때는 serialization하게 저장하게 되어 있다. (org.apache.cassandra.utils.BloomFilterSerializer.java)
bloom filter 의 hashcount 를 integer type으로 저장하고 그 다음에는 워드 개수(word number, bit 길이)를 저장한다. 그 다음에 page size만큼 page를 읽어와 bit 값을 저장한다.
public class BloomFilterSerializer implements ISerializer<BloomFilter> dos.writeInt(bf.getHashCount()); for (int p = 0; p < pageCount; p++) … } |
# Filter
Bloom Filter는 org.apache.cassandra.utils.Filter 추상 클래스를 상속받았다.
package org.apache.cassandra.utils; public abstract class Filter int getHashCount() public abstract void add(ByteBuffer key); public abstract boolean isPresent(ByteBuffer key); |
# BloomFilter
org.apache.cassandra.utils.BloomFilter.java 이다.
abstract 메서드를 상속받은 두개의 메소드의 구현은 아래와 같다.
제일 중요한 것은 확률적으로 잘 분산시킬 수 있는 알고리즘인데, 일반적으로는 SHA 기반의 알고리즘을 사용하여 난수를 만들어내는 데, 카산드라는 “Less Hashing, Same Performance: Building a Better Bloom Filter” (http://www.eecs.harvard.edu/~kirsch/pubs/bbbf/esa06.pdf) 과 MurMurHash(http://murmurhash.googlepages.com/)를 이용하고 있다.
SHA보다 빠르고, 적당하게 잘 분산시킬 수(good collision resistance) 있다. hashcount와 주어진 key, OpenBit 길이(디폴트는 20개)로 만들어진 세트(hash bucket)에서 long [] 타입의 정보를 읽는다.
add 일 경우에는 fastGet를
public void add(ByteBuffer key) public boolean isPresent(ByteBuffer key) private long[] getHashBuckets(ByteBuffer key) // Murmur is faster than an SHA-based approach and provides as-good collision /** Sets the bit at the specified index. /** Returns true or false for the specified bit index. |
MurmurHash 클래스를 살펴본다. 이 클래스를 살펴보기 전에 성능을 봐야 하는데. intel core 2 duo 2.4 서버를 기준으로 했을 때, 초당 처리율을 최고를 자랑한다.
Excellent performance - measured on an Intel Core 2 Duo @ 2.4 ghz
OneAtATime - 354.163715 mb/sec
FNV - 443.668038 mb/sec
SuperFastHash - 985.335173 mb/sec
lookup3 - 988.080652 mb/sec
MurmurHash 1.0 - 1363.293480 mb/sec
MurmurHash 2.0 - 2056.885653 mb/sec
/** long h64 = (seed & 0xffffffffL) ^ (m64 * length); int lenLongs = length >> 3; for (int i = 0; i < lenLongs; ++i) long k64 = ((long) key.get(offset+i_8+0) & 0xff) + (((long) key.get(offset+i_8+1) & 0xff)<<8) + h64 ^= k64; int rem = length & 0x7; switch (rem) h64 ^= h64 >>> r64; return h64; } |
'general java' 카테고리의 다른 글
[Hudson+Spring Batch] master/slave 구성하기 (0) | 2012.03.26 |
---|---|
전화번호와 관련된 자바 라이브러리 (0) | 2012.03.19 |
java에서 파일을 잘 저장하기 (sync, flush) (0) | 2012.02.28 |
Common CLI 와 Properties 사용 예제 (0) | 2012.02.17 |
JVisualvm 맛보기 용하기 (0) | 2012.02.16 |