对rgw用cosbench压测(写),用ifstat观察网卡的压力情况:
网卡进出流量
可以看到明显的写放大现象,public网络的进是1G/s而出是1.5G左右。
然后单独发送上传请求到rgw,用tcpdump抓包再用wireshark解析发现,rgw发往osd的流中包含两份对象内容:
流中内容与对象内容对比
确定是rgw的对象上传功能存在写放大现象。
再改变场景对抓几个包看看,发现了规律:1. 当第一次上传时没有放大现象,第二次上传时发生放大。
2. 上传1M时,抓包拿到的包大小为2M,上传2M时为4M,上传8M时为12M,上传100M时为104M
根据上述现象猜测是head对象存在重复向osd上传的逻辑(集群rgw_max_chunk_size为4M)
修改rgw中的msg模块代码,观察rgw向osd发送消息的行为:
代码修改
然后查到对象所在的pg,用于过滤rgw的日志:
rgw日志
此处上传的对象为1M,从此确定rgw将head对象重复向osd上传,导致了网卡观察到的写放大。
最后查看代码逻辑发现 assume_noent 这个变量控制着这里的重复上传到osd 的行为
重复上传逻辑
上github查看相关的提交发现:
commit message
commit message
trick
为了提升第一次写的性能(改后是无脑写 改之前都是先stat读一下对象才写),所以牺牲了覆盖写head对象时候的带宽占用(稳定重试一次)