Apache HBase 문제 해결과 디버깅

Apache HBase 문제 해결과 디버깅

이 문서는 HBase 문제를 해결하고 디버깅하는 방법을 설명해요. 로그 위치와 로그 레벨, GC 로그, 각종 도구, 그리고 클라이언트·NameNode·RegionServer·Master·ZooKeeper·EC2 등에서 흔히 마주치는 오류들을 다뤄요. 문제가 생겼을 때 체계적으로 접근할 수 있는 지침이에요.

출처: 문서

본문

일반 지침

항상 master 로그부터 시작하세요(TODO: 어느 줄?). 보통은 같은 줄을 계속 반복해서 인쇄할 거예요. 그렇지 않다면 문제가 있는 거예요. Google은 당신이 보는 예외에 대한 몇 가지 검색 결과를 반환해야 해요.

오류는 Apache HBase에서 좀처럼 혼자 오지 않아요. 보통 무언가 잘못되면 그 뒤에는 수백 개의 예외와 스택 트레이스가 사방에서 따라올 거예요. 이런 유형의 문제에 접근하는 가장 좋은 방법은 로그를 위로 올라가며 모든 것이 시작된 곳까지 가는 것이에요. 예를 들어 RegionServers의 요령 하나는 중단할 때 일부 메트릭을 인쇄한다는 것이므로 Dump를 grep하면 문제의 시작 지점 근처에 도달할 수 있어요.

RegionServer 자살(suicide)은 '정상'이에요. 무언가 잘못됐을 때 그렇게 하는 것이 그들의 방식이기 때문이에요. 예를 들어 ulimit와 max transfer threads(가장 중요한 두 초기 설정, [ulimit]과 dfs.datanode.max.transfer.threads 참고)를 변경하지 않으면 어느 시점에 DataNodes가 새 스레드를 만들 수 없게 되어, HBase 관점에서는 HDFS가 사라진 것처럼 보여요. MySQL 데이터베이스가 갑자기 로컬 파일 시스템의 파일에 접근할 수 없게 되면 어떻게 될지 생각해 보세요. HBase와 HDFS의 경우도 똑같아요. RegionServers가 할복(seppuku)을 하는 또 다른 아주 흔한 이유는 기본 ZooKeeper 세션 타임아웃보다 오래 지속되는 장기간 가비지 컬렉션 일시 정지에 들어갈 때예요. GC 일시 정지에 대한 자세한 내용은 Todd Lipcon의 3부작 블로그 게시물과 위의 Long GC pauses를 참고하세요.

로그

핵심 프로세스 로그는 다음과 같아요... (<user>를 서비스를 시작한 사용자로, <hostname>을 머신 이름으로 바꾸세요)

NameNode: $HADOOP_HOME/logs/hadoop--namenode-.log

DataNode: $HADOOP_HOME/logs/hadoop--datanode-.log

JobTracker: $HADOOP_HOME/logs/hadoop--jobtracker-.log

TaskTracker: $HADOOP_HOME/logs/hadoop--tasktracker-.log

HMaster: $HBASE_HOME/logs/hbase--master-.log

RegionServer: $HBASE_HOME/logs/hbase--regionserver-.log

ZooKeeper: TODO

로그 위치

스탠드얼론 배포의 경우 로그는 당연히 단일 머신에 있지만, 이것은 개발 구성일 뿐이에요. 프로덕션 배포는 클러스터에서 실행해야 해요.

NameNode

NameNode 로그는 NameNode 서버에 있어요. HBase Master는 보통 NameNode 서버에서 실행되고 ZooKeeper도 마찬가지예요.

더 작은 클러스터의 경우 JobTracker/ResourceManager도 보통 NameNode 서버에서 실행돼요.

DataNode

각 DataNode 서버는 HDFS용 DataNode 로그와 HBase용 RegionServer 로그를 가질 거예요.

또한 각 DataNode 서버는 MapReduce 작업 실행을 위한 TaskTracker/NodeManager 로그도 가질 거예요.

로그 레벨

RPC 수준 로깅 활성화

RegionServer에서 RPC 수준 로깅을 활성화하면 서버의 타이밍에 대한 통찰을 자주 얻을 수 있어요. 활성화되면 스피되는 로그의 양이 방대해져요. 짧은 시간 동안만 이 로깅을 켜 두는 것이 권장돼요. RPC 수준 로깅을 활성화하려면 RegionServer UI로 이동해 Log Level을 클릭하세요. org.apache.hadoop.hbase.ipc 패키지에 대해 로그 레벨을 TRACE로 설정한 다음 RegionServer 로그를 tail하세요. 분석하세요.

비활성화하려면 로그 레벨을 INFO 수준으로 되돌리세요.

같은 로그 설정은 Master와 클라이언트에서도 동작해요.

여러 SLF4J 바인딩 처리(로그 구성 재정의 방지)

로컬에 Hadoop 설치(macOS에서 Homebrew로 설치한 것과 같은)가 있다면 bin/start-hbase.sh로 HBase를 스탠드얼론 모드로 시작할 때 "multiple SLF4J bindings" 경고가 발생할 수 있어요. 예를 들어 머신에서 HBase를 시작할 때 다음과 같은 것이 보일 수 있어요.

SLF4J: Class path contains multiple SLF4J bindings.
SLF4J: Found binding in [jar:file:/opt/homebrew/Cellar/hadoop/3.4.1/libexec/share/hadoop/common/lib/slf4j-reload4j-1.7.36.jar!/org/slf4j/impl/StaticLoggerBinder.class]
SLF4J: Found binding in [jar:file:$HOME/.m2/repository/org/apache/logging/log4j/log4j-slf4j-impl/2.25.3/log4j-slf4j-impl-2.25.3.jar!/org/slf4j/impl/StaticLoggerBinder.class]
SLF4J: See http://www.slf4j.org/codes.html#multiple_bindings for an explanation.
SLF4J: Actual binding is of type [org.slf4j.impl.Reload4jLoggerFactory]

이것은 bin/hbase 스크립트가 로컬 Hadoop 설치를 자동으로 감지해 그 클래스패스를 HBase에 추가하기 때문에 일어나요. Hadoop 설치가 레거시 Reload4j(또는 Log4j 1.2) 바인더를 사용한다면 SLF4J가 HBase Log4j2 바인더보다 그것을 우선할 수 있어요. 이렇게 되면 conf/log4j2.properties 파일과 HBASE_ROOT_LOGGER 환경 변수가 완전히 무시돼요.

이 문제를 피하려면 HBASE_DISABLE_HADOOP_CLASSPATH_LOOKUP을 true로 설정할 수 있어요. conf/hbase-env.sh에서 다음 줄의 주석을 해제해 직접 수정할 수 있어요.

export HBASE_DISABLE_HADOOP_CLASSPATH_LOOKUP="true"

참고: HBASE_DISABLE_HADOOP_CLASSPATH_LOOKUP 설정은 HBase가 분산 모드일 때는 문제를 고치지 않아요. 대신 다른 경고가 있을 수 있어요.

JVM 가비지 컬렉션 로그

이 섹션의 모든 예시 Garbage Collection 로그는 Java 8 출력을 기반으로 해요. Java 9 이상에서 Unified Logging이 도입되면서 아주 다른 모습의 로그가 나올 거예요.

HBase는 메모리 집약적이며, 기본 GC를 사용하면 Juliet Pause라고도 알려진 "GC of Death"를 포함해 모든 스레드에서 긴 일시 정지를 볼 수 있어요. 이 문제를 디버깅하거나 실제로 발생하는지 확인하는 데 도움이 되도록 Java 가상 머신에서 GC 로깅을 켤 수 있어요.

활성화하려면 hbase-env.sh에서 아래 줄 중 하나의 주석을 해제하세요.

# This enables basic gc logging to the .out file.
# export SERVER_GC_OPTS="-verbose:gc -XX:+PrintGCDetails -XX:+PrintGCDateStamps"

# This enables basic gc logging to its own file.
# export SERVER_GC_OPTS="-verbose:gc -XX:+PrintGCDetails -XX:+PrintGCDateStamps -Xloggc:<FILE-PATH>"

# This enables basic GC logging to its own file with automatic log rolling. Only applies to jdk 1.6.0_34+ and 1.7.0_2+.
# export SERVER_GC_OPTS="-verbose:gc -XX:+PrintGCDetails -XX:+PrintGCDateStamps -Xloggc:<FILE-PATH> -XX:+UseGCLogFileRotation -XX:NumberOfGCLogFiles=1 -XX:GCLogFileSize=512M"

# If <FILE-PATH> is not replaced, the log file(.gc) would be generated in the HBASE_LOG_DIR.

이 시점에 다음과 같은 로그가 보일 거예요.

64898.952: [GC [1 CMS-initial-mark: 2811538K(3055704K)] 2812179K(3061272K), 0.0007360 secs] [Times: user=0.00 sys=0.00, real=0.00 secs]
64898.953: [CMS-concurrent-mark-start]
64898.971: [GC 64898.971: [ParNew: 5567K->576K(5568K), 0.0101110 secs] 2817105K->2812715K(3061272K), 0.0102200 secs] [Times: user=0.07 sys=0.00, real=0.01 secs]

이 섹션에서 첫 줄은 CMS의 초기 마크에 0.0007360초 일시 정지를 나타내요. 이것은 해당 시간 동안 전체 VM, 모든 스레드를 일시 정지해요.

세 번째 줄은 "minor GC"를 나타내며 VM을 0.0101110초(즉 10밀리초) 일시 정지해요. "ParNew"를 약 5.5m에서 576k로 줄였어요. 이 주기 후반에 다음을 볼 수 있어요.

64901.445: [CMS-concurrent-mark: 1.542/2.492 secs] [Times: user=10.49 sys=0.33, real=2.49 secs]
64901.445: [CMS-concurrent-preclean-start]
64901.453: [GC 64901.453: [ParNew: 5505K->573K(5568K), 0.0062440 secs] 2868746K->2864292K(3061272K), 0.0063360 secs] [Times: user=0.05 sys=0.00, real=0.01 secs]
64901.476: [GC 64901.476: [ParNew: 5563K->575K(5568K), 0.0072510 secs] 2869283K->2864837K(3061272K), 0.0073320 secs] [Times: user=0.05 sys=0.01, real=0.01 secs]
64901.500: [GC 64901.500: [ParNew: 5517K->573K(5568K), 0.0120390 secs] 2869780K->2865267K(3061272K), 0.0121150 secs] [Times: user=0.09 sys=0.00, real=0.01 secs]
64901.529: [GC 64901.529: [ParNew: 5507K->569K(5568K), 0.0086240 secs] 2870200K->2865742K(3061272K), 0.0087180 secs] [Times: user=0.05 sys=0.00, real=0.01 secs]
64901.554: [GC 64901.555: [ParNew: 5516K->575K(5568K), 0.0107130 secs] 2870689K->2866291K(3061272K), 0.0107820 secs] [Times: user=0.06 sys=0.00, real=0.01 secs]
64901.578: [CMS-concurrent-preclean: 0.070/0.133 secs] [Times: user=0.48 sys=0.01, real=0.14 secs]
64901.578: [CMS-concurrent-abortable-preclean-start]
64901.584: [GC 64901.584: [ParNew: 5504K->571K(5568K), 0.0087270 secs] 2871220K->2866830K(3061272K), 0.0088220 secs] [Times: user=0.05 sys=0.00, real=0.01 secs]
64901.609: [GC 64901.609: [ParNew: 5512K->569K(5568K), 0.0063370 secs] 2871771K->2867322K(3061272K), 0.0064230 secs] [Times: user=0.06 sys=0.00, real=0.01 secs]
64901.615: [CMS-concurrent-abortable-preclean: 0.007/0.037 secs] [Times: user=0.13 sys=0.00, real=0.03 secs]
64901.616: [GC[YG occupancy: 645 K (5568 K)]64901.616: [Rescan (parallel) , 0.0020210 secs]64901.618: [weak refs processing, 0.0027950 secs] [1 CMS-remark: 2866753K(3055704K)] 2867399K(3061272K), 0.0049380 secs] [Times: user=0.00 sys=0.01, real=0.01 secs]
64901.621: [CMS-concurrent-sweep-start]

첫 줄은 CMS 동시 마크(가비지 찾기)가 2.4초 걸렸음을 나타내요. 그러나 이것은 동시 2.4초이며, 어느 시점에도 Java는 일시 정지되지 않았어요.

몇 개의 마이너 GC가 더 있고, 그다음 마지막 두 번째 줄에 일시 정지가 있어요.

