Apache HBase 성능 튜닝

Apache HBase 성능 튜닝

이 문서는 HBase 성능을 튜닝하는 방법을 설명해요. 운영체제, 네트워크, Java/GC, HBase 구성, 스키마 설계, 읽기·쓰기 패턴, HDFS까지 성능에 영향을 주는 다양한 측면을 다뤄요. HBase 클러스터의 성능을 최적화하고 싶다면 이 문서의 지침을 하나씩 적용해 보세요.

출처: 문서

본문

운영체제

메모리

RAM, RAM, RAM. HBase를 굶기지 마세요.

64-bit

64비트 플랫폼(및 64비트 JVM)을 사용하세요.

스와핑

스와핑을 주의하세요. swappiness를 0으로 설정하세요.

CPU

Hadoop이 네이티브 하드웨어 체크섬을 사용하도록 설정했는지 확인하세요. hadoop.native.lib를 참고하세요.

네트워크

네트워크 문제가 Hadoop과 HBase 성능을 저하시키는 것을 피하는 데 아마 가장 중요한 요인은 사용되는 스위칭 하드웨어예요. 프로젝트 초기에 내린 결정이 클러스터 크기를 두 배·세 배(또는 그 이상)로 늘릴 때 주요 문제를 일으킬 수 있어요.

고려할 중요한 항목:

  • 디바이스의 스위칭 용량
  • 연결된 시스템 수
  • 업링크 용량

단일 스위치

이 구성에서 가장 중요한 단일 요인은 하드웨어의 스위칭 용량이 스위치에 연결된 모든 시스템이 생성할 수 있는 트래픽을 처리할 수 있는지 여부예요. 일부 저가 상용 하드웨어는 전체 스위치가 활용할 수 있는 것보다 느린 스위칭 용량을 가질 수 있어요.

다중 스위치

다중 스위치는 아키텍처의 잠재적 함정이에요. 저가 하드웨어의 가장 일반적인 구성은 스위치 간 단순한 1Gbps 업링크예요. 자주 간과되는 이 병목 지점은 클러스터 통신의 병목이 되기 쉽지만 많은 데이터를 읽고 쓰는 MapReduce 작업에서 특히 이 업링크를 통한 통신이 포화될 수 있어요.

이 문제의 완화는 비교적 간단하며 여러 방법으로 수행할 수 있어요.

  • 구축하려는 클러스터 규모에 적절한 하드웨어를 사용하세요.
  • 더 큰 단일 스위치 구성을 사용하세요. 예: 2x 24 포트 대신 단일 48 포트.
  • 업링크에 포트 트렁킹을 구성해 여러 인터페이스를 활용해 스위치 간 대역폭을 늘리세요.

다중 랙

다중 랙 구성은 다중 스위치와 같은 잠재적 문제를 가지며, 두 주요 영역에서 성능 저하를 겪을 수 있어요.

  • 낮은 스위치 용량 성능
  • 다른 랙으로의 부족한 업링크

랙의 스위치가 모든 호스트를 최대 속도로 처리할 수 있는 적절한 스위칭 용량을 가진다면, 다음으로 흔한 문제는 클러스터의 더 많은 부분을 랙에 걸쳐 분산시키는 것과 관련돼요. 다중 랙에 걸쳐 있을 때 문제를 피하는 가장 쉬운 방법은 포트 트렁킹을 사용해 다른 랙으로의 본딩 업링크를 만드는 것이에요. 그러나 이 방법의 단점은 잠재적으로 사용될 수 있는 포트의 오버헤드예요. 예를 들어 랙 A에서 랙 B로 8Gbps 포트 채널을 만들 때 24개 포트 중 8개를 랙 간 통신에 사용하면 수익이 낮은데, 너무 적게 사용하면 클러스터를 최대한 활용하지 못할 수 있어요.

랙 간 10Gbe 링크를 사용하면 성능이 크게 향상될 거예요. 스위치가 10Gbe 업링크를 지원하거나 확장 카드를 허용한다고 가정하면 업링크가 아닌 머신용으로 포트를 아낄 수 있어요.

네트워크 인터페이스

모든 네트워크 인터페이스가 제대로 동작하고 있나요? 확실한가요? Case Study #1 (Performance Issue On A Single Node)의 Troubleshooting Case Study를 참고하세요.

네트워크 일관성과 파티션 허용성

CAP Theorem은 분산 시스템이 다음 세 가지 특성 중 두 가지를 유지할 수 있다고 말해요.

  • Consistency(일관성) — 모든 노드가 같은 데이터를 봄.
  • Availability(가용성) — 모든 요청이 성공했는지 실패했는지에 대한 응답을 받음.
  • Partition tolerance(파티션 허용성) — 일부 구성 요소가 다른 구성 요소에 대해 사용할 수 없게 되어도 시스템이 계속 동작함.

HBase는 결정을 내려야 할 때 일관성과 파티션 허용성을 선호해요. Coda Hale는 파티션 허용성이 왜 그렇게 중요한지 http://codahale.com/you-cant-sacrifice-partition-tolerance/에서 설명해요.

Robert Yokota는 Aphyr의 Call Me Maybe 시리즈를 모델로 한 기법을 사용해 네트워크 파티션 상황에서 HBase의 파티션 허용성을 테스트하기 위해 Jepson이라는 자동 테스트 프레임워크를 사용했어요. 블로그 게시물과 부록으로 제공되는 결과는 HBase가 올바르게 동작함을 보여줘요.

Java

가비지 컬렉터와 Apache HBase

긴 GC 일시 정지

Avoiding Full GCs with MemStore-Local Allocation Buffers 프레젠테이션에서 Todd Lipcon은 특히 로딩 중 HBase에서 흔한 두 가지 stop-the-world 가비지 컬렉션 사례를 설명해요. CMS 실패 모드와 old generation 힙 조각화입니다.

