AMv2 개발자 설명
AMv2 개발자 설명 (AMv2 Description for Devs)
AMv2(AssignmentManager Version 2)는 HBase 할당(Assignment) 시스템을 ProcedureV2 기반으로 재설계한 것이에요. 느린 할당과 region이 RIT(Regions-In-Transition)에 갇히는 문제의 근본 원인을 해결하려는 목표로, 모든 할당·충돌 처리·분할·병합을 Procedure로 재구성해요.
출처: 문서
본문
AMv2 프로젝트는 Assignment를 재작성한 것으로, 운영에서 겪는 많은 문제의 근본 원인, 즉 느린 할당과 region이 악명 높은 RIT(Regions-In-Transition) 림보 상태에서 잘못 배치되어 오프라인으로 갇히는 문제를 해결하려는 시도예요.
다음은 AMv2의 핵심 측면에 대한 개발자용 메모로, 특별한 순서는 없어요.
배경 (Background)
HBase 1.x의 할당은 운영에 문제가 많았어요. 이유를 보기 어렵지 않아요. region 상태는 RPC 너머 ZooKeeper에 보관돼요(최종 상태 — 즉 OPEN 또는 CLOSED — 는 hbase:meta 테이블에 게시돼요). HBase-1.x.x에서 상태는 Master와 RegionServer 모두가 동시에 상태 편집을 할 수 있는(Master와 RegionServer가 hbase:meta 테이블과 ZooKeeper에 모두) 다중 작성자를 가져요. 시계가 어긋나거나 watcher를 놓치면 상태 변경이 건너뛰거나 덮어쓸 수 있어요. HBase 엔티티 — 테이블, region — 의 잠금은 포괄적이지 않아서 테이블 연산(disable/enable)이 region 수준 연산(분할 또는 병합)과 충돌할 수 있어요. region 상태는 분산되어 있어 추론하고 테스트하기 어려워요. 할당은 각 할당이 원격 znode를 전환을 통해 이동시키기 때문에 운영상 느려요. 클러스터 크기는 수십만 region에서 정체되기 쉬우며, 그 이상에서는 클러스터 시작/종료가 몇 시간이 걸리고 손상되기 쉬워요.
AMv2(AssignmentManager Version 2)는 hbase-1.x AssignmentManager를 ProcedureV2(HBASE-12439) 기반 위에 올린 리팩토링(HBASE-14350)이에요. ProcedureV2(Pv2)는 다단계 상태 머신을 기술하고 실행할 수 있게 해주는, 이름이 어색한 시스템이에요. 성능이 좋고 모든 상태를 크래시 후 복구 가능한 Store에 영속화해요. ProcedureV2 시스템에 대해 더 배우려면 동반 챕터인 Procedure Framework (Pv2)를 참고해 주세요.
AMv2에서 모든 할당, 충돌 처리, 분할, 병합이 Procedure(v2)로 재구성돼요. ZooKeeper는 혼합에서 제거돼요. 이전과 마찬가지로 최종 할당 상태는 비-Master 참여자(모든 클라이언트)가 읽도록 hbase:meta에 게시되며, 중간 상태는 로컬 Pv2 WAL 기반 'store'에 보관되지만 활성 Master, 단일 작성자만 상태를 진화시켜요. Master의 인메모리 클러스터 이미지가 권위이며, 불일치가 있으면 RegionServer가 따르도록 강제돼요. Pv2는 모든 핵심 HBase 엔티티 — namespace, 테이블, region — 에 공유/배타 잠금을 추가해 한 번에 한 행위자가 접근하게 하고 연산이 리소스를 두고 경쟁하는 것(move/split, disable/assign 등)을 방지해요.
전용되고 성능이 좋은 상태 머신 위에서 모든 연산이 공통 Procedure 형태를 취하고 단일 상태 작성자만 있는 AM 재설계는 우리 AM을 새로운 수준의 복원력과 규모로 끌어올려요.
새 시스템 (New System)
각 region의 Assign 또는 Unassign은 이제 Procedure예요. Move(Region) Procedure는 Procedure의 복합체로, Unassign Procedure 다음에 Assign Procedure가 실행되는 것이에요. Move Procedure는 Assign과 Unassign을 직렬로 생성한 다음 그 완료를 기다려요.
그리고 그런 식으로 이어져요. ServerCrashProcedure는 WAL 분할 작업을 생성하고, 이어서 충돌한 서버에서 호스팅되던 모든 region의 재할당을 하위 프로시저(subprocedure)로 생성해요.
AMv2 프로시저는 Master의 ProcedureExecutor 인스턴스에서 실행돼요. 모든 프로시저는 Pv2 프레임워크가 제공하는 유틸리티를 사용해요.
예를 들어, 프로시저는 각 상태 전환을 프레임워크의 Procedure Store에 영속화해요. 기본 구현은 HDFS에 보관되는 WAL로 수행돼요. 크래시 시 Store를 다시 열고 할당 상태 머신을 크래시 직전의 상태로 되돌리기 위해 Procedure 전환의 모든 WAL을 다시 실행해요. 그런 다음 Procedure 실행을 계속해요.
새 시스템에서 Master는 할당에 관한 모든 것의 권위자예요. 이전에는 모호했어요; 예를 들어 RegionServer가 Split 연산을 담당했어요. Master는 region 상태와 서버의 인메모리 이미지를 유지해요. 불일치가 있으면 Master가 항상 우세하며, 극단에서는 불일치하는 RegionServer를 종료시킬 거예요.
새 RegionStateStore 클래스가 최종 region 상태(OPEN 또는 CLOSED든)를 hbase:meta 테이블에 게시하는 역할을 담당해요.
RegionServer는 이제 Connection에서 자신의 실행 버전을 보고해요. 이 버전은 rolling restart 마이그레이션을 실행할 때 AM 내부에서 사용할 수 있어요.
프로시저 상세 (Procedures Detail)
Assign/Unassign
Assign과 Unassign은 공통 RegionTransitionProcedure를 상속해요. RTP 인스턴스가 region에 잠금을 걸기 때문에 한 번에 region당 하나의 RegionTransitionProcedure만 실행될 수 있어요. RTP 기본 Procedure에는 세 단계가 있어요; 프로시저를 저장하는 단계(REGION_TRANSITION_QUEUE); 원격 regionserver가 성공적인 open을 보고하거나 실패할 때까지 대기하는 프로시저 open 또는 close의 전달 후 일시정지(REGION_TRANSITION_DISPATCH) 또는 요청을 처리하는 서버가 크래시했음을 알리는 알림; 그리고 마지막으로 성공적인 open/close를 hbase:meta에 등록하는 단계(REGION_TRANSITION_FINISH)예요.
여기 region 56f985a727afe80a184dac75fbf6860c의 할당이 로그에서 어떻게 보이는지 보여줘요. 이 할당은 Server Crash(프로세스 ID 1176 또는 pid=1176, 프로시저의 부모일 때 ppid=1176으로 식별됨)에 의해 촉발되었어요. 할당은 pid=1179이며, 이 Server Crash가 할당하는 두 번째 region이에요.
2017-05-23 12:04:24,175 INFO [ProcExecWrkr-30] procedure2.ProcedureExecutor: Initialized subprocedures=[{pid=1178, ppid=1176, state=RUNNABLE:REGION_TRANSITION_QUEUE; AssignProcedure table=IntegrationTestBigLinkedList, region=bfd57f0b72fd3ca77e9d3c5e3ae48d76, target=ve0540.halxg.example.org,16020,1495525111232}, {pid=1179, ppid=1176, state=RUNNABLE:REGION_TRANSITION_QUEUE; AssignProcedure table=IntegrationTestBigLinkedList, region=56f985a727afe80a184dac75fbf6860c, target=ve0540.halxg.example.org,16020,1495525111232}]
다음으로 프레임워크에 프로시저를 큐에 넣어('등록') 할당을 시작해요.
2017-05-23 12:04:24,241 INFO [ProcExecWrkr-30] assignment.AssignProcedure: Start pid=1179, ppid=1176, state=RUNNABLE:REGION_TRANSITION_QUEUE; AssignProcedure table=IntegrationTestBigLinkedList, region=56f985a727afe80a184dac75fbf6860c, target=ve0540.halxg.example.org,16020,1495525111232; rit=OFFLINE, location=ve0540.halxg.example.org,16020,1495525111232; forceNewPlan=false, retain=false
프로시저의 프로세스 id(여기서는 pid=1179)를 추적해 로그에서 프로시저 실행을 추적해 주세요.
다음으로 전달(dispatch) 단계로 이동해 hbase:meta 테이블을 갱신해 region 상태를 server ve540에서 OPENING으로 설정해요. 그런 다음 ve540에 region을 열도록 요청하는 rpc를 전달해요. 이후 ve540에서 region을 성공적으로 열었는지(아닌지) 메시지를 받을 때까지 Assign을 일시정지해요.
2017-05-23 12:04:24,494 INFO [ProcExecWrkr-38] assignment.RegionStateStore: pid=1179 updating hbase:meta row=IntegrationTestBigLinkedList,H\xE3@\x8D\x964\x9D\xDF\x8F@9\x0F\xC8\xCC\xC2,1495566261066.56f985a727afe80a184dac75fbf6860c., regionState=OPENING, regionLocation=ve0540.halxg.example.org,16020,1495525111232
2017-05-23 12:04:24,498 INFO [ProcExecWrkr-38] assignment.RegionTransitionProcedure: Dispatch pid=1179, ppid=1176, state=RUNNABLE:REGION_TRANSITION_DISPATCH; AssignProcedure table=IntegrationTestBigLinkedList, region=56f985a727afe80a184dac75fbf6860c, target=ve0540.halxg.example.org,16020,1495525111232; rit=OPENING, location=ve0540.halxg.example.org,16020,1495525111232
아래는 region이 ve540에서 성공적으로 열렸다는 수신 보고를 기록한 내용이에요. 프로시저가 깨어나요(스레드 이름, ProcedureExecutor 스레드인 ProcExecWrkr-9로 프로시저가 실행 중임을 알 수 있어요). 깨어난 프로시저는 hbase:meta의 상태를 갱신해 region이 ve0540에서 열렸음을 나타내요. 그런 다음 완료를 보고하고 종료해요.
2017-05-23 12:04:26,643 DEBUG [RpcServer.default.FPBQ.Fifo.handler=46,queue=1,port=16000] assignment.RegionTransitionProcedure: Received report OPENED seqId=11984985, pid=1179, ppid=1176, state=RUNNABLE:REGION_TRANSITION_DISPATCH; AssignProcedure table=IntegrationTestBigLinkedList, region=56f985a727afe80a184dac75fbf6860c, target=ve0540.halxg.example.org,16020,1495525111232; rit=OPENING, location=ve0540.halxg.example.org,16020,1495525111232
2017-05-23 12:04:26,643 INFO [ProcExecWrkr-9] assignment.RegionStateStore: pid=1179 updating hbase:meta row=IntegrationTestBigLinkedList,H\xE3@\x8D\x964\x9D\xDF\x8F@9\x0F\xC8\xCC\xC2,1495566261066.56f985a727afe80a184dac75fbf6860c., regionState=OPEN, openSeqNum=11984985, regionLocation=ve0540.halxg.example.org,16020,1495525111232
2017-05-23 12:04:26,836 INFO [ProcExecWrkr-9] procedure2.ProcedureExecutor: Finish suprocedure pid=1179, ppid=1176, state=SUCCESS; AssignProcedure table=IntegrationTestBigLinkedList, region=56f985a727afe80a184dac75fbf6860c, target=ve0540.halxg.example.org,16020,1495525111232
Unassign은 기본 RegionTransitionProcedure를 기반으로 하므로 비슷해 보여요. 동일한 상태 전환을 가지며 기본적으로 같은 단계를 수행하지만 다른 상태 이름(CLOSING, CLOSED)을 사용해요.
대부분의 다른 프로시저는 Pv2 StateMachine 구현의 하위 클래스예요. Table 중심과 Region 중심 StateMachine 유형이 모두 있어요.
UI
Master 상단 바에서 이제 'Procedures&Locks' 탭을 찾을 수 있어요. 이 탭은 못생겼지만 유용한 페이지로 안내해요. 현재 실행 중인 프로시저와 프레임워크 잠금을 덤프해요. 무엇이 갇혔는지 알 수 없을 때 이것을 보세요; 적어도 문제가 있는 프로시저를 식별할 거예요(pid를 가져와 로그를 grep해 보세요...). ROLLEDBACK 또는 오랫동안 RUNNING 상태인 pid를 찾아보세요.
로깅 (Logging)
프로시저는 프로세스 id를 pid=로, 부모 id를 ppid=로 어디서나 기록해요. pid를 grep하고 프로시저 연산의 이력을 볼 수 있도록 작업이 완료되어 있어요.
구현 메모 (Implementation Notes)
이 섹션에서는 머리를 긁게 될 수 있는 시도를 줄이기 위해 운영의 몇 가지 특성을 기록해요.
Region 전환 RPC와 RS 하트비트가 Master에 거의 동시에 도착할 수 있음
RegionServer의 Region 전환 보고는 이제 RS 하트비팅('RegionServerServices' Service)과 구별되는 RPC예요. 하트비트와 상태 갱신이 Master에 거의 동시에 도착할 수 있어요. Master는 region에 대한 내부 상태를 갱신하지만, 이 동일한 상태는 하트비트 처리 시 확인돼요. 예상치 못한 것을 발견할 수 있어요; 즉, region이 방금 CLOSED로 보고됐는데 하트비트는 RS 보고에 이어 region이 OPEN인 것을 발견해 놀라는 경우예요. 새 시스템에서 모든 하위는 Master의 클러스터 상태 이해에 따르도록 강제되며, Master는 정렬되지 않은 엔티티를 종료/닫을 거예요.
위를 해결하기 위해 인메모리 Master 상태에 lastUpdate를 추가했어요. 행동하기 전에 region 상태가 어느 정도 숙성(vintage)되도록 해요(현재 1초).
Master를 RegionServer로 또는 시스템 테이블만 하는 RegionServer로
AMv2는 현재 master 브랜치 기본값인 HMaster가 시스템 테이블만 보유하는 것을 강제해요; 즉, HBase 클러스터의 Master는 RegionServer 역할도 하지만 hbase:meta, hbase:namespace 등 핵심 시스템 테이블의 독점 호스트예요. 이로 인해 몇 가지 테스트 실패가 발생하는데, AMv1은 (그렇게 하지 말아야 하지만) hbase:meta를 Master에서 옮기는 것을 허용하는 반면 AMv2는 그렇지 않기 때문이에요.
새 구성 (New Configs)
이 구성들은 언제 바꿔야 하는지 문서화가 필요해요.
hbase.procedure.remote.dispatcher.threadpool.size
기본값 128
hbase.procedure.remote.dispatcher.delay.msec
기본값 150ms
hbase.procedure.remote.dispatcher.max.queue.size
기본값 32
hbase.regionserver.rpc.startup.waittime
기본값 60초
도구 (Tools)
HBASE-15592 Print Procedure WAL Content
HBASE-18152의 패치 [AMv2] Corrupt Procedure WAL file; procedure data stored out of order https://issues.apache.org/jira/secure/attachment/12871066/reading_bad_wal.patch
MasterProcedureSchedulerPerformanceEvaluation
다른 프레임워크 구성 요소와 독립적으로 procedure scheduler에서 잠금과 큐의 성능을 테스트하는 도구예요. proc 시스템에 실질적인 변경 후에 실행해 주세요. 멋진 출력을 출력해요:
******************************************
Time - addBack : 5.0600sec
Ops/sec - addBack : 1.9M
Time - poll : 19.4590sec
Ops/sec - poll : 501.9K
Num Operations : 10000000
Completed : 10000006
Yield : 22025876
Num Tables : 5
Regions per table : 10
Operations type : both
Threads : 10
******************************************
Raw format for scripts
RESULT [num_ops=10000000, ops_type=both, num_table=5, regions_per_table=10, threads=10, num_yield=22025876, time_addback_ms=5060, time_poll_ms=19459]
더 알아보기 (Learn more)
Procedure Framework (Pv2), Assignment, Regions 등 HBase 마스터와 할당 관련 문서를 이어서 보시길 권해요.