64901.616: [GC[YG occupancy: 645 K (5568 K)]64901.616: [Rescan (parallel) , 0.0020210 secs]64901.618: [weak refs processing, 0.0027950 secs] [1 CMS-remark: 2866753K(3055704K)] 2867399K(3061272K), 0.0049380 secs] [Times: user=0.00 sys=0.01, real=0.01 secs]

여기서 일시 정지는 힙을 'remark'하는 0.0049380초(즉 4.9밀리초)예요.

이 시점에서 sweep이 시작되고 힙 크기가 줄어드는 것을 볼 수 있어요.

64901.637: [GC 64901.637: [ParNew: 5501K->569K(5568K), 0.0097350 secs] 2871958K->2867441K(3061272K), 0.0098370 secs] [Times: user=0.05 sys=0.00, real=0.01 secs]
...  lines removed ...
64904.936: [GC 64904.936: [ParNew: 5532K->568K(5568K), 0.0070720 secs] 1365024K->1360689K(3061272K), 0.0071930 secs] [Times: user=0.05 sys=0.00, real=0.01 secs]
64904.953: [CMS-concurrent-sweep: 2.030/3.332 secs] [Times: user=9.57 sys=0.26, real=3.33 secs]

이 시점에서 CMS sweep은 3.332초가 걸렸고 힙은 약 ~2.8GB에서 1.3GB(대략)로 내려갔어요.

여기서 핵심은 이 모든 일시 정지를 낮게 유지하는 것이에요. CMS 일시 정지는 항상 낮지만, ParNew가 커지기 시작하면 마이너 GC 일시 정지가 100ms에 가까워지고, 100ms를 초과하고 최대 400ms까지 치를 수 있어요.

이것은 상대적으로 작아야 하는 ParNew의 크기 때문일 수 있어요. HBase를 한동안 실행한 후 ParNew가 아주 크다면(한 예시에서 ParNew가 약 150MB였음) ParNew의 크기를 제한해야 할 수 있어요(클수록 컬렉션 시간이 길어지지만 너무 작으면 객체가 너무 빨리 old gen으로 승격돼요). 아래에서 new gen 크기를 64m으로 제한해요.

hbase-env.sh에 아래 줄을 추가하세요.

export SERVER_GC_OPTS="$SERVER_GC_OPTS -XX:NewSize=64m -XX:MaxNewSize=64m"

마찬가지로 클라이언트 프로세스에 GC 로깅을 활성화하려면 hbase-env.sh에서 아래 줄 중 하나의 주석을 해제하세요.

# This enables basic gc logging to the .out file.
# export CLIENT_GC_OPTS="-verbose:gc -XX:+PrintGCDetails -XX:+PrintGCDateStamps"

# This enables basic gc logging to its own file.
# export CLIENT_GC_OPTS="-verbose:gc -XX:+PrintGCDetails -XX:+PrintGCDateStamps -Xloggc:<FILE-PATH>"

# This enables basic GC logging to its own file with automatic log rolling. Only applies to jdk 1.6.0_34+ and 1.7.0_2+.
# export CLIENT_GC_OPTS="-verbose:gc -XX:+PrintGCDetails -XX:+PrintGCDateStamps -Xloggc:<FILE-PATH> -XX:+UseGCLogFileRotation -XX:NumberOfGCLogFiles=1 -XX:GCLogFileSize=512M"

# If <FILE-PATH> is not replaced, the log file(.gc) would be generated in the HBASE_LOG_DIR .

GC 일시 정지에 대한 자세한 내용은 Todd Lipcon의 3부작 블로그 게시물과 위의 Long GC pauses를 참고하세요.

리소스

메일링 리스트

Apache HBase 메일링 리스트에 질문하세요. 'dev' 메일링 리스트는 실제로 Apache HBase를 구축하는 개발자 커뮤니티와 현재 개발 중인 기능을 위한 것이고, 'user'는 일반적으로 출시된 Apache HBase 버전에 대한 질문에 사용돼요. 메일링 리스트로 가기 전에 먼저 메일링 리스트 아카이브를 검색해 질문에 이미 답변이 있는지 확인하세요. 중국어로 소통하는 것을 선호하는 사람은 'user' 목록 대신 'user-zh' 메일링 리스트를 사용할 수 있어요. 질문을 만드는 데 시간을 들이세요. 좋은 질문을 만드는 아이디어는 Getting Answers를 참고하세요. 모든 컨텍스트를 포함하고 작성자가 매뉴얼과 목록에서 답을 찾으려 했다는 증거를 보여주는 양질의 질문은 신속한 응답을 받을 가능성이 더 높아요.

Slack

https://the-asf.slack.com/의 #hbase

IRC

(Slack 채널에서 더 신속한 응답을 받을 가능성이 높아요)

irc.freenode.net의 #hbase

JIRA

JIRA는 Hadoop/HBase 특정 이슈를 찾을 때도 정말 유용해요.

도구

내장 도구

Master 웹 인터페이스

Master는 기본적으로 포트 16010에 웹 인터페이스를 시작해요.

Master web UI는 생성된 테이블과 그 정의(예: ColumnFamilies, blocksize 등)를 나열해요. 또한 클러스터에서 사용 가능한 RegionServers와 선택된 상위 수준 메트릭(requests, regions 수, usedHeap, maxHeap)이 나열돼요. Master web UI는 각 RegionServer의 web UI로의 탐색을 허용해요.

RegionServer 웹 인터페이스

RegionServers는 기본적으로 포트 16030에 웹 인터페이스를 시작해요.

RegionServer web UI는 온라인 region과 그 시작/끝 키, 그리고 특정 시점의 RegionServer 메트릭(requests, regions, storeFileIndexSize, compactionQueueSize 등)을 나열해요.

메트릭 정의에 대한 자세한 내용은 HBase Metrics를 참고하세요.

zkcli

zkcli는 ZooKeeper 관련 문제를 조사하는 데 매우 유용한 도구예요. 호출하려면:

./hbase zkcli -server host:port <cmd> <args>

명령(및 인자)은:

  connect host:port
  get path [watch]
  ls path [watch]
  set path data [version]
  delquota [-n|-b] path
  quit
  printwatches on|off
  create [-s] [-e] path data acl
  stat path [watch]
  close
  ls2 path [watch]
  history
  listquota path
  setAcl path acl
  getAcl path
  sync path
  redo cmdno
  addauth scheme auth
  delete path [version]
  setquota -n|-b val path
유지보수 모드

클러스터가 어떤 상태에서 멈추고 표준 기법이 진전되지 않는다면 클러스터를 "유지보수 모드"로 재시작할 수 있어요. 이 모드는 기능과 표면이 급격히 줄어들어 hbase:meta 테이블 수리/복구 같은 아주 낮은 수준의 변경을 수행하기 더 쉽게 해요.

유지보수 모드에 들어가려면 hbase-site.xml 또는 master 프로세스를 시작할 때 시스템 프로퍼티(-D...=true)로 hbase.master.maintenance_mode를 true로 설정하세요. 이 모드에 들어가고 나가는 것에는 서비스 재시작이 필요하지만, 전형적인 사용은 HBase Master가 이미 시작 어려움에 직면했을 때일 거예요.

유지보수 모드가 활성화되면 master가 모든 시스템 테이블을 호스팅할 거예요. 그것을 위한 충분한 메모리가 있는지 확인하세요. RegionServers에는 사용자 공간 테이블의 어떤 region도 할당되지 않을 거예요. 사실 유지보수 모드에서는 완전히 사용되지 않게 돼요. 또한 master는 어떤 coprocessor도 로드하지 않고, 정규화나 merge/split 연산도 실행하지 않으며, 할당량도 강제하지 않아요.

외부 도구

tail

tail은 파일의 끝을 볼 수 있게 해 주는 명령줄 도구예요. -f 옵션을 추가하면 새 데이터가 사용 가능할 때 새로 고쳐져요. 무슨 일이 일어나고 있는지 궁금할 때 유용한데, 예를 들어 클러스터가 종료되거나 시작되는 데 오랜 시간이 걸릴 때 새 터미널을 열고 master 로그(그리고 아마 몇 개의 RegionServers)를 tail하면 돼요.

top

top은 아마도 머신에서 무엇이 실행 중이고 리소스가 어떻게 소비되는지 처음 보려고 할 때 가장 중요한 도구 중 하나예요. 프로덕션 시스템의 예시:

top - 14:46:59 up 39 days, 11:55,  1 user,  load average: 3.75, 3.57, 3.84
Tasks: 309 total,   1 running, 308 sleeping,   0 stopped,   0 zombie
Cpu(s):  4.5%us,  1.6%sy,  0.0%ni, 91.7%id,  1.4%wa,  0.1%hi,  0.6%si,  0.0%st
Mem:  24414432k total, 24296956k used,   117476k free,     7196k buffers
Swap: 16008732k total,  14348k used, 15994384k free, 11106908k cached

  PID USER      PR  NI  VIRT  RES  SHR S %CPU %MEM  TIME+  COMMAND
15558 hadoop    18  -2 3292m 2.4g 3556 S   79 10.4   6523:52 java
13268 hadoop    18  -2 8967m 8.2g 4104 S   21 35.1   5170:30 java
 8895 hadoop    18  -2 1581m 497m 3420 S   11  2.1   4002:32 java
...

여기서 지난 5분 동안 시스템 부하 평균이 3.75임을 볼 수 있는데, 이것은 대략 그 5분 동안 평균적으로 3.75개 스레드가 CPU 시간을 기다리고 있었다는 뜻이에요. 일반적으로 완벽한 활용은 코어 수와 같고, 그 수 이하이면 머신이 과소 활용되고 초과하면 과다 활용이에요. 이것은 중요한 개념이에요. 더 이해하려면 이 기사를 참고하세요: http://www.linuxjournal.com/article/9001.

부하 외에도 시스템이 사용 가능한 거의 모든 RAM을 사용하지만 대부분 OS 캐시(좋은 것)에 사용된다는 것을 볼 수 있어요. swap에는 몇 KB만 있고 이것이 원하는 것이에요. 높은 수치는 Java 시스템 성능의 천적인 스와핑 활동을 나타내요. 스와핑을 감지하는 또 다른 방법은 부하 평균이 하늘로 치솟는 경우예요(비록 이것은 죽어가는 디스크 같은 것에 의해서도 발생할 수 있지만).

프로세스 목록은 기본적으로 그렇게 유용하지 않아요. 우리가 아는 것은 3개의 java 프로세스가 CPU의 약 111%를 사용하고 있다는 것뿐이에요. 어느 것이 어느 것인지 알려면 c를 입력하면 각 줄이 확장돼요. 1을 입력하면 여기에 보이는 것처럼 모두의 평균이 아니라 각 CPU가 어떻게 사용되는지에 대한 세부 정보를 줄 거예요.

jps

jps는 모든 JDK와 함께 제공되며 현재 사용자의 java 프로세스 ID를 제공해요(root면 모든 사용자의 ID를 줌). 예시:

hadoop@sv4borg12:~$ jps
1322 TaskTracker
17789 HRegionServer
27862 Child
1158 DataNode
25115 HQuorumPeer
2950 Jps
19750 ThriftServer
18776 jmx

순서대로 보면:

  • Hadoop TaskTracker, 로컬 Childs를 관리
  • HBase RegionServer, 지역 제공
  • Child, 그 MapReduce 작업, 정확히 어떤 타입인지 구분할 수 없음
  • Hadoop TaskTracker, 로컬 Childs를 관리
  • Hadoop DataNode, 블록 제공
  • HQuorumPeer, ZooKeeper 앙상블 멤버
  • Jps, 글쎄... 현재 프로세스
  • ThriftServer, thrift가 시작된 경우에만 실행될 특별한 것
  • jmx, 우리 모니터링 플랫폼의 일부인 로컬 프로세스(이름이 형편없을 수도 있음). 아마 없을 거예요.

그런 다음 프로세스를 시작한 전체 명령줄을 확인하는 등 작업을 할 수 있어요.

hadoop@sv4borg12:~$ ps aux | grep HRegionServer
hadoop   17789  155 35.2 9067824 8604364 ?     S<l  Mar04 9855:48 /usr/java/jdk1.6.0_14/bin/java -Xmx8000m -XX:+DoEscapeAnalysis -XX:+AggressiveOpts -XX:+UseConcMarkSweepGC -XX:NewSize=64m -XX:MaxNewSize=64m -XX:CMSInitiatingOccupancyFraction=88 -verbose:gc -XX:+PrintGCDetails -XX:+PrintGCTimeStamps -Xloggc:/export1/hadoop/logs/gc-hbase.log -Dcom.sun.management.jmxremote.port=10102 -Dcom.sun.management.jmxremote.authenticate=true -Dcom.sun.management.jmxremote.ssl=false -Dcom.sun.management.jmxremote.password.file=/home/hadoop/hbase/conf/jmxremote.password -Dcom.sun.management.jmxremote -Dhbase.log.dir=/export1/hadoop/logs -Dhbase.log.file=hbase-hadoop-regionserver-sv4borg12.log -Dhbase.home.dir=/home/hadoop/hbase -Dhbase.id.str=hadoop -Dhbase.root.logger=INFO,DRFA -Djava.library.path=/home/hadoop/hbase/lib/native/Linux-amd64-64 -classpath /home/hadoop/hbase/bin/../conf:[many jars]:/home/hadoop/hadoop/conf org.apache.hadoop.hbase.regionserver.HRegionServer start
jstack

