Skip to content

Region Metadata Management

刘涛 edited this page Jun 12, 2020 · 1 revision

region状态快速查看和恢复设计

一、查看

0x01 instance信息维护

每个实例每隔30s上报,Meta会置实例状态为PB::NORMAL,同时更新时间戳,如果实例3次心跳间隔还未上报心跳状态会被置为PB::FAULTY,超过60次心跳间隔还未上报心跳状态会置为pb::DEAD。

0x02 region信息维护

每一个region都是一个raft-group,正常情况下,region是三副本,设为(A,B,C),A为leader。baikalStore会定期将region信息上报给MetaServer,其中Leader每隔30s上报一次,follower每隔30min上报一次。

Role 上报间隔
Leader:A 30s
Follower:B,C 30min

MeteServer维护了一个_region_state_map记录region的状态(NORMAL or FAULTY)和Leader上报时的系统时间,Leader在3次心跳间隔未成功上报心跳该region状态会被置为FAULTY。只有region的Leader更新_region_state_map。

目前region删除的场景有:

场景 描述
删除表 执行drop table时表对于的region信息也会被删除,meta会根据之前上报的region信息获取所有peers,向这些peer都发删除请求。这里meta记录的信息可能不是最新的(比如刚进行了add_peer),导致region的peer未被删除;如果region刚分裂成功,新分裂出的region还未上报给Meat时也不能被删除。
负载均衡 删除peer的前提是peer数大于表配置的副本数1.修改resource_tag会先在新的resource_tag实例上add_peer然后删除老resource_tag的peer,即resource_tag和表不匹配的peer优先被删除2.保证机房副本分布或实例peer数均衡情况下优先选择多出来的peer进行删除
人工向store发送remove_region指令 人工处理脏region时会这样做,但是一般不需要,在上报peer时会判断peer是否有效
  • 注:上报peer时会判断peer是否有效会判断peer的log_index,如果peer的log_index比meta的大,表明peer数据更新,先不删除
case 描述
节点dead(长时间未上报心跳) 节点长时间不上报心跳,meta认为节点dead,尝试删除region的raft-group中的这个节点的peer,删除条件:1.region满足副本条件(不满足先尝试add_peer) 2.region有leader(leader最近上报过心跳)

0x02 想解决的问题

region的某个peer在遇到实例宕机,或者磁盘满导致peer的raft状态机ERROR,或者被误删除,这种情况下三副本一个副本不可用,导致可用性降低,一旦再有一个副本出问题,raft就选不了主。在迁移时meta只是根据实例状态判断是否可以迁移,可能实例状态是正常的但是region的peer是不可用的(磁盘满导致peer的raft状态ERROR,或者被误删除)。

希望能够:

  1. 快速发现region的peer是否可用,以便及时调整
  2. region删除后有恢复能力

二、恢复

  1. meta维护region每个peer的状态,在Leader进行心跳上报时更新,这些状态作为参考,在负载均衡进行remove_peer时可以作为选择依
  2. region增加一个类似ttl的功能
peer角色 处理
leader leader接收到删除请求后,记录一个标记,将自己设置为raft-group唯一节点(只保留一个副本节省空间),停止上报心跳,等到一个配置的ttl时间才真正删除。要考虑的问题: 1. store重启,要保证记录标记成功,meta处理response
follower 直接删除。要考虑的问题: 1.region之前就没有选出主,[A,B,C]至少有两个不可用,如果此时有一个副本是好的,可以将该副本按Leader流程处理,三副本都不可用的场景先不考虑
总结 可以选择一个健康的副本,将其设置为raft-group唯一节点(只保留一个副本节省空间),停止上报心跳,等到一个配置的ttl时间才真正删除

需要恢复时,meta主动向store发请求,让region重新上报心跳,只要在ttl时间内,这个机制可以保证数据快速恢复。

  1. meta发送删除region的操作用一个队列进行,方便控制

  2. 删除表操作也引入ttl功能

三、设计实现

