尊重原创,引用注明出处。
杨红刚 <[email protected]>
//////////////////////////////////////////////////////////////////
对象删除操作、对象覆盖操作都会产生需要被删除的对象。这些对象由垃圾回收线程进行周期性、批量删除。
配置项 | 描述 | 默认 |
---|---|---|
rgw gc max objs | 垃圾回收进程在一个处理周期内可处理的最大对象数 | 32 |
rgw gc obj min wait | 对象可被删除并由垃圾回收器处理前最少等待多长时间 | 7200s |
rgw gc processor max time | 两个连续的垃圾回收周期起点的最大时间间隔 | 3600 |
rgw gc processor period | 垃圾回收进程的运行周期 | 3600 |
运行时查看gc相关配置:
[root@yhg-2 cmds]# ceph daemon /var/run/ceph/yhg-client.radosgw.yhg-yhg-yhg-2.asok config show | grep _gc_ "rgw_enable_gc_threads": "true", "rgw_gc_max_objs": "32", "rgw_gc_obj_min_wait": "7200", "rgw_gc_processor_max_time": "3600", "rgw_gc_processor_period": "3600",
18 class RGWGC { // 用于访问ceph集群 19 CephContext *cct; 20 RGWRados *store; // rgw gc max objs 21 int max_objs; 22 string *obj_names; // 用于gc控制的各个对象的名字数组 23 atomic_t down_flag; // 指示gc worker退出 24 25 int tag_index(const string& tag); // 形如“yhg-yhg.5457.98” 26 27 class GCWorker : public Thread { 28 CephContext *cct; 29 RGWGC *gc; 30 Mutex lock; 31 Cond cond; 32 33 public: 34 GCWorker(CephContext *_cct, RGWGC *_gc) : cct(_cct), gc(_gc), lock("GCWorker") {} 35 void *entry(); 36 void stop(); 37 }; 38 39 GCWorker *worker; // 控制gc的工作线程
查看系统中的待gc的任务:
[root@yhg-2 cmds]# radosgw-admin gc list --cluster yhg --include-all [ { "tag": "yhg-yhg.5457.98", "time": "2016-04-13 10:25:22.086624", "objs": [ { "pool": "dpool1", "oid": "yhg-yhg.5457.9__shadow_.f06aUKl22Jmey6-vPeZijxeIhFNe4MA_1", "key": "", "instance": "" }, { "pool": "dpool1", "oid": "yhg-yhg.5457.9__shadow_.f06aUKl22Jmey6-vPeZijxeIhFNe4MA_2", "key": "", "instance": "" }, { "pool": "dpool1", "oid": "yhg-yhg.5457.9__shadow_.f06aUKl22Jmey6-vPeZijxeIhFNe4MA_3", "key": "", "instance": "" } ] } ]
Note
gc objs有两类索引,一类是 tag 索引,另一类是time索引。
查看用于gc的pool和对象:
[root@yhg-2 ~]# for ((i=0;i<32;i++)); do echo ">>>"$i;rados -p .rgw.gc listomapkeys gc.$i --cluster yhg; done ... >>>16 0_yhg-yhg.5457.98 <<--------<<<<< tag信息 1_01460543122.086624419 >>>17 ... >>>31 [root@yhg-2 ~]# rados -p .rgw.gc listxattr gc.16 --cluster yhg lock.gc_process // 需要gc调的对象的名字以及所在的pool的信息 [root@yhg-2 ~]# rados -p .rgw.gc listomapvals gc.16 --cluster yhg 0_yhg-yhg.5457.98 value: (499 bytes) : 0000 : 01 01 ed 01 00 00 0f 00 00 00 79 68 67 2d 79 68 : ..........yhg-yh 0010 : 67 2e 35 34 35 37 2e 39 38 01 01 cc 01 00 00 03 : g.5457.98....... 0020 : 00 00 00 02 01 92 00 00 00 06 00 00 00 64 70 6f : .............dpo 0030 : 6f 6c 31 39 00 00 00 79 68 67 2d 79 68 67 2e 35 : ol19...yhg-yhg.5 0040 : 34 35 37 2e 39 5f 5f 73 68 61 64 6f 77 5f 2e 66 : 457.9__shadow_.f 0050 : 30 36 61 55 4b 6c 32 32 4a 6d 65 79 36 2d 76 50 : 06aUKl22Jmey6-vP 0060 : 65 5a 69 6a 78 65 49 68 46 4e 65 34 4d 41 5f 31 : eZijxeIhFNe4MA_1 0070 : 00 00 00 00 01 01 41 00 00 00 39 00 00 00 79 68 : ......A...9...yh 0080 : 67 2d 79 68 67 2e 35 34 35 37 2e 39 5f 5f 73 68 : g-yhg.5457.9__sh 0090 : 61 64 6f 77 5f 2e 66 30 36 61 55 4b 6c 32 32 4a : adow_.f06aUKl22J 00a0 : 6d 65 79 36 2d 76 50 65 5a 69 6a 78 65 49 68 46 : mey6-vPeZijxeIhF 00b0 : 4e 65 34 4d 41 5f 31 00 00 00 00 02 01 92 00 00 : Ne4MA_1......... 00c0 : 00 06 00 00 00 64 70 6f 6f 6c 31 39 00 00 00 79 : .....dpool19...y 00d0 : 68 67 2d 79 68 67 2e 35 34 35 37 2e 39 5f 5f 73 : hg-yhg.5457.9__s 00e0 : 68 61 64 6f 77 5f 2e 66 30 36 61 55 4b 6c 32 32 : hadow_.f06aUKl22 00f0 : 4a 6d 65 79 36 2d 76 50 65 5a 69 6a 78 65 49 68 : Jmey6-vPeZijxeIh 0100 : 46 4e 65 34 4d 41 5f 32 00 00 00 00 01 01 41 00 : FNe4MA_2......A. 0110 : 00 00 39 00 00 00 79 68 67 2d 79 68 67 2e 35 34 : ..9...yhg-yhg.54 0120 : 35 37 2e 39 5f 5f 73 68 61 64 6f 77 5f 2e 66 30 : 57.9__shadow_.f0 0130 : 36 61 55 4b 6c 32 32 4a 6d 65 79 36 2d 76 50 65 : 6aUKl22Jmey6-vPe 0140 : 5a 69 6a 78 65 49 68 46 4e 65 34 4d 41 5f 32 00 : ZijxeIhFNe4MA_2. 0150 : 00 00 00 02 01 92 00 00 00 06 00 00 00 64 70 6f : .............dpo 0160 : 6f 6c 31 39 00 00 00 79 68 67 2d 79 68 67 2e 35 : ol19...yhg-yhg.5 0170 : 34 35 37 2e 39 5f 5f 73 68 61 64 6f 77 5f 2e 66 : 457.9__shadow_.f 0180 : 30 36 61 55 4b 6c 32 32 4a 6d 65 79 36 2d 76 50 : 06aUKl22Jmey6-vP 0190 : 65 5a 69 6a 78 65 49 68 46 4e 65 34 4d 41 5f 33 : eZijxeIhFNe4MA_3 01a0 : 00 00 00 00 01 01 41 00 00 00 39 00 00 00 79 68 : ......A...9...yh 01b0 : 67 2d 79 68 67 2e 35 34 35 37 2e 39 5f 5f 73 68 : g-yhg.5457.9__sh 01c0 : 61 64 6f 77 5f 2e 66 30 36 61 55 4b 6c 32 32 4a : adow_.f06aUKl22J 01d0 : 6d 65 79 36 2d 76 50 65 5a 69 6a 78 65 49 68 46 : mey6-vPeZijxeIhF 01e0 : 4e 65 34 4d 41 5f 33 00 00 00 00 92 1e 0e 57 a3 : Ne4MA_3.......W. 01f0 : c8 29 05 : .). 1_01460543122.086624419 value: (499 bytes) : 0000 : 01 01 ed 01 00 00 0f 00 00 00 79 68 67 2d 79 68 : ..........yhg-yh 0010 : 67 2e 35 34 35 37 2e 39 38 01 01 cc 01 00 00 03 : g.5457.98....... 0020 : 00 00 00 02 01 92 00 00 00 06 00 00 00 64 70 6f : .............dpo 0030 : 6f 6c 31 39 00 00 00 79 68 67 2d 79 68 67 2e 35 : ol19...yhg-yhg.5 0040 : 34 35 37 2e 39 5f 5f 73 68 61 64 6f 77 5f 2e 66 : 457.9__shadow_.f 0050 : 30 36 61 55 4b 6c 32 32 4a 6d 65 79 36 2d 76 50 : 06aUKl22Jmey6-vP 0060 : 65 5a 69 6a 78 65 49 68 46 4e 65 34 4d 41 5f 31 : eZijxeIhFNe4MA_1 0070 : 00 00 00 00 01 01 41 00 00 00 39 00 00 00 79 68 : ......A...9...yh 0080 : 67 2d 79 68 67 2e 35 34 35 37 2e 39 5f 5f 73 68 : g-yhg.5457.9__sh 0090 : 61 64 6f 77 5f 2e 66 30 36 61 55 4b 6c 32 32 4a : adow_.f06aUKl22J 00a0 : 6d 65 79 36 2d 76 50 65 5a 69 6a 78 65 49 68 46 : mey6-vPeZijxeIhF 00b0 : 4e 65 34 4d 41 5f 31 00 00 00 00 02 01 92 00 00 : Ne4MA_1......... 00c0 : 00 06 00 00 00 64 70 6f 6f 6c 31 39 00 00 00 79 : .....dpool19...y 00d0 : 68 67 2d 79 68 67 2e 35 34 35 37 2e 39 5f 5f 73 : hg-yhg.5457.9__s 00e0 : 68 61 64 6f 77 5f 2e 66 30 36 61 55 4b 6c 32 32 : hadow_.f06aUKl22 00f0 : 4a 6d 65 79 36 2d 76 50 65 5a 69 6a 78 65 49 68 : Jmey6-vPeZijxeIh 0100 : 46 4e 65 34 4d 41 5f 32 00 00 00 00 01 01 41 00 : FNe4MA_2......A. 0110 : 00 00 39 00 00 00 79 68 67 2d 79 68 67 2e 35 34 : ..9...yhg-yhg.54 0120 : 35 37 2e 39 5f 5f 73 68 61 64 6f 77 5f 2e 66 30 : 57.9__shadow_.f0 0130 : 36 61 55 4b 6c 32 32 4a 6d 65 79 36 2d 76 50 65 : 6aUKl22Jmey6-vPe 0140 : 5a 69 6a 78 65 49 68 46 4e 65 34 4d 41 5f 32 00 : ZijxeIhFNe4MA_2. 0150 : 00 00 00 02 01 92 00 00 00 06 00 00 00 64 70 6f : .............dpo 0160 : 6f 6c 31 39 00 00 00 79 68 67 2d 79 68 67 2e 35 : ol19...yhg-yhg.5 0170 : 34 35 37 2e 39 5f 5f 73 68 61 64 6f 77 5f 2e 66 : 457.9__shadow_.f 0180 : 30 36 61 55 4b 6c 32 32 4a 6d 65 79 36 2d 76 50 : 06aUKl22Jmey6-vP 0190 : 65 5a 69 6a 78 65 49 68 46 4e 65 34 4d 41 5f 33 : eZijxeIhFNe4MA_3 01a0 : 00 00 00 00 01 01 41 00 00 00 39 00 00 00 79 68 : ......A...9...yh 01b0 : 67 2d 79 68 67 2e 35 34 35 37 2e 39 5f 5f 73 68 : g-yhg.5457.9__sh 01c0 : 61 64 6f 77 5f 2e 66 30 36 61 55 4b 6c 32 32 4a : adow_.f06aUKl22J 01d0 : 6d 65 79 36 2d 76 50 65 5a 69 6a 78 65 49 68 46 : mey6-vPeZijxeIhF 01e0 : 4e 65 34 4d 41 5f 33 00 00 00 00 92 1e 0e 57 a3 : Ne4MA_3.......W. 01f0 : c8 29 05 : .).
在rgw 实例守护进程启动过程中,调用到如下函数中时
// rgw/rgw_rados.cc 1547 int RGWRados::init_complete() ... 1624 gc = new RGWGC(); // 创建gc对象 1625 gc->initialize(cct, this); 1626 1627 if (use_gc_thread) 1628 gc->start_processor(); // 启动gc worker线程
// rgw/rgw_gc.cc // 设置CephContext和RGWRados,用于和后端ceph 集群交互 24 void RGWGC::initialize(CephContext *_cct, RGWRados *_store) { 25 cct = _cct; 26 store = _store; // 解析rgw gc max objs配置项 28 max_objs = cct->_conf->rgw_gc_max_objs; 29 if (max_objs > HASH_PRIME) 30 max_objs = HASH_PRIME; // 初始化gc 对象数组 32 obj_names = new string[max_objs]; 33 34 for (int i = 0; i < max_objs; i++) { 35 obj_names[i] = gc_oid_prefix; 36 char buf[32]; 37 snprintf(buf, 32, ".%d", i); 38 obj_names[i].append(buf);
// rgw/rgw_gc.cc 276 void *RGWGC::GCWorker::entry() { 277 do { 278 utime_t start = ceph_clock_now(cct); 279 dout(2) << "garbage collection: start" << dendl; // 进行一次垃圾删除操作 280 int r = gc->process(); 281 if (r < 0) { 282 dout(0) << "ERROR: garbage collection process() returned error r=" << r << dendl; 283 } 284 dout(2) << "garbage collection: stop" << dendl; 285 // 需要退出? 286 if (gc->going_down()) 287 break; 288 289 utime_t end = ceph_clock_now(cct); 290 end -= start; 291 int secs = cct->_conf->rgw_gc_processor_period; 292 // 刚才的垃圾清理操作耗时超过了gc周期? 293 if (secs <= end.sec()) 294 continue; // next round 295 296 secs -= end.sec(); 297 298 lock.Lock(); // 在下一个gc周期到期前先睡会儿 299 cond.WaitInterval(cct, lock, utime_t(secs, 0)); 300 lock.Unlock(); 301 } while (!gc->going_down()); 302 303 return NULL; 304 }
235 int RGWGC::process() 当中随机选择一个 gc object (index),然后调用
131 int RGWGC::process(int index, int max_secs)随机选择gc object (index)的过程有点废,因为随机选中的gc object上不一定是记录有待删除对象信息。可能随机了一轮都没有选到含有待删除对象的index。
// rgw/rgw_gc.cc 235 int RGWGC::process() 236 { 237 int max_secs = cct->_conf->rgw_gc_processor_max_time; 238 239 unsigned start; 240 int ret = get_random_bytes((char *)&start, sizeof(start)); 241 if (ret < 0) 242 return ret; 243 244 for (int i = 0; i < max_objs; i++) { // 选择一个gc object/index,而这个对象上可能没有包含待删除对象列表信息 245 int index = (i + start) % max_objs; // 该函数调用可能是空走一场,没有卵用 246 ret = process(index, max_secs); 247 if (ret < 0) 248 return ret; 249 }
// rgw/rgw_gc.cc 131 int RGWGC::process(int index, int max_secs)
// rgw/rgw_gc.cc 148 int ret = l.lock_exclusive(&store->gc_pool_ctx, obj_names[index]);
// rgw/rgw_gc.cc 160 int max = 100; 161 std::list<cls_rgw_gc_obj_info> entries; // 调用了ceph 集群端的 rgw gc_list 服务函数 162 ret = cls_rgw_gc_list(store->gc_pool_ctx, obj_names[index], marker, max, true, entries, &truncated);
下面的entries 列表中值有一个项,该项包含一个包含了3个待删除对象的列表。
// 此处显示的entries和日志中的不同,是另一次跟踪的结果。 (gdb) print entries $227 = std::list = { [0] = { tag = "yhg-yhg.5457.102", chain = { objs = std::list = { [0] = { pool = "dpool1", key = { name = "yhg-yhg.5457.9__shadow_.W1hIqrwLfgryxeyjYpuN1gXcOIlxji__1", instance = "" }, loc = "" }, [1] = { pool = "dpool1", key = { name = "yhg-yhg.5457.9__shadow_.W1hIqrwLfgryxeyjYpuN1gXcOIlxji__2", instance = "" }, loc = "" }, [2] = { pool = "dpool1", key = { name = "yhg-yhg.5457.9__shadow_.W1hIqrwLfgryxeyjYpuN1gXcOIlxji__3", instance = "" }, loc = "" } } }, time = { tv = { tv_sec = 1460548119, tv_nsec = 734893236 } } } }
// rgw/rgw_gc.cc 189 ret = store->get_rados_handle()->ioctx_create(obj.pool.c_str(), *ctx); ... 202 dout(0) << "gc::process: removing " << obj.pool << ":" << key_obj.get_object() << dendl; 203 ObjectWriteOperation op; // 见下面的 E1 204 cls_refcount_put(op, info.tag, true); 205 ret = ctx->operate(key_obj.get_object(), &op);
E1
cls_refcount_put 的对象的refs为空时,会将关联对象删除。
// cls/refcount/cls_refcount.cc 120 static int cls_rc_refcount_put(cls_method_context_t hctx, bufferlist *in, bufferlist *out) ... 160 if (objr.refs.empty()) { 161 return cls_cxx_remove(hctx); // 删除对象 162 }
删除 2. 数据结构 节中 listomapkeys 列举出来的信息。
// rgw/rgw_gc.cc 228 if (!remove_tags.empty()) 229 RGWGC::remove(index, remove_tags);
>> 2 garbage collection: start >> 0 gc::process: removing dpool1:yhg-yhg.5457.9__shadow_.f06aUKl22Jmey6-vPeZijxeIhFNe4MA_1 >> 0 gc::process: removing dpool1:yhg-yhg.5457.9__shadow_.f06aUKl22Jmey6-vPeZijxeIhFNe4MA_2 >> 0 gc::process: removing dpool1:yhg-yhg.5457.9__shadow_.f06aUKl22Jmey6-vPeZijxeIhFNe4MA_3 >> 2 garbage collection: stop
gc 对象pool中的对象gc.[0-31]有两个作用:一个是用于gc worker互斥控制,一个是在其omap中存放了待删除对象的名字和其对象的数据pool的名字。
gc chain (struct cls_rgw_obj_chain) 就是 3.3.2 处理选定的gc object上的待删除对象 中的chain。包含了多个待删除对象的名字和所在的pool信息等。
在下述的3中情况下,会添加待删除对象到gc chain。
Multipart上传被取消时,需要将已经上传的片段对象删除。
// rgw/rgw_op.cc 3140 void RGWAbortMultipart::execute()
覆盖写(put一个已经存在的对象)时,旧的对象片段需要gc掉。
// rgw/rgw_rados.cc 3297 /** 3298 * Write/overwrite an object to the bucket storage. 3299 * bucket: the bucket to store the object in 3300 * obj: the object name/key 3301 * data: the object contents/value 3302 * size: the amount of data to write (data must be this long) 3303 * mtime: if non-NULL, writes the given mtime to the bucket storage 3304 * attrs: all the given attrs are written to bucket storage for the given object 3305 * exclusive: create object exclusively 3306 * Returns: 0 on success, -ERR# otherwise. 3307 */ 3308 int RGWRados::Object::Write::write_meta(uint64_t size, 3309 map<string, bufferlist>& attrs) // 在complete_atomic_modification中,调用了update_gc_chain/send_chain操作 3431 r = target->complete_atomic_modification();
// rgw/rgw_rados.cc 4660 /** 4661 * Delete an object. 4662 * bucket: name of the bucket storing the object 4663 * obj: name of the object to delete 4664 * Returns: 0 on success, -ERR# otherwise. 4665 */ 4666 int RGWRados::Object::Delete::delete_obj() ... 4773 if (removed) { // 在complete_atomic_modification中,调用了update_gc_chain/send_chain操作 4774 int ret = target->complete_atomic_modification();
// gc chain 结构 814 struct cls_rgw_obj_chain { 815 list<cls_rgw_obj> objs; // 该chain包含的对象信息 816 ... // 将<pool, key, loc> 标识的对象添加到chain中 819 void push_obj(string& pool, cls_rgw_obj_key& key, string& loc) { 820 cls_rgw_obj obj; 821 obj.pool = pool; 822 obj.key = key; 823 obj.loc = loc; 824 objs.push_back(obj); 825 } // 表示chain中的一个对象 770 struct cls_rgw_obj { 771 string pool; 772 cls_rgw_obj_key key; 773 string loc; // 表示一个对象 214 struct cls_rgw_obj_key { 215 string name; // 对象的名字 216 string instance;
下述的3个操作会修改ceph集群端的 gc chain。而3.3.2 处理选定的gc object上的待删除对象 中会从gc chain上取对象列表并删除。
将manifest中包含的所有对象添加到gc chain上。
// rgw/rgw_rados.cc 4439 void RGWRados::update_gc_chain(rgw_obj& head_obj, RGWObjManifest& manifest, cls_rgw_obj_chain *chain)
调用ceph集群端 rgw相关的类的 gc_set_entry 方法,将gc chain传递到ceph集群端。本质上是更新了gc.XXX对象的omap信息。
// rgw/rgw_gc.cc 63 ObjectWriteOperation op; // cls/rgw/cls_rgw_client.cc 580 op.exec("rgw", "gc_set_entry", in); // rgw/rgw_gc.cc 68 if (sync) 69 return store->gc_operate(obj_names[i], &op); 70 71 return store->gc_aio_operate(obj_names[i], &op);
最终调用了如下函数:
// cls/rgw/cls_rgw.cc 2791 static int gc_update_entry(cls_method_context_t hctx, uint32_t expiration_secs, 2792 cls_rgw_gc_obj_info& info)
对 update_gc_chain/send_chain_to_gc 的封装。
[1] gc 过程 http://lyang.top/2015/12/11/Ceph-radosgw-gc-%E5%A4%84%E7%90%86%E8%BF%87%E7%A8%8B/