jstack은 로그를 보는 것 외에 java 프로세스가 무엇을 하고 있는지 알아내려 할 때 가장 중요한 도구 중 하나예요. 프로세스 ID를 주기 위해 jps와 함께 사용해야 해요. 스레드 목록을 보여주는데, 각 스레드에는 이름이 있고 생성된 순서로 나타나요(그래서 맨 위가 가장 최근 스레드). 몇 가지 예시예요.

master로부터 할 일을 기다리는 RegionServer의 메인 스레드:

"regionserver60020" prio=10 tid=0x0000000040ab4000 nid=0x45cf waiting on condition [0x00007f16b6a96000..0x00007f16b6a96a70]
java.lang.Thread.State: TIMED_WAITING (parking)
    at sun.misc.Unsafe.park(Native Method)
        - parking to wait for  <0x00007f16cd5c2f30> (a java.util.concurrent.locks.AbstractQueuedSynchronizer$ConditionObject)
    at java.util.concurrent.locks.LockSupport.parkNanos(LockSupport.java:198)
    at java.util.concurrent.locks.AbstractQueuedSynchronizer$ConditionObject.awaitNanos(AbstractQueuedSynchronizer.java:1963)
    at java.util.concurrent.LinkedBlockingQueue.poll(LinkedBlockingQueue.java:395)
    at org.apache.hadoop.hbase.regionserver.HRegionServer.run(HRegionServer.java:647)
    at java.lang.Thread.run(Thread.java:619)

현재 파일에 플러시 중인 MemStore flusher 스레드:

"regionserver60020.cacheFlusher" daemon prio=10 tid=0x0000000040f4e000 nid=0x45eb in Object.wait() [0x00007f16b5b86000..0x00007f16b5b87af0]
java.lang.Thread.State: WAITING (on object monitor)
    at java.lang.Object.wait(Native Method)
    at java.lang.Object.wait(Object.java:485)
    at org.apache.hadoop.ipc.Client.call(Client.java:803)
        - locked <0x00007f16cb14b3a8> (a org.apache.hadoop.ipc.Client$Call)
    at org.apache.hadoop.ipc.RPC$Invoker.invoke(RPC.java:221)
    at $Proxy1.complete(Unknown Source)
    at sun.reflect.GeneratedMethodAccessor38.invoke(Unknown Source)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
    at java.lang.reflect.Method.invoke(Method.java:597)
    at org.apache.hadoop.io.retry.RetryInvocationHandler.invokeMethod(RetryInvocationHandler.java:82)
    at org.apache.hadoop.io.retry.RetryInvocationHandler.invoke(RetryInvocationHandler.java:59)
    at $Proxy1.complete(Unknown Source)
    at org.apache.hadoop.hdfs.DFSClient$DFSOutputStream.closeInternal(DFSClient.java:3390)
        - locked <0x00007f16cb14b470> (a org.apache.hadoop.hdfs.DFSClient$DFSOutputStream)
    at org.apache.hadoop.hdfs.DFSClient$DFSOutputStream.close(DFSClient.java:3304)
    at org.apache.hadoop.fs.FSDataOutputStream$PositionCache.close(FSDataOutputStream.java:61)
    at org.apache.hadoop.fs.FSDataOutputStream.close(FSDataOutputStream.java:86)
    at org.apache.hadoop.hbase.io.hfile.HFile$Writer.close(HFile.java:650)
    at org.apache.hadoop.hbase.regionserver.StoreFile$Writer.close(StoreFile.java:853)
    at org.apache.hadoop.hbase.regionserver.Store.internalFlushCache(Store.java:467)
        - locked <0x00007f16d00e6f08> (a java.lang.Object)
    at org.apache.hadoop.hbase.regionserver.Store.flushCache(Store.java:427)
    at org.apache.hadoop.hbase.regionserver.Store.access$100(Store.java:80)
    at org.apache.hadoop.hbase.regionserver.Store$StoreFlusherImpl.flushCache(Store.java:1359)
    at org.apache.hadoop.hbase.regionserver.HRegion.internalFlushcache(HRegion.java:907)
    at org.apache.hadoop.hbase.regionserver.HRegion.internalFlushcache(HRegion.java:834)
    at org.apache.hadoop.hbase.regionserver.HRegion.flushcache(HRegion.java:786)
    at org.apache.hadoop.hbase.regionserver.MemStoreFlusher.flushRegion(MemStoreFlusher.java:250)
    at org.apache.hadoop.hbase.regionserver.MemStoreFlusher.flushRegion(MemStoreFlusher.java:224)
    at org.apache.hadoop.hbase.regionserver.MemStoreFlusher.run(MemStoreFlusher.java:146)

할 일(put, delete, scan 등)을 기다리는 핸들러 스레드:

"IPC Server handler 16 on 60020" daemon prio=10 tid=0x00007f16b011d800 nid=0x4a5e waiting on condition [0x00007f16afefd000..0x00007f16afefd9f0]
   java.lang.Thread.State: WAITING (parking)
          at sun.misc.Unsafe.park(Native Method)
              - parking to wait for  <0x00007f16cd3f8dd8> (a java.util.concurrent.locks.AbstractQueuedSynchronizer$ConditionObject)
          at java.util.concurrent.locks.LockSupport.park(LockSupport.java:158)
          at java.util.concurrent.locks.AbstractQueuedSynchronizer$ConditionObject.await(AbstractQueuedSynchronizer.java:1925)
          at java.util.concurrent.LinkedBlockingQueue.take(LinkedBlockingQueue.java:358)
          at org.apache.hadoop.hbase.ipc.HBaseServer$Handler.run(HBaseServer.java:1013)

그리고 카운터의 increment를 바쁘게 수행하는 것(마지막 값을 읽기 위해 스캐너를 만들려는 단계):

"IPC Server handler 66 on 60020" daemon prio=10 tid=0x00007f16b006e800 nid=0x4a90 runnable [0x00007f16acb77000..0x00007f16acb77cf0]
   java.lang.Thread.State: RUNNABLE
          at org.apache.hadoop.hbase.regionserver.KeyValueHeap.<init>(KeyValueHeap.java:56)
          at org.apache.hadoop.hbase.regionserver.StoreScanner.<init>(StoreScanner.java:79)
          at org.apache.hadoop.hbase.regionserver.Store.getScanner(Store.java:1202)
          at org.apache.hadoop.hbase.regionserver.HRegion$RegionScanner.<init>(HRegion.java:2209)
          at org.apache.hadoop.hbase.regionserver.HRegion.instantiateInternalScanner(HRegion.java:1063)
          at org.apache.hadoop.hbase.regionserver.HRegion.getScanner(HRegion.java:1055)
          at org.apache.hadoop.hbase.regionserver.HRegion.getScanner(HRegion.java:1039)
          at org.apache.hadoop.hbase.regionserver.HRegion.getLastIncrement(HRegion.java:2875)
          at org.apache.hadoop.hbase.regionserver.HRegion.incrementColumnValue(HRegion.java:2978)
          at org.apache.hadoop.hbase.regionserver.HRegionServer.incrementColumnValue(HRegionServer.java:2433)
          at sun.reflect.GeneratedMethodAccessor20.invoke(Unknown Source)
          at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
          at java.lang.reflect.Method.invoke(Method.java:597)
          at org.apache.hadoop.hbase.ipc.HBaseRPC$Server.call(HBaseRPC.java:560)
          at org.apache.hadoop.hbase.ipc.HBaseServer$Handler.run(HBaseServer.java:1027)

HDFS에서 데이터를 받는 스레드:

"IPC Client (47) connection to sv4borg9/10.4.24.40:9000 from hadoop" daemon prio=10 tid=0x00007f16a02d0000 nid=0x4fa3 runnable [0x00007f16b517d000..0x00007f16b517dbf0]
   java.lang.Thread.State: RUNNABLE
          at sun.nio.ch.EPollArrayWrapper.epollWait(Native Method)
          at sun.nio.ch.EPollArrayWrapper.poll(EPollArrayWrapper.java:215)
          at sun.nio.ch.EPollSelectorImpl.doSelect(EPollSelectorImpl.java:65)
          at sun.nio.ch.SelectorImpl.lockAndDoSelect(SelectorImpl.java:69)
              - locked <0x00007f17d5b68c00> (a sun.nio.ch.Util$1)
              - locked <0x00007f17d5b68be8> (a java.util.Collections$UnmodifiableSet)
              - locked <0x00007f1877959b50> (a sun.nio.ch.EPollSelectorImpl)
          at sun.nio.ch.SelectorImpl.select(SelectorImpl.java:80)
          at org.apache.hadoop.net.SocketIOWithTimeout$SelectorPool.select(SocketIOWithTimeout.java:332)
          at org.apache.hadoop.net.SocketIOWithTimeout.doIO(SocketIOWithTimeout.java:157)
          at org.apache.hadoop.net.SocketInputStream.read(SocketInputStream.java:155)
          at org.apache.hadoop.net.SocketInputStream.read(SocketInputStream.java:128)
          at java.io.FilterInputStream.read(FilterInputStream.java:116)
          at org.apache.hadoop.ipc.Client$Connection$PingInputStream.read(Client.java:304)
          at java.io.BufferedInputStream.fill(BufferedInputStream.java:218)
          at java.io.BufferedInputStream.read(BufferedInputStream.java:237)
              - locked <0x00007f1808539178> (a java.io.BufferedInputStream)
          at java.io.DataInputStream.readInt(DataInputStream.java:370)
          at org.apache.hadoop.ipc.Client$Connection.receiveResponse(Client.java:569)
          at org.apache.hadoop.ipc.Client$Connection.run(Client.java:477)

그리고 RegionServer가 죽은 후 리스를 복구하려는 master:

"LeaseChecker" daemon prio=10 tid=0x00000000407ef800 nid=0x76cd waiting on condition [0x00007f6d0eae2000..0x00007f6d0eae2a70]
--
   java.lang.Thread.State: WAITING (on object monitor)
          at java.lang.Object.wait(Native Method)
          at java.lang.Object.wait(Object.java:485)
          at org.apache.hadoop.ipc.Client.call(Client.java:726)
          - locked <0x00007f6d1cd28f80> (a org.apache.hadoop.ipc.Client$Call)
          at org.apache.hadoop.ipc.RPC$Invoker.invoke(RPC.java:220)
          at $Proxy1.recoverBlock(Unknown Source)
          at org.apache.hadoop.hdfs.DFSClient$DFSOutputStream.processDatanodeError(DFSClient.java:2636)
          at org.apache.hadoop.hdfs.DFSClient$DFSOutputStream.<init>(DFSClient.java:2832)
          at org.apache.hadoop.hdfs.DFSClient.append(DFSClient.java:529)
          at org.apache.hadoop.hdfs.DistributedFileSystem.append(DistributedFileSystem.java:186)
          at org.apache.hadoop.fs.FileSystem.append(FileSystem.java:530)
          at org.apache.hadoop.hbase.util.FSUtils.recoverFileLease(FSUtils.java:619)
          at org.apache.hadoop.hbase.regionserver.wal.HLog.splitLog(HLog.java:1322)
          at org.apache.hadoop.hbase.regionserver.wal.HLog.splitLog(HLog.java:1210)
          at org.apache.hadoop.hbase.master.HMaster.splitLogAfterStartup(HMaster.java:648)
          at org.apache.hadoop.hbase.master.HMaster.joinCluster(HMaster.java:572)
          at org.apache.hadoop.hbase.master.HMaster.run(HMaster.java:503)

OpenTSDB

OpenTSDB은 시계열을 저장하는 데 Apache HBase를 사용하고 다운샘플이 필요 없으므로 Ganglia의 훌륭한 대안이에요. OpenTSDB를 호스팅하는 자신의 HBase 클러스터를 모니터링하는 것은 좋은 연습이에요.

다음은 거의 동시에 시작된 수백 개의 컴팩션으로 고통받아 IO 성능에 심각한 영향을 주는 클러스터의 예시예요: (TODO: compactionQueueSize를 그리는 그래프 삽입)

