上回书讲完了部署,部署完成之后,就开始了无休止的调优,对于Ceph运维人员来说最头痛的莫过于两件事:一、Ceph调优;二、Ceph运维。调优是件非常头疼的事情,下面来看看运维小哥是如何调优的,运维小哥根据网上资料进行了一个调优方法论(调优总结)。

关卡三:部署调优关之调优(一)

难度:五颗星

优化方法论

通过对网上公开资料的分析进行总结,对Ceph的优化离不开以下几点:

硬件层面· 硬件规划· SSD选择· BIOS设置操作系统层面· Linux Kernel· 内存· Cgroup网络层面· 巨型帧· 中断亲和· 硬件加速Ceph层面· Ceph Configurations· PG Number调整

硬件优化

1、硬件规划· Processor

ceph-osd进程在运行过程中会消耗CPU资源,所以一般会为每一个ceph-osd进程绑定一个CPU核上。当然如果你使用EC方式,可能需要更多的CPU资源。

ceph-mon进程并不十分消耗CPU资源,所以不必为ceph-mon进程预留过多的CPU资源。

ceph-msd也是非常消耗CPU资源的,所以需要提供更多的CPU资源。

· 内存

ceph-mon和ceph-mds需要2G内存,每个ceph-osd进程需要1G内存,当然2G更好。

· 网络规划

万兆网络现在基本上是跑Ceph必备的,网络规划上,也尽量考虑分离cilent和cluster网络。

2、SSD选择