첫 번째를 해결하려면 -XX:CMSInitiatingOccupancyFraction을 추가하고 기본값에서 내려서 기본보다 일찍 CMS를 시작하세요. 60 또는 70퍼센트에서 시작하세요(임계값을 낮출수록 GC가 더 많이 수행되고 CPU가 더 많이 사용돼요). 두 번째 조각화 문제를 해결하기 위해 Todd는 (MSLAB)이라는 실험적 기능을 추가했는데, Apache HBase 0.90.x에서는 명시적으로 활성화해야 해요(Apache 0.92.x HBase에서는 기본적으로 켜져 있음). Configuration에서 hbase.hregion.memstore.mslab.enabled를 true로 설정하세요. 배경과 세부사항은 인용된 슬라이드를 참고하세요. 최신 JVM은 조각화에 더 잘 대응하므로 최신 릴리스를 실행하고 있는지 확인하세요. Identifying concurrent mode failures caused by fragmentation 메시지를 읽어 보세요. 활성화하면 각 MemStore 인스턴스가 최소한 하나의 MSLAB 인스턴스 메모리를 차지하게 된다는 점에 유의하세요. 수천 개의 region이나 각각 많은 column family를 가진 많은 region이 있다면 이 MSLAB 할당이 힙 할당의 상당 부분을 차지할 수 있고, 극단적인 경우 OOME를 일으킬 수 있어요. 이 경우 MSLAB을 비활성화하거나, 사용하는 메모리 양을 낮추거나, 서버당 region 수를 줄이세요.

쓰기 중심 워크로드가 있다면 HBASE-8163 MemStoreChunkPool: An improvement for JAVA GC when using MSLAB을 확인하세요. 쓰기 중심 로딩 중 young GC의 양을 낮추는 구성을 설명해요. HBASE-8163이 설치되어 있지 않고 young GC 시간을 개선하려는 경우 고려할 한 가지 요령은 — 우리의 Liang Xie에게서 얻은 것 — hbase-env.sh의 GC 구성 -XX:PretenureSizeThreshold를 hbase.hregion.memstore.mslab.chunksize 크기보다 약간 작게 설정해 MSLAB 할당이 young gen이 아니라 직접 tenured 공간에서 일어나게 하는 것이에요. 이렇게 하는 이유는 이러한 MSLAB 할당은 어차피 old gen에 도달할 가능성이 높고, eden 공간의 s0와 s1 사이의 복사 비용과 MSLAB이 충분한 tenure를 달성한 후 young에서 old gen으로의 업 복사 비용을 지불하는 대신 약간의 YGC churn을 아끼고 직접 old gen에 할당하기 위해서예요.

긴 GC의 다른 원인은 JVM 자체 로깅일 수 있어요. Eliminating Large JVM GC Pauses Caused by Background IO Traffic을 참고하세요.

GC 로그에 대한 자세한 내용은 JVM Garbage Collection Logs를 참고하세요.

오프힙(off-heap) Block Cache를 활성화하는 것도 고려하세요. 이것은 GC 일시 정지 시간을 완화하는 것으로 입증됐어요. Block Cache를 참고하세요.

HBase 구성

Recommended Configurations를 참고하세요.

99번째 백분위수 개선

hedged_reads를 시도하세요.

컴팩션 관리

더 큰 시스템의 경우 compactions and splits 관리를 고려하는 것이 좋을 수 있어요.

hbase.regionserver.handler.count

hbase.regionserver.handler.count를 참고하세요.

hfile.block.cache.size

hfile.block.cache.size를 참고하세요. RegionServer 프로세스의 메모리 설정이에요.

Blockcache를 위한 프리페치 옵션

HBASE-9857은 Column family 또는 RegionServer 프로퍼티가 설정된 경우 BlockCache를 열 때 HFile 내용을 프리페치하는 새 옵션을 추가해요. 이 옵션은 HBase 0.98.3 이상에서 사용할 수 있어요. 목적은 캐시가 열린 후 가능한 한 빠르게 BlockCache를 워밍하는 것으로, 인메모리 테이블 데이터를 사용하고 프리페칭을 캐시 미스로 계산하지 않는 것이에요. 빠른 읽기에 좋지만, 프리로드할 데이터가 BlockCache에 들어가지 않는다면 좋은 생각이 아니에요. 모든 데이터 블록이 캐시에 들어갈 때까지의 시간 대비 프리페칭의 IO 영향을 튜닝하는 데 유용해요.

주어진 column family에 프리페칭을 활성화하려면 HBase Shell이나 API를 사용할 수 있어요.

HBase Shell로 프리페치 활성화

hbase> create 'MyTable', { NAME => 'myCF', PREFETCH_BLOCKS_ON_OPEN => 'true' }

API로 프리페치 활성화

// ...
HTableDescriptor tableDesc = new HTableDescriptor("myTable");
HColumnDescriptor cfDesc = new HColumnDescriptor("myCF");
cfDesc.setPrefetchBlocksOnOpen(true);
tableDesc.addFamily(cfDesc);
// ...

CacheConfig의 API 문서를 참고하세요.

프리페치가 동작하는 것을 보려면 hbase-2.0+에서는 org.apache.hadoop.hbase.io.hfile.HFileReaderImpl, 이전 버전(hbase-1.x)에서는 org.apache.hadoop.hbase.io.hfile.HFileReaderV2의 TRACE 수준 로깅을 활성화하세요.

hbase.regionserver.global.memstore.size

hbase.regionserver.global.memstore.size를 참고하세요. 필요에 따라 RegionServer 프로세스에 대해 자주 조정되는 메모리 설정이에요.

hbase.regionserver.global.memstore.size.lower.limit

hbase.regionserver.global.memstore.size.lower.limit을 참고하세요. 필요에 따라 RegionServer 프로세스에 대해 자주 조정되는 메모리 설정이에요.

hbase.hstore.blockingStoreFiles

hbase.hstore.blockingStoreFiles을 참고하세요. RegionServer 로그에 차단(blocking)이 있다면 이것을 늘리는 것이 도움이 될 수 있어요.

hbase.hregion.memstore.block.multiplier

hbase.hregion.memstore.block.multiplier을 참고하세요. RAM이 충분하다면 이것을 늘리는 것이 도움이 될 수 있어요.

hbase.regionserver.checksum.verify

HBase가 데이터블록에 체크섬을 쓰게 해서 읽을 때마다 체크섬 탐색을 하지 않게 하세요.

hbase.regionserver.checksum.verify, hbase.hstore.bytes.per.checksum, hbase.hstore.checksum.algorithm을 참고하세요. 자세한 내용은 HBASE-5074 support checksums in HBase block cache 릴리스 노트를 참고하세요.

callQueue 옵션 튜닝

HBASE-11355은 성능을 높일 수 있는 여러 callQueue 튜닝 메커니즘을 도입해요. 몇 가지 벤치마킹 정보는 JIRA를 참고하세요.