머신별, 클러스터별 모든 중요한 그래프로 대시보드를 구축해 문제 디버깅을 한 번에 빠르게 살펴볼 수 있게 하는 것이 좋은 관행이에요. 예를 들어 StumbleUpon에는 OS와 Apache HBase 양쪽의 가장 중요한 메트릭이 있는 클러스터당 하나의 대시보드가 있어요. 그런 다음 머신 수준으로 내려가 더 상세한 메트릭을 얻을 수 있어요.

clusterssh+top

clusterssh+top은 가난한 사람의 모니터링 시스템 같아요. 머신이 몇 대뿐일 때 설정이 매우 쉬우므로 꽤 유용할 수 있어요. clusterssh를 시작하면 머신당 하나의 터미널과, 당신이 입력하는 것이 모든 창에 다시 입력되는 또 다른 터미널을 줘요. 즉 top을 한 번 입력하면 모든 머신에서 동시에 시작되어 클러스터의 현재 상태에 대한 전체 보기를 줘요. 또한 모든 로그를 동시에 tail하고 파일을 편집하는 등 할 수 있어요.

클라이언트

HBase 클라이언트에 대한 자세한 내용은 client를 참고하세요.

ScannerTimeoutException 또는 UnknownScannerException

이것은 클라이언트에서 RegionServer로의 RPC 호출 사이 시간이 스캔 타임아웃을 초과하면 던져져요. 예를 들어 Scan.setCaching이 500으로 설정되면 ResultScanner에서 500번의 .next() 호출마다 RPC 호출이 일어나 다음 행 배치를 가져오는데, 데이터가 500행 블록으로 클라이언트로 전송되기 때문이에요. setCaching 값을 줄이는 것이 옵션일 수 있지만, 이 값을 너무 낮게 설정하면 많은 행을 처리하는 데 비효율적이에요.

Scan Caching을 참고하세요.

Thrift와 Java API의 성능 차이

ScannerTimeoutException 또는 UnknownScannerException에서 논의한 대로 Scan.setCaching이 너무 높으면 낮은 성능이나 ScannerTimeoutExceptions가 발생할 수 있어요. Thrift 클라이언트가 주어진 워크로드에 대해 잘못된 캐싱 설정을 사용하면 Java API에 비해 성능이 떨어질 수 있어요. Thrift 클라이언트에서 주어진 스캔의 캐싱을 설정하려면 scannerGetList(scannerId, numRows) 메서드를 사용하세요. 여기서 numRows는 캐시할 행 수를 나타내는 정수예요. 한 경우에 Thrift 스캔의 캐시를 1000에서 100으로 줄이면 같은 쿼리로 Java API에 거의 근접한 성능이 증가했음이 발견됐어요.

또한 Thrift로 Scans를 사용하는 것에 대한 Jesse Andersen의 블로그 게시물을 참고하세요.

Scanner.next 호출 시 LeaseException

어떤 상황에서 RegionServer에서 데이터를 가져오는 클라이언트는 일반적인 ScannerTimeoutException 또는 UnknownScannerException 대신 LeaseException을 받아요. 보통 예외의 출처는 org.apache.hadoop.hbase.regionserver.Leases.removeLease(Leases.java:230)(줄 번호는 다를 수 있음)이에요. 느리거나 멈춘 RegionServer#next 호출의 컨텍스트에서 발생하는 경향이 있어요. hbase.rpc.timeout > hbase.client.scanner.timeout.period로 설정하면 예방할 수 있어요. Harsh J가 메일링 리스트 스레드 HBase, mail # user - Lease does not exist exceptions의 일부로 이 이슈를 조사했어요.

정상 운영 중 셸 또는 클라이언트 애플리케이션이 많은 무서운 예외를 던짐

0.20.0부터 org.apache.hadoop.hbase.*의 기본 로그 레벨은 DEBUG예요.

클라이언트에서 $HBASE_HOME/conf/log4j.properties를 편집하고 log4j.logger.org.apache.hadoop.hbase=DEBUG를 log4j.logger.org.apache.hadoop.hbase=INFO로, 또는 심지어 log4j.logger.org.apache.hadoop.hbase=WARN으로 변경하세요.

압축과 함께 긴 클라이언트 일시 정지

이것은 Apache HBase dist-list에서 꽤 흔한 질문이에요. 시나리오는 클라이언트가 보통 상대적으로 최적화되지 않은 HBase 클러스터에 많은 데이터를 삽입하는 것이에요. 압축은 문제의 원인이 아니지만 일시 정지를 악화시킬 수 있어요.

region 사전 생성 패턴에 대해 Table Creation: Pre-Creating Regions을 참고하고 테이블이 단일 region으로 시작하지 않는지 확인하세요.

클러스터 구성에 대해서는 HBase Configurations를 참고하세요. 특히 hbase.hstore.blockingStoreFiles, hbase.hregion.memstore.block.multiplier, MAX_FILESIZE(region 크기), MEMSTORE_FLUSHSIZE.를요.

일시 정지가 왜 생길 수 있는지에 대한 약간 더 긴 설명은 다음과 같아요. Puts는 때때로 MemStores에 의해 차단되는데, MemStores는 컴팩션해야 할 파일이 너무 많아 컴팩터가 같은 데이터를 반복적으로 컴팩션해야 해서 차단된 flusher 스레드에 의해 차단돼요. 이 상황은 마이너 컴팩션에서도 발생할 수 있어요. 이 상황을 악화시키는 것은 Apache HBase가 메모리의 데이터를 압축하지 않는다는 것이에요. 따라서 MemStore에 있는 64MB가 압축 후 6MB 파일이 될 수 있는데 — 더 작은 StoreFile이 됨. 장점은 더 많은 데이터가 같은 region에 패킹된다는 것이지만, 성능은 더 큰 파일을 쓸 수 있음으로 얻어지므로 HBase는 새 StoreFile을 쓰기 전에 flushsize까지 기다려요. 그리고 더 작은 StoreFiles는 컴팩션의 대상이 돼요. 압축이 없으면 파일이 훨씬 커서 컴팩션이 많이 필요하지 않지만, 이것은 I/O를 희생한 것이에요.

보안 클라이언트 연결 ([Caused by GSSException: No valid credentials provided...])

다음 오류를 만날 수 있어요.

Secure Client Connect ([Caused by GSSException: No valid credentials provided
        (Mechanism level: Request is a replay (34) V PROCESS_TGS)])

이 이슈는 MIT Kerberos replay_cache 구성 요소의 버그 #1201과 #5924에 의해 발생해요. 이 버그들은 옛 버전의 krb5-server가 Principal로부터 보내진 후속 요청을 잘못 차단하게 했어요. 이것은 krb5-server가 한 클라이언트(각 RegionServer에 대한 멀티스레딩 연결 인스턴스를 가진 one HTable instance)로부터 보내진 연결을 차단하게 했어요. Request is a replay (34) 같은 메시지는 클라이언트 로그에 기록돼요. HTable이 실패한 각 연결에 대해 기본적으로 5 * 10(50)번 재시도하므로 메시지를 무시할 수 있어요. HTable은 재시도 후 RegionServer에 대한 어떤 연결이라도 실패하면 IOException을 던질 거라서, HTable 인스턴스용 사용자 클라이언트 코드가 그것을 더 처리할 수 있어요. 참고: HTable은 HBase 1.0에서 deprecated이며, Table을 사용하는 것이 좋아요.

대안으로, 이 문제를 해결하는 버전(예: krb5-server-1.10.3)으로 krb5-server를 업데이트하세요. 자세한 내용은 JIRA HBASE-10379를 참고하세요.

ZooKeeper 클라이언트 연결 오류

이런 오류...

11/07/05 11:26:41 WARN zookeeper.ClientCnxn: Session 0x0 for server null,
 unexpected error, closing socket connection and attempting reconnect
 java.net.ConnectException: Connection refused: no further information
        at sun.nio.ch.SocketChannelImpl.checkConnect(Native Method)
        at sun.nio.ch.SocketChannelImpl.finishConnect(Unknown Source)
        at org.apache.zookeeper.ClientCnxn$SendThread.run(ClientCnxn.java:1078)
 11/07/05 11:26:43 INFO zookeeper.ClientCnxn: Opening socket connection to
 server localhost/127.0.0.1:2181
 11/07/05 11:26:44 WARN zookeeper.ClientCnxn: Session 0x0 for server null,
 unexpected error, closing socket connection and attempting reconnect
 java.net.ConnectException: Connection refused: no further information
        at sun.nio.ch.SocketChannelImpl.checkConnect(Native Method)
        at sun.nio.ch.SocketChannelImpl.finishConnect(Unknown Source)
        at org.apache.zookeeper.ClientCnxn$SendThread.run(ClientCnxn.java:1078)
 11/07/05 11:26:45 INFO zookeeper.ClientCnxn: Opening socket connection to
 server localhost/127.0.0.1:2181

...은 ZooKeeper가 다운되었거나 네트워크 문제로 연결할 수 없기 때문이에요.

zkcli 유틸리티가 ZooKeeper 문제를 조사하는 데 도움이 될 수 있어요.

힙 크기는 안정적인데도 클라이언트 메모리 부족(off-heap/direct heap이 계속 커짐)

아마도 HBase, mail # user - Suspected memory leak에서 설명되고 해결되고, HBase, mail # dev - FeedbackRe: Suspected memory leak에서 계속된 메일 스레드에서 설명되는 이슈를 마주치고 있을 가능성이 높아요. 해결책은 클라이언트 측 JVM에 -XX:MaxDirectMemorySize의 합리적인 값을 전달하는 것이에요. 기본적으로 MaxDirectMemorySize는 -Xmx 최대 힙 크기 설정과 같아요(-Xmx가 설정된 경우). 더 작은 값으로 설정해 보세요(예: 한 사용자는 클라이언트 측 힙이 12g일 때 1g으로 설정하고 성공했어요). 너무 작게 설정하면 FullGCs가 생기므로 조금 넉넉히 유지하세요. 특히 새 실험적 서버 측 off-heap 캐시를 실행 중이라면 이 설정을 클라이언트 측에만 두고 싶을 거예요. 이 기능은 큰 직접 버퍼를 사용할 수 있어야 하기 때문이에요(클라이언트 측과 서버 측 구성 디렉터리를 분리해야 할 수도 있음).

보안 클라이언트가 연결할 수 없음 ([Caused by GSSException: No valid credentials provided(Mechanism level: Failed to find any Kerberos tgt)])

이 증상을 만드는 여러 원인이 있을 수 있어요.

먼저 유효한 Kerberos 티켓이 있는지 확인하세요. 보안 Apache HBase 클러스터와 통신을 설정하려면 하나가 필요해요. klist 명령줄 유틸리티를 실행해 현재 자격 증명 캐시의 티켓(있는 경우)을 조사하세요. 티켓이 나열되지 않으면 keytab을 지정하거나 원하는 프린시펄의 비밀번호를 대화형으로 입력해 kinit 명령을 실행해 티켓을 얻어야 해요.

그런 다음 Java Security Guide troubleshooting section을 참고하세요. 거기서 다루는 가장 흔한 문제는 javax.security.auth.useSubjectCredsOnly 시스템 프로퍼티 값을 false로 설정하면 해결돼요.

MIT Kerberos가 자격 증명 캐시를 쓰는 형식의 변경 때문에, Oracle JDK 6 Update 26 및 이전 버전에는 Java가 MIT Kerberos 1.8.1 이상 버전이 만든 Kerberos 자격 증명 캐시를 읽을 수 없게 하는 버그가 있어요. 환경에 이 문제를 일으키는 구성 요소 조합이 있다면, 이 문제를 해결하려면 먼저 kinit으로 로그인한 다음 kinit -R로 자격 증명 캐시를 즉시 새로 고치세요. 새로 고침은 문제가 되는 형식 없이 자격 증명 캐시를 다시 써요.

JDK 1.4 이전에는 JCE가 번들되지 않은 제품이었기 때문에 JCA와 JCE가 정기적으로 분리된 별개 구성 요소로 언급됐어요. JCE가 JDK 7.0에 번들되었으므로 그 구분은 덜 명확해졌어요. JCE는 JCA와 같은 아키텍처를 사용하므로, JCE는 JCA의 일부로 더 적절히 생각해야 해요.

JDK 1.5 또는 이전 버전 때문에 Java Cryptography Extension 또는 JCE를 설치해야 할 수 있어요. JCE jar가 서버와 클라이언트 시스템 모두의 클래스패스에 있는지 확인하세요.