硬件的选择也直接决定了Ceph集群的性能,从成本考虑,一般选择SATA SSD作为Journal,Intel SSD DC S3500 Series(http://www.intel.com/content/www/us/en/solid-state-drives/solid-state-drives-dc-s3500-series.html)基本是目前看到的方案中的首选。400G的规格4K随机写可以达到11000 IOPS。如果在预算足够的情况下,推荐使用PCIE SSD,性能会得到进一步提升,但是由于Journal在向数据盘写入数据时Block后续请求,所以Journal的加入并未呈现出想象中的性能提升,但是的确会对Latency有很大的改善。

如何确定你的SSD是否适合作为SSD Journal,可以参考SéBASTIEN HAN的Ceph: How to Test if Your SSD Is Suitable as a Journal Device?(http://www.sebastien-han.fr/blog/2014/10/10/ceph-how-to-test-if-your-ssd-is-suitable-as-a-journal-device/),这里面他也列出了常见的SSD的测试结果,从结果来看SATA SSD中,Intel S3500性能表现最好。

3、BIOS设置

(1)Hyper-Threading(HT)

使用超线程(Hyper-Threading)技术,可以实现在一个CPU物理核心上提供两个逻辑线程并行处理任务,在拥有12个物理核心的E5 2620 v3中,配合超线程,可以达到24个逻辑线程。更多的逻辑线程可以让操作系统更好地利用CPU,让CPU尽可能处于工作状态。基本做云平台的,VT和HT打开都是必须的,超线程技术(HT)就是利用特殊的硬件指令,把两个逻辑内核模拟成两个物理芯片,让单个处理器都能使用线程级并行计算,进而兼容多线程操作系统和软件,减少了CPU的闲置时间,提高的CPU的运行效率。
1
图1 打开超线程

(2)关闭节能

很多服务器出于能耗考虑,在出场时会在BIOS中打开节能模式,在节能模式下,CPU会根据机器负载动态调整频率。但是这个动态调频并不像想象中的那么美好,有时候会因此影响CPU的性能,在像Ceph这种需要高性能的应用场景下,建议关闭节能模式。关闭节能后,对性能还是有所提升的。

2
图2关闭节能

当然也可以在操作系统级别进行调整,详细的调整过程请参考链接(http://www.servernoobs.com/avoiding-cpu-speed-scaling-in-modern-linux-distributions-running-cpu-at-full-speed-tips/),但是不知道是不是由于BIOS已经调整的缘故,所以在CentOS 6.6上并没有发现相关的设置。

for CPUFREQ in /sys/devices/system/cpu/cpu*/cpufreq/scaling_governor; do [ -f $CPUFREQ ] || continue; echo -n performance > $CPUFREQ; done

(3)NUMA

简单来说,NUMA思路就是将内存和CPU分割为多个区域,每个区域叫做NODE,然后将NODE高速互联。 node内cpu与内存访问速度快于访问其他node的内存,NUMA可能会在某些情况下影响ceph-osd(http://lists.ceph.com/pipermail/ceph-users-ceph.com/2013-December/036211.html)。解决的方案,一种是通过BIOS关闭NUMA,另外一种就是通过cgroup将ceph-osd进程与某一个CPU Core以及同一NODE下的内存进行绑定。但是第二种看起来更麻烦,所以一般部署的时候可以在系统层面关闭NUMA。
3
图3 关闭NUMA

CentOS系统下,通过修改/etc/grub.conf文件,添加numa=off来关闭NUMA。

kernel /vmlinuz-2.6.32-504.12.2.el6.x86_64 ro root=UUID=870d47f8-0357-4a32-909f-74173a9f0633 rd_NO_LUKS rd_NO_LVM.UTF-8 rd_NO_MD SYSFONT=latarcyrheb-sun16 crashkernel=auto  KEYBOARDTYPE=pc KEYTABLE=us rd_NO_DM   biosdevname=0 numa=off

操作系统优化

1、Linux Kernel

Linux操作系统在服务器市场中占据了相当大的份额,各种发行版及其衍生版在不同领域中承载着各式各样的服务。针对不同的应用环境,可以对Linux的性能进行相应的调整,性能调优涵盖了虚拟内存管理、I/O子系统、进程调度系统、文件系统等众多内容,这里仅讨论对于Ceph性能影响显著的部分内容。

在Linux的各种发行版中,为了保证对硬件的兼容和可靠性,很多内核参数都采用了较为保守的设置,然而这无法满足我们对于高性能计算的需求,为了Ceph能更好地利用系统资源,我们需要对部分参数进行调整。

(1)调度

Linux默认的I/O调度一般针对磁盘寻址慢的特性做了专门优化,但对于SSD而言,由于访问磁盘不同逻辑扇区的时间几乎是一样的,这个优化就没有什么作用了,反而耗费了CPU时间。所以,使用Noop调度器替代内核默认的CFQ。操作如下:

echo noop > /sys/block/sdX/queue/scheduler

而机械硬盘设置为:

echo deadline > /sys/block/sdX/queue/scheduler

(2)预读

Linux默认的预读read_ahead_kb并不适合RADOS对象存储读,建议设置更大值:

echo “8192” > /sys/block/sdX/queue/read_ahead_kb

(3)进程数量

OSD进程需要消耗大量进程。关于内核PID上限,如果单服务器OSD数量多的情况下,建议设置更大值:

echo 4194303 > /proc/sys/kernel/pid_max

调整CPU频率,使其运行在最高性能下:

echo performance | tee /sys/devices/system/cpu/cpu*/cpufreq/scaling_governor >/dev/null2、内存

(1)SMP和NUMA

SMP(Symmetric Multi Processor)架构中,所有的CPU共享全部资源,如总线、内存和I/O等。多个CPU之间对称工作,无主从或从属关系。每个CPU都需要通过总线访问内存,整个系统中的内存能被每个CPU平等(消耗时间相同)的访问。然而,在CPU数量不断增加后,总线的压力不断增加,最终导致CPU的处理能力大大降低。

NUMA架构体系中由多个节点组成,每个节点有若干CPU和它们独立的本地内存组成,各个节点通过互联模块(CrossbarSwitch)进行访问,所以每个CPU可以访问整个系统的内存。但是,访问本地内存的速度远比访问远程内存要快,导致在进程发生调度后可能需要访问远端内存,这种情况下程序的效率会大大降低。

Ceph目前并未对NUMA架构的内存做过多优化,在日常使用过程中,我们通常使用2~4颗CPU,这种情况下,选择SMP架构的内存在效率上还是要高一些。如果条件允许,可以通过进程绑定的方法,在保证CPU能尽可能访问自身内存的前提下,使用NUMA架构。

(2)SWAP

当系统中的物理内存不足时,就需要将一部分内存非活跃(inactive)内存页置换到交换分区(SWAP)中。有时候我们会发现,在物理内存还有剩余的情况下,交换分区就已经开始被使用了,这就涉及到kernel中关于交换分区的使用策略,由vm.swappiness这个内核参数控制,该参数代表使用交换分区的程度:当值为0时,表示进可能地避免换页操作;当值为100时,表示kernel会积极的换页,这会产生大量磁盘IO。因此,在内存充足的情况下,我们一般会将该参数设置为0以保证系统性能。设定Linux操作系统参数:vm.swappiness=0,配置到/etc/sysctl.conf。

(3)内存管理

Ceph默认使用TCmalloc管理内存,在非全闪存环境下,TCmalloc的性能已经足够。全闪存的环境中,建议增加TCmalloc的Cache大小或者使用jemalloc替换TCmalloc。

增加TCmalloc的Cache大小需要设置环境变量,建议设置为256MB大小:

TCMALLOC_MAX_TOTAL_THREAD_CACHE_BYTES=268435456

使用jemalloc需要重新编译打包Ceph,修改编译选项:

–with-jemalloc–without-tcmalloc3、Cgroup

Cgroups是control groups的缩写,是Linux内核提供的一种可以限制、记录、隔离进程组(process groups)所使用的物理资源(如CPU、Memory、IO等)的机制。最初由Google的工程师提出,后来被整合进Linux内核。Cgroups也是LXC为实现虚拟化所使用的资源管理手段,可以说没有Cgroups就没有LXC。Cgroups内容非常丰富,展开讨论完全可以单独写一篇,这里我们简单说下Cgroups在Ceph中的应用。

说到Cgroups,就不得不说下CPU的架构,以E5-2620 v3为例(见图4):整颗CPU共享L3缓存,每个物理核心有独立的L1和L2缓存,如果开启超线程后两个逻辑CPU会共享同一块L1和L2,所以,在使用Cgroups的时候,我们需要考虑CPU的缓存命中问题。

4
图4 E5 2620 v3 CPU拓扑图

查看CPU的拓扑,可以通过hwloc工具(http://www.open-mpi.org/projects/hwloc/)来辨别CPU号码与真实物理核心的对应关系。例如在配置2个Intel(R) Xeon(R) CPU E5-2680 v2的服务器,CPU拓扑:

Machine (64GB)  NUMANode L#0 (P#0 32GB)    Socket L#0 + L3 L#0 (25MB)      L2 L#0 (256KB) + L1d L#0 (32KB) + L1i L#0 (32KB) + Core L#0        PU L#0 (P#0)        PU L#1 (P#20)      L2 L#1 (256KB) + L1d L#1 (32KB) + L1i L#1 (32KB) + Core L#1        PU L#2 (P#1)        PU L#3 (P#21)


      L2 L#2 (256KB) + L1d L#2 (32KB) + L1i L#2 (32KB) + Core L#2

        PU L#4 (P#2)

        PU L#5 (P#22)

      L2 L#3 (256KB) + L1d L#3 (32KB) + L1i L#3 (32KB) + Core L#3

        PU L#6 (P#3)

        PU L#7 (P#23)

      L2 L#4 (256KB) + L1d L#4 (32KB) + L1i L#4 (32KB) + Core L#4

        PU L#8 (P#4)

        PU L#9 (P#24)

      L2 L#5 (256KB) + L1d L#5 (32KB) + L1i L#5 (32KB) + Core L#5

        PU L#10 (P#5)

        PU L#11 (P#25)

      L2 L#6 (256KB) + L1d L#6 (32KB) + L1i L#6 (32KB) + Core L#6

        PU L#12 (P#6)

        PU L#13 (P#26)

      L2 L#7 (256KB) + L1d L#7 (32KB) + L1i L#7 (32KB) + Core L#7

        PU L#14 (P#7)

        PU L#15 (P#27)

      L2 L#8 (256KB) + L1d L#8 (32KB) + L1i L#8 (32KB) + Core L#8

        PU L#16 (P#8)

        PU L#17 (P#28)

      L2 L#9 (256KB) + L1d L#9 (32KB) + L1i L#9 (32KB) + Core L#9

        PU L#18 (P#9)

        PU L#19 (P#29)

    HostBridge L#0

      PCIBridge

        PCIBridge

          PCIBridge

            PCI 8086:1d6a

      PCIBridge

        PCI 8086:1521

          Net L#0 “eno1”

        PCI 8086:1521

          Net L#1 “eno2”

        PCI 8086:1521

          Net L#2 “eno3”

        PCI 8086:1521

          Net L#3 “eno4”

      PCIBridge

        PCI 1000:0079

          Block L#4 “sda”

          Block L#5 “sdb”

          Block L#6 “sdc”

          Block L#7 “sdd”

          Block L#8 “sde”

      PCIBridge

        PCI 102b:0522

          GPU L#9 “card0”

          GPU L#10 “controlD64”

      PCI 8086:1d02

        Block L#11 “sr0”

  NUMANode L#1 (P#1 32GB)

    Socket L#1 + L3 L#1 (25MB)

      L2 L#10 (256KB) + L1d L#10 (32KB) + L1i L#10 (32KB) + Core L#10

        PU L#20 (P#10)

        PU L#21 (P#30)

      L2 L#11 (256KB) + L1d L#11 (32KB) + L1i L#11 (32KB) + Core L#11

        PU L#22 (P#11)

        PU L#23 (P#31)

      L2 L#12 (256KB) + L1d L#12 (32KB) + L1i L#12 (32KB) + Core L#12

        PU L#24 (P#12)

        PU L#25 (P#32)

      L2 L#13 (256KB) + L1d L#13 (32KB) + L1i L#13 (32KB) + Core L#13

        PU L#26 (P#13)

        PU L#27 (P#33)

      L2 L#14 (256KB) + L1d L#14 (32KB) + L1i L#14 (32KB) + Core L#14

        PU L#28 (P#14)

        PU L#29 (P#34)

      L2 L#15 (256KB) + L1d L#15 (32KB) + L1i L#15 (32KB) + Core L#15

        PU L#30 (P#15)

        PU L#31 (P#35)

      L2 L#16 (256KB) + L1d L#16 (32KB) + L1i L#16 (32KB) + Core L#16

        PU L#32 (P#16)

        PU L#33 (P#36)

      L2 L#17 (256KB) + L1d L#17 (32KB) + L1i L#17 (32KB) + Core L#17

        PU L#34 (P#17)

        PU L#35 (P#37)

      L2 L#18 (256KB) + L1d L#18 (32KB) + L1i L#18 (32KB) + Core L#18

        PU L#36 (P#18)

        PU L#37 (P#38)

      L2 L#19 (256KB) + L1d L#19 (32KB) + L1i L#19 (32KB) + Core L#19

        PU L#38 (P#19)

        PU L#39 (P#39)

    HostBridge L#7

      PCIBridge

        PCI 8086:10fb

          Net L#12 “enp129s0f0”

        PCI 8086:10fb

          Net L#13 “enp129s0f1”

由此可见,操作系统识别的CPU号和物理核心是一一对应的关系,在对程序做CPU绑定或者使用Cgroups进行隔离时,注意不要跨CPU,以便更好地命中内存和缓存。另外也看到,不同HostBridge的对应PCI插槽位置不一样,管理着不同的资源,CPU中断设置时候也需要考虑这个因素。

总结一下,使用Cgroups的过程中,我们应当注意以下问题:

· 防止进程跨CPU核心迁移,以更好的利用缓存;

· 防止进程跨物理CPU迁移,以更好的利用内存和缓存;

· Ceph进程和其他进程会互相抢占资源,使用Cgroups做好隔离措施;

· 为Ceph进程预留足够多的CPU和内存资源,防止影响性能或产生OOM。尤其是高性能环境中并不能完全满足Ceph进程的开销,在高性能场景(全SSD)下,每个OSD进程可能需要高达6GHz的CPU和4GB以上的内存。

因为优化部分涉及内容较多,所以分为两篇文章来讲述,希望本文能够给予Ceph新手参考,请读者见仁见智,预知后事如何,请期待《部署调优关卡之调优二》。