callqueue 수를 늘리려면 hbase.ipc.server.num.callqueue를 1보다 큰 값으로 설정하세요. callqueue를 별도의 읽기 및 쓰기 큐로 분할하려면 hbase.ipc.server.callqueue.read.ratio를 0과 1 사이의 값으로 설정하세요. 이 계수는 큐를 쓰기(.5 미만) 또는 읽기(.5 초과) 쪽으로 가중치를 둬요. 다른 말로, 이 계수는 분할된 큐 중 몇 퍼센트를 읽기에 사용할지 결정해요. 다음 예시는 몇 가지 가능성을 보여줘요. 어떤 설정을 사용하든 항상 적어도 하나의 쓰기 큐가 있다는 점에 유의하세요.

  • 기본값 0은 큐를 분할하지 않아요.
  • .3 값은 큐의 30%를 읽기에, 70%를 쓰기에 사용해요. hbase.ipc.server.num.callqueue에 10 값이 주어지면 3개 큐는 읽기에, 7개는 쓰기에 사용돼요.
  • .5 값은 읽기 큐와 쓰기 큐를 같은 수로 사용해요. hbase.ipc.server.num.callqueue에 10 값이 주어지면 5개 큐는 읽기에, 5개는 쓰기에 사용돼요.
  • .6 값은 큐의 60%를 읽기에, 40%를 쓰기에 사용해요. hbase.ipc.server.num.callqueue에 10 값이 주어지면 6개 큐는 읽기에, 4개는 쓰기에 사용돼요.
  • 1.0 값은 하나의 큐를 쓰기 요청 처리에 사용하고, 다른 모든 큐는 읽기 요청을 처리해요. 1.0보다 높은 값은 1.0 값과 같은 효과를 가져요. hbase.ipc.server.num.callqueue에 10 값이 주어지면 9개 큐는 읽기에, 1개는 쓰기에 사용돼요.

hbase.ipc.server.callqueue.scan.ratio 옵션을 설정해 읽기 큐를 분할할 수도 있는데, 짧은 읽기(Get 연산에서)와 긴 읽기(Scan 연산에서)에 별도 큐가 사용되게 해요. 이 옵션은 Gets와 Scans에 사용되는 읽기 큐의 비율을 결정하는 0과 1 사이의 계수예요. .5 미만이면 Gets에 더 많은 큐가, .5 초과면 scans에 더 많은 큐가 사용돼요. 어떤 설정을 사용하든 Get 연산에 최소한 하나의 읽기 큐가 사용돼요.

  • 0 값은 읽기 큐를 분할하지 않아요.
  • .3 값은 읽기 큐의 70%를 Gets에, 30%를 Scans에 사용해요. hbase.ipc.server.num.callqueue에 20, hbase.ipc.server.callqueue.read.ratio에 .5가 주어지면 10개 큐가 읽기에 사용되고, 그 10개 중 7개는 Gets에, 3개는 Scans에 사용돼요.
  • .5 값은 읽기 큐의 절반을 Gets에, 절반을 Scans에 사용해요. hbase.ipc.server.num.callqueue에 20, hbase.ipc.server.callqueue.read.ratio에 .5가 주어지면 10개 큐가 읽기에 사용되고, 그 10개 중 5개는 Gets에, 5개는 Scans에 사용돼요.
  • .7 값은 읽기 큐의 30%를 Gets에, 70%를 Scans에 사용해요. hbase.ipc.server.num.callqueue에 20, hbase.ipc.server.callqueue.read.ratio에 .5가 주어지면 10개 큐가 읽기에 사용되고, 그 10개 중 3개는 Gets에, 7개는 Scans에 사용돼요.
  • 1.0 값은 읽기 큐 중 하나를 제외한 전부를 Scans에 사용해요. hbase.ipc.server.num.callqueue에 20, hbase.ipc.server.callqueue.read.ratio에 .5가 주어지면 10개 큐가 읽기에 사용되고, 그 10개 중 1개는 Gets에, 9개는 Scans에 사용돼요.

새 옵션 hbase.ipc.server.callqueue.handler.factor를 사용해 큐 수를 프로그래밍 방식으로 튜닝할 수 있어요.

  • 0 값은 모든 핸들러 사이에서 단일 공유 큐를 사용해요.
  • 1 값은 각 핸들러에 대해 별도 큐를 사용해요.
  • 0과 1 사이의 값은 핸들러 수에 대해 큐 수를 튜닝해요. 예를 들어 .5 값은 두 핸들러마다 하나의 큐를 공유해요. 큐가 더 많으면(예: 핸들러당 하나의 큐) 큐에 작업을 추가하거나 선택할 때 경합이 줄어들어요. 단점은 오래 실행되는 작업이 있는 큐가 있으면 핸들러가 대기 작업이 있는 다른 큐를 처리하는 대신 그 큐에서 실행을 기다리게 될 수 있다는 거예요.

이 값들이 주어진 RegionServer에 적용되려면 RegionServer를 재시작해야 해요. 이 파라미터는 테스트 목적이며 신중하게 사용해야 해요.

ZooKeeper

ZooKeeper 구성에 대한 정보는 ZooKeeper를 참고하고, 전용 디스크를 갖는 부분을 참고하세요.

스키마 설계

Column Families 수

On the number of column families을 참고하세요.

키와 속성 길이

Try to minimize row and column sizes을 참고하세요. 압축 주의 사항에 대해서는 However...도 참고하세요.

테이블 RegionSize

특정 테이블이 구성된 기본 regionsize와 다른 regionsize를 요구하는 경우 TableDescriptorBuilder의 setMaxFileSize로 regionsize를 테이블별로 설정할 수 있어요.

자세한 내용은 Determining region count and size를 참고하세요.

블룸 필터

블룸 필터는 만든 사람 Burton Howard Bloom의 이름을 따서 명명됐는데, 주어진 요소가 데이터 집합의 멤버인지 예측하도록 설계된 데이터 구조예요. 블룸 필터의 양성 결과는 항상 정확하지 않지만 음성 결과는 정확함이 보장돼요. 블룸 필터는 기존 해싱 메커니즘이 실용적이지 않을 정도로 큰 데이터 집합에 대해 "충분히 정확"하도록 설계돼요. 블룸 필터에 대한 일반적인 정보는 http://en.wikipedia.org/wiki/Bloom_filter를 참고하세요.

HBase의 관점에서 블룸 필터는 주어진 Get 연산(블룸 필터는 Scans에는 동작하지 않음)의 디스크 읽기를 원하는 Row를 포함할 가능성이 있는 StoreFiles만으로 줄이는 가벼운 인메모리 구조를 제공해요. 잠재적 성능 향상은 병렬 읽기 수에 따라 증가해요.

블룸 필터 자체는 각 HFile의 메타데이터에 저장되고 업데이트할 필요가 없어요. region이 RegionServer에 배포되어 HFile이 열릴 때 블룸 필터가 메모리에 로드돼요.

