1.集群模型图
集群管理节点
---------->RootServer<------------
| /|\ | |
| | | |
| 动态数据暂存节点 | 静态数据节点
| (差异化数据) | (集成了热数据缓存功能)
Client--------->UpdateServer<--|----ChunkServers
| /|\ | /|\
| | | |
---------->MergeServers--- |
查询时整合静态、动态数据 |
|_________________|
2.ChunckServer(Chunck : 数据块)
|
|客户端请求静态数据
______________\|/_______________
|网络处理--------------->任务队列 |
| \ / |
| 接口子系统 |
| / \ |
| / \ |
|Tablet<-----------------每日合并 |
| | _______________/ |
| | / |
|SSTable--------------->Cache |
|________________________________|
3.数据模型
tablet数据(OceanBase将表的数据动态切分为tablet)
|
|--静态部分:存放在chunkserver;
|--动态部分:存放在updateserver,定期同步到chunkserver;(客户端的更新请求<包括新增,修改和删除>都直接访问updateserver)
|
|--元数据:rootserver维护;(客户端在初始化时会请求rootserver,获取updateserver的地址信息)
|
|--数据查询:客户端根据相应的rowkey向rootserver查询其对应的tablet信息,rootserver返回相应的mergeserver地址,
| 然后<请求相应的mergeserver>获取数据;
| |
| |--根据rowkey从rootserver获取相应的tablet信息(包括负责该tablet的chunkserver列表)
| |--请求相应的chunkserver,获取静态数据
| |--请求updateserver获取相应的更新数据
| |--合并静态数据和动态数据,返回给客户端
SSTable(转储的快照文件:负责数据查找和读取)
|
|--包含多个block 及 一个block index(block index由该block负责的数据的最后一个key和该block在SSTable文件中的位置组成)
|--为了提高block的读取性能,chunkserver还将block缓存在内存中
|--Block index和block的cache都采用LRU的策略淘汰
| |
| |-- least recently used;
|--SSTable会建立一些信息来索引数据,比如相关key在SSTable中的偏移,IndexBuilder即用来建立这些信息
4.SSTable索引生成部分源码
int ObSSTableBlockIndexBuilder::add_entry(const uint64_t table_id,
const uint64_t column_group_id,
const ObRowkey &key,
const int32_t record_size) {
//合法性校验略~
//初始化 index_item
ObSSTableBlockIndexItem index_item;
index_item.rowkey_column_count_ = static_cast<int16_t>(key.get_obj_cnt());
index_item.column_group_id_ = static_cast<uint16_t>(column_group_id);
index_item.table_id_ = static_cast<uint32_t>(table_id);
index_item.block_record_size_ = record_size;
index_item.block_end_key_size_ = static_cast<int16_t>(key.get_serialize_objs_size());
index_item.reserved_ = 0;
if (OB_ERROR == index_items_buf_.add_index_item(index_item)){
TBSYS_LOG(WARN, "failed to add index item");
return OB_ERROR;
}
if(OB_ERROR == end_keys_buf_.add_key(key)){
TBSYS_LOG(WARN, "failed to add end key");
return OB_ERROR;
}
index_block_header_.sstable_block_count_++;
return OB_SUCCESS;
}
int ObSSTableBlockIndexBuilder::build_block_index(const bool use_binary_rowkey,
char* index_block,
const int64_t buffer_size,
int64_t& index_size){
//合法性校验略~
int ret ;
int64_t index_block_size = get_index_block_size();
int64_t index_items_size = get_index_items_size();
int64_t header_size = index_block_header_.get_serialize_size();
int64_t pos = 0;
index_block_header_.end_key_char_stream_offset_ = static_cast<int32_t>(header_size + index_items_size);
index_block_header_.rowkey_flag_ = use_binary_rowkey ? 0 : 1;
if (OB_SUCCESS == index_block_header_.serialize(index_block,header_size, pos)){
char* ptr = index_block + pos;
ret = index_items_buf_.get_data(ptr, buffer_size - header_size);
if (OB_SUCCESS == ret){
ptr += index_items_size;
ret = end_keys_buf_.get_data(ptr, buffer_size - header_size - index_items_size);
if (OB_SUCCESS == ret){
index_size = index_block_size;
}
}
}else{
TBSYS_LOG(WARN, "failed to serialize index block header");
ret = OB_ERROR;
}
return ret;
}