现状
sas 场景
sas盘场景下,由于有raid卡的缓存加成,以及journal的顺序写特性,因此性能比sas裸盘要好很多,单osd单副本场景下数据(未调优):
1 2 3 4 |
job1: (g=0): rw=randwrite, bs=4K-4K/4K-4K/4K-4K, ioengine=rbd, iodepth=64 write: io=316136KB, bw=2589.8KB/s, iops=647, runt=122107msec clat (msec): min=2, max=7502, avg=98.86, stdev=280.79 |
经过配置项调整后,同样的测试用例和单osd节点,iops从600多提升到1010左右。调整的配置项是:
1 2 3 |
osd_client_message_cap = 50000 #线上配置是100 filestore_queue_max_ops = 50000 #线上配置是50 |
但此时内存占用会暴涨,原因是后端data落盘跟不上journal落盘速度,大量op保存在内存中排队。
而裸盘的fio数据:
1 2 3 4 |
fio -filename=/var/lib/ceph/osd/ceph-34/fio.data -rw=randwrite -bs=4k -iodepth=128 -numjobs=2 -ioengine=libaio -direct=1 -runtime=60 -group_reporting -size=1000G -name=sdb1 write: io=78768KB, bw=1303.1KB/s, iops=325, runt= 60447msec clat (msec): min=8, max=4049, avg=392.82, stdev=281.27 |
因此sas盘场景没有仔细调优,主要是在ssd场景下进行的各种对比测试。
需要注意的是,throttle放开的参数在sas场景下不能放开,否则会导致内存暴涨(sas盘性能跟不上,不需要设置太高的throttle)。
ssd 场景
9台物理机(近期上线的机器,cpu应该稍好),每台20个ssd盘(Intel S4500),4k随机写fio+rbd模式下,9个卷(每个500G)可以并发跑到72000个IOPS左右。
1 2 3 4 |
write: io=3856.9MB, bw=32852KB/s, iops=8212, runt=120219msec slat (usec): min=0, max=15124, avg= 5.45, stdev=51.21 clat (msec): min=1, max=703, avg=15.54, stdev=25.71 |
fio测试过程中性能稳定无波动,osd后端磁盘IO压力均衡,每个osd均在2000~4000iops范围波动。
同样的9台物理机,每台3个ssd盘(Intel S4500),跑4k随机写裸盘fio+libaio,每个节点可以达到15W iops。
而在线下环境的pubt2-ceph0/1/2 3台节点上(E5-2660 v4 2.0GHz,两个节点ssd盘是SAMSUNG MZ7LM960HMJP,PM863a,官方标称随机写24K IOPS;另外一台是INTEL SSDSC2BB016T7,S3520,官方标称随机写17K IOPS),用线上环境试用的1.2-0版本进行对比测试,配置项使用线上的,无绑核,fio跑在独立的节点上。4k随机写总体iops性能为30652,平均单卷3405:
1 2 3 |
write: io=825868KB, bw=13623KB/s, iops=3405, runt= 60624msec clat (msec): min=1, max=1356, avg=37.57, stdev=84.53 |
分析过程及优化手段
注意:下面的分析及优化都是针对的ssd盘场景。
整个分析过程主要依赖的手段包括:
1. perf counter,增加自定义counter
2. 日志,添加耗时统计
3. kill -USR1,获取调用栈
4. Linux perf工具,查看cpu资源占用情况
5. 修改代码,增加io落盘开关,做到无io落盘情况下分析osd层性能,排除磁盘对性能数据的影响
其他期望尝试的工具是lttng+blkin,但H版本这个感觉做的不完善,代码里很多地方都没有打点,后续L版本可以尝试。
单osd性能分析
首先要分析的是单osd、单副本场景下的rbd卷4k随机写性能,分析的是有io落盘和无io落盘两种情况下的性能差距,并找出无io落盘情况下osd层的性能瓶颈点。
9个卷,(4k随机写,128iodepth),有IO落盘(未mock FileStore和journal),单卷性能:
1 2 3 |
write: io=461228KB, bw=3840.1KB/s, iops=960, runt=120082msec clat (msec): min=1, max=1468, avg=133.29, stdev=117.17 |
9个卷,(4k随机写,128iodepth),无IO落盘(mock FileStore和journal),单卷性能:
1 2 3 |
write: io=717212KB, bw=5974.2KB/s, iops=1493, runt=120052msec clat (msec): min=1, max=141, avg=85.69, stdev= 9.74 |
可以看出无io落盘场景下,平均时延过高,因此通过dump_historic_ops分析时延较长的位置,
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 |
{ "description": "osd_op(client.8984.0:11873 rbd_data.21f66b8b4567.000000000001bb3d [] 13.f568b271 ack+ondisk+write+known_if_redirecte d e970)", "initiated_at": "2019-08-22 17:35:39.837373", "age": 0.992912, "duration": 0.982060, ...... { "time": "2019-08-22 17:35:39.837512", "event": "started" }, { "time": "2019-08-22 17:35:39.837613", "event": "commit_queued_for_journal_write" }, { "time": "2019-08-22 17:35:39.840339", "event": "write_thread_in_journal_buffer" ##### 这里 }, { "time": "2019-08-22 17:35:39.888499", "event": "journaled_completion_queued" ##### 到这里 }, { "time": "2019-08-22 17:35:39.892560", "event": "filestore_queued_op" }, { "time": "2019-08-22 17:35:39.892565", "event": "filestore_do_op" }, { "time": "2019-08-22 17:35:39.892603", "event": "filestore_do_op_end" }, { "time": "2019-08-22 17:35:39.924675", ##### 到这里 "event": "op_commit" }, { "time": "2019-08-22 17:35:39.924698", "event": "commit_sent" }, |
Filestore相关event影响排序,因此修改代码去掉了之后,
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 |
{ "description": "osd_op(client.9820.0:135 rbd_data.21f26b8b4567.000000000000ac1a [] 13.f87a5531 ack+ondisk+write+known_if_redirected e994)", "initiated_at": "2019-08-23 16:26:38.362347", "age": 30.219829, "duration": 0.136654, ...... { "time": "2019-08-23 16:26:38.402545", "event": "started" }, { "time": "2019-08-23 16:26:38.402654", "event": "commit_queued_for_journal_write" }, { "time": "2019-08-23 16:26:38.403273", "event": "write_thread_in_journal_buffer" ## 这里 }, { "time": "2019-08-23 16:26:38.444155", "event": "journaled_completion_queued" ## 到这里40ms左右 }, { "time": "2019-08-23 16:26:38.498969", ## 到这里又50ms左右 "event": "op_commit" }, { "time": "2019-08-23 16:26:38.499001", "event": "commit_sent" } |
前半段在等待journal落盘,后半段是journal落盘之后等待回调。
但需要注意的是,history ops并不能完全表现真实性能瓶颈,只能作为参考,只有耗时最长的20个op才会列出来,是最大值,而非平均值。
官方代码已有的perf平均值数据如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
"journal_latency": { "avgcount": 972945, "sum": 258.177185807 }, "op_latency": { "avgcount": 973143, "sum": 68849.737076609 }, "op_process_latency": { "avgcount": 973143, "sum": 68685.614715542 }, |
可以看出journal_latency平均值很低,才0.26ms,也就是说绝大部分情况下commit_queued_for_journal_write到journaled_completion_queued阶段都是不怎么耗时的,op_process_latency平均延时比较高。因此需要通过增加perf counter来对比验证瓶颈点。
通过增加perf counter,journal commit可以看出回调耗时较长:
1 2 3 4 5 6 7 8 9 |
"repop_all_commited_latency": { ## ReplicatedPG::repop_all_committed的时间点减去ReplicatedPG::eval_repop首次进入的时间点的差值,这段平均耗时统计值与fio的平均时延比较接近 "avgcount": 335625, "sum": 67348.398432313 "op_commit_lock_latency": { ## 已排除是BlessedContext::finish里面的pg->lock加锁导致的耗时长 "avgcount": 671250, "sum": 44.412470067 } |
当前finisher线程是1个,不能修改,之前正好看到社区代码有修改这部分,增加finisher回调线程数量,于是尝试合入进行对比(https://github.com/ceph/ceph/pull/6486/commits )。
增加finisher线程前(默认都是1个线程):
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
"journaled_ahead_to_op_commit_latency": { "avgcount": 325212, "sum": 67107.237113916 }, ## fio的平均时延正好跟这个回调耗时匹配 "finisher-journal": { "queue_len": 0 }, "finisher-onapply": { "queue_len": 21 }, "finisher-ondisk": { "queue_len": 1133 }, |
增加finisher线程后:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 |
"journaled_ahead_to_op_commit_latency": { "avgcount": 988516, "sum": 891.208668089 }, "finisher-filestore-apply-0": { "queue_len": 0 }, ...... "finisher-filestore-apply-4": { "queue_len": 2 }, "finisher-filestore-ondisk-0": { "queue_len": 0 }, ...... "finisher-filestore-ondisk-9": { "queue_len": 0 }, "finisher-journal": { "queue_len": 0 }, |
增加finisher线程数量后,队列中等待的op数量已经没有堆积,fio性能偶尔可以从原来的每个卷1200左右增加到1800左右,但更多时候是下降的,到800多,需要进一步分析原因。
说明还有其他地方有性能瓶颈。
统计perf counter耗时,发现提交journal之后到op_commit耗时仍然比较长(上面有之前的数据),当时没想到具体的瓶颈点,翻了社区提交的性能优化代码找到一个相关的改动,合入之后发现提升挺明显(https://github.com/ceph/ceph/commit/eb020b6a6a75c69f71dc29fd607a4626bed28366 ),单osd单副本9个卷无IO落盘,每个卷性能从1490提高到2200:
1 2 3 |
write: io=529944KB, bw=8826.1KB/s, iops=2206, runt= 60037msec clat (msec): min=3, max=125, avg=57.99, stdev= 5.59 |
有IO落盘(从960提升到1490):
1 2 3 |
write: io=162348KB, bw=5982.1KB/s, iops=1495, runt= 27139msec clat (msec): min=1, max=150, avg=85.56, stdev= 8.77 |
根据晨会上宏松的建议,看了下所有的pr,涉及到osd层、pg层、journal层、FileStore层的performance优化都过滤下,看看有么有可以拿过来的。找到一个https://github.com/ceph/ceph/commit/a75a9a8178f42ba7363de4929af5da140b64c668 ,合入后无IO落盘场景(其他条件同上),每个卷性能从2206提升到2320:
1 2 3 4 5 6 |
write: io=557512KB, bw=9285.4KB/s, iops=2321, runt= 60042msec write: io=557496KB, bw=9285.3KB/s, iops=2321, runt= 60041msec write: io=557620KB, bw=9287.2KB/s, iops=2321, runt= 60043msec clat (msec): min=2, max=141, avg=55.13, stdev= 4.90 clat (msec): min=3, max=133, avg=55.13, stdev= 4.92 |
有IO落盘场景,从1490提升到1527:
1 2 3 |
write: io=366880KB, bw=6109.2KB/s, iops=1527, runt= 60054msec clat (msec): min=1, max=205, avg=83.80, stdev=12.87 |
其他的可以合入的patch也都合入测试了,发现并没有提升。
分析无IO落盘场景下的fio结果,发现时延还是比较高,平均55ms,于是通过kill -USR1看了下top里cpu占用最高的线程的调用栈(多kill几次),发现每次调用栈都是在打印日志,于是尝试把日志级别都改成0(主要是内存级别,因此文件级别已经是0了),
1 2 |
for d in `sudo ceph daemon osd.37 config show| grep '"debug_' | awk -F: '{print $1}' | sed 's/"//g'`; do sudo ceph daemon osd.37 config set $d 0; done |
使用上面的脚本,关掉所有模块日志(包括内存日志)之后,性能有很大提升。
无IO落盘提升非常大(延时敏感,每个卷从2320提升到5718,翻1倍还要多):
1 2 3 |
write: io=1340.1MB, bw=22875KB/s, iops=5718, runt= 60028msec clat (usec): min=1320, max=48165, avg=22373.50, stdev=809.35 |
有IO落盘,从1527提升到1770:
1 2 3 |
write: io=425060KB, bw=7082.5KB/s, iops=1770, runt= 60016msec clat (usec): min=783, max=2614.1K, avg=72280.76, stdev=122010.96 |
上述单osd场景下,也对比过64个pg和256个pg的性能,256 pg性能比64个要好一些,因此上述优化都是在256 pg场景下测试的。
单节点3 osd 3副本性能分析
使用上面修改过代码及配置项的版本部署3副本场景(共3个osd位于同一个节点上,排除网络影响),进行性能测试。
3副本(3个osd,在同一节点上),256 pg,无io落盘场景下,版本为未合入CLDNBS-1383相关pr的版本,也即CLDNBS-1358相关commit合入的版本,配置项与线上环境相同,9个客户端卷,每个卷的iops情况(单osd cpu利用率1000%左右):
1 2 3 |
write: io=308464KB, bw=5130.7KB/s, iops=1282, runt= 60122msec clat (msec): min=1, max=381, avg=99.78, stdev=113.20 |
有io落盘iops情况(单osd cpu利用率400%~800%之间波动):
1 2 3 |
write: io=93144KB, bw=1542.7KB/s, iops=385, runt= 60379msec clat (msec): min=2, max=3905, avg=331.87, stdev=487.11 |
3副本(3个osd,在同一节点上),256 pg,无io落盘场景下,版本为未合入CLDNBS-1383相关pr的版本,也即CLDNBS-1358相关commit合入的版本,配置项与CLDNBS-1358测试时相同,9个客户端卷,每个卷的iops情况(单osd cpu利用率1000%左右):
1 2 3 |
write: io=284264KB, bw=4728.4KB/s, iops=1182, runt= 60119msec clat (msec): min=1, max=267, avg=108.27, stdev=66.00 |
有io落盘iops情况(单osd cpu利用率1300%左右):
1 2 3 |
write: io=230180KB, bw=3830.5KB/s, iops=957, runt= 60093msec clat (msec): min=2, max=319, avg=133.65, stdev=69.22 |
主pg数量不均衡,导致一个osd处理的osd_op数量比其他两个少40W(180W~220W),经过手工调整后(
hzwangpan@pubt2-ceph2 ceph $ ceph osd primary-affinity 35 0.95
set osd.35 primary-affinity to 0.95 (8622592)
hzwangpan@pubt2-ceph2 ceph $ ceph pg ls-by-primary 35| wc ),iops有一些提升(无io落盘场景,其他同上):
1 2 3 |
write: io=306644KB, bw=5102.2KB/s, iops=1275, runt= 60101msec clat (msec): min=1, max=247, avg=100.34, stdev=62.83 |
问题:无io落盘3个osd场景下,为啥性能仍然较差?
首先通过增加perf counter分析到osd之间的repop发送和接收过程较慢导致的,并进一步通过debug_ms=10日志确认。 之后再Pipe::reader()里面增加耗时和队列长度统计,并分析日志,9个卷无IO落盘场景下,可以看出sent队列长度为1100+,repop相关dispatch耗时在0.1ms左右,与客户端时延接近(120+ms),而单卷无IO落盘场景下,sent队列长度为100+,dispatch耗时不变,客户端时延14ms左右,也即与9个卷场景相差9倍左右(但单卷和9个卷的总体iops相差不大),由此可见,是服务端来不及处理高并发的IO,在服务端排队导致的时延较高。另外还在Pipe::writer()里增加代码进行测试,发现out_q队列长度均非常小,基本都在1或者0,没有排队。
查看cpu利用率最高的线程,均为Pipe::reader()线程,达到90%以上,kill -USR1看到是在mark_event,尝试关掉optracker功能之后(osd_enable_op_tracker = false),9个卷128iodepth无IO落盘,iops从1050左右提升到1680+,时延从122ms降低到75ms。每个osd的cpu利用率也从1200%降低到750%左右。
另外尝试把Pipe:reader线程绑定到独立的cpu上,把osd的其他线程绑定到其他cpu上,iops有一点提升,从1680+提升到1700+。
把日志都改成0级别(包括内存),iops提升到1950+。以上均为无io落盘,9个卷128iodepth。
3节点57 osd 3副本性能分析
9个卷,57个osd(3节点,每节点19个osd),有io落盘(关闭optracker、关闭日志),4k随机写,128iodepth,平均每个卷的性能:
1 2 3 |
write: io=995372KB, bw=16585KB/s, iops=4146, runt= 60017msec clat (msec): min=1, max=161, avg=30.73, stdev=16.42 |
用老的版本,老的配置项,同样的测试用例,同样的环境,iops性能为:
1 2 3 |
write: io=760796KB, bw=12671KB/s, iops=3167, runt= 60042msec clat (msec): min=1, max=1272, avg=40.38, stdev=77.00 |
两种场景下,前4个核都已经跑满,经过对比发现前4个核跑满是因为被osd和fio线程占用了。
绑核之后(fio、osd线程绑定到4-55,fio分散到3个节点执行,每个节点跑3个卷),老的版本加老的配置,同样的测试场景下,性能提升到:
1 2 3 |
write: io=884548KB, bw=14609KB/s, iops=3652, runt= 60550msec clat (msec): min=1, max=1572, avg=35.00, stdev=87.48 |
同样的绑核策略,新版本+新配置项,性能提升:
1 2 3 |
write: io=1178.4MB, bw=20102KB/s, iops=4960, runt= 60027msec clat (msec): min=1, max=442, avg=25.33, stdev=13.11 |
此时发现cpu是瓶颈,于是尝试采用async messager替换simple messager来对比测试(需要backport高版本的async功能),async比simple的线程数要少很多,cpu占用应该也会少一些。发现async比simple有提升,可以跑到5270左右了(simple是4960左右)。
之后才做了其他对比测试,以下数据均为async messager:
1. 尝试不绑定osd线程到4-55 cpu,iops下降到5260左右(fio线程是否绑定4-55 cpu对性能几乎无影响)。
2. 绑核,减少线程数,可以跑到5500左右:
filestore_op_threads = 16
osd_op_num_threads_per_shard = 1
osd_op_num_shards = 16
filestore_ondisk_finisher_threads = 8
filestore_apply_finisher_threads = 8
osd_enable_op_tracker = true
其他配置不变
3. 关闭osd_enable_op_tracker,可以跑到5570左右,其他配置不变
4. 尝试把fio跑在其他节点(与osd节点分开),其他不变,可以跑到5819;把async改为simple messager,同样的场景,可以跑到5106
线上环境使用的1.2-0版本进行对比测试,配置项使用线上的,无绑核,fio跑在独立的节点上。4k随机写总体iops性能为30652,平均单卷3405,
1 2 3 |
write: io=825868KB, bw=13623KB/s, iops=3405, runt= 60624msec clat (msec): min=1, max=1356, avg=37.57, stdev=84.53 |
绑核后性能提升到33145,平均单卷3682:
1 2 3 |
write: io=893156KB, bw=14749KB/s, iops=3687, runt= 60556msec clat (msec): min=1, max=1596, avg=34.70, stdev=97.10 |
尝试绑核并且修改配置文件,1.2-0版本可以跑到总iops 47750,平均单卷5305:
1 2 3 |
write: io=1246.5MB, bw=21257KB/s, iops=5314, runt= 60044msec clat (usec): min=873, max=2790.6K, avg=24075.40, stdev=126415.06 |
尝试每个节点只用6个osd,性能也比19个osd高,单卷iops平均6415(总57735),时延在19~20ms。单osd cpu利用率在700~800%左右,内存最大到12G左右,原因是数据落盘比journal延迟10几秒,此时ssd盘才达到瓶颈。
总结:
- cpu是瓶颈(测试过程中除了前4个cpu只跑软中断有20~30%的idle之后,其他cpuidle基本都接近0),ssd盘性能仍有较大余量
- async messager性能最好,线程数量少很多,cpu利用率比较低一些,性能可以提升一些,总iops可以跑到52374
- 优化代码合入对多osd场景的最终性能影响有限,原因是cpu利用率是瓶颈,ssd性能发挥不出来,对单osd性能提升比较明显
- 绑定cpu对性能有提升
- 内存日志级别也要调整到0,对性能有提升
- 打开op tracker在无io落盘场景下对性能影响较大,但在有io落盘场景下不明显,可以接受
- 通过perf top分析可以看出,cpu利用率占用较多的是内存分配释放操作,其次是bufferlist、字符串等操作
配置项改动:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 |
--- online.conf 2019-10-23 14:24:52.738763518 +0800 +++ ceph.conf 2019-10-23 14:27:08.326466021 +0800 @@ -1,4 +1,6 @@ [global] +enable experimental unrecoverable data corrupting features = ms-type-async +ms_type = async @@ -32,11 +27,71 @@ +osd_pg_object_context_cache_count = 1024 +filestore_queue_max_ops = 5000 +filestore_queue_max_bytes = 1048576000 +filestore_ondisk_finisher_threads = 4 +filestore_apply_finisher_threads = 4 +osd_client_message_cap = 5000 +osd_client_message_size_cap = 1048576000 +journal_queue_max_ops = 5000 +journal_queue_max_bytes = 524288000 +journal_max_write_entries = 5000 +journal_max_write_bytes = 20971520 + +debug_none = 0 +debug_lockdep = 0 +debug_context = 0 +debug_crush = 0 +debug_mds = 0 +debug_mds_balancer = 0 +debug_mds_locker = 0 +debug_mds_log = 0 +debug_mds_log_expire = 0 +debug_mds_migrator = 0 +debug_buffer = 0 +debug_timer = 0 +debug_filer = 0 +debug_striper = 0 +debug_objecter = 0 +debug_rados = 0 +debug_rbd = 0 +debug_rbd_replay = 0 +debug_journaler = 0 +debug_objectcacher = 0 +debug_client = 0 +debug_osd = 0 +debug_optracker = 0 +debug_objclass = 0 +debug_filestore = 0 +debug_keyvaluestore = 0 +debug_journal = 0 +debug_ms = 0 +debug_mon = 0 +debug_monc = 0 +debug_paxos = 0 +debug_tp = 0 +debug_auth = 0 +debug_crypto = 0 +debug_finisher = 0 +debug_heartbeatmap = 0 +debug_perfcounter = 0 +debug_rgw = 0 +debug_civetweb = 0 +debug_javaclient = 0 +debug_asok = 0 +debug_throttle = 0 +debug_refs = 0 +debug_xio = 0 |
其他改进手段
- 优化osd的cpu利用率,进一步发挥ssd盘的性能
- 可以考虑混合部署sas和ssd,降低ssd盘的密度,更好的发挥ssd盘的性能