또한 unlimited strength JCE policy files를 다운로드해야 할 수도 있어요. 다운로드한 파일을 압축 해제하고 추출한 다음 정책 jar를 /lib/security에 설치하세요.

master registry 문제 해결

  • 연결 문제의 경우 보통 "MasterRegistryFetchException: Exception making rpc to masters..." 같은 예외가 클라이언트 로그에 기록돼요. 로깅은 클라이언트가 시도한 master 엔드포인트 목록을 포함해요. 스택 트레이스의 아래쪽 부분이 근본 원인을 포함해야 해요. 연결 문제(ConnectionRefused?)를 의심한다면 master 엔드포인트가 클라이언트에서 접근 가능한지 확인하세요.
  • hedging된 RPC로 인해 master에 더 높은 부하가 있다고 의심되면, hedging fan out을 줄이거나( hbase.rpc.hedged.fanout 통해) 클라이언트가 master registry 목적으로 접근할 수 있는 master 집합을 제한( hbase.masters 통해)해 제어할 수 있어요.

자세한 내용은 Master Registry (new as of 2.3.0)과 Client configuration and dependencies connecting to an HBase cluster를 참고하세요.

MapReduce

클러스터에 있다고 생각하지만 실제로는 로컬

다음 스택트레이스는 ImportTsv를 사용해 발생했지만, 이런 것은 잘못 구성된 어떤 작업에서도 발생할 수 있어요.

    WARN mapred.LocalJobRunner: job_local_0001
java.lang.IllegalArgumentException: Can't read partitions file
       at org.apache.hadoop.hbase.mapreduce.hadoopbackport.TotalOrderPartitioner.setConf(TotalOrderPartitioner.java:111)
       at org.apache.hadoop.util.ReflectionUtils.setConf(ReflectionUtils.java:62)
       at org.apache.hadoop.util.ReflectionUtils.newInstance(ReflectionUtils.java:117)
       at org.apache.hadoop.mapred.MapTask$NewOutputCollector.<init>(MapTask.java:560)
       at org.apache.hadoop.mapred.MapTask.runNewMapper(MapTask.java:639)
       at org.apache.hadoop.mapred.MapTask.run(MapTask.java:323)
       at org.apache.hadoop.mapred.LocalJobRunner$Job.run(LocalJobRunner.java:210)
Caused by: java.io.FileNotFoundException: File _partition.lst does not exist.
       at org.apache.hadoop.fs.RawLocalFileSystem.getFileStatus(RawLocalFileSystem.java:383)
       at org.apache.hadoop.fs.FilterFileSystem.getFileStatus(FilterFileSystem.java:251)
       at org.apache.hadoop.fs.FileSystem.getLength(FileSystem.java:776)
       at org.apache.hadoop.io.SequenceFile$Reader.<init>(SequenceFile.java:1424)
       at org.apache.hadoop.io.SequenceFile$Reader.<init>(SequenceFile.java:1419)
       at org.apache.hadoop.hbase.mapreduce.hadoopbackport.TotalOrderPartitioner.readPartitions(TotalOrderPartitioner.java:296)

...스택의 중요한 부분이 보이나요? 그것은...

at org.apache.hadoop.mapred.LocalJobRunner$Job.run(LocalJobRunner.java:210)

LocalJobRunner는 작업이 클러스터가 아니라 로컬에서 실행 중임을 의미해요.

이 문제를 해결하려면 HBase 의존성을 포함하도록 HADOOP_CLASSPATH를 설정해 MR 작업을 실행해야 해요. "hbase classpath" 유틸리티를 사용해 쉽게 할 수 있어요. 예를 들어(VERSION을 HBase 버전으로 대체):

HADOOP_CLASSPATH=`hbase classpath` hadoop jar $HBASE_HOME/hbase-mapreduce-VERSION.jar rowcounter usertable

HBase MapReduce 작업과 클래스패스에 대한 자세한 내용은 HBase, MapReduce, and the CLASSPATH를 참고하세요.

작업 시작 시 java.lang.IllegalAccessError: com/google/protobuf/HBaseZeroCopyByteString 또는 class com.google.protobuf.ZeroCopyLiteralByteString cannot access its superclass com.google.protobuf.LiteralByteString

HBASE-10304 Running an hbase job jar: IllegalAccessError: class com.google.protobuf.ZeroCopyLiteralByteString cannot access its superclass com.google.protobuf.LiteralByteString과 HBASE-11118 non environment variable solution for "IllegalAccessError: class com.google.protobuf.ZeroCopyLiteralByteString cannot access its superclass com.google.protobuf.LiteralByteString"을 참고하세요. 이 이슈는 spark 작업을 실행하려 할 때도 나타날 수 있어요. HBASE-10877 HBase non-retriable exception list should be expanded을 참고하세요.

NameNode

NameNode에 대한 자세한 내용은 HDFS를 참고하세요.

테이블과 region의 HDFS 활용

HBase가 HDFS에서 얼마나 많은 공간을 사용하는지 확인하려면 NameNode에서 hadoop 셸 명령을 사용하세요. 예를 들어...

hadoop fs -dus /hbase/

...은 모든 HBase 객체에 대한 요약된 디스크 활용을 반환해요.

hadoop fs -dus /hbase/myTable

...은 HBase 테이블 'myTable'에 대한 요약된 디스크 활용을 반환해요.

hadoop fs -du /hbase/myTable

...은 HBase 테이블 'myTable' 아래의 region 목록과 그 디스크 활용을 반환해요.

HDFS 셸 명령에 대한 자세한 내용은 HDFS FileSystem Shell documentation을 참고하세요.

HBase 객체를 위해 HDFS 탐색

때로는 HDFS에 존재하는 HBase 객체를 탐색해야 할 필요가 있을 거예요. 이 객체들에는 WALs(Write Ahead Logs), 테이블, region, StoreFiles 등이 포함될 수 있어요. 가장 쉬운 방법은 포트 50070에서 실행되는 NameNode 웹 애플리케이션을 사용하는 것이에요. NameNode 웹 애플리케이션은 클러스터의 모든 DataNode에 대한 링크를 제공해서 원활히 탐색할 수 있어요.

클러스터에서 HBase 테이블의 HDFS 디렉터리 구조는...

/hbase
    /data
        /<Namespace>                    (Namespaces in the cluster)
            /<Table>                    (Tables in the cluster)
                /<Region>               (Regions for the table)
                    /<ColumnFamily>     (ColumnFamilies for the Region for the table)
                        /<StoreFile>    (StoreFiles for the ColumnFamily for the Regions for the table)

HBase WAL의 HDFS 디렉터리 구조는...

/hbase
    /WALs
        /<RegionServer>    (RegionServers)
            /<WAL>         (WAL files for the RegionServer)

fsck 같은 다른 비셸 진단 유틸리티는 HDFS User Guide을 참고하세요.

데이터가 있는 크기 0의 WAL들

문제: RegionServer의 WALs 디렉터리에 있는 모든 파일 목록을 얻을 때, 한 파일의 크기가 0인데 데이터를 포함해요.

답변: 그것은 HDFS 특이점이에요. 현재 쓰여지고 있는 파일은 크기가 0으로 보이지만, 일단 닫히면 실제 크기를 보여줄 거예요.

사용 사례

HBase 객체를 위해 HDFS를 쿼리하는 흔한 두 가지 사용 사례는 테이블의 비컴팩션 정도를 연구하는 것이에요. 각 ColumnFamily에 많은 수의 StoreFiles가 있다면 메이저 컴팩션의 필요성을 나타낼 수 있어요. 또한 메이저 컴팩션 후 결과 StoreFile이 "작다면" 테이블의 ColumnFamilies 축소 필요성을 나타낼 수 있어요.

예상치 못한 파일시스템 증가

HBase가 파일시스템을 예상치 못하게 급증시키는 것을 보면 두 가지 가능한 범인은 스냅샷과 WAL이에요.

스냅샷

스냅샷을 만들 때 HBase는 그 스냅샷 시점에 테이블의 상태를 재생성하는 데 필요한 모든 것을 유지해요. 여기에는 삭제된 셀이나 만료된 버전이 포함돼요. 이런 이유로 스냅샷 사용 패턴을 잘 계획하고 더 이상 필요하지 않은 스냅샷을 정리해야 해요. 스냅샷은 /hbase/.hbase-snapshot에 저장되고, 스냅샷 복원에 필요한 아카이브는 /hbase/archive/<tablename>/<region>/<column_family>/에 저장돼요.

스냅샷이나 아카이브를 HDFS로 수동 관리하지 마세요. HBase는 그것을 관리하기 위한 API와 HBase Shell 명령을 제공해요. 자세한 내용은 ops.snapshots을 참고하세요.

WAL

Write-ahead 로그(WAL)는 상태에 따라 HBase 루트 디렉터리(보통 /hbase/)의 하위 디렉터리에 저장돼요. 이미 처리된 WAL은 /hbase/oldWALs/에, 손상된 WAL은 검사용으로 /hbase/.corrupt/에 저장돼요. 이 하위 디렉터리 중 하나의 크기가 커지고 있다면 HBase 서버 로그를 조사해 WAL이 올바르게 처리되지 않는 근본 원인을 찾으세요.

복제를 사용하고 /hbase/oldWALs/가 예상보다 더 많은 공간을 사용한다면, 복제가 비활성화되어 있을 때 피어가 있는 한 WAL이 저장된다는 것을 기억하세요.

WAL을 HDFS로 수동 관리하지 마세요.

네트워크

네트워크 스파이크

주기적 네트워크 스파이크를 보고 있다면 compactionQueues를 확인해 메이저 컴팩션이 일어나고 있는지 살펴볼 수 있어요.

컴팩션 관리에 대한 자세한 내용은 Managed Compactions을 참고하세요.

루프백 IP

HBase는 루프백 IP 주소가 127.0.0.1이기를 기대해요.

네트워크 인터페이스

모든 네트워크 인터페이스가 제대로 동작하고 있나요? 확실한가요? Case Studies의 Troubleshooting Case Study를 참고하세요.

RegionServer

RegionServers에 대한 자세한 내용은 RegionServer를 참고하세요.

시작 오류

Master는 시작하지만 RegionServers는 시작하지 않음

Master는 RegionServers가 127.0.0.1의 IP를 가진다고 믿어요. 이것은 localhost이며 master 자신의 localhost로 해석돼요.

RegionServers가 Master에게 자신의 IP 주소가 127.0.0.1이라고 잘못 알리고 있어요.

region servers에서 /etc/hosts를 수정하세요. 다음에서...

# Do not remove the following line, or various programs
# that require network functionality will fail.
127.0.0.1               fully.qualified.regionservername regionservername  localhost.localdomain localhost
::1             localhost6.localdomain6 localhost6

...로(localhost에서 master 노드의 이름 제거)...

# Do not remove the following line, or various programs
# that require network functionality will fail.
127.0.0.1               localhost.localdomain localhost
::1             localhost6.localdomain6 localhost6
압축 링크 오류

LZO 같은 압축 알고리즘은 각 클러스터에 설치하고 구성해야 하므로 이것은 시작 오류의 빈번한 근원이에요. 이런 메시지가 보이면...

11/02/20 01:32:15 ERROR lzo.GPLNativeCodeLoader: Could not load native gpl library
java.lang.UnsatisfiedLinkError: no gplcompression in java.library.path
        at java.lang.ClassLoader.loadLibrary(ClassLoader.java:1734)
        at java.lang.Runtime.loadLibrary0(Runtime.java:823)
        at java.lang.System.loadLibrary(System.java:1028)

...압축 라이브러리에 경로 문제가 있어요. LZO compression configuration의 Configuration 섹션을 참고하세요.

파일시스템의 hsync 부족으로 RegionServer 중단

클러스터에 대한 쓰기의 데이터 내구성을 제공하기 위해 HBase는 write ahead log에 상태를 내구성 있게 저장할 수 있는 능력에 의존해요. 필요 호출의 가용성을 확인하는 것을 지원하는 Apache Hadoop Common의 파일시스템 API 버전을 사용할 때, HBase는 안전하게 동작할 수 없다고 판단하면 클러스터를 사전에 중단해요.

RegionServer 역할의 경우 장애가 다음과 같이 로그에 나타날 거예요.