meta根据region上报的心跳信息维护每个peer的状态在_region_peer_state_map中,为不同的状态定义了如下状态值:

enum PeerStatus {    
      STATUS_NORAML             = 0; // 正常状态    
      STATUS_UNSTABLE           = 1; // add_peer时正在catchup    STATUS_ERROR              = 3; // raft leader连不上peer,一般可能是peer对应实例挂掉,或者peer被误删了    
      STATUS_ILLEGAL_PEER       = 4; // 无效的peer,add_peer false negitive的peer或者set_peer后残留的peer    
      STATUS_NOT_HEARTBEAT      = 5; // region长时间未上报心跳到meta,meta将peer状态设置为STATUS_NOT_HEARTBEAT    
      STATUS_NO_LEADER          = 6; // peer上报meta时如果没有leader时设置    
      STATUS_SET_PEER           = 7; // 在执行OP_RECOVERY_ALL_REGION恢复reigon时表明该region是通过set_peer恢复(说明至少有一个peer存活)    
      STATUS_INITED             = 8; // 在执行OP_RECOVERY_ALL_REGION恢复reigon时表明该region是通过init_region恢复(说明所有peer都没了) 
};

meta为每个region维护一个有效的peer集合和无效的peer集合

struct RegionPeerState {    
		std::map legal_peers_state;  // 有效集合    
		std::map ilegal_peers_state; // 无效集合 
};  
ThreadSafeMap        _region_peer_state_map;

在leader上报心跳时会更新有效集合,在peer上报心跳时如果说自己没有leader那么有效集合和无效集合都可能被更新。

// peer没有leader 
if (peer_info.has_exist_leader() && !peer_info.exist_leader()) {    
    bool legal_peer = check_legal_peer(master_region_info);    
    if (!legal_peer) {        
        new_peer_info.set_peer_status(pb::STATUS_ILLEGAL_PEER);      
        peer_state.ilegal_peers_state[instance] = new_peer_info;    
    } else {       
    		new_peer_info.set_peer_status(pb::STATUS_NO_LEADER);        
    		peer_state.legal_peers_state[instance] = new_peer_info;   
    }    
    _region_peer_state_map.set(region_id, peer_state);
}

1.查询

通过发送QUERY_REGION_PEER_STATUS指令给meta查询peer有问题的region的信息,有问题的peer包括

  1. ilegal_peers_state中所有的peer
  2. legal_peers_state记录的peer状态有问题(region_healthy_check_function函数会定期检查region是否上报心跳,没有及时上报心跳会将peer状态设置为STATUS_NOT_HEARTBEAT) src/tools/script/meta_query_region_peers_status.sh
echo -e "query region peer status\n" 
echo 'param: address' 
curl -d '{  "op_type" : "QUERY_REGION_PEER_STATUS" }' 
http://$1/MetaService/query 

查询目的是查看region peer状态信息,判断region是否有问题,给之后恢复提供帮助,因为meta的信息是定时上报的,所以有滞后,进行恢复时需要更多的信息指导。

2.恢复

通过发送OP_RECOVERY_ALL_REGION指令给meta快速恢复有问题的region,包括两种

  1. 有peer存活的region,向每个peer查询log_index,同时询问是否有leader,没有leader时,选log_index最大的peer通过强制set_peer恢复该region的读写
  2. region的所有peer都未存活,此时根据meta保存的region信息选择一个peer通过init_region来恢复读写
  3. 可以按照resource_tags控制恢复集群 src/tools/script/meta_region_recovery.sh
#!/bin/bash 
echo -e '\n' 
echo -e "bad region recovery" 
curl -d '{    "op_type" : "OP_RECOVERY_ALL_REGION",    "resource_tags" : ["atom", "ocpc"] }' http://$1/MetaService/meta_manager 

恢复之前必做步骤

  1. 检查是否有实例挂掉(机器宕机,进程退出不存在)

  2. 检查实例是否卡住(因为压力过大没有及时上报心跳,磁盘满了)