9.4 ChunkServer实现机制
ChunkServer用于存储基线数据,它由如下基本部分组成:
●管理子表,主动实现子表分裂,配合RootServer实现子表迁移、删除、合并;
●SSTable,根据主键有序存储每个子表的基线数据;
●基于LRU实现块缓存(Block cache)以及行缓存(Row cache);
●实现Direct IO,磁盘IO与CPU计算并行化;
●通过定期合并&数据分发获取UpdateServer的冻结数据,从而分散到整个集群。
每台ChunkServer服务着几千到几万个子表的基线数据,每个子表由若干个SSTable组成(一般为1个)。下面从SSTable开始介绍ChunkServer的内部实现。
9.4.1 子表管理
每台ChunkServer服务于多个子表,子表的个数一般在10000~100000之间。Chunk-Server内部通过ObMultiVersionTabletImage来存储每个子表的索引信息,包括数据行数(row_count),数据量(occupy_size),校验和(check_sum),包含的SSTable列表,所在磁盘编号(disk_no)等,代码如下:
class ObMultiVersionTabletImage
{
public:
//获取第一个包含指定数据范围的子表
//@param[in]range数据范围
//@param[in]scan_direction正向扫描(默认)还是逆向扫描
//@param[in]version子表的版本号
//@param[out]tablet获取的子表索引结构
int acquire_tablet(const ObNewRange&range,const ScanDirection scan_direction,const int64_t version,ObTablet*&tablet)const;
//释放一个子表
int release_tablet(ObTablet*tablet);
//新增一个子表,load_sstable表示是否立即加载其中的SSTable文件
int add_tablet(ObTablet*tablet,const bool load_sstable=false);
//每日合并后升级子表到新版本,load_sstable表示是否立即加载新版本的SSTable文件
int upgrade_tablet(ObTabletold_tablet,ObTabletnew_tablet,const bool load_sstable=false);
//每日合并后升级子表到新版本,且子表发生分裂,有一个变成多个。load_sstable表示是否立即加载分裂后的SSTable文件
int upgrade_tablet(ObTabletold_tablet,ObTabletnew_tablets[],const int32_t split_size,const bool load_sstable=false);
//删除一个指定数据范围和版本的子表
int remove_tablet(const ObNewRange&range,const int64_t version);
//删除一个表格对应的所有子表
int delete_table(const uint64_t table_id);
//获取下一批需要进行每日合并的子表
//@param[in]version子表的版本号
//@param[out]size下一批需要进行每日合并的子表个数
//@param[out]tablets下一批需要进行每日合并的子表索引结构
int get_tablets_for_merge(const int64_t version,int64_t&size,ObTablet*&tablets[])const;
};
ChunkServer维护了多个版本的子表数据,每日合并后升级子表的版本号。如果子表发生分裂,每日合并后将由一个子表变成多个子表。子表相关的操作方法包括:
1)add_tablet:新增一个子表。如果load_sstable参数为true,那么,立即加载其中的SSTable文件。否则,使用延迟加载策略,即读取子表时再加载其中的SSTable。
2)remove_tablet:删除一个子表。RootServer发现某个子表的副本数过多,则会通知其中某台ChunkServer删除指定的子表。
3)delete_table:删除表格。用户执行删除表格命令时,RootServer会通知每台ChunkServer删除表格包含的所有子表。
4)upgrade_tablet:每日合并后升级子表的版本号。如果没有发生分裂,只需要将老子表的版本号加1;否则,将老子表替换为多个范围连续的新子表,每个新子表的版本号均为老子表的版本号加1。
5)acquire_tablet/release_tablet:读取时首先调用acquire_tablet获取一个子表,增加该子表的引用计数从而防止它在读取过程中被释放掉,接着读取其中的SSTable,最后调用release_tablet释放子表。
6)get_tablets_for_merge:每日合并时通过调用该函数获取下一批需要进行每日合并的子表。