2018-04-05 11:36:22,785 ERROR [regionserver/192.168.1.123:16020] wal.AsyncFSWALProvider: The RegionServer async write ahead log provider relies on the ability to call hflush and hsync for proper operation during component failures, but the current FileSystem does not support doing so. Please check the config value of 'hbase.wal.dir' and ensure it points to a FileSystem mount that has suitable capabilities for output streams.
2018-04-05 11:36:22,799 ERROR [regionserver/192.168.1.123:16020] regionserver.HRegionServer: ***** ABORTING region server 192.168.1.123,16020,1522946074234: Unhandled: cannot get log writer *****
java.io.IOException: cannot get log writer
        at org.apache.hadoop.hbase.wal.AsyncFSWALProvider.createAsyncWriter(AsyncFSWALProvider.java:112)
        at org.apache.hadoop.hbase.regionserver.wal.AsyncFSWAL.createWriterInstance(AsyncFSWAL.java:612)
        at org.apache.hadoop.hbase.regionserver.wal.AsyncFSWAL.createWriterInstance(AsyncFSWAL.java:124)
        at org.apache.hadoop.hbase.regionserver.wal.AbstractFSWAL.rollWriter(AbstractFSWAL.java:759)
        at org.apache.hadoop.hbase.regionserver.wal.AbstractFSWAL.rollWriter(AbstractFSWAL.java:489)
        at org.apache.hadoop.hbase.regionserver.wal.AsyncFSWAL.<init>(AsyncFSWAL.java:251)
        at org.apache.hadoop.hbase.wal.AsyncFSWALProvider.createWAL(AsyncFSWALProvider.java:69)
        at org.apache.hadoop.hbase.wal.AsyncFSWALProvider.createWAL(AsyncFSWALProvider.java:44)
        at org.apache.hadoop.hbase.wal.AbstractFSWALProvider.getWAL(AbstractFSWALProvider.java:138)
        at org.apache.hadoop.hbase.wal.AbstractFSWALProvider.getWAL(AbstractFSWALProvider.java:57)
        at org.apache.hadoop.hbase.wal.WALFactory.getWAL(WALFactory.java:252)
        at org.apache.hadoop.hbase.regionserver.HRegionServer.getWAL(HRegionServer.java:2105)
        at org.apache.hadoop.hbase.regionserver.HRegionServer.buildServerLoad(HRegionServer.java:1326)
        at org.apache.hadoop.hbase.regionserver.HRegionServer.tryRegionServerReport(HRegionServer.java:1191)
        at org.apache.hadoop.hbase.regionserver.HRegionServer.run(HRegionServer.java:1007)
        at java.lang.Thread.run(Thread.java:745)
Caused by: org.apache.hadoop.hbase.util.CommonFSUtils$StreamLacksCapabilityException: hflush and hsync
        at org.apache.hadoop.hbase.io.asyncfs.AsyncFSOutputHelper.createOutput(AsyncFSOutputHelper.java:69)
        at org.apache.hadoop.hbase.regionserver.wal.AsyncProtobufLogWriter.initOutput(AsyncProtobufLogWriter.java:168)
        at org.apache.hadoop.hbase.regionserver.wal.AbstractProtobufLogWriter.init(AbstractProtobufLogWriter.java:167)
        at org.apache.hadoop.hbase.wal.AsyncFSWALProvider.createAsyncWriter(AsyncFSWALProvider.java:99)
        ... 15 more

스탠드얼론 모드로 실행을 시도하고 이 오류를 보았다면 Quick Start - Standalone HBase 섹션을 다시 살펴보고 주어진 구성 설정을 모두 포함했는지 확인하세요.

HDFS에 대한 접근을 초기화할 수 없어 RegionServer 중단

HBase-2.x는 더 나은 성능을 제공하고 리소스를 덜 소비하므로 AsyncFSWAL을 사용하려고 할 거예요. 하지만 AsyncFSWAL의 문제는 DFSClient 구현의 내부를 해킹한다는 것이므로, 단순한 패치 릴리스에 대해서도 hadoop을 업그레이드할 때 쉽게 깨질 수 있어요.

wal provider를 지정하지 않으면, AsyncFSWAL을 초기화하지 못할 때 옛 FSHLog로 폴백하려고 시도하지만 항상 동작하지는 않을 수 있어요. 장애는 다음과 같이 로그에 나타날 거예요.

18/07/02 18:51:06 WARN concurrent.DefaultPromise: An exception was
thrown by org.apache.hadoop.hbase.io.asyncfs.FanOutOneBlockAsyncDFSOutputHelper$13.operationComplete()
java.lang.Error: Couldn't properly initialize access to HDFS
internals. Please update your WAL Provider to not make use of the
'asyncfs' provider. See HBASE-16110 for more information.
     at org.apache.hadoop.hbase.io.asyncfs.FanOutOneBlockAsyncDFSOutputSaslHelper.<clinit>(FanOutOneBlockAsyncDFSOutputSaslHelper.java:268)
     at org.apache.hadoop.hbase.io.asyncfs.FanOutOneBlockAsyncDFSOutputHelper.initialize(FanOutOneBlockAsyncDFSOutputHelper.java:661)
     at org.apache.hadoop.hbase.io.asyncfs.FanOutOneBlockAsyncDFSOutputHelper.access$300(FanOutOneBlockAsyncDFSOutputHelper.java:118)
     at org.apache.hadoop.hbase.io.asyncfs.FanOutOneBlockAsyncDFSOutputHelper$13.operationComplete(FanOutOneBlockAsyncDFSOutputHelper.java:720)
     at org.apache.hadoop.hbase.io.asyncfs.FanOutOneBlockAsyncDFSOutputHelper$13.operationComplete(FanOutOneBlockAsyncDFSOutputHelper.java:715)
     at org.apache.hbase.thirdparty.io.netty.util.concurrent.DefaultPromise.notifyListener0(DefaultPromise.java:507)
     at org.apache.hbase.thirdparty.io.netty.util.concurrent.DefaultPromise.notifyListeners0(DefaultPromise.java:500)
     at org.apache.hbase.thirdparty.io.netty.util.concurrent.DefaultPromise.notifyListenersNow(DefaultPromise.java:479)
     at org.apache.hbase.thirdparty.io.netty.util.concurrent.DefaultPromise.notifyListeners(DefaultPromise.java:420)
     at org.apache.hbase.thirdparty.io.netty.util.concurrent.DefaultPromise.trySuccess(DefaultPromise.java:104)
     at org.apache.hbase.thirdparty.io.netty.channel.DefaultChannelPromise.trySuccess(DefaultChannelPromise.java:82)
     at org.apache.hbase.thirdparty.io.netty.channel.epoll.AbstractEpollChannel$AbstractEpollUnsafe.fulfillConnectPromise(AbstractEpollChannel.java:638)
     at org.apache.hbase.thirdparty.io.netty.channel.epoll.AbstractEpollChannel$AbstractEpollUnsafe.finishConnect(AbstractEpollChannel.java:676)
     at org.apache.hbase.thirdparty.io.netty.channel.epoll.AbstractEpollChannel$AbstractEpollUnsafe.epollOutReady(AbstractEpollChannel.java:552)
     at org.apache.hbase.thirdparty.io.netty.channel.epoll.EpollEventLoop.processReady(EpollEventLoop.java:394)
     at org.apache.hbase.thirdparty.io.netty.channel.epoll.EpollEventLoop.run(EpollEventLoop.java:304)
     at org.apache.hbase.thirdparty.io.netty.util.concurrent.SingleThreadEventExecutor$5.run(SingleThreadEventExecutor.java:858)
     at org.apache.hbase.thirdparty.io.netty.util.concurrent.DefaultThreadFactory$DefaultRunnableDecorator.run(DefaultThreadFactory.java:138)
     at java.lang.Thread.run(Thread.java:748)
 Caused by: java.lang.NoSuchMethodException:
org.apache.hadoop.hdfs.DFSClient.decryptEncryptedDataEncryptionKey(org.apache.hadoop.fs.FileEncryptionInfo)
     at java.lang.Class.getDeclaredMethod(Class.java:2130)
     at org.apache.hadoop.hbase.io.asyncfs.FanOutOneBlockAsyncDFSOutputSaslHelper.createTransparentCryptoHelper(FanOutOneBlockAsyncDFSOutputSaslHelper.java:232)
     at org.apache.hadoop.hbase.io.asyncfs.FanOutOneBlockAsyncDFSOutputSaslHelper.<clinit>(FanOutOneBlockAsyncDFSOutputSaslHelper.java:262)
     ... 18 more

이 오류를 만나면 구성 파일에 FSHLog, 즉 filesystem을 명시적으로 지정하세요.

<property>
  <name>hbase.wal.provider</name>
  <value>filesystem</value>
</property>

그리고 [email protected] 또는 [email protected]에 장애와 hadoop 버전을 알리는 이메일을 보내는 것을 잊지 마세요. 다음 릴리스에서 가능한 한 빨리 문제를 고치려 노력할 거예요.

런타임 오류

RegionServer 멈춤

옛 JVM(< 1.6.0\u21?)을 실행 중인가요? 스레드 덤프를 볼 때 스레드가 BLOCKED인데 모두가 차단된 잠금을 아무도 소유하지 않는 것처럼 보이나요? HBASE 3622 Deadlock in HBaseServer (JVM bug?)을 참고하세요. HBase HBASE_OPTS의 _conf/hbase-env.sh*에 -XX:+UseMembar를 추가하면 고칠 수 있어요.

java.io.IOException...(Too many open files)

이런 로그 메시지가 보이면...

2010-09-13 01:24:17,336 WARN org.apache.hadoop.hdfs.server.datanode.DataNode:
Disk-related IOException in BlockReceiver constructor. Cause is java.io.IOException: Too many open files
        at java.io.UnixFileSystem.createFileExclusively(Native Method)
        at java.io.File.createNewFile(File.java:883)

... ulimit and nproc configuration의 Getting Started 섹션을 참고하세요.

xceiverCount 258 exceeds the limit of concurrent xcievers 256

이것은 보통 DataNode 로그에 나타나요.

TODO: 링크 추가. xceivers configuration의 Getting Started 섹션을 참고하세요.

시스템 불안정, 그리고 "java.lang.OutOfMemoryError: unable to createnew native thread in exceptions"이 HDFS DataNode 로그 또는 다른 시스템 데몬의 로그에 존재

ulimit과 nproc configuration의 Getting Started 섹션을 참고하세요. 최근 Linux 배포판의 기본값은 1024인데, HBase에는 너무 낮아요.

DFS 불안정 및/또는 RegionServer 리스 타임아웃

이런 경고 메시지가 보이면...

2009-02-24 10:01:33,516 WARN org.apache.hadoop.hbase.util.Sleeper: We slept xxx ms, ten times longer than scheduled: 10000
2009-02-24 10:01:33,516 WARN org.apache.hadoop.hbase.util.Sleeper: We slept xxx ms, ten times longer than scheduled: 15000
2009-02-24 10:01:36,472 WARN org.apache.hadoop.hbase.regionserver.HRegionServer: unable to report to master for xxx milliseconds - retrying

...또는 full GC 컴팩션을 본다면 full GC를 겪고 있을 수 있어요.

"No live nodes contain current block" 및/또는 YouAreDeadException

이 오류는 OS 파일 핸들이 부족해졌거나 노드에 연결할 수 없는 심각한 네트워크 문제 기간에 발생할 수 있어요.

ulimit과 nproc configuration의 Getting Started 섹션을 참고하고 네트워크를 확인하세요.

ZooKeeper SessionExpired 이벤트

Master 또는 RegionServers가 로그에 다음과 같은 메시지와 함께 종료:

WARN org.apache.zookeeper.ClientCnxn: Exception
closing session 0x278bd16a96000f to sun.nio.ch.SelectionKeyImpl@355811ec
java.io.IOException: TIMED OUT
       at org.apache.zookeeper.ClientCnxn$SendThread.run(ClientCnxn.java:906)
WARN org.apache.hadoop.hbase.util.Sleeper: We slept 79410ms, ten times longer than scheduled: 5000
INFO org.apache.zookeeper.ClientCnxn: Attempting connection to server hostname/IP:PORT
INFO org.apache.zookeeper.ClientCnxn: Priming connection to java.nio.channels.SocketChannel[connected local=/IP:PORT remote=hostname/IP:PORT]
INFO org.apache.zookeeper.ClientCnxn: Server connection successful
WARN org.apache.zookeeper.ClientCnxn: Exception closing session 0x278bd16a96000d to sun.nio.ch.SelectionKeyImpl@3544d65e
java.io.IOException: Session Expired
       at org.apache.zookeeper.ClientCnxn$SendThread.readConnectResult(ClientCnxn.java:589)
       at org.apache.zookeeper.ClientCnxn$SendThread.doIO(ClientCnxn.java:709)
       at org.apache.zookeeper.ClientCnxn$SendThread.run(ClientCnxn.java:945)
ERROR org.apache.hadoop.hbase.regionserver.HRegionServer: ZooKeeper session expired

