RGW 的GC深入解析与调优
什么是GC
Garbage Collection缩写GC,简称垃圾回收。在RGW中GC一般都是指一些异步的磁盘空间回收操作,一般下面三种情况会发生GC。 1. 客户端执行删除Object操作,对应的Object所占用的磁盘空间会交由后台GC处理。 2. 客户端执行Object覆盖写入操作,旧Object相关的空间需要释放。 3. 客户端执行上传操作(分块上传),上传过程中会产生一些shadow文件,这些上传过程中产生的临时数据也会纳入GC的回收。
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的过程,其中涉及到几个和GC效率有直接关系的几个参数,大家可以根据各自线上情况去调优。
参数调优的几点心得
- GC worker的数量由rgw_gc_max_objs来控制,设置这个参数的时候要考虑到你线上业务是否会有大量的GC操作,不要盲目调高。
- rgw_gc_processor_max_time控制每次GC任务最多能够执行的时长,要考虑到你底层存储设备的负载情况,高速存储设备可以适当缩小,但是当底层存储设备比较慢并且负载较高的时候,考虑到GC的额外性能消耗,可能就要调大这个时长了。
- rgw_gc_obj_min_wait 这个控制删除数据以后多久以后开始真正的底层数据回收,默认是2小时,如果线上对空间资源利用率比较敏感,可以适当缩短。
- rgw_gc_processor_period 这个控制多久时长以后GCworker开始下一轮的GC操作,如果单次GC需要操作的列表条目数较少,可以适当缩短这个参数。
- JavaScript 教程
- JavaScript 编辑工具
- JavaScript 与HTML
- JavaScript 与Java
- JavaScript 数据结构
- JavaScript 基本数据类型
- JavaScript 特殊数据类型
- JavaScript 运算符
- JavaScript typeof 运算符
- JavaScript 表达式
- JavaScript 类型转换
- JavaScript 基本语法
- JavaScript 注释
- Javascript 基本处理流程
- Javascript 选择结构
- Javascript if 语句
- Javascript if 语句的嵌套
- Javascript switch 语句
- Javascript 循环结构
- Javascript 循环结构实例
- Javascript 跳转语句
- Javascript 控制语句总结
- Javascript 函数介绍
- Javascript 函数的定义
- Javascript 函数调用
- Javascript 几种特殊的函数
- JavaScript 内置函数简介
- Javascript eval() 函数
- Javascript isFinite() 函数
- Javascript isNaN() 函数
- parseInt() 与 parseFloat()
- escape() 与 unescape()
- Javascript 字符串介绍
- Javascript length属性
- javascript 字符串函数
- Javascript 日期对象简介
- Javascript 日期对象用途
- Date 对象属性和方法
- Javascript 数组是什么
- Javascript 创建数组
- Javascript 数组赋值与取值
- Javascript 数组属性和方法
- 轻松学Pytorch –Mask-RCNN图像实例分割
- docker安装awvs13
- 远程连接kail Permission denied或者refused【已解决】
- 设计模式~原始模型模式(二)
- 面向对象的7种设计原则(6)-迪米特原则
- LeetCode 刷题记录 1-5
- 你掉的是这个免费服务器,还是这个 Docker 实验平台
- 我能赢吗
- 最长公共子串/序列问题
- 个性化终端 | zsh bash oh-my-zsh
- VirtualBox无限嵌套方法 | 虚拟机套娃
- Win10 LTSC 激活方法 | Win10专业版(永久激活)长期服务版 LTSC 2019密钥
- Nginx代理以及面向未来的HTTP
- git的基本使用
- 一、玩转Git三剑客-Git基础