HBase는 블룸 필터를 접어(folding) 크기를 줄이고 거짓 양성률을 원하는 범위 내로 유지하는 몇 가지 튜닝 메커니즘을 포함해요.

블룸 필터는 HBASE-1200에서 도입됐어요. HBase 0.96부터 행 기반 블룸 필터가 기본으로 활성화돼요(HBASE-8450).

HBase와 관련된 블룸 필터에 대한 자세한 내용은 Bloom Filters 또는 다음 Quora 토론을 참고하세요: How are bloom filters used in HBase?.

블룸 필터를 사용할 때

HBase 0.96부터 행 기반 블룸 필터가 기본으로 활성화돼요. 데이터의 특성과 HBase에 로드되는 방식에 따라 이를 비활성화하거나 일부 테이블을 row+column 블룸 필터로 변경할 수 있어요.

블룸 필터가 긍정적 영향을 가질 수 있는지 확인하려면 RegionServer 메트릭에서 blockCacheHitRatio 값을 확인하세요. 블룸 필터가 활성화되면 블룸 필터가 확실히 필요 없는 블록을 걸러내므로 blockCacheHitRatio 값이 증가해야 해요.

행 또는 row+column 조합에 대해 블룸 필터를 활성화할 수 있어요. 일반적으로 전체 행을 스캔한다면 row+column 조합은 어떤 이점도 제공하지 않아요. 행 기반 블룸 필터는 row+column Get에서 동작할 수 있지만 그 반대는 안 돼요. 그러나 열 수준 Puts가 많아서 행이 모든 StoreFile에 존재할 수 있다면, 행 기반 필터는 항상 양성 결과를 반환해 이점이 없어요. 행당 하나의 열이 없는 한 row+column 블룸 필터는 더 많은 키를 저장하기 위해 더 많은 공간을 요구해요. 블룸 필터는 각 데이터 엔트리의 크기가 최소 몇 킬로바이트일 때 가장 잘 동작해요.

데이터가 몇 개의 더 큰 StoreFiles에 저장되면 하위 수준 스캔 중 특정 행을 찾기 위한 추가 디스크 IO를 피할 수 있어 오버헤드가 줄어들어요.

블룸 필터는 삭제 시 다시 구축해야 하므로 삭제가 많은 환경에는 적합하지 않을 수 있어요.

블룸 필터 활성화

블룸 필터는 Column Family에 대해 활성화돼요. HColumnDescriptor의 setBloomFilterType 메서드나 HBase API를 사용해 할 수 있어요. 유효한 값은 NONE, ROW(기본), ROWCOL이에요. ROW와 ROWCOL에 대한 자세한 내용은 When To Use Bloom Filters을 참고하세요. ColumnFamilyDescriptorBuilder의 API 문서도 참고하세요.

다음 예시는 테이블을 만들고 colfam1 column family에 ROWCOL 블룸 필터를 활성화해요.

hbase> create 'mytable',{NAME => 'colfam1', BLOOMFILTER => 'ROWCOL'}
블룸 필터의 서버 전체 동작 구성

hbase-site.xml에서 다음 설정을 구성할 수 있어요.

Parameter Default Description
io.storefile.bloom.enabled yes 문제가 생기면 서버 전체에서 블룸 필터를 끄려면 no로 설정
io.storefile.bloom.error.rate .01 블룸 필터의 평균 거짓 양성률. 폴딩은 거짓 양성률을 유지하는 데 사용됨. 백분율의 십진수 표현으로 표시됨.
io.storefile.bloom.max.fold 7 보장된 최대 폴드율. 이 설정을 바꾸는 것은 필요하지 않아야 하며 권장되지 않음.
io.storefile.bloom.max.keys 128000000 기본(단일 블록) 블룸 필터의 경우 최대 키 수를 지정함.
io.storefile.delete.family.bloom.enabled true Delete Family 블룸 필터를 활성화하고 StoreFile에 저장하는 마스터 스위치.
io.storefile.bloom.block.size 131072 대상 Bloom 블록 크기. 이 정도 크기의 블룸 필터 블록이 데이터 블록과 인터리브됨.
hfile.block.bloom.cacheonwrite false 복합 블룸 필터의 인라인 블록에 대한 cache-on-write 활성화.

ColumnFamily BlockSize

블록 크기는 테이블의 각 ColumnFamily에 대해 구성할 수 있고 기본값은 64k예요. 더 큰 셀 값은 더 큰 블록 크기를 요구해요. 블록 크기와 결과 StoreFile 인덱스 사이에는 역관계가 있어요(즉 블록 크기가 두 배가 되면 결과 인덱스는 대략 절반이 되어야 함).

자세한 내용은 ColumnFamilyDescriptorBuilder와 Store를 참고하세요.

인메모리 ColumnFamilies

ColumnFamilies는 선택적으로 인메모리로 정의될 수 있어요. 데이터는 다른 ColumnFamily와 마찬가지로 여전히 디스크에 영속화돼요. 인메모리 블록은 Block Cache에서 가장 높은 우선순위를 가지지만, 전체 테이블이 메모리에 있을 것이라는 보장은 아니에요.

자세한 내용은 ColumnFamilyDescriptorBuilder를 참고하세요.

압축

프로덕션 시스템은 ColumnFamily 정의와 함께 압축을 사용해야 해요. 자세한 내용은 Compression and Data Block Encoding In HBase을 참고하세요.

하지만...

압축은 데이터를 디스크에서 압축해요. 메모리(예: MemStore)에 있거나 와이어(예: RegionServer와 Client 간 전송)에 있을 때는 압축이 풀려요. 그래서 ColumnFamily 압축 사용이 모범 사례지만, 과도한 크기의 Keys, ColumnFamily 이름, Column 이름의 영향을 완전히 제거하지는 못해요.

스키마 설계 팁은 Try to minimize row and column sizes을, HBase가 내부적으로 데이터를 저장하는 방법에 대한 자세한 내용은 KeyValue를 참고하세요.

HBase 일반 패턴

상수

사람들이 HBase를 시작할 때 이런 코드를 쓰는 경향이 있어요.

Get get = new Get(rowkey);
Result r = table.get(get);
byte[] b = r.getValue(Bytes.toBytes("cf"), Bytes.toBytes("attr"));  // returns current version of value

하지만 특히 루프(및 MapReduce 작업) 안에서는 columnFamily와 column 이름을 바이트 배열로 반복 변환하는 것이 놀랍게도 비싸요. 이렇게 바이트 배열에 상수를 사용하는 것이 더 좋아요.