JVM이 모든 스레드를 일시 정지시키는("stop the world") 장기 실행 가비지 컬렉션을 하고 있어요. RegionServer의 로컬 ZooKeeper 클라이언트가 하트비트를 보낼 수 없으므로 세션이 타임아웃돼요. 설계상 타임아웃 후 ZooKeeper 앙상블에 연결할 수 없는 어떤 노드든 종료해서 이미 다른 곳에 할당된 데이터를 서비스하지 않도록 해요.

  • 충분한 RAM을 주세요(hbase-env.sh에서). 기본 1GB로는 장기 실행 import를 유지하지 못할 거예요.
  • 스왑하지 마세요. JVM은 스와핑에서 절대 잘 동작하지 않아요.
  • RegionServer 스레드를 CPU 굶기지 않도록 하세요. 예를 들어 4코어 머신에서 6개의 CPU 집약적 작업을 사용하는 MapReduce 작업을 실행한다면, RegionServer를 충분히 굶겨 더 긴 가비지 컬렉션 일시 정지를 만들고 있을 가능성이 있어요.
  • ZooKeeper 세션 타임아웃을 늘리세요

세션 타임아웃을 늘리려면 hbase-site.xml에 다음을 추가해 기본 60초에서 120초로 늘리세요.

<property>
  <name>zookeeper.session.timeout</name>
  <value>120000</value>
</property>
<property>
  <name>hbase.zookeeper.property.tickTime</name>
  <value>6000</value>
</property>

더 높은 타임아웃을 설정한다는 것은 실패한 RegionServer가 서비스하는 region이 다른 RegionServer로 전송되는 데 적어도 그 시간이 걸린다는 뜻이에요. 실시간 요청을 서비스하는 프로덕션 시스템에는 1분 미만으로 설정하고 각 머신의 메모리 부하를 낮추기 위해(따라서 머신당 수집할 가비지가 줄어듦) 클러스터를 초과 프로비저닝할 것을 권장해요.

이것이 (처음에 모든 데이터를 HBase에 로드하는 것처럼) 한 번만 발생하는 업로드 중이라면 bulk loading을 고려하세요.

ZooKeeper 문제 해결에 대한 다른 일반 정보는 ZooKeeper, The Cluster Canary를 참고하세요.

NotServingRegionException

이 예외는 DEBUG 수준에서 RegionServer 로그에서 발견되면 "정상"이에요. 이 예외는 클라이언트에게 다시 반환되고, 그런 다음 클라이언트는 hbase:meta로 돌아가 이동된 region의 새 위치를 찾아요.

그러나 NotServingRegionException이 ERROR로 기록되면 클라이언트가 재시도를 소진한 것이고 무언가 잘못됐을 가능성이 있어요.

로그가 '2011-01-10 12:40:48,407 INFO org.apache.hadoop.io.compress.CodecPool: Gotbrand-new compressor' 메시지로 넘침

압축 라이브러리의 네이티브 버전을 사용하지 않고 있어요. HBASE-1900 Put back native support when hadoop 0.21 is released을 참고하세요. hadoop의 네이티브 libs를 HBase lib 디렉터리 아래로 복사하거나 심링크로 제자리에 걸면 메시지가 사라질 거예요.

Server handler X on 60020 caught: java.nio.channels.ClosedChannelException

이런 유형의 메시지가 보이면 region server가 클라이언트로부터 데이터를 읽거나 보내려 했지만 클라이언트가 이미 사라졌다는 뜻이에요. 전형적인 원인은 클라이언트가 죽었거나(MapReduce 작업이 죽거나 실패할 때 이런 메시지의 폭풍이 보임) 클라이언트가 SocketTimeoutException을 받은 경우예요. 무해하지만, 그것들을 유발하는 무언가를 하고 있지 않다면 조금 더 파고드는 것을 고려해야 해요.

역방향 DNS로 인한 스냅샷 오류

스냅샷을 포함한 HBase의 여러 연산은 제대로 구성된 역방향 DNS에 의존해요. Amazon EC2 같은 일부 환경은 역방향 DNS에 문제가 있어요. RegionServers에서 다음 같은 오류를 보면 역방향 DNS 구성을 확인하세요.

2013-05-01 00:04:56,356 DEBUG org.apache.hadoop.hbase.procedure.Subprocedure: Subprocedure 'backup1'
coordinator notified of 'acquire', waiting on 'reached' or 'abort' from coordinator.

일반적으로 RegionServer가 보고하는 호스트 이름은 Master가 도달하려는 호스트 이름과 같아야 해요. RegionServer의 시작 로그에서 다음 유형의 메시지를 찾아 호스트 이름 불일치를 볼 수 있어요.

2013-05-01 00:03:00,614 INFO org.apache.hadoop.hbase.regionserver.HRegionServer: Master passed us hostname
to use. Was=myhost-1234, Now=ip-10-55-88-99.ec2.internal

종료 오류

(본문 없음)

Master

Master에 대한 자세한 내용은 master를 참고하세요.

시작 오류

Master가 HBase migrations 스크립트를 실행해야 한다고 말함

그것을 실행하면 HBase migrations 스크립트가 루트 디렉터리에 파일이 없다고 말해요.

HBase는 루트 디렉터리가 존재하지 않거나 HBase가 이전에 실행되어 이미 초기화되었을 것을 기대해요. Hadoop DFS를 사용해 HBase용 새 디렉터리를 만들면 이 오류가 발생할 거예요. HBase 루트 디렉터리가 현재 존재하지 않거나 이전 HBase 실행으로 초기화되었는지 확인하세요. 확실한 해결책은 Hadoop dfs를 사용해 HBase 루트를 삭제하고 HBase가 디렉터리를 직접 만들고 초기화하도록 두는 것이에요.

Packet len6080218 is out of range!

클러스터에 많은 region이 있고 위 섹션 제목에서 보고된 것과 같은 오류를 로그에서 보면, HBASE-4246 Cluster with too many regions cannot withstand some master failover scenarios을 참고하세요.

파일시스템의 hsync 부족으로 Master가 활성이 되지 못함

HBase의 내부 클러스터 운영 프레임워크는 write ahead log에 상태를 내구성 있게 저장할 수 있는 능력을 요구해요. 필요 호출의 가용성을 확인하는 것을 지원하는 Apache Hadoop Common의 파일시스템 API 버전을 사용할 때, HBase는 안전하게 동작할 수 없다고 판단하면 클러스터를 사전에 중단해요.

Master 역할의 경우 장애가 다음과 같이 로그에 나타날 거예요.

2018-04-05 11:18:44,653 ERROR [Thread-21] master.HMaster: Failed to become active master
java.lang.IllegalStateException: The procedure WAL relies on the ability to hsync for proper operation during component failures, but the underlying filesystem does not support doing so. Please check the config value of 'hbase.procedure.store.wal.use.hsync' to set the desired level of robustness and ensure the config value of 'hbase.wal.dir' points to a FileSystem mount that can provide it.
        at org.apache.hadoop.hbase.procedure2.store.wal.WALProcedureStore.rollWriter(WALProcedureStore.java:1034)
        at org.apache.hadoop.hbase.procedure2.store.wal.WALProcedureStore.recoverLease(WALProcedureStore.java:374)
        at org.apache.hadoop.hbase.procedure2.ProcedureExecutor.start(ProcedureExecutor.java:530)
        at org.apache.hadoop.hbase.master.HMaster.startProcedureExecutor(HMaster.java:1267)
        at org.apache.hadoop.hbase.master.HMaster.startServiceThreads(HMaster.java:1173)
        at org.apache.hadoop.hbase.master.HMaster.finishActiveMasterInitialization(HMaster.java:881)
        at org.apache.hadoop.hbase.master.HMaster.startActiveMasterManager(HMaster.java:2048)
        at org.apache.hadoop.hbase.master.HMaster.lambda$run$0(HMaster.java:568)
        at java.lang.Thread.run(Thread.java:745)

스탠드얼론 모드로 실행을 시도하고 이 오류를 보았다면 Quick Start - Standalone HBase 섹션을 다시 살펴보고 주어진 구성 설정을 모두 포함했는지 확인하세요.

종료 오류

(본문 없음)

ZooKeeper

시작 오류

Could not find my address: xyz in list of ZooKeeper quorum servers

ZooKeeper 서버가 시작하지 못하고 그 오류를 던져요. xyz는 서버 이름이에요.

이것은 이름 조회 문제예요. HBase가 어떤 머신에서 ZooKeeper 서버를 시작하려 하지만 그 머신이 hbase.zookeeper.quorum 구성에서 자신을 찾지 못해요.

오류 메시지에 제시된 호스트 이름을 사용한 값 대신 사용하세요. DNS 서버가 있다면 hbase-site.xml에서 hbase.zookeeper.dns.interface와 hbase.zookeeper.dns.nameserver를 설정해 올바른 FQDN으로 해석되도록 할 수 있어요.

ZooKeeper, 클러스터의 카나리아

ZooKeeper는 클러스터의 "광산의 카나리아"예요. 문제가 있으면 무엇보다 먼저 알아차릴 거라서 그 것이 행복한지 확인하는 것이 윙윙거리는 클러스터로 가는 지름길이에요.

ZooKeeper Operating Environment Troubleshooting 페이지를 참고하세요. 디스크와 네트워킹 성능, 즉 ZooKeeper와 HBase가 실행되는 운영 환경을 확인하는 데 도움이 되는 제안과 도구가 있어요.

또한 zkcli 유틸리티가 ZooKeeper 문제를 조사하는 데 도움이 될 수 있어요.

Amazon EC2

ZooKeeper가 Amazon EC2에서 동작하지 않는 것 같음

HBase가 Amazon EC2 인스턴스로 배포될 때 시작하지 않아요. Master 및/또는 RegionServer 로그에 다음과 같은 예외가 나타나요.

  2009-10-19 11:52:27,030 INFO org.apache.zookeeper.ClientCnxn: Attempting
  connection to server ec2-174-129-15-236.compute-1.amazonaws.com/10.244.9.171:2181
  2009-10-19 11:52:27,032 WARN org.apache.zookeeper.ClientCnxn: Exception
  closing session 0x0 to sun.nio.ch.SelectionKeyImpl@656dc861
  java.net.ConnectException: Connection refused

보안 그룹 정책이 공용 주소의 ZooKeeper 포트를 차단하고 있어요. ZooKeeper 쿼럼 피어 목록을 구성할 때 내부 EC2 호스트 이름을 사용하세요.

Amazon EC2에서의 불안정성

HBase와 Amazon EC2에 대한 질문은 HBase dist-list에서 자주 나와요.

EC2 클러스터로의 원격 Java 연결이 동작하지 않음

사용자 리스트의 Andrew의 답변을 여기서 확인하세요: Remote Java client connection into EC2 instance.

HBase와 Hadoop 버전 문제

...cannot communicate with client version...

로그에 다음과 같은 것이 보이면... 2012-09-24 10:20:52,168 FATAL org.apache.hadoop.hbase.master.HMaster: Unhandled exception. Starting shutdown. org.apache.hadoop.ipc.RemoteException: Server IPC version 7 cannot communicate with client version 4 ... Hadoop 1.0.x 클라이언트를 가진 HBase에서 Hadoop 2.0.x와 통신하려 하고 있나요? Hadoop 2.0에 맞춰 빌드된 HBase를 사용하거나 Maven에 -Dhadoop.profile=2.0 속성을 전달해 HBase를 다시 빌드하세요(자세한 내용은 Building against various Hadoop versions 참고).

HBase와 HDFS

Apache HDFS에 대한 일반 구성 지침은 이 가이드의 범위 밖이에요. HDFS 구성에 대한 광범위한 정보는 https://hadoop.apache.org/에서 사용 가능한 문서를 참조하세요. 이 섹션은 HBase의 관점에서 HDFS를 다뤄요.

대부분의 경우 HBase는 데이터를 Apache HDFS에 저장해요. 여기에는 데이터를 포함하는 HFiles와, 데이터가 HFiles에 쓰이기 전에 저장하고 RegionServer 크래시로부터 보호하는 write-ahead 로그(WAL)가 포함돼요. HDFS는 분산되어 있기 때문에 HBase의 데이터에 신뢰성과 보호를 제공해요. 최대 효율로 동작하려면 HBase는 데이터가 로컬로 사용 가능해야 해요. 따라서 각 RegionServer에 HDFS DataNode를 실행하는 것이 좋은 관행이에요.

HBase와 HDFS에 대한 중요 정보와 지침

HBase는 HDFS의 클라이언트다.

HBase는 HDFS 클라이언트이며 HDFS DFSClient 클래스를 사용하고, 이 클래스에 대한 참조는 다른 HDFS 클라이언트 로그 메시지와 함께 HBase 로그에 나타나요.

