Garbage Collection缩写GC,简称垃圾回收。在RGW中GC一般都是指一些异步的磁盘空间回收操作,一般下面三种情况会发生GC。 1. 客户端执行删除Object操作,对应的Object所占用的磁盘空间会交由后台GC处理。 2. 客户端执行Object覆盖写入操作,旧Object相关的空间需要释放。 3. 客户端执行上传操作(分块上传),上传过程中会产生一些shadow文件,这些上传过程中产生的临时数据也会纳入GC的回收。
GC是以thread方式在rgw服务启动时候进行启动,对应的启动调用流程如下。
每个GCworker启动的时候都会有一个数字ID标识,这个ID其实就是对应到gc pool里面的Object的ID名称,GC的任务列表就存储在每个gc pool里面对应的Object的omap中,如果gc队列发生爆炸式增长或是拥塞,那么这个omap体积也会爆炸式增长,在底层做scrub的时候会极大消耗磁盘的性能,同时还可能会引发客户端请求发生阻塞而出现504错误最终影响服务可用性。值得注意的是GCworker启动时的ID是通过一个随机算法选择的,如果已经有相同ID的其他GCworker正在运行,则获取锁失败,要重新运行随机选择算法。GCworekr启动的流程如下
GCworker的随机选择算法如下,其中max_objs表示gc worker总数。
int RGWGC::process()
{
int max_secs = cct->_conf->rgw_gc_processor_max_time;
unsigned start;
int ret = get_random_bytes((char *)&start, sizeof(start));
if (ret < 0)
return ret;
for (int i = 0; i < max_objs; i++) {
int index = (i + start) % max_objs;
ret = process(index, max_secs);
if (ret < 0)
return ret;
}
return 0;
}
需要回收的Object在达到指定条件后会丢进对应的gc队列,进行处理,如下图所示
gc 队列的数据结构如下,每个china通过唯一的的tag名称进行标识。
需要注意的是每个gc的记录会生成两种类型的索引记录,0开头的以名称为标识和1开头以时间戳为标识,最终插入到gc Object所在OSD的omap的LevelDB记录中。
/*
* We hold the garbage collection chain data under two different indexes: the first 'name' index
* keeps them under a unique tag that represents the chains, and a second 'time' index keeps
* them by their expiration timestamp
*/
#define GC_OBJ_NAME_INDEX 0
#define GC_OBJ_TIME_INDEX 1
static string gc_index_prefixes[] = { "0_",
"1_" };
最后一张图来总结整个GC的过程,其中涉及到几个和GC效率有直接关系的几个参数,大家可以根据各自线上情况去调优。