public static final byte[] CF = "cf".getBytes();
public static final byte[] ATTR = "attr".getBytes();
...
Get get = new Get(rowkey);
Result r = table.get(get);
byte[] b = r.getValue(CF, ATTR);  // returns current version of value

HBase에 쓰기

배치 로딩

가능하면 bulk load 도구를 사용하세요. Bulk Loading을 참고하세요. 그렇지 않으면 아래에 주의하세요.

테이블 생성: 사전 생성 영역

HBase의 테이블은 기본적으로 하나의 region으로 초기에 생성돼요. 벌크 임포트의 경우, 이것은 모든 클라이언트가 분할되어 클러스터에 분산될 만큼 커질 때까지 같은 region에 쓴다는 뜻이에요. 벌크 임포트 과정을 빠르게 하는 유용한 패턴은 빈 region을 사전 생성하는 것이에요. 너무 많은 region은 실제로 성능을 저하시킬 수 있으므로 보수적으로 하세요.

HBase API를 사용해 분할을 사전 생성하는 두 가지 다른 접근이 있어요. 첫 번째는 기본 Admin 전략( Bytes.split에 구현됨)에 의존하는 것이에요.

byte[] startKey = ...;      // your lowest key
byte[] endKey = ...;        // your highest key
int numberOfRegions = ...;  // # of regions to create
admin.createTable(table, startKey, endKey, numberOfRegions);

HBase API를 사용하는 다른 접근은 분할을 직접 정의하는 것이에요.

byte[][] splits = ...;   // create your own splits
admin.createTable(table, splits);

HBase Shell을 사용해 분할 옵션을 지정해 테이블을 만들어 비슷한 효과를 얻을 수 있어요.

# create table with specific split points
hbase>create 't1','f1',SPLITS => ['\x10\x00', '\x20\x00', '\x30\x00', '\x40\x00']

# create table with four regions based on random bytes keys
hbase>create 't2','f1', { NUMREGIONS => 4 , SPLITALGO => 'UniformSplit' }

# create table with five regions based on hex keys
create 't3','f1', { NUMREGIONS => 5, SPLITALGO => 'HexStringSplit' }

키스페이스를 이해하고 region을 사전 생성하는 것과 관련된 문제는 Relationship Between RowKeys and Region Splits를 참고하세요. 수동 region 사전 분할에 대한 논의는 manual region splitting decisions을 참고하세요. HBase Shell로 테이블을 사전 분할하는 방법에 대한 자세한 내용은 Pre-splitting tables with the HBase Shell을 참고하세요.

테이블 생성: 지연 로그 플러시(Deferred Log Flush)

Write Ahead Log(WAL)를 사용하는 Puts의 기본 동작은 WAL 편집이 즉시 쓰여지는 것이에요. 지연 로그 플러시를 사용하면 WAL 편집이 플러시 기간까지 메모리에 유지돼요. 이점은 집계되고 비동기적인 WAL 쓰기이지만, 잠재적 단점은 RegionServer가 내려가면 아직 플러시되지 않은 편집이 손실된다는 거예요. 그러나 이것은 Puts에 WAL을 아예 사용하지 않는 것보다는 안전해요.

지연 로그 플러시는 TableDescriptorBuilder를 통해 테이블에서 구성할 수 있어요. hbase.regionserver.optionallogflushinterval의 기본값은 1000ms예요.

HBase 클라이언트: Puts에서 WAL 끄기

자주 요청되는 것은 Puts의 성능을 높이기 위해 WAL을 비활성화하는 것이에요. 이것은 bulk load에만 적절해요. region server 크래시 시 WAL의 보호를 제거해 데이터를 위험에 빠뜨리기 때문이에요. Bulk loads는 크래시 시 데이터 손실의 위험이 거의 없이 다시 실행할 수 있어요.

bulk load가 아닌 다른 것에 WAL을 비활성화하면 데이터가 위험해져요.

일반적으로 Puts에는 WAL을 사용하고, 로딩 처리량이 우려되는 곳에서는 벌크 로딩 기법을 사용하는 것이 가장 좋아요. 일반 Puts의 경우 위험을 능가할 성능 향상을 보지 못할 가능성이 높아요. WAL을 비활성화하려면 Disabling the WAL을 참고하세요.

HBase 클라이언트: RegionServer별로 Puts 그룹화

writeBuffer를 사용하는 것에 더해, Put을 RegionServer별로 그룹화하면 writeBuffer 플러시당 클라이언트 RPC 호출 수를 줄일 수 있어요. 현재 MASTER에 이렇게 하는 HTableUtil 유틸리티가 있지만, 0.90.x 이하를 사용한다면 그걸 복사하거나 자신만의 버전을 구현할 수 있어요.

MapReduce: 리듀서 건너뛰기

MR 작업에서(예: TableOutputFormat 사용) HBase 테이블에 많은 데이터를 쓸 때, 특히 Mapper에서 Puts가 방출되는 경우 리듀서 단계를 건너뛰세요. 리듀서 단계를 사용하면 Mapper의 모든 출력(Puts)이 디스크에 스풀된 다음, 아마 오프노드일 다른 Reducers로 정렬/shuffle돼요. HBase에 직접 쓰는 것이 훨씬 효율적이에요.

HBase를 소스와 싱크로 사용하는 요약 작업의 경우 쓰기가 리듀서 단계에서 나올 거예요(예: 값을 요약한 후 결과를 쓰기). 이것은 위의 경우와 다른 처리 문제예요.

안티 패턴: 핫 영역(Hot Region)

모든 데이터가 한 번에 한 region에 쓰여지고 있다면 time series 데이터 처리 섹션을 다시 읽어 보세요.

또한 region을 사전 분할했는데 키가 단조롭게 증가하지 않음에도 모든 데이터가 여전히 단일 region에 쌓인다면, 키스페이스가 실제로 분할 전략과 함께 동작하는지 확인하세요. region이 "잘 분할"된 것처럼 보이지만 데이터와 함께 동작하지 않는 이유는 다양해요. HBase 클라이언트가 RegionServers와 직접 통신하므로 이는 RegionLocator.getRegionLocation로 얻을 수 있어요.

Table Creation: Pre-Creating Regions과 HBase Configurations를 참고하세요.

HBase에서 읽기

성능 문제가 있다면 메일링 리스트가 도움이 될 수 있어요.

스캔 캐싱