여러 곳에서 구성이 필요하다.

HBase와 관련된 일부 HDFS 구성은 HDFS(서버) 측에서 수행해야 해요. 다른 것은 HBase(클라이언트 측) 내에서 수행해야 해요. 또 다른 설정은 서버와 클라이언트 양쪽에 설정해야 해요.

HBase에 영향을 주는 쓰기 오류는 HBase 로그가 아닌 HDFS 로그에 기록될 수 있다.

쓰기 시 HDFS는 한 DataNode에서 다른 DataNode로 통신을 파이프라인해요. HBase는 HDFS 클라이언트 클래스를 사용해 HDFS NameNode와 DataNode 양쪽과 통신해요. DataNode 간 통신 문제는 HBase 로그가 아닌 HDFS 로그에 기록돼요.

HBase는 두 개의 다른 포트를 사용해 HDFS와 통신한다.

HBase는 ipc.Client 인터페이스와 DataNode 클래스를 사용해 DataNode와 통신해요. 이것들에 대한 참조는 HBase 로그에 나타나요. 이 각 통신 채널은 다른 포트(기본적으로 50010과 50020)를 사용해요. 포트는 dfs.datanode.address와 dfs.datanode.ipc.address 파라미터를 통해 HDFS 구성에 구성돼요.

오류는 HBase, HDFS 또는 둘 다에 기록될 수 있다.

HBase에서 HDFS 문제를 해결할 때 오류를 양쪽 로그에서 확인하세요.

HDFS는 노드를 죽은 것으로 표시하는 데 시간이 걸린다. HDFS를 구성해 오래된(stale) DataNode를 피할 수 있다.

기본적으로 HDFS는 노드가 630초 동안 연결할 수 없을 때까지 죽은 것으로 표시하지 않아요. Hadoop 1.1과 Hadoop 2.x에서는 이 확인이 기본적으로 비활성화되어 있지만 오래된 DataNode에 대한 확인을 활성화해 완화할 수 있어요. 읽기와 쓰기에 대한 확인을 별도로 활성화할 수 있는데, dfs.namenode.avoid.read.stale.datanode와 dfs.namenode.avoid.write.stale.datanode 설정으로요. 오래된 DataNode는 dfs.namenode.stale.datanode.interval(기본 30초) 동안 연결할 수 없었던 것입니다. 오래된 datanode는 피하고 읽기 또는 쓰기 연산의 마지막 가능한 대상으로 표시돼요. 구성 세부사항은 HDFS 문서를 참고하세요.

HDFS 재시도와 타임아웃에 대한 설정은 HBase에 중요하다.

다양한 재시도와 타임아웃에 대한 설정을 구성할 수 있어요. 항상 현재 권장 사항과 기본값은 HDFS 문서를 참조하세요. HBase에 중요한 일부 설정이 여기 나열돼 있어요. 기본값은 Hadoop 2.3 기준 최신이에요. 가장 최신 값과 권장 사항은 Hadoop 문서를 확인하세요.

HBase Balancer와 HDFS Balancer는 호환되지 않는다.

HDFS balancer는 HDFS 블록을 DataNode 간에 고르게 분산하려 해요. HBase는 region split이나 장애 후 지역성을 복원하기 위해 컴팩션에 의존해요. 이 두 유형의 밸런싱은 서로 잘 동작하지 않아요.

과거에 일반적으로 받아들여진 조언은 HDFS 로드 밸런서를 끄고 HBase balancer에 의존하는 것이었어요. HDFS balancer가 지역성을 저하시킬 것이기 때문이에요. 이 조언은 HDFS 버전이 2.7.1보다 낮다면 여전히 유효해요.

HDFS-6133은 HDFS 서비스 구성에서 dfs.datanode.block-pinning.enabled 프로퍼티를 true로 설정해 즐겨찾기 노드(favored-nodes, pinned) 블록을 HDFS 로드 밸런서에서 제외할 수 있는 능력을 제공해요.

HBase balancer 클래스(conf: hbase.master.loadbalancer.class)를 여기에 문서화된 org.apache.hadoop.hbase.favored.FavoredNodeLoadBalancer로 전환해 HBase가 HDFS favored-nodes 기능을 사용하도록 활성화할 수 있어요.

HDFS-6133은 HDFS 2.7.0 이상에서 사용할 수 있지만, HBase는 HDFS 2.7.0에서 실행하는 것을 지원하지 않으므로, 이 기능을 HBase와 함께 사용하려면 HDFS 2.7.1 이상을 사용해야 해요.

연결 타임아웃

연결 타임아웃은 클라이언트(HBASE)와 HDFS DataNode 사이에서 발생해요. 연결을 설정할 때, 읽기를 시도할 때, 또는 쓰기를 시도할 때 발생할 수 있어요. 아래 두 설정은 함께 사용되며 DFSClient와 DataNode, ipc.cClient와 DataNode 사이의 연결, 그리고 두 DataNode 사이의 통신에 영향을 줘요.

dfs.client.socket-timeout (기본: 60000)

연결을 설정하거나 읽을 때 클라이언트 연결이 타임아웃되기까지의 시간. 값은 밀리초로 표현되므로 기본은 60초예요.

dfs.datanode.socket.write.timeout (기본: 480000)

쓰기 연산이 타임아웃되기까지의 시간. 기본은 8분이며 밀리초로 표현돼요.

전형적인 오류 로그

다음 유형의 오류가 로그에서 자주 보여요.

INFO HDFS.DFSClient: Failed to connect to /xxx50010, add to deadNodes and continue java.net.SocketTimeoutException: 60000 millis timeout while waiting for channel to be ready for connect. ch : java.nio.channels.SocketChannel[connection-pending remote=/region-server-1:50010]:: 블록에 대한 모든 DataNode가 죽었고 복구가 불가능해요. 이 오류로 이어지는 이벤트 시퀀스는 다음과 같아요.

INFO org.apache.hadoop.HDFS.DFSClient: Exception in createBlockOutputStream java.net.SocketTimeoutException: 69000 millis timeout while waiting for channel to be ready for connect. ch : java.nio.channels.SocketChannel[connection-pending remote=/ xxx:50010]:: 이 유형의 오류는 쓰기 문제를 나타내요. 이 경우 master가 로그를 분할하려 해요. 로컬 DataNode가 없어서 원격 DataNode에 연결하려 하지만 DataNode가 죽었어요.

단위 또는 통합 테스트 실행

테스트 실행 시 MiniDFSCluster의 런타임 예외

다음 같은 것이 보이면

...
java.lang.NullPointerException: null
at org.apache.hadoop.hdfs.MiniDFSCluster.startDataNodes
at org.apache.hadoop.hdfs.MiniDFSCluster.<init>
at org.apache.hadoop.hbase.MiniHBaseCluster.<init>
at org.apache.hadoop.hbase.HBaseTestingUtility.startMiniDFSCluster
at org.apache.hadoop.hbase.HBaseTestingUtility.startMiniCluster
...

또는

...
java.io.IOException: Shutting down
at org.apache.hadoop.hbase.MiniHBaseCluster.init
at org.apache.hadoop.hbase.MiniHBaseCluster.<init>
at org.apache.hadoop.hbase.MiniHBaseCluster.<init>
at org.apache.hadoop.hbase.HBaseTestingUtility.startMiniHBaseCluster
at org.apache.hadoop.hbase.HBaseTestingUtility.startMiniCluster
...

... 테스트를 시작하기 전에 umask 022 명령을 시도하세요. 이것은 HDFS-2556에 대한 해결책이에요.

사례 연구

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

암호화 기능

sun.security.pkcs11.wrapper.PKCS11Exception: CKR_ARGUMENTS_BAD

이 문제는 궁극적으로 다음에 의해 발생하는 예외로 나타나요.

Caused by: sun.security.pkcs11.wrapper.PKCS11Exception: CKR_ARGUMENTS_BAD
  at sun.security.pkcs11.wrapper.PKCS11.C_DecryptUpdate(Native Method)
  at sun.security.pkcs11.P11Cipher.implDoFinal(P11Cipher.java:795)

이 문제는 일부 Linux 공급업체가 배포하는 OpenJDK 7의 일부 버전에 영향을 주는 것으로 보여요. NSS가 기본 제공자로 구성돼 있어요. 호스트가 x86_64 아키텍처라면, 공급업체 패키지가 결함을 포함하는지에 따라 NSS 제공자가 올바르게 동작하지 않을 거예요.

이 문제를 해결하려면 JRE 홈 디렉터리를 찾아 lib/security/java.security 파일을 편집하세요. 파일을 편집해 다음 줄을 주석 처리하세요.

security.provider.1=sun.security.pkcs11.SunPKCS11 ${java.home}/lib/security/nss.cfg

그런 다음 나머지 제공자를 그에 맞게 다시 번호를 매기세요.

운영체제 특정 문제

페이지 할당 실패

이 이슈는 CentOS 6.2 및 아마 CentOS 6.5에 영향을 주는 것으로 알려져 있어요. https://bugzilla.redhat.com/show_bug.cgi?id=770545에 따르면 Red Hat Enterprise Linux의 일부 버전에도 영향을 줄 수 있어요.

일부 사용자가 다음 오류를 보았다고 보고했어요.

kernel: java: page allocation failure. order:4, mode:0x20

min_free_kbytes 값을 높이면 이 문제를 고칠 수 있다고 보고됐어요. 이 파라미터는 시스템의 RAM 양의 백분율로 설정되며 https://docs.kernel.org/admin-guide/sysctl/vm.html#min-free-kbytes에 더 자세히 설명돼 있어요.

시스템의 현재 값을 찾으려면 다음 명령을 실행하세요.

[user@host]# cat /proc/sys/vm/min_free_kbytes

다음으로 값을 높이세요. 값을 두 배, 그다음 네 배로 시도해 보세요. 값이 너무 낮거나 너무 높으면 시스템에 해로운 영향을 줄 수 있다는 점에 유의하세요. 구체적인 권장 사항은 운영체제 공급업체에 문의하세요.

다음 명령으로 min_free_kbytes 값을 수정하세요. VALUE를 의도한 값으로 대체:

[user@host]# echo <value> > /proc/sys/vm/min_free_kbytes

JDK 문제

NoSuchMethodError: java.util.concurrent.ConcurrentHashMap.keySet

로그에서 이게 보이면:

Caused by: java.lang.NoSuchMethodError: java.util.concurrent.ConcurrentHashMap.keySet()Ljava/util/concurrent/ConcurrentHashMap$KeySetView;
  at org.apache.hadoop.hbase.master.ServerManager.findServerWithSameHostnamePortWithLock(ServerManager.java:393)
  at org.apache.hadoop.hbase.master.ServerManager.checkAndRecordNewServer(ServerManager.java:307)
  at org.apache.hadoop.hbase.master.ServerManager.regionServerStartup(ServerManager.java:244)
  at org.apache.hadoop.hbase.master.MasterRpcServices.regionServerStartup(MasterRpcServices.java:304)
  at org.apache.hadoop.hbase.protobuf.generated.RegionServerStatusProtos$RegionServerStatusService$2.callBlockingMethod(RegionServerStatusProtos.java:7910)
  at org.apache.hadoop.hbase.ipc.RpcServer.call(RpcServer.java:2020)
  ... 4 more

jdk8로 컴파일하고 jdk7에서 실행하려 했는지 확인하세요. 그렇다면 이건 동작하지 않아요. jdk8에서 실행하거나 jdk7로 재컴파일하세요. HBASE-10607 JDK8 NoSuchMethodError involving ConcurrentHashMap.keySet if running on JRE 7을 참고하세요.

G1 사용 시 mslab으로 인한 full gc

mslab이 사용하는 chunk의 기본 크기는 2MB예요. G1을 사용할 때 heapRegionSize가 4MB라면 이 chunk들은 humongous 객체로 할당되어 한 region을 독점 할당하고, 나머지 2MB는 메모리 조각이 돼요.

사용된 힙 비율이 충분히 높지 않아도 많은 메모리 조각이 full gc로 이어질 수 있어요.

G1HeapRegionSize는 initial_heap_size와 max_heap_size로 계산돼요. 더 잘 이해하기 위한 몇 가지 경우가 있어요.

  • xmx=10G -> region size 2M
  • xms=10G, xmx=10G -> region size 4M
  • xmx=20G -> region size 4M
  • xms=20G, xmx=20G -> region size 8M
  • xmx=30G -> region size 4M
  • xmx=32G -> region size 8M

아래와 같이 chunk 크기를 2047KB로 약간 줄이면 이 문제를 피할 수 있어요.

hbase.hregion.memstore.mslab.chunksize 2096128

더 알아보기 (Learn more)