En entornos de producción, es posible encontrarse con regiones permanentemente en estado RIT (Region In Transition) al intentar fusionarlas. Un escenario común es que las regiones queden bloqueadas en el estado MERGING_NEW. Aunque esta condición no afecta directamente al servicio existente, impide que el balanceo de carga se ejecute correctamente. Si un RegionServer se reinicia durante este periodo, las regiones alojadas en él no se redistribuirán, ya que HBase deshabilita el balanceo mientras haya regiones en RIT. El comando manual balancer tampoco tendrá efecto.
Si esta situación no se corrige, reinicios posteriores de nodos pueden desencadenar un desequilibrio crítico en la distribución de regiones, degradando significativamente el rendimiento del clúster. La investigación en el sistema de seguimiento de incidencias de HBase revela que este comportamiento se debe al bug HBASE-17682. La causa raíz se encuentra en la lógica de código que no maneja adecuadamente el estado MERGING_NEW, permitiendo que el flujo de ejecución caiga en una rama no prevista.
Código original con el problema:
for (RegionState regState : transitionMap.values()) {
RegionInfo info = regState.getRegion();
if (activeRegions.contains(info)) {
log.info("Transición {} será gestionada por el procedimiento de recuperación del servidor para {}", regState, serverName);
} else if (serverName.equals(regState.getServerName())) {
if (regState.isPendingOpen() || regState.isOpenOrOpeningFailed() || regState.isOffline()) {
log.info("Región encontrada en {} para reasignación mediante procedimiento de recuperación del servidor para {}", regState, serverName);
rits.add(info);
} else if (regState.isNewForSplit()) {
cleanableRegions.add(regState.getRegion());
} else {
log.warn("ESTADO INESPERADO: {}", regState);
}
}
}
Código corregido con la solución aplicada:
for (RegionState regState : transitionMap.values()) {
RegionInfo info = regState.getRegion();
if (activeRegions.contains(info)) {
log.info("Transición {} será gestionada por el procedimiento de recuperación del servidor para {}", regState, serverName);
} else if (serverName.equals(regState.getServerName())) {
if (regState.isPendingOpen() || regState.isOpenOrOpeningFailed() || regState.isOffline()) {
log.info("Región encontrada en {} para reasignación mediante procedimiento de recuperación del servidor para {}", regState, serverName);
rits.add(info);
} else if (regState.isNewForSplit() || regState.isNewForMerge()) {
cleanableRegions.add(regState.getRegion());
} else {
log.warn("ESTADO INESPERADO: {}", regState);
}
}
}
No obstante, aplicar este parche en un clúster de producción activo puede no ser factible inmediatamente. Se requiere una solución temporal para desbloquear el RIT permanente sin causar interrupciones prolongadas. El análisis del flujo de fusión de regiones muestra que MERGING_NEW es un estado inicial que reside únicamente en la memoria del Master activo. Los Masters en estado de reserva no poseen esta información.
La solución temporal consiste en provocar un conmutación (failover) del Master de HBase. Dado que HBase está diseñado para alta disponibilidad, esta operación es transparente para las aplicaciones cliente. Tras la conmutación, el nuevo Master activo no tendrá conocimiento de los estados MERGING_NEW huérfanos, permitiendo que el sistema se recupere. Este procedimiento sirve como medida correctiva inmediata, posterior a la cual se debe planificar la aplicación del parche definitivo y la actualización de versión del clúster.