예를 들어 HBase를 MapReduce 작업의 입력 소스로 사용한다면, MapReduce 작업에 대한 입력 Scan 인스턴스가 setCaching을 기본값(1)보다 크게 설정했는지 확인하세요. 기본값을 사용하면 map-task가 처리하는 각 레코드마다 region-server에 콜백을 만든다는 뜻이에요. 예를 들어 이 값을 500으로 설정하면 한 번에 500행을 클라이언트로 전송해 처리하게 돼요. 캐시 값이 크면 클라이언트와 RegionServer 모두에서 메모리 비용이 더 들기 때문에 무조건 큰 것이 좋은 것은 아니에요.

MapReduce 작업에서 스캔 캐싱

MapReduce 작업의 스캔 설정은 특별한 주의가 필요해요. 클라이언트가 다음 데이터 집합을 위해 RegionServer로 돌아가기 전에 레코드 배치를 처리하는 데 더 오래 걸리면 Map 작업에서 타임아웃(예: UnknownScannerException)이 발생할 수 있어요. 이 문제는 행별로 중요한 처리가 발생하기 때문에 생길 수 있어요. 행을 빠르게 처리한다면 캐싱을 더 높게 설정하세요. 행을 더 느리게 처리한다면(예: 행당 많은 변환, 쓰기) 캐싱을 더 낮게 설정하세요.

타임아웃은 비-MapReduce 사용 사례(예: 스캔을 수행하는 단일 스레드 HBase 클라이언트)에서도 발생할 수 있지만, MapReduce 작업에서 자주 수행되는 처리가 이 문제를 악화시키는 경향이 있어요.

스캔 속성 선택

스캔이 다수의 행을 처리하는 데 사용될 때(특히 MapReduce 소스로 사용될 때), 선택되는 속성을 인지하세요. scan.addFamily가 호출되면 지정된 ColumnFamily의 모든 속성이 클라이언트로 반환될 거예요. 사용 가능한 속성 중 일부만 처리된다면 입력 스캔에 그 속성들만 지정해야 해요. 속성 과선택(over-selection)은 큰 데이터셋에서 사소하지 않은 성능 페널티이기 때문이에요.

스캔 시크(seek) 피하기

scan.addColumn으로 열을 명시적으로 선택하면 HBase는 선택된 열 사이를 시크하는 시크 연산을 예약해요. 행에 열이 적고 각 열에 버전이 몇 개뿐일 때 이것은 비효율적일 수 있어요. 시크 연산은 일반적으로 최소 5-10개의 열/버전 또는 512-1024바이트를 지나치지 않으면 더 느려요.

시크 연산이 예약되기 전에 몇 개의 열/버전을 앞서 보아 다음 열/버전을 찾을 수 있는지 확인하기 위해, 새로운 속성 Scan.HINT_LOOKAHEAD를 Scan 객체에 설정할 수 있어요. 다음 코드는 RegionServer에 시크가 예약되기 전에 next의 두 번 반복을 시도하도록 지시해요.

Scan scan = new Scan();
scan.addColumn(...);
scan.setAttribute(Scan.HINT_LOOKAHEAD, Bytes.toBytes(2));
table.getScanner(scan);

MapReduce - 입력 분할

HBase 테이블을 소스로 사용하는 MapReduce 작업에서 "느린" map task가 같은 Input Split(즉 데이터를 제공하는 RegionServer)을 가진 것처럼 보이는 패턴이 있다면, Case Study #1 (Performance Issue On A Single Node)의 Troubleshooting Case Study를 참고하세요.

ResultScanners 닫기

이것은 성능을 개선하는 것이라기보다 성능 문제를 피하는 것에 가까워요. ResultScanners를 닫는 것을 잊으면 RegionServers에 문제를 일으킬 수 있어요. ResultScanner 처리를 항상 try/catch 블록 안에 넣으세요.

Scan scan = new Scan();
// set attrs...
ResultScanner rs = table.getScanner(scan);
try {
  for (Result r = rs.next(); r != null; r = rs.next()) {
    // process result...
  }
} finally {
  rs.close();  // always close the ResultScanner!
}
table.close();

블록 캐시

Scan 인스턴스는 setCacheBlocks 메서드로 RegionServer의 블록 캐시를 사용하도록 설정할 수 있어요. MapReduce 작업에 대한 입력 스캔의 경우 이것은 false여야 해요. 자주 접근하는 행에는 블록 캐시를 사용하는 것이 좋아요.

블록 캐시를 오프힙으로 옮겨 더 많은 데이터를 캐시하세요. Off-heap Block Cache를 참고하세요.

Row Keys의 최적 로딩

row key만 필요한(패밀리, qualifier, 값, 타임스탬프 없음) 테이블 scan을 수행할 때, setFilter로 MUST_PASS_ALL 연산자가 있는 FilterList를 스캐너에 추가하세요. 필터 목록에는 FirstKeyOnlyFilter와 KeyOnlyFilter가 모두 포함되어야 해요. 이 필터 조합을 사용하면 최악의 경우 RegionServer가 디스크에서 단일 값을 읽고 단일 행에 대해 클라이언트로의 네트워크 트래픽이 최소가 돼요.

동시성: 데이터 분산 모니터링

높은 수의 동시 읽기를 수행할 때 대상 테이블의 데이터 분산을 모니터링하세요. 대상 테이블이 너무 적은 region을 가진다면 읽기가 너무 적은 노드에서 제공될 가능성이 있어요.

Table Creation: Pre-Creating Regions과 HBase Configurations를 참고하세요.

블룸 필터

블룸 필터를 활성화하면 디스크에 갈 필요를 줄이고 읽기 대기 시간을 개선하는 데 도움이 될 수 있어요.

블룸 필터는 HBase-1200 Add bloomfilters에서 개발됐어요. 개발 과정 — 왜 동적이 아닌 정적 블룸인지 — 그리고 HBase에서 블룸에 고유하게 관련된 속성 개요와 가능한 미래 방향에 대해서는 HBASE-1200에 첨부된 BloomFilters in HBase 문서의 Development Process 섹션을 참고하세요. 여기 설명된 블룸 필터는 실제로 HBase 블룸의 버전 2예요. 0.19.x까지의 버전에서 HBase는 European Commission One-Lab Project 034819의 작업에 기반한 동적 블룸 옵션을 가졌어요. HBase 블룸 작업의 핵심은 나중에 Hadoop으로 끌어올려 org.apache.hadoop.io.BloomMapFile을 구현했어요. HBase 블룸 버전 1은 그렇게 잘 동작하지 못했어요. 버전 2는 처음부터 재작성했지만 역시 one-lab 작업에서 시작해요.

