Ceph H版本性能调优总结




现状

sas 场景

sas盘场景下,由于有raid卡的缓存加成,以及journal的顺序写特性,因此性能比sas裸盘要好很多,单osd单副本场景下数据(未调优):

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左右。调整的配置项是:

osd_client_message_cap = 50000 #线上配置是100
filestore_queue_max_ops = 50000 #线上配置是50

但此时内存占用会暴涨,原因是后端data落盘跟不上journal落盘速度,大量op保存在内存中排队。

而裸盘的fio数据:

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左右。

  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:

  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),单卷性能:

  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),单卷性能:

  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分析时延较长的位置,

 {
            "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影响排序,因此修改代码去掉了之后,

 {
            "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平均值数据如下:

"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可以看出回调耗时较长:

        "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个线程):

        "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线程后:

"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:

  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):

  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:

  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:

  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了),

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倍还要多):

  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:

  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%左右):

  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%之间波动):

  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%左右):

  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%左右):

  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落盘场景,其他同上):

  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,平均每个卷的性能:

  write: io=995372KB, bw=16585KB/s, iops=4146, runt= 60017msec
    clat (msec): min=1, max=161, avg=30.73, stdev=16.42

用老的版本,老的配置项,同样的测试用例,同样的环境,iops性能为:

  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个卷),老的版本加老的配置,同样的测试场景下,性能提升到:

  write: io=884548KB, bw=14609KB/s, iops=3652, runt= 60550msec
    clat (msec): min=1, max=1572, avg=35.00, stdev=87.48

同样的绑核策略,新版本+新配置项,性能提升:

  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,

  write: io=825868KB, bw=13623KB/s, iops=3405, runt= 60624msec
    clat (msec): min=1, max=1356, avg=37.57, stdev=84.53

绑核后性能提升到33145,平均单卷3682:

  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:

  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盘才达到瓶颈。

总结:

  1. cpu是瓶颈(测试过程中除了前4个cpu只跑软中断有20~30%的idle之后,其他cpuidle基本都接近0),ssd盘性能仍有较大余量
  2. async messager性能最好,线程数量少很多,cpu利用率比较低一些,性能可以提升一些,总iops可以跑到52374
  3. 优化代码合入对多osd场景的最终性能影响有限,原因是cpu利用率是瓶颈,ssd性能发挥不出来,对单osd性能提升比较明显
  4. 绑定cpu对性能有提升
  5. 内存日志级别也要调整到0,对性能有提升
  6. 打开op tracker在无io落盘场景下对性能影响较大,但在有io落盘场景下不明显,可以接受
  7. 通过perf top分析可以看出,cpu利用率占用较多的是内存分配释放操作,其次是bufferlist、字符串等操作

配置项改动:

--- 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

其他改进手段

  1. 优化osd的cpu利用率,进一步发挥ssd盘的性能
  2. 可以考虑混合部署sas和ssd,降低ssd盘的密度,更好的发挥ssd盘的性能