Bloom Filters도 참고하세요.

Bloom StoreFile 풋프린트

블룸 필터는 StoreFile 일반 FileInfo 데이터 구조에 엔트리를 추가한 다음 StoreFile 메타데이터 섹션에 두 개의 추가 엔트리를 추가해요.

StoreFile FileInfo 데이터 구조의 BloomFilter

FileInfo는 NONE, ROW 또는 ROWCOL로 설정되는 BLOOM_FILTER_TYPE 엔트리를 가져요.

StoreFile 메타데이터의 BloomFilter 엔트리

BLOOM_FILTER_META는 Bloom 크기, 사용된 해시 함수 등을 보유해요. 크기가 작고 StoreFile.Reader 로드 시 캐시돼요.

BLOOM_FILTER_DATA는 실제 bloomfilter 데이터예요. 필요에 따라 획득돼요. 활성화되면(기본적으로 활성화) LRU 캐시에 저장돼요.

블룸 필터 구성

io.storefile.bloom.enabled 전역 킬 스위치

Configuration의 io.storefile.bloom.enabled는 문제가 발생할 경우 킬 스위치 역할을 해요. 기본 = true.

io.storefile.bloom.error.rate

io.storefile.bloom.error.rate = 평균 거짓 양성률. 기본 = 1%. 비율을 절반으로 줄이면(예: .5%) == 블룸 엔트리당 +1 비트.

io.storefile.bloom.max.fold

io.storefile.bloom.max.fold = 보장된 최소 폴드율. 대부분의 사람은 이걸 건드리지 않아야 해요. 기본 = 7, 또는 원래 크기의 최소 1/128로 줄어들 수 있어요. 이 옵션이 무엇을 의미하는지에 대한 자세한 내용은 BloomFilters in HBase 문서의 Development Process 섹션을 참고하세요.

Hedged Reads

Hedged reads는 HDFS의 기능으로, Hadoop 2.4.0에서 HDFS-5776으로 도입됐어요. 일반적으로 각 읽기 요청에 대해 단일 스레드가 생성돼요. 그러나 hedged reads가 활성화되면 클라이언트는 약간의 구성 가능한 시간을 기다리고, 읽기가 반환되지 않으면 같은 데이터의 다른 블록 복제본에 대해 두 번째 읽기 요청을 생성해요. 먼저 반환되는 것은 사용되고 다른 읽기 요청은 폐기돼요.

Hedged reads는 "...이상점(outlier) datanode를 제거하는 데 매우 좋아서, 대기 시간에 민감한 설정에 매우 좋은 선택이 돼요. 그러나 처리량 최대화를 찾고 있다면, hedged reads는 일반적으로 느려질 때 부하 증폭을 만들 경향이 있어요. 요컨대, 특정 처리량 임계값 부근에서 실행할 때 비우아한(비정상적) 성능 저하를 주시해야 해요." (HBASE-17083에서 Ashu Pachauri 인용).

hedged reads를 활성화한 상태로 실행할 때 명심할 다른 우려 사항:

  • 네트워크 혼잡을 일으킬 수 있어요. HBASE-17083 참고.
  • 풀에 대한 차단이 병목이 되지 않도록 스레드 풀을 충분히 크게 설정하세요(다시 HBASE-17083 참고).

(HBASE-17083에서 Yu Li)

HBase RegionServer는 HDFS 클라이언트이므로, RegionServer의 hbase-site.xml에 다음 프로퍼티를 추가하고 값을 환경에 맞게 튜닝하여 HBase에서 hedged reads를 활성화할 수 있어요.

Hedged Reads 구성

  • dfs.client.hedged.read.threadpool.size - hedged reads를 처리하는 데 전념하는 스레드 수. 0(기본값)이면 hedged reads가 비활성화됨.
  • dfs.client.hedged.read.threshold.millis - 두 번째 읽기 스레드를 생성하기 전에 기다리는 밀리초 수.

Hedged Reads 구성 예시

<property>
  <name>dfs.client.hedged.read.threadpool.size</name>
  <value>20</value>  <!-- 20 threads -->
</property>
<property>
  <name>dfs.client.hedged.read.threshold.millis</name>
  <value>10</value>  <!-- 10 milliseconds -->
</property>

클러스터에서 hedged reads 설정을 튜닝하려면 다음 메트릭을 사용하세요. 자세한 내용은 HBase Metrics를 참고하세요.

Hedged Reads 메트릭

  • hedgedReadOps - hedged read 스레드가 트리거된 횟수. 읽기 요청이 자주 느리거나 hedged reads가 너무 빨리 트리거되고 있음을 나타낼 수 있음.
  • hedgeReadOpsWin - hedged read 스레드가 원래 스레드보다 빨랐던 횟수. 주어진 RegionServer가 요청 서비스에 문제가 있음을 나타낼 수 있음.
  • hedgedReadOpsInCurThread - hedged read가 executor에서 거부되고 현재 스레드에서 실행하도록 폴백해야 했던 횟수. 현재 hedged read 스레드 풀 크기가 적절하지 않음을 나타낼 수 있음.

HBase에서 삭제

HBase 테이블을 큐로 사용

HBase 테이블은 때때로 큐로 사용돼요. 이 경우 이런 방식으로 사용되는 테이블에 정기적으로 메이저 컴팩션을 수행하는 데 특별한 주의를 기울여야 해요. Data Model에 문서화된 대로 행을 삭제로 표시하면 추가 StoreFiles가 생성되어 읽기 시 처리되어야 해요. Tombstone은 메이저 컴팩션으로만 정리돼요.

Compaction과 Admin.majorCompact도 참고하세요.

Delete RPC 동작

Table.delete(Delete)는 writeBuffer를 사용하지 않는다는 점에 유의하세요. 각 호출마다 RegionServer RPC를 실행할 거예요. 많은 수의 삭제에는 Table.delete(List)를 고려하세요.

hbase.client.Delete를 참고하세요.

HDFS

HBase는 HDFS에서 실행되므로 HDFS가 어떻게 동작하고 HBase에 어떻게 영향을 주는지 이해하는 것이 중요해요.

저지연 읽기의 현재 문제

HDFS의 원래 사용 사례는 배치 처리가었어요. 그래서 저지연 읽기는 역사적으로 우선순위가 아니었어요. Apache HBase의 채택이 증가하면서 이것이 바뀌고 있고, 이미 여러 개선이 개발 중이에요. Umbrella Jira Ticket for HDFS Improvements for HBase를 참고하세요.

로컬 데이터 활용

HDFS-2246을 통해 Hadoop 1.0.0(또한 0.22.1, 0.23.1, CDH3u3과 HDP 1.0)부터 DFSClient가 데이터가 로컬일 때 DataNode를 거치지 않고 "short circuit"을 취해 직접 디스크에서 읽을 수 있게 됐어요. 이것이 HBase에 의미하는 바는 RegionServers가 DataNode와 대화하기 위해 소켓을 열어야 하는 대신 자기 머신의 디스크에서 직접 읽을 수 있다는 것이고, 전자가 일반적으로 훨씬 빠르다는 것이에요. JD의 Performance Talk를 참고하세요. short circuit 읽기에 대한 더 많은 논의는 HBase, mail # dev - read short circuit 스레드를 참고하세요.

"short circuit" 읽기를 활성화하려면 Hadoop 버전에 달려 있어요. 원래 shortcircuit read 패치는 Hadoop 2의 HDFS-347에서 크게 개선됐어요. 옛 구현과 새 구현의 차이에 대한 자세한 내용은 http://blog.cloudera.com/blog/2013/08/how-improved-short-circuit-local-reads-bring-better-performance-and-security-to-hadoop/를 참고하세요. 후자의 더 나은 버전의 shortcircuit을 활성화하는 방법은 Hadoop shortcircuit reads configuration page를 참고하세요. 예를 들어 hbase-site.xml에 추가된 short-circuit 읽기를 활성화하는 최소 구성을 살펴보세요.

<property>
  <name>dfs.client.read.shortcircuit</name>
  <value>true</value>
  <description>
    This configuration parameter turns on short-circuit local reads.
  </description>
</property>
<property>
  <name>dfs.domain.socket.path</name>
  <value>/home/stack/sockets/short_circuit_read_socket_PORT</value>
  <description>
    Optional.  This is a path to a UNIX domain socket that will be used for
    communication between the DataNode and local HDFS clients.
    If the string "_PORT" is present in this path, it will be replaced by the
    TCP port of the DataNode.
  </description>
</property>

공유 도메인 소켓을 호스팅하는 디렉터리의 권한에 주의하세요. dfsclient는 hbase 사용자가 아닌 다른 사용자에게 열려 있으면 불평할 거예요.

HDFS-347이 없는 HDFS-2246이 있는 옛 Hadoop에서 실행 중이라면 두 가지 구성을 설정해야 해요. 먼저 hdfs-site.xml을 수정해야 해요. dfs.block.local-path-access.user 프로퍼티를 shortcut을 사용할 수 있는 유일한 사용자로 설정하세요. 이것은 HBase를 시작한 사용자여야 해요. 그런 다음 hbase-site.xml에서 dfs.client.read.shortcircuit을 true로 설정하세요.

서비스 — 최소한 HBase RegionServers — 새 구성을 적용하려면 재시작해야 해요.

dfs.client.read.shortcircuit.buffer.size

이 값의 기본값은 트래픽이 많은 HBase에서 실행할 때 너무 높아요. HBase에서 이 값이 설정되지 않으면 기본 1M에서 128k로 내려요(HBase 0.98.0과 0.96.1부터). HBASE-8143 HBase on Hadoop 2 with local short circuit reads (ssr) causes OOM을 참고하세요. HBase의 Hadoop DFSClient는 열려 있는 각 블록에 대해 이 크기의 직접 바이트 버퍼를 할당할 거예요. HBase가 HDFS 파일을 항상 열어 두기 때문에 이것은 빠르게 누적될 수 있어요.

HBase vs HDFS의 성능 비교

배치 컨텍스트(예: MapReduce 소스 또는 싱크)에서 HBase가 HDFS 파일만큼 성능이 좋지 않은 이유는 dist-list에서 꽤 흔한 질문이에요. 짧은 대답은 HBase가 HDFS보다 훨씬 많은 것을 한다는 것이에요(예: KeyValues 읽기, 가장 최신 행 또는 지정된 타임스탬프 반환 등). 따라서 HBase는 이 처리 컨텍스트에서 HDFS보다 4-5배 느려요. 개선의 여지가 있고 이 격차는 시간이 지나면서 줄어들 거지만, 이 사용 사례에서 HDFS는 항상 더 빠를 거예요.

Amazon EC2

성능 질문은 Amazon EC2 환경에서 흔해요. 공유 환경이기 때문이에요. 전용 서버와 같은 처리량을 보지 못할 거예요. EC2에서 테스트를 실행하는 관점에서 같은 이유로 여러 번 실행하세요(즉 공유 환경이라 서버에서 무슨 일이 일어나는지 모름).

EC2에서 실행 중이고 dist-list에 성능 질문을 올린다면, EC2 문제가 사실상 별도의 성능 문제 클래스이므로 이 사실을 처음에 밝히세요.

HBase와 MapReduce 공동 배치

HBase와 MapReduce에 다른 클러스터를 갖는 것이 종종 권장돼요. 더 나은 표현은: 실시간 요청을 서비스하는 HBase를 무거운 MR 워크로드와 공동 배치하지 마세요. OLTP와 OLAP에 최적화된 시스템은 상충하는 요구를 가지며 하나가 다른 하나에게 질 거예요. 보통 전자가 그래요. 예를 들어 짧은 지연 민감 디스크 읽기는 가능한 한 많은 처리량을 짜내려 하는 더 긴 읽기 뒤에서 기다려야 해요. HBase에 쓰는 MR 작업도 플러시와 컴팩션을 생성할 거고, 이는 차례로 Block Cache의 블록을 무효화할 거예요.

실시간 HBase 클러스터의 데이터를 MR에서 처리해야 한다면 CopyTable로 델타를 보내거나 복제를 사용해 OLAP 클러스터에서 새 데이터를 실시간으로 얻을 수 있어요. 최악의 경우 정말 둘 다 공동 배치해야 한다면, MR이 보통 구성하는 것보다 더 적은 Map과 Reduce 슬롯을 사용하도록 설정하세요. 어쩌면 하나만요.

HBase를 OLAP 연산에 사용할 때는 ZooKeeper 세션 타임아웃을 더 높게 구성하고 MemStores에 더 많은 메모리를 주는 것과 같은 강화된 방식으로 설정하는 것이 좋아요(워크로드가 보통 긴 스캔이므로 Block Cache는 많이 사용되지 않을 것이라는 논거).

사례 연구

성능 및 문제 해결 사례 연구는 Apache HBase Case Studies를 참고하세요.

더 알아보기 (Learn more)