Linux性能调优
Linux发行版和Linux内核提供了各种参数和设置,以让Linux管理员调整系统从而得到最大限度的性能。正如本书之前所描述的,没有神奇的调整旋钮可以任意调整应用程序的性能。下面章节中讨论的设置将改善某些硬件配置和应用程序的性能。它们有可能对于提高Web服务器性能,对于数据库服务器的性能会产生不利影响。
本章介绍了调整Linux发行版2.6内核的步骤。目前2.6发行版内核,从2.6.9到2.6.19有所不同,一些调整选项可能只适用于一个特定的内核版本。描述这些参数的目的是可以让你在大多数情况下改善性能,并使你对Linux中的技术有基本的了解,包括:
□ Linux内存管理
□ 系统清理
□ 磁盘子系统调优
□ 使用sysctl对内核调优
□ 网络优化
本章包括以下几个部分:
□ 调整原则
□ 安装注意事项
□ 更改内核参数
□ 调整处理器子系统
□ 调整内存子系统
□ 调整磁盘子系统
□ 调整网络子系统
□ 限制资源使用
5.1 调整原则
调整任何系统应该遵循一些简单的原则,其中最重要的是变更管理。通常系统调优的第一步应该是分析和评估当前系统配置。确保系统按照硬件制造商所述运行,所有设备在最佳的模式下运行,这将为以后的任何调整创建一个坚实的基础。另外在执行任何特定调整任务之前,系统被设计为最佳性能,最小化运行不必要的任务和子系统。最后,当对特定系统进行调整的时候,应该注意的是,调整通常是让系统适应一个特定的工作负载。因此,系统在预期的负载特征下会有更好的表现,但是在不同的工作模式下它可能表现得更糟。举个例子来说,调整系统具有低延迟,但大多数的时候不良影响在磁盘上。
5.1.1 变更管理
虽然不是与性能调优严格相关,但是变更管理可能是成功进行性能调优的一个重要手段。以下因素可能是你的第二天性,但是作为一个提醒,我们要强调几点:
□ 在调整任何Linux系统之前,实施适当的变更管理过程。
□ 绝不在生产服务器上开始调整设置。
□ 绝不在调整过程期间改变一个以上的变量。
□ 重新启动可能提高性能的参数;有时统计会发挥作用。
□ 记录成功的参数并分析它们,无论你认为它们是多么微不足道。Linux性能可以大大受益于在生产环境中获得的任何结果。
5.2 安装注意事项
理想情况下,在服务器系统上对一个特定性能目标的调优,应该从设计和安装阶段开始。适当的安装就是调整系统适应工作量模式,这能为之后的调优节省大量的时间。
5.2.1 安装
在一个完美的世界中,任何指定系统的调优都是在一个非常早期的阶段就开始了。理想情况下,一个系统是专门针对应用程序的需要和预期工作量所定制的。我们知道,一般一个管理员由于一个瓶颈需要调整一个已经安装好的系统,但是我们要强调的是,调优可能在操作系统的初始化安装期间也是有用的。
在开始Linux安装之前,有几个问题需要解决,包括:
□ 处理器技术的选择
□ 磁盘技术的选择
□ 应用程序
然而这些问题超出了本书的范围。
理想情况下,在开始安装之前先回答以下问题:
□ 我需要什么特点和版本的Linux? 在你收集了商业需求和应用程序需求之后,决定使用哪个Linux版本。企业通常有合同协议,可以将一个特定Linux发行版作为普通使用。经济能力和合同利益决定使用的Linux版本。然而,如果你在选择Linux发行版本上有完全的自由,则有以下一些问题需要考虑:
• 支持企业级Linux发行版或是一个定制发行版。在一些科学的环境中可以接受运行一个不受支持的Linux版本,比如Fedora。考虑到企业工作负载,我们强烈建议使用完全支持的发行版,比如Red Hat Enterprise Linux或Novell SUSE Enterprise Linux。
• 什么版本的企业发行版?几乎每个企业Linux发行版都有自己的特点,它们的内核版本、支持的软件包、特征等,最重要的是它们在硬件支持的水平上有所不同。在任何安装之前,仔细查看支持的硬件配置,这样将不会遗漏任何硬件的功能。
□ 选择正确的内核。 企业级Linux发行版提供了几种内核软件包。出于性能考虑,一定要为你的系统选择最合适的内核。然而,大多数情况下正确的内核是在安装程序中选择的。记住,准确的内核软件包名称由于发行版不同是有差异的。
注意: 最新的内核具有被称为SMAP切换的能力,它可在启动时优化自己。详情参考发行版说明。
□ 选择什么样的分区布局? 磁盘子系统的分区布局通常是由应用程序的需要、系统管理方面考虑、个人喜好所决定的,而不是由性能所决定的。在大多数情况下已经给出分区布局。我们唯一的建议是,如果可能,应使用一个swap分区。swap分区,而不是swap文件,对性能是有好处的,因为没有文件系统的开销。swap分区很简单,还可以扩展额外的swap分区,或如果需要甚至是扩展swap文件。
□ 使用的文件系统是什么? 不同的文件系统在数据完整性和性能上有不同的特点。一些文件系统可能在有些Linux发行版或应用程序上是被不支持的。对于大多数服务器,安装程序建议的默认文件系统将提供足够的性能。如果你有最小延迟或最大吞吐量的具体需求,则建议你根据这些需求选择各自的文件系统。参考5.6节中详细的选择标准。
□ 软件包的选择:“最小化”或是“所有”? 在Linux的安装期间,管理员面临着要选择“最小化”还是“所有”的安装方法。有些人喜欢所有安装,因为这样很少需要解决安装软件包的依赖性。
考虑以下几点:虽然没有涉及性能,选择“所有”或“几乎所有”的安装方式对于系统安全威胁有很重要的影响。在生产系统上开发工具的可用性可能导致明显的安全威胁。安装较少的数据包,浪费更少的磁盘空间,一个具有较多空闲空间的磁盘要比一个具有很小空闲空间的磁盘性能更好。如果需要,智能化软件安装程序,比如Red Hat Packet Manager或rpm或yum将自动解决依赖性。因此,建议你考虑最小化软件包选择,只安装那些可以使应用程序成功实现的必需软件包。
□ Netfilter配置。 你需要决定Netfilter防火墙配置是否需要。Netfilter防火墙通常被用来保护系统免受恶意攻击。然而,太过复杂的防火墙规则在高数据流量环境中会降低性能。参考5.7.8节中的内容。
□ SELinux。 在某些Linux发行版中,比如Red Hat Enterprise Linux 5.x,安装程序让你选择是否开启SELinux。SELinux会带来明显的性能损失,并且应仔细地评估是否真的需要为一个特定的系统通过SELinux提供额外的安全。更多信息参考5.2.4节的介绍。
□ 运行级别的选择。 在安装过程最后给出的选择是:系统默认运行级别的选择。除非你有特殊的需要,在运行级别5(图形用户模式)运行你的系统,否则强烈建议你在所有服务器系统上使用运行级别3。正常情况下在一个数据中心中驻留的系统是不应该需要图形界面的,运行级别5的开销是相当大的。如果安装程序不提供运行级别的选择,建议你在初始化系统配置之后手动选择运行级别3。
5.2.2 检查当前的配置
如前所述,尝试为任何系统建立一个坚实的基础是很重要的。坚实的基础可确保所有子系统按照设计的方式工作,没有异常。一个异常的例子是一个千兆网络接口卡和一个有网络性能瓶颈的服务器。如果网卡自动协商为100MBit半双工,则调整Linux内核的TCP/IP实现可能没有多大用处。了解系统理论能力是非常重要的。
□ CPU
• CPU(S)模式是什么?处理器的架构是哪一个?使用什么主板芯片?
• 多少个socket?每个CPU有多少个核心?如果核心支持超线程,那么每个核心上有多少个线程?每个socket是如何连接的,数据速率是多少(QPI, HyperTransport, FSB)?
• CPU每个层级的cache有多大?cache是核心私有的还是与socket上的其他核心共享的,还是与一个系统中的其他socket共享的?cache是如何被组织和访问的?
• 处理器支持哪些特征?处理器支持硬件虚拟化吗?处理器的架构是32bit还是64bit?有其他特殊功能或指令吗?
□ 内存
• 系统有多少内存?硬件允许的最大数量的内存是多少?
• 系统使用的内存技术是什么?它具有什么带宽和延迟?
• 系统的内存是如何被连接的,通过一个Northbridge和前端总线,或者直接到CPU;是SMP或NUMA吗?如果是NUMA,NUMA节点使用什么技术,当访问不同区域的内存时会有什么影响?
□ 存储
• 附加在系统上的存储设备是什么类型的?实际设备是什么模型?它们是基于旋转磁盘片的传统硬盘,还是固态硬盘(solid-state disk–SSD)驱动器?
• 传统的硬盘,它们有没有寻址时间和旋转延迟?你期待的最大化带宽和延迟是多少?访问驱动器不同分区的速度变化是多少?
• SSD驱动器,它们使用的闪存是MLC还是SLC?它们支持TRIM吗?如何有效地对它们的耐久性和垃圾收集系统进行测量?
• 磁盘阵列,已使用的硬件RAID级别是什么?在一个阵列里有多少个存储设备?RAID级别是条带,在阵列中每个条带的大小是多少?
• 直连式存储使用什么进行互连(SATA、SAS或其他)?它是怎么连接主板到系统的其他部分呢?是否有充足的带宽让所有的设备支持通信的连接?
• SAN设备,使用Fibre Channel或iSCSI越过以太网?SAN设备的带宽和延迟是多少?多路经SAN设备,基于可用路径的性能变化几何?
□ 网络
• 系统上可用的网络接口卡是什么?使用的网络技术是什么(以太网,无限带宽技术等)?
• 对机器来说什么网络是可用的或需要的?什么是VLAN?如何大量利用这些网络?它们有特殊用途吗(存储网络、带外管理等)?它们运转的速度是多少?
• 我们需要特别的能力吗(例如,I/O虚拟化可以将一个网卡划分成多种vNIC作为系统上的guest虚拟机)?
物理访问一台机器可以容易地回答这些问题,通常管理员在一个远程数据中心管理主机。下面我们将寻找能够用来帮助系统管理员远程收集系统上使用的硬件的信息的方法和工具。
1.查看内核消息
一个系统上有关硬件最简单、最详细、最直接的信息源常常是Linux内核。因为内核是访问所有硬件的主要介质。内核通过/proc文件系统、/sys文件系统和内核消息来公开此信息。
我们可以从内核消息中找到可用的信息。为了能在几乎任何环境中生成消息,设计机制为:将内核消息写入到一个预分配的环形缓冲区,像是已知的dmesg缓冲区。想要读取消息,必须以某种方式将它们放入用户空间。
在RHEL中,这些消息被klogd进程监听,并将消息转发到syslog(或rsyslog)日志库,记录的内核消息默认放在/var/log/messages下。另一种方法是使用dmesg命令导出当前dmesg缓冲区中的内容。
通常审查dmesg缓冲区有3个动机:
□ 回顾一下启动时的硬件检测。
□ 观察显示出的硬件连接或检测的信息。
□ 观察显示出的警告或错误情况发生的信息。
在启动之后,dmesg缓冲区将包含大量信息,下面是dmesg的部分输出:
Initializing cgroup subsys cpuset
Initializing cgroup subsys cpu
Linux version 2.6.32-431.el6.x86_64 (mockbuild@x86-023.build.eng.bos.redhat.com) (gcc
version 4.4.7 20120313 (Red Hat 4.4.7-4) (GCC)) #1 SMP Sun Nov 10 22:19:54 EST 2013
Command line: ro root=/dev/mapper/VolGroup-lv_root rd_NO_LUKS LANG=en_US.UTF-8 rd_NO_MD
rd_LVM_LV=VolGroup/lv_swap SYSFONT=latarcyrheb-sun16 rd_LVM_LV=VolGroup/lv_root
KEYBOARDTYPE=pc KEYTABLE=us rd_NO_DM rhgb quiet
KERNEL supported cpus:
Intel GenuineIntel
AMD AuthenticAMD
Centaur CentaurHauls
Disabled fast string operations
BIOS-provided physical RAM map:
BIOS-e820: 0000000000000000 - 000000000009ec00 (usable)
BIOS-e820: 000000000009ec00 - 00000000000a0000 (reserved)
BIOS-e820: 00000000000dc000 - 0000000000100000 (reserved)
BIOS-e820: 0000000000100000 - 000000007fee0000 (usable)
BIOS-e820: 000000007fee0000 - 000000007feff000 (ACPI data)
BIOS-e820: 000000007feff000 - 000000007ff00000 (ACPI NVS)
BIOS-e820: 000000007ff00000 - 0000000080000000 (usable)
BIOS-e820: 00000000f0000000 - 00000000f8000000 (reserved)
BIOS-e820: 00000000fec00000 - 00000000fec10000 (reserved)
BIOS-e820: 00000000fee00000 - 00000000fee01000 (reserved)
BIOS-e820: 00000000fffe0000 - 0000000100000000 (reserved)
DMI present.
SMBIOS version 2.4 @ 0xF6B30
DMI: VMware, Inc. VMware Virtual Platform/440BX Desktop Reference Platform, BIOS 6.00 07/31/2013
Phoenix BIOS detected: BIOS may corrupt low RAM, working around it.
e820 update range: 0000000000000000 - 0000000000010000 (usable) ==> (reserved)
Hypervisor detected: VMware
e820 update range: 0000000000000000 - 0000000000001000 (usable) ==> (reserved)
e820 remove range: 00000000000a0000 - 0000000000100000 (usable)
last_pfn = 0x80000 max_arch_pfn = 0x400000000
…
然而当前的消息将填充缓冲区,并随着时间的推移最终循环并覆盖原来的信息。因此,在每次启动,Red Hat Enterprise Linux存储当前dmesg缓冲区的内容到/var/log/dmesg。花费一些时间查阅内核启动信息能够得到关于一个平台的硬件的综合情况。
2.查看CPU信息
现代系统中通常有多个CPU,每个socket会有多个核心,可能每个核心有多个超线程,有不同级别的本地和共享cache。lscpu命令可以提供一个本地配置的快速概要。
下面是lscpu的输出和相关信息的说明:
[root@zyg ~]# lscpu
Architecture: x86_64 #cpu架构
CPU op-mode(s): 32-bit, 64-bit
CPU(s): 16 #内核在调度任务时可用的逻辑CPU数量
Thread(s) per core: 2 #每个核心上超线程的数量
Core(s) per socket: 4 #每个socket上核心的数量
CPU socket(s): 2 #物理socket的数量
NUMA node(s): 2 #NUMA系统上内存总线的数量
Vendor ID: GenuineIntel
CPU family: 6
Model: 44
Stepping: 2
CPU MHz: 2393.967
Virtualization: VT-x #CPU硬件虚拟化支持
L1d cache: 32K #CPU相关的cache大小
L1i cache: 32K
L2 cache: 256K
L3 cache: 12288K
NUMA node0 CPU(s): 0,2,4,6,8,10,12,14 #映射逻辑CPU到NUMA地址总线
NUMA node1 CPU(s): 1,3,5,7,9,11,13,15
lscpu列出多个CPU cache的大小,它不会告诉我们逻辑CPU是如何共享cache的。使用lscpu–p,可输出cache共享信息:
[root@zyg ~]# lscpu -p
programs. Each different item in every column has an unique ID
starting from zero.
CPU,Core,Socket,Node,,L1d,L1i,L2,L3
0,0,0,0,,0,0,0,0
1,1,1,1,,1,1,1,1
2,2,0,0,,2,2,2,0
3,3,1,1,,3,3,3,1
4,4,0,0,,4,4,4,0
5,5,1,1,,5,5,5,1
6,6,0,0,,6,6,6,0
7,7,1,1,,7,7,7,1
8,0,0,0,,0,0,0,0
9,1,1,1,,1,1,1,1
10,2,0,0,,2,2,2,0
11,3,1,1,,3,3,3,1
12,4,0,0,,4,4,4,0
13,5,1,1,,5,5,5,1
14,6,0,0,,6,6,6,0
15,7,1,1,,7,7,7,1
注意最后4个字段,L1和L2 cache每对超线程是不同的,L3 cache是被各自socket上的所有核心共享的,附加一个单独的内存地址总线。
lscpu命令是在Red Hat Enterprise Linux 6中引入的。在之前的Red Hat Enterprise Linux版本中,使用x86info命令提供类似的信息,其可在x86info软件包中找到。下面显示的是x86info输出的部分信息:
[root@zyg ~]# x86info
x86info v1.25. Dave Jones 2001-2009
Feedback to davej@redhat.com .
Found 16 CPUs
CPU #1
EFamily: 0 EModel: 2 Family: 6 Model: 44 Stepping: 2
CPU Model: Unknown model.
Processor name string: Intel(R) Xeon(R) CPU E5620 @ 2.40GHz
Type: 0 (Original OEM) Brand: 0 (Unsupported)
Number of cores per physical package=16
Number of logical processors per socket=32
Number of logical processors per core=2
APIC ID: 0x20 Package: 0 Core: 1 SMT ID 0
————————————————————————–
CPU #2
EFamily: 0 EModel: 2 Family: 6 Model: 44 Stepping: 2
CPU Model: Unknown model.
Processor name string: Intel(R) Xeon(R) CPU E5620 @ 2.40GHz
Type: 0 (Original OEM) Brand: 0 (Unsupported)
Number of cores per physical package=16
Number of logical processors per socket=32
Number of logical processors per core=2
APIC ID: 0x0 Package: 0 Core: 0 SMT ID 0
————————————————————————–
……
3.确定SMBIOS/DMI信息
Dmidecode工具(由dmidecode软件包提供)可以探测本地System Management BIOS(SMBIOS)和Desktop Management Interface(DMI)并提供大量有关本地硬件的信息。
首先看到BIOS的信息:
[root@zyg ~]# dmidecode
dmidecode 2.10
SMBIOS 2.6 present.
84 structures occupying 5097 bytes.
Table at 0xCF49C000.
Handle 0xDA00, DMI type 218, 11 bytes
OEM-specific Type
Header and Data:
DA 0B 00 DA B2 00 17 00 0E 20 00
Handle 0x0000, DMI type 0, 24 bytes
BIOS Information
Vendor: Dell Inc.
Version: 6.1.0
Release Date: 10/18/2011
Address: 0xF0000
Runtime Size: 64 kB
ROM Size: 4096 kB
Characteristics:
ISA is supported
PCI is supported
PNP is supported
BIOS is upgradeable
BIOS shadowing is allowed
Boot from CD is supported
Selectable boot is supported
EDD is supported
Japanese floppy for Toshiba 1.2 MB is supported (int 13h)
5.25”/360 kB floppy services are supported (int 13h)
5.25”/1.2 MB floppy services are supported (int 13h)
3.5”/720 kB floppy services are supported (int 13h)
8042 keyboard services are supported (int 9h)
Serial services are supported (int 14h)
CGA/mono video services are supported (int 10h)
ACPI is supported
USB legacy is supported
BIOS boot specification is supported
Function key-initiated network boot is supported
Targeted content distribution is supported
BIOS Revision: 6.1
相关服务器的系统信息:
Handle 0x0100, DMI type 1, 27 bytes
System Information
Manufacturer: Dell Inc.
Product Name: PowerEdge R710
Version: Not Specified
Serial Number: C5V8D3X
UUID: 6C6C6566-0035-5610-8038-C3C06F663358
Wake-up Type: Power Switch
SKU Number: Not Specified
Family: Not Specified
相关服务器上(部分)CPU的信息:
Handle 0x0400, DMI type 4, 40 bytes
Processor Information
Socket Designation: CPU1
Type: Central Processor
Family: Xeon
Manufacturer: Intel
ID: C2 06 02 00 FF FB EB BF
Signature: Type 0, Family 6, Model 44, Stepping 2
Flags:
FPU (Floating-point unit on-chip)
VME (Virtual mode extension)
DE (Debugging extension)
PSE (Page size extension)
TSC (Time stamp counter)
MSR (Model specific registers)
PAE (Physical address extension)
MCE (Machine check exception)
CX8 (CMPXCHG8 instruction supported)
APIC (On-chip APIC hardware supported)
SEP (Fast system call)
MTRR (Memory type range registers)
PGE (Page global enable)
MCA (Machine check architecture)
CMOV (Conditional move instruction supported)
PAT (Page attribute table)
PSE-36 (36-bit page size extension)
CLFSH (CLFLUSH instruction supported)
DS (Debug store)
ACPI (ACPI supported)
MMX (MMX technology supported)
FXSR (Fast floating-point save and restore)
SSE (Streaming SIMD extensions)
SSE2 (Streaming SIMD extensions 2)
SS (Self-snoop)
HTT (Hyper-threading technology)
TM (Thermal monitor supported)
PBE (Pending break enabled)
Version: Intel(R) Xeon(R) CPU E5620 @ 2.40GHz
Voltage: 1.2 V
External Clock: 5860 MHz
Max Speed: 3600 MHz
Current Speed: 2400 MHz
Status: Populated, Enabled
Upgrade: Socket LGA1366
L1 Cache Handle: 0x0700
L2 Cache Handle: 0x0701
L3 Cache Handle: 0x0702
Serial Number: Not Specified
Asset Tag: Not Specified
Part Number: Not Specified
Core Count: 4
Core Enabled: 4
Thread Count: 8
Characteristics:
64-bit capable
列出主板上多种设备,比如网络接口卡、显卡、RAID控制器:
Handle 0x0A00, DMI type 10, 16 bytes
On Board Device 1 Information
Type: Video
Status: Enabled
Description: Embedded Matrox G200 Video
On Board Device 2 Information
Type: Ethernet
Status: Enabled
Description: Embedded Broadcom 5709C NIC 1
On Board Device 3 Information
Type: Ethernet
Status: Enabled
Description: Embedded Broadcom 5709C NIC 2
On Board Device 4 Information
Type: Ethernet
Status: Enabled
Description: Embedded Broadcom 5709C NIC 3
On Board Device 5 Information
Type: Ethernet
Status: Enabled
Description: Embedded Broadcom 5709C NIC 4
On Board Device 6 Information
Type: SAS Controller
Status: Enabled
Description: Integrated RAID Controller
还有已安装的(部分)RAM信息:
Handle 0x1000, DMI type 16, 15 bytes
Physical Memory Array
Location: System Board Or Motherboard
Use: System Memory
Error Correction Type: Multi-bit ECC
Maximum Capacity: 288 GB
Error Information Handle: Not Provided
Number Of Devices: 18
Handle 0x1101, DMI type 17, 28 bytes
Memory Device
Array Handle: 0x1000
Error Information Handle: Not Provided
Total Width: 72 bits
Data Width: 64 bits
Size: 4096 MB
Form Factor: DIMM
Set: 1
Locator: DIMM_A2
Bank Locator: Not Specified
Type: DDR3
Type Detail: Synchronous
Speed: 1333 MHz
Manufacturer: 00CE04B380CE
Serial Number: 86B07DE9
Asset Tag: 02120621
Part Number: M393B5273DH0-YH9
Rank: 2
注意这些信息是由内核中sysfs文件系统提供的,在/sys/class/dmi目录下:
[root@zyg ~]# ls /sys/class/dmi/id/
bios_date board_serial chassis_type product_name sys_vendor
bios_vendor board_vendor chassis_vendor product_serial uevent
bios_version board_version chassis_version product_uuid
board_asset_tag chassis_asset_tag modalias product_version
board_name chassis_serial power subsystem
[root@zyg ~]# cat /sys/class/dmi/id/product_name
PowerEdge R710
[root@zyg ~]# cat /sys/class/dmi/id/product_uuid
66656C6C-3500-1056-8038-C3C06F663358
[root@zyg ~]# cat /sys/class/dmi/id/product_serial
C5V8D6X
5.2.3 最小化资源使用
以最高性能水平设计的系统必须最小化任何资源的浪费。赛车不能够提供如同普通客车的舒适,但是驾驶的目的是尽可能地比奖杯持有者快,并且舒适的座椅是资源的浪费。同样的道理也适用于服务器系统。运行消耗内存的GUI和大量不必要的守护进程将会降低整体性能。本节介绍系统资源消耗的优化。
1.守护进程
在Linux发行版默认安装之后,有些不必要的服务和守护进程可能会被启用。要禁用不需要的守护进程减少整个系统的内存占用量,减少运行进程的数量和上下文切换,更重要的是,减少暴露的各种安全威胁。禁用不需要的守护进程也可以降低服务器的启动时间。
默认情况下,在大多数系统上,有些已经启动的守护进程可以被安全地停止和禁用。表5-1列出了在各种Linux发行版中已经启动的守护进程。如果适用,应考虑在你的环境中禁用它们。注意,表中列出了一些商用Linux发行版各自的守护进程。特定的Linux安装在运行守护进程的确切数量上可能有所不同。这些守护进程更详细的说明,参考下面的system-config-services的显示。
表5-1 默认安装的可调整启动的守护进程
NetworkManager 这是一个简单管理网络连接的工具,如果你希望手工管理网络可以禁用
abrt-ccpp
abrt-oops
abrtd abrt(automatic bug report tool)服务监控应用程序崩溃并收集崩溃时数据,稍后汇报给Bugzilla以方便开发者修复。可以禁用
acpid Advanced Configuration and PowerInterface,为替代传统的APM电源管理标准而推出的新型电源管理标准。建议笔记本用户开启它。服务器一般不需要acpi
atd 在特定的时间运行at命令来调度要运行的命令。如果不使用可以禁用
autofs 自动挂载需求的文件系统(例如,自动挂载CD-ROM)。在服务器系统上,文件系统很少有自动挂载
bluetooth 当发现蓝牙设备时,触发bluetoothd启动。如果不连接蓝牙设备可以禁用
cgconfig 创建和设置control group文件系统。如果不使用cgroup可以禁用
cgred cgroup规则引擎用来自动对进程进行分类。如果不使用可以禁用
cpuspeed 守护进程将自动调整CPU的频率,在服务器环境中,建议关闭这个守护进程
cpus 通用UNIX打印系统,如果不打算在服务器上使用打印服务可以禁用
dnsmasq 如果你的服务器不是用作DNS缓存服务器可以禁用
ebtables 与iptables类似,只不过是对数据链路层的MAC做过滤,可以禁用
firstboot 在第一次安装后引导你对系统进行配置,可以禁用
hacacheclean 将mod_disk_cache的存储缓冲区所占用的空间限定在一个合理的水平。可以禁用
ip6tables ipv6防火墙,服务器一般不启用,可以禁用
iptables ipv4防火墙,服务器一般不启用,可以禁用
kdump 在系统崩溃、死锁或者死机的时候用来收集内存运行的状态和数据信息,可以禁用
mdmonitor 检查系统上的所有软件RAID阵列的状态,可以禁用
netcf-transaction 保存当前网络配置的状态,并在稍后恢复配置或提交新的配置。可以禁用
netconsole 用于将本地主机的日志信息打印到远程主机上,如果不使用远程日志,可以禁用
nfs 如果不是使用NFS服务,可以禁用
ntpd NTP(网络时间协议)用来与时间服务器进行时间同步。如果不需要进行时间同步,可以禁用
ntpdate 用通过轮询NTP服务器得到的时间来设置本地日期和时间。如果不需要进行时间同步,可以禁用
numad 动态监视系统的运行和内存的使用,并动态平衡CPU和内存的负载。如果不使用NUMA架构的服务器,可以禁用
oddjobd oddjobd服务提供支持,当无特权的应用程序需要执行一组特权操作时,代表它们执行。可以禁用
postfix 系统中的MTA,如果服务器不需要邮件服务,可以禁用
psacct 审计系统账号连接时间,用户操作。可以禁用
quota_nld 监听netlink socket并通过内核产生磁盘配额记录警告,并将其传递给系统D-Bus或终端用户。可以禁用
radvd 定期发送IPv6路由通告消息和回应路由请求消息。可以禁用
rdisc 用来在本地子网中发现路由器。可以禁用
restorecond 使用inotify寻找在/etc/selinux/restorecond.conf文件中指定的新文件,并恢复正确的安全上下文。如果不使用SELinux,可以禁用
rhnsd 负责定期连接到红帽网络服务器来检查更新、通知。如果没有购买红帽的服务,可以禁用
rngd 收集来自硬件源的熵值并写入到/dev/random/。可以禁用
rpcidmapd 在NFSv4挂载时,用来映射用户名和组到UID和GID。如果服务器不使用NFS服务,可以禁用
rpcsvcgssd 管理服务器上的RPCSEC GSS,用于安全NFS挂载。如果服务器不使用NFS服务,可以禁用
rsync 如果服务器不使用xinetd的rsync服务,可以禁用
sandbox 当使用sandbox、xguest、pam_namespace的时候,该服务将不实际运行任何服务,而是在/var/tmp、/tmp/、家目录中使用这些工具。如果不使用sandbox、xguest、pam_namespace,可以禁用
saslauthd 使用cyrus-sasl库处理明文验证请求。如果不使用cyrus-sasl库,可以禁用
smartd 监控本地硬盘的SMART(Self-Monitoring, Analysis, Reporting Technology)状态,并提供先进的磁盘退化和故障的报警。可以禁用
sssd 提供了一组守护进程来管理访问远程目录和身份验证机制。如果不使用用户帐号的远程验证可以禁用
wdaemon 帮助X.org支持Wacom手写板。可以禁用
winbind 允许UNIX系统利用Windows NT的用户账号信息。如果服务器不提供samba服务或samba服务器不是通过Windows域验证。可以禁用
wpa_supplicant 这是一个用来连接无线网络的工具。在不使用无线网络的系统上可以禁用
ypbind 这个守护进程是在NIS/YP客户端上运行的,并将它绑定到一个NIS域。作为NIS客户端它的运行必须基于glibc,但是在使用NIS的系统上不应该启用它
在Red Hat Enterprise Linux和Novell SUSE上,chkconfig命令为管理员提供了易于使用的界面用来更改各种守护进程的启动选项。使用chkconfig运行的第一个命令是检查所有运行的守护进程:
[root@zyg ~]# chkconfig –list | grep on
如果你不希望守护进程在下次机器启动时启动,可以root身份运行下列命令之一。它们可实现相同的效果,不同之处在于第二个命令在所有运行级别禁用守护进程,而–level标志可以用来说明确切的运行级别:
[root@zyg ~]# chkconfig –level 2345 postfix off
[root@zyg ~]# chkconfig postfix off
提示: 如果不想浪费时间等待重新启动的完成,只需要分别改变运行级别为1,并返回3或5。
还有另外一个有用的系统命令,/sbin/service,它可以让管理员立刻改变任何已注册服务的状态。在第一个实例中,通过运行这个命令,管理员可以始终选择检查一个服务(例如,sendmail)的当前状态:
[root@zyg ~]# service postfix status
在下面的例子中,使用这个命令立刻停止sendmail守护进程:
[root@zyg ~]# service postfix stop
service命令特别有用,因为它可以让你立刻核实是否需要一个守护进程。通过chkconfig执行的更改不会立刻激活,除非改变系统的运行级别或执行重新启动。然而,通过service命令禁用的守护进程,在重新启动之后将重新启用。对于不可使用service命令的Linux发行版,可以通过init.d目录启动或停止守护进程。检查CUPS守护进程的状态,例如,可以像这样执行:
[root@zyg ~]# /etc/init.d/cups status
同样,可以通过基于图形界面的程序修改已启动的守护进程,如图5-1所示。在Red Hat Enterprise Linux中运行服务配置图形界面,单击System→Administration→Services命令,或运行system-config-services这个命令。
图5-1 Red Hat服务配置接口
2.更改运行级别
只要有可能,不要在Linux服务器上运行图形用户界面。通常情况下,大多数Linux管理员都认为,在Linux服务器上是不需要图形界面的。通过命令行,可以重定向X显示,通过Web浏览器界面,所有管理的任务可以有效地被实现。如果你更喜欢图形界面,有几个有用的基于Web的工具,比如webmin、Linuxconf、SWAT。
提示: 即使在本地服务器上禁用GUI,你仍可以远程连接并使用图形界面。要做到这一点,使用带有-X参数的ssh命令。
如果必须使用图形界面,要根据需要启动和停止而不是一直运行。大多数情况下,当机器启动起来的时候,不要启动X Server,服务器应该运行在运行级别3。如果想重新启动X Server,则可以在命令提示符下使用startx。
□ 通过使用runlevel命令确定机器运行在哪个运行级别。这将打印出之前的(当前运行级别的上一次运行级别)运行级别和当前的运行级别。例如,N 5表示,没有之前的运行级别(N),当前运行级别是5。
□ 使用init命令可以在运行级别之间切换。例如,切换到运行级别3,输入命令init 3。
在Linux中使用的运行级别:
0 Halt(停止。不要设置为初始默认运行级别,否则在启动引导过程结束之后,服务器将立即关闭。)
1 Single user mode(单用户模式)
2 Multiuser,without NFS(同运行级别3一样,但是没有联网)
3 Full multiuser mode(多用户字符界面)
4 Unused(未使用)
5 X11(多用户图形界面)
6 Reboot(不要设置为初始默认运行级别,否则在启动时,服务器将连续重新启动。)
设置一台机器在开机时的初始运行级别,如下面所示,修改/etc/inittab文件:
id:3:initdefault:
修改/etc/inittab
[root@zyg ~]# vim /etc/inittab
inittab is only used by upstart for the default runlevel.
#
ADDING OTHER CONFIGURATION HERE WILL HAVE NO EFFECT ON YOUR SYSTEM.
#
System initialization is started by /etc/init/rcS.conf
#
Individual runlevels are started by /etc/init/rc.conf
#
Ctrl-Alt-Delete is handled by /etc/init/control-alt-delete.conf
#
Terminal gettys are handled by /etc/init/tty.conf and /etc/init/serial.conf,
with configuration in /etc/sysconfig/init.
#
upstart works, see init(5), init(8), and initctl(8).
#
Default runlevel. The runlevels used are:
# 0 - halt (Do NOT set initdefault to this)
# 1 - Single user mode
# 2 - Multiuser, without NFS (The same as 3, if you do not have networking)
# 3 - Full multiuser mode
# 4 - unused
# 5 - X11
# 6 - reboot (Do NOT set initdefault to this)
#
id:3:initdefault:
5.2.4 SELinux
Red Hat Enterprise Linux 4引入了一个新的安全模型,SELinux(Security Enhanced Linux),很明显使用它可以拥有更高的安全性。SELinux引入的强制访问策略模式克服了Linux使用的标准自主访问模型的局限性。如图5-2所示SELinux在用户和进程级别上强制安全性,所以任何特定进程的安全漏洞,只影响分配给这个进程的资源,而不是整个系统。SElinux的工作就像是一个虚拟机器。例如,如果一个恶意攻击者利用Apache使用根目录,那么只有分配给Apache守护进程的资源会被破坏。
图5-2 SELinux的原理概述
然而,强制使用这样一个基于安全模型的策略是要付出代价的。用户或进程每次访问系统资源时,SELinux必须控制I/O设备。检查权限的过程中可以导致高达10%的开销。SELinux对于任何边缘服务器是很有价值的,比如防火墙,或是Web服务器,但是添加到后台数据库服务器的安全级别可以在性能上带来无法证实的损失。
通常情况下,禁用SELinux最简单的方法是起初就不要安装它。但是通常使用默认参数的系统就已经安装了,也没有注意到SELinux会影响性能。在安装之后也可以禁用SELinux,在GRUB引导加载程序中,在正在运行的内核所在行中附加条目selinux=0即可。
编辑grub.conf文件禁用SELinux:
[root@zyg ~]# vim /boot/grub/grub.conf
grub.conf generated by anaconda
#
Note that you do not have to rerun grub after making changes to this file
NOTICE: You have a /boot partition. This means that
# all kernel and initrd paths are relative to /boot/, eg.
# root (hd0,0)
# kernel /vmlinuz-version ro root=/dev/mapper/VolGroup-lv_root
# initrd /initrd-[generic-]version.img
#boot=/dev/sda
default=0
timeout=5
splashimage=(hd0,0)/grub/splash.xpm.gz
hiddenmenu
title Red Hat Enterprise Linux (2.6.32-431.el6.x86_64)
root (hd0,0)
kernel /vmlinuz-2.6.32-431.el6.x86_64 ro root=/dev/mapper/VolGroup-lv_root
rd_NO_LUKS LANG=en_US.UTF-8 rd_NO_MD rd_LVM_LV=VolGroup/lv_swap SYSFONT=
latarcyrheb-sun16 rd_LVM_LV=VolGroup/lv_root KEYBOARDTYPE=pc KEYTABLE=us rd_NO_DM
rhgb quiet selinux=0
initrd /initramfs-2.6.32-431.el6.x86_64.img 另一个禁用SELinux的方法是通过存储在/etc/selinux/config下的SELinux配置文件。如下所示可通过配置文件禁用SELinux:
[root@zyg ~]# vim /etc/sysconfig/selinux
This file controls the state of SELinux on the system.
SELINUX= can take one of these three values:
# enforcing - SELinux security policy is enforced.
# permissive - SELinux prints warnings instead of enforcing.
# disabled - No SELinux policy is loaded.
SELINUX=disabled
SELINUXTYPE= can take one of these two values:
# targeted - Targeted processes are protected,
# mls - Multi Level Security protection.
SELINUXTYPE=targeted
如果你决定在基于Linux的服务器上使用SELinux,则它的设置可以调整,以更好地适应你的环境。在一个运行的系统上,检查缓存的Linux Security Modules(LSM)的工作设置,权限是否超过默认的Access Vector Cache (AVC)512条目的大小。
最长链的长度检查/selinux/avc/hash_stats。超过10表示可能存在瓶颈。
提示: 检查访问向量缓存(access vector cache)的使用统计,可以另外使用avcstat工具。
如果系统在Access Vector Cache中出现瓶颈(例如,沉重负载的防火墙),尝试调整/selinux/avc/cache_threshold为一个稍高的值,并重新检测hash统计。
5.2.5 编译内核
创建和编译你自己的内核所提高的系统性能,远比通常认为的影响要小。随着大多数Linux版本的发行,现代的内核是模块化的,它们只加载所使用的部件。重新编译内核可以减小内核大小和整体行为(例如,实时行为)。改变源代码中的某些参数也可能产生一些系统性能。
前面已经说过,定制内核可以获得性能提升,但是很难证明,在企业环境中运行一个不被支持的内核所要面临的挑战。
当重新编译内核时,不要试图使用特殊的编译器标志,比如-C09。已经手工调整过源代码的Linux内核与GNU C编译器匹配。使用特殊的编译器标志,最好的可能是带来较低内核性能,最坏是破坏代码。
记住,除非你真的知道你在做什么,否则,由于设置错误的内核参数,你实际上可能会降低系统性能。
5.3 更改内核参数
虽然多数情况下不建议修改和重新编译内核源代码,但还是有另一种手段,通过更改内核参数来调整Linux内核功能。proc文件系统提供了一个用于访问正在运行的内核的接口,可以用它来进行监控和在联机状态下更改内核设置。
要查看当前内核配置,可以在/proc/sys目录中选择一个内核参数,并对相应的文件使用cat命令。下面我们来剖析系统当前内存过量使用策略。输出0告诉我们,在授权为应用程序请求进行内存分配之前,系统将一直检测可用内存。要更改此默认行为,可以使用echo命令,并给它提供一个新的值,在例子中我们使用1(1意味着内核在每次授权内存分配时,不检测分配是否能满足)。
用proc文件系统改变内核参数:
[root@zyg ~]# cat /proc/sys/vm/overcommit_memory
0
[root@zyg ~]# echo 1 > /proc/sys/vm/overcommit_memory
上面所展示的使用cat和echo快速改变内核参数的方法,适用于任何系统的proc文件系统。它也有两个明显的缺点:
□ echo命令对参数不执行任何一致性检查。
□ 所有对内核的更改在系统重新启动之后会丢失。
为了克服这一点,一个被称为sysctl的工具可以帮助管理员更改内核参数。
提示: 默认情况下,内核只包含必要的模块,可以让你在无需重新启动的情况下使用sysctl更改。但是,如果选择移除此支持(在操作系统安装时),那么只有在重新启动Linux之后更改才会生效。
5.3.1 proc文件系统
proc文件系统不是一个真正的文件系统,但尽管如此,它是非常有用的。它不存储数据,而它提供了一个访问正在运行的内核的接口。proc文件系统使管理员在联机状态下可以监控和更改内核。下面描述了一个proc文件系统的样本。大多数Linux工具依靠/porc提供的信息进行性能测量。
下面是/proc文件系统示例:
[root@zyg ~]# ls /proc/
1 1501 1802 270 290 41 46463 59 9 irq schedstat
10 1502 1804 271 291 411 47 6 963 kallsyms scsi
11 1544 1806 272 292 42 47630 60 acpi kcore self
1111 1549 1821 273 293 428 48 61 asound keys slabinfo
1112 1569 1888 274 294 429 48214 62 buddyinfo key-users softirqs
112 1589 19 275 295 43 48897 63 bus kmsg stat
1120 1596 197 276 296 44 48948 64 cgroups kpagecount swaps
1162 16 198 277 297 44003 48952 65 cmdline kpageflags sys
12 1635 199 278 3 45 49 66 cpuinfo loadavg sysrq-trigger
13 1645 2 279 30 45208 49069 67 crypto locks sysvipc
1322 17 20 28 31 45301 49079 68 devices mdstat timer_list
1376 1714 209 280 32 45305 5 69 diskstats meminfo timer_stats
1390 1723 21 281 33 45312 50 7 dma misc tty
14 1738 210 282 34 45317 51 74 driver modules uptime
1405 1746 22 283 35 45493 52 75 execdomains mounts version
1416 1757 23 284 36 45901 523 757 fb mpt vmallocinfo
1419 1770 24 285 37 46 53 76 filesystems mtd vmstat
1435 1783 25 286 38 46075 54 77 fs mtrr zoneinfo
1466 1796 26 287 39 46243 55 78 interrupts net
1467 1798 268 288 4 46453 56 8 iomem pagetypeinfo
1492 18 269 289 40 46456 57 80 ioports partitions
15 1800 27 29 409 46460 58 81 ipmi sched_debug
查看proc文件系统,我们可以区分服务不同用户的几个子目录,但因为proc目录中的大部分信息是不易于人阅读的,建议你使用工具,比如vmstat以更可读的方式显示各种统计信息。记住,proc文件系统中包含的布局和信息,因不同的文件系统架构而不同。
□ /proc目录中的文件。 proc根目录中的各种文件涉及一些相关的系统统计。在这里可以找到通过Linux工具比如vmstat和cpuinfo作为输出源的信息。
□ 数字1到X。 通过数字表示的不同子目录指的是运行的进程或它们各自的进程ID(PID)。目录结构总是从PID1开始指向init进程,并上升到各自的系统运行的PID的数量。每个数字的子目录存储进程相关的统计信息。这种数据示例是进程的虚拟内存映射。
□ Acpi。 ACPI指的是大多数现代桌面和笔记本系统支持的高级配置和电源接口。因为ACPI是主要的PC技术,它常常在服务器系统上是被禁用的。关于ACPI的更多信息参考http://www.apci.info。
□ bus。 这个子目录包含关于总线子系统的信息,比如,PCI总线或各自系统的USB接口。
□ irq。 这个子目录包含关于系统中中断信息。这个目录中的每个子目录指的是一个中断,并可能是一个连接的设备,比如一个网络接口卡。在irq子目录中,可以改变一个特定中断的CPU亲和力。
□ net。 这个子目录包含关于网络接口的大量原始统计,比如接收的组播数据包或每个接口的路由。
□ scsi。 这个子目录包含关于各自的系统的SCSI子系统信息,比如连接的设备或驱动程序版本。子目录ips指的是在大多数IBM System x服务器上发现的IBM ServeRAID控制器。
□ sys。 在sys子目录中可以找到可调整的内核参数,比如虚拟内存管理器或网络协议栈的行为。在/proc/sys中涵盖了各种选项和可调整的值。
□ ttytty。 该子目录包含了关于系统的各个虚拟终端和它连接的物理设备的信息。
5.3.2 存储参数的位置
控制内核行为的内核参数存储在/proc中(特别是/proc/sys中)。
读取/proc目录树中的文件,一个简单地查看配置参数(相关内核、进程、内存、网络、其他组件)的方法。系统中运行的每个进程在/proc中都有一个以进程ID(PID)命名的目录。表5-2中列出了一些包含内核信息的文件。
表5-2 /proc中的参数文件
参数 说明
/proc/sys/abi 这个目录可能包含文件与应用程序二进制信息。参阅Documentation/sysctl/abi.txt获取更多信息
/proc/sys/debug 此目录可能为空
/proc/sys/dev 这个目录包含特定设备的信息(例如,dev/cdrom/info)。在某些系统上,可能为空
/proc/sys/fs 特定的文件系统。文件句柄、inode、dentry和配额调优
/proc/sys/kernel 这个目录包含的文件用来控制一系列的内核参数
/proc/sys/net 内核网络部分的调整,参阅Documentation/networking/
/proc/sys/vm 这个目录包含的文件涉及内存管理调优,buffer和cache管理
5.3.3 使用sysctl命令
sysctl命令使用/proc/sys目录树中文件的名字作为参数。例如,修改shmmax内核参数,可以显示(使用cat命令)和更改(使用echo命令)/proc/sys/kernel/shmmax文件:
[root@zyg ~]# cat /proc/sys/kernel/shmmax
68719476736
[root@zyg ~]# echo 68719476740 > /proc/sys/kernel/shmmax
[root@zyg ~]# cat /proc/sys/kernel/shmmax
68719476740
但是,使用这些命令很容易引入错误,因此建议你使用sysctl命令,因为它在做任何更改之前检查数据的一致性。例如:
[root@zyg ~]# sysctl kernel.shmmax
kernel.shmmax = 68719476740
[root@zyg ~]# sysctl -w kernel.shmmax=68719476736
kernel.shmmax = 68719476736
[root@zyg ~]# sysctl kernel.shmmax
kernel.shmmax = 68719476736
保持内核的更改直至下一次重新启动仍有效。如果你希望永久改变,可以编辑/etc/sysctl. conf文件并添加相应的命令,例如:
kernel.shmmax = 68719476736
在下次重新启动时,参数文件将被读取。使用下面的命令,不重启也可以做同样的事情:
[root@zyg ~]# sysctl–p
5.4 调整处理器子系统
在任何一台计算机中,无论是一个手持式设备还是一个科学应用的集群,主要的子系统是实际做计算的处理器。在过去的十年间,摩尔定律导致处理器子系统的发展明显要比其他子系统更快。其结果是,瓶颈很少在CPU中发生,除非系统的唯一目的是数字处理。这说明,Intel兼容的服务器系统的平均CPU使用率低于10%。了解发生在处理器层级的瓶颈和为提高CPU性能知道可能的调整参数是很重要的。
5.4.1 调整进程优先级
正如我们在1.1.4节中所述的。进程的优先级可分为静态(实时)优先级和动态(非实时)优先级。首先我们可以使用chrt命令来查看进程的调度策略:
[root@zyg ~]# chrt -m
SCHED_OTHER min/max priority : 0/0
SCHED_FIFO min/max priority: 1/99
SCHED_RR min/max priority: 1/99
SCHED_BATCH min/max priority : 0/0
SCHED_IDLE min/max priority: 0/0
这里有2个实时调度策略:SCHED_RR和SCHED_FIFO。SCHED_RR是一个轮询调度策略。相同优先级别进程使用轮询调度策略,只允许在一个最大时间片内运行。SCHED_FIFO使用先进先出调度策略。它一直运行直到I/O阻塞,然后调用sched_yield或是被一个高优先级的进程抢占。
能够使用sched_setscheduler为应用程序设置调度策略。如果应用程序没有被设计为实时的,则可以通过chrt命令来设置实时调度程序。通过策略和优先级参数来运行一个实时优先级应用程序。
[root@zyg ~]# chrt -f 60 zyg
如果程序已经运行,也可以使用chrt命令进行调整:
[root@zyg ~]# chrt -p 46453
pid 46453’s current scheduling policy: SCHED_OTHER
pid 46453’s current scheduling priority: 0
[root@zyg ~]# chrt -p -f 50 46453
[root@zyg ~]# chrt -p 46453
pid 46453’s current scheduling policy: SCHED_FIFO
pid 46453’s current scheduling priority: 50
还有3个非实时调度策略:SCHED_NORMAL、SCHED_BATCH和SCHED_IDLE。SCHED_NORMAL是一个标准的轮询风格的时间共享策略。SCHED_BATCH是为了执行批处理风格的程序而设计的。每当SCHED_NORMAL工作时,SCHED_BATCH几乎不会抢占,因此任务运行时间更长,并能更好地利用cache。SCHED_IDLE用于运行非常低的优先级应用程序(实际上是一个比nice 19还低的优先级)。
改变SCHED_NORMAL的优先级,使用nice或renice命令。Linux支持的nice等级可从19(最低优先级)到-20(最高优先级),默认值是0。更改一个程序的nice等级到负数(使它有较高的优先级),需要使用root登录或su切换到root。这是动态优先级,意味着内核通过调整+/- 5级可以提高或者降低这些进程的系统优先级。如果进程运行得太慢,可以通过给它一个较低的nice等级从而分配给它更多的CPU。当然,这也意味着其他程序将拥有较少的处理器周期,并且将运行得更慢。
使用-5的nice级别运行程序zyg,运行下面的命令:
[root@zyg ~]# nice -n 5 zyg
更改一个已经运行的程序的nice级别,运行下面的命令:
renice
更该一个PID为2500的程序的nice级别到10,运行下面的命令:
[root@zyg ~]# renice 10 2610
5.4.2 CPU亲和力
简单地说,CPU亲和力(CPU Affinity)是为了把一个或多个进程(线程)绑定到一个或多个CPU核心上。
1.taskset
通过正在运行的进程的PID,taskset可用于设置或检索该进程的CPU亲和力,或者,可以使用CPU亲和力开始一个新的命令。CPU亲和力表示为十六进制的位掩码(bitmask),最低位bit对应第一个逻辑CPU,最高位bit对应最后一个逻辑CPU。
图5-3以逻辑4核CPU为例,显示了它们的掩码。
图5-3 逻辑CPU与位掩码
使用taskset查看正在运行的zyg.sh的CPU亲和力,并将其绑定在CPU1上运行:
[root@zyg ~]# ps -ef | grep zyg.sh
root 49177 49157 95 13:54 pts/1 00:00:12 /bin/bash ./zyg.sh
root 49179 48952 0 13:54 pts/0 00:00:00 grep zyg.sh
[root@zyg ~]# taskset -p 49177
pid 49177’s current affinity mask: f
[root@zyg ~]# taskset -p 2 49177
pid 49177’s current affinity mask: f
pid 49177’s new affinity mask: 2
使用taskset在开始运行zyg.sh时就指定绑定在CPU3上运行:
[root@zyg ~]# taskset -c 3 ./zyg/sh
2.cgroup
在一般操作中,内核将确定一个进程将运行在哪一个CPU上。每次调度器可以在任意可用的CPU上重新调度一个进程。对于大多数工作负载这样还好,但有时我们需要对进程进行限制,允许该进程运行在特定CPU上。例如,限制一个内存密集型进程仅用1个或2个CPU,以增加cache命中的机会,从而增加整体性能。
在一个NUMA系统上,这可以有效地限制CPU和内存区域,确保一个进程总是可以尽可能快地访问到内存。
有一种可伸缩的方法可实现上述要求,就是使用cpuset cgroup。在cpuset cgroup中可以找到(其中)下面的可调整参数(具体设置方法参见5.8节)。
□ cpuset.cpus。 在cgroup中可以使用的CPU。可以是一个范围,比如0~3,也可以是逗号分隔的列表,比如0、2、4或是一个组合,比如0、2~4。
□ cpuset.mems。 在这个cgroup中使用哪一个NUMA内存区域。语法和cpuset.cpus相同。
□ cpuset.{cpu,memory}_exclusive。 如果你希望这个cgroup中CPU/内存是独有的,则可以设置为1。例如,父进程和子进程可以使用,但是其他进程不允许触碰这些CPU或内存区域。
注意: 当不使用NUMA时,或者,不是在一个具有NUMA能力的系统上,必须设置cpuset.mems。在这些系统上将只有一个内存范围:0。
3.虚拟机CPU亲和力
就像进程可以绑定在特定的CPU上一样,在虚拟机里的VCPU也可以绑定在hypervisor中的物理CPU上。这可以用来增加cache命中率或是为特定的工作负载手动平衡CPU。CPU绑定可以通过以下2种方法来实现:
□ 如图5-4所示在virt-manager中打开虚拟机,在虚拟机的Details对话框中Processor选项卡中设置。
图5-4 虚拟机绑定CPU
□ 通过虚拟机的libvirtd xml配置文件,我们有2种选择可以实现:
• 改变所有CPU的CPU亲和力,让hypervisor选择物理CPU进程绑定。要做到这一点需要在xml文件中找到块,并给它添加一个cpuset属性。例如,限制
hypervisor只能从物理CPU 2和3选择VCPU,可以改变块:
[root@zyg ~]# virsh vcpuinfo rhel6u5-1
VCPU: 0
CPU: 1
State: running
CPU time: 186.3s
CPU Affinity: yyyy
VCPU: 1
CPU: 1
State: running
CPU time: 185.1s
CPU Affinity: yyyy
• 使用virsh edit rhel6u5-1编辑一个虚拟机的xml配置文件:
rhel6u5-1
2ffe2bd4-ead9-5cd6-3d28-0a77ba53fec2
524288
524288
<vcpu placement='static’cpuset='2-3'
>2</vcpu>
hvm
• 我们可以发现,只有CPU2与CPU3是yes。
[root@zyg ~]# virsh vcpuinfo rhel6u5-1
VCPU: 0
CPU: 2
State: running
CPU time: 6.3s
CPU Affinity: --yy
VCPU: 1
CPU: 2
State: running
CPU time: 5.1s
CPU Affinity: --yy
• 将特定的VCPU绑定到特定的物理CPU。为此我们需要添加一个新块,并使用virsh edit rhel6u5-1编辑一个虚拟机的xml配置文件:
rhel6u5-1
2ffe2bd4-ead9-5cd6-3d28-0a77ba53fec2
524288
524288
2
hvm
[root@zyg ~]# virsh vcpuinfo rhel6u5-1
VCPU: 0
CPU: 2
State: running
CPU time: 16.3s
CPU Affinity: --y-
VCPU: 1
CPU: 3
State: running
CPU time: 15.1s
CPU Affinity: ---y
注意: 如果在cpuset属性中选择多个物理CPU,那么基于当前的负载hypervisor可在这些CPU之间自由地选择和切换。
注意: 编辑一个虚拟机的xml配置文件,推荐方法是使用virsh edit vm-name。如果libvirtd当前没有运行也可以在/etc/libvirtd/qemu/下直接编辑文件。
5.4.3 平衡中断
一个中断(interrupt)是一个来自硬件(hard-interrupt)或者软件(soft-interrupt)的信号,表明这里有个工作现在要做。中断有些时候被称为IRQ(Interrupt ReQuest)。因为当它出现的时候表明有一个中断需要处理,CPU需要选择在其上执行相应的代码。在一个单CPU系统上选择是简单的,但是当有多个有效CPU的时候,选择在哪一个CPU上执行代码就变得有趣了。
/proc/interrupts文件详细描述了,在一个特定的CPU上处理特定的中断的情况。
确定内核在哪个CPU上执行特定的中断处理程序,可以查看/proc/irq/number/smp_affinity文件。在这个文件中有一个位掩码(bitmask),以十六进制数表示。一个中断被允许在哪个CPU上处理,相应的bit位将被设置为1;如果内核不允许中断使用所述的CPU,bit位将被设置为0。
计算出来的值关联某一个CPU,可以使用公式:value=2^n,n是CPU的编号,第一个CPU起始于0。如果给出的是1则表示CPU0,2表示CPU1,4表示CPU3等。CPU7(第8个CPU)可以是128或十六进制的0x80。
例如我们想限制中断50仅用CPU 0、2、7,可以这样进行计算:2^0 + 2^2 + 2^7 = 133= 0x85,并将从shell计算得到的结果直接设置为affinity-mask:
printf '%0x' $[2**0 + 2**2 + 2**7] > /proc/irq/50/smp_affinity
默认在新安装的RHEL上会启用一个称为irqbalance的守护进程。irqbalance的目的是每10秒钟调整所有中断的smp_affinity,因此,当执行一个中断处理程序时有较高的机会得到cache命中。在单核系统和双核系统上,由于它们共享L2cache,因此irqbalance将什么也不做。
下面所示在/etc/sysconfig/irqbalance中有2个设置,它们能够影响irqbalance守护进程的行为。
1.ONESHOT
当其被设置为yes时,irqbalance将在sleep一分钟之后启动,重新平衡中断一次然后退出。如果你不想招致每十秒唤醒irqbalance的开销,这是很有用的。
2.IRQ_AFFINITY_MASK
如果设置了它,irqbalance将只分配中断到那些被列出的CPU,设置的计算与smp_affinity是一样的方法。这对于从中断处理中隔离CPU是很有用的。
5.4.4 NUMA系统
1.NUMA拓扑
早先的多处理器系统是基于对称多处理结构(Symmetric Multiprocessing, SMP)而设计的,每个CPU核心通过一个共享总线访问系统RAM。如图5-5所示每个CPU核心访问主内存使用一个共享的前端总线通信,一个内存控制中心(Memory Controller Hub、MCH或northbridge)。MCH上的内存控制器负责管理如何访问到系统RAM。
图5-5 统一内存架构UMA及前端总线FSB
注意: MCH也控制系统的显卡和内存的通信。MCH使用一个低速链路连接到ICH(I/O Controller Hub或者“southbridge”),它处理其他PCI设备、磁盘及其他一些周边设备(USB、PS/2等)的通信。
这可以较为容易构建,并且所有CPU可以同样快速地访问所有内存地址:它是一个统一内存架构(Uniform Memory Architecture)。然而,随着更多的处理器被添加进系统,由于共享总线架构,瓶颈和竞争变得更加糟糕。
为了缓解这个瓶颈,基于非统一内存架构(Non-Uniform Memory Architecture, NUMA)的系统变得越来越普遍。这些基于NUMA系统的主存储器通过单独的总线直接连接到单独的处理器或CPU封装。
在NUMA系统上,每个核心仍旧能够访问所有的内存,但是通过本地总线访问内存要比远程总线更快。通常,增加访问时间被说成是一种广义上从CPU核心到它试图访问的内存的距离。
从优化的角度来看,这意味着一个进程在一个特定的处理器上运行会拥有非常快的内存访问,其所有的内存都存储在直接连接到本地处理器的RAM中。这也意味着,如果一个程序的部分内存连接到另一个处理器,则当访问内存区域时性能可能会出乎意料地慢。
在图5-6中,内存控制器现在位于每个CPU模型上,并通过该模型中的核心共享。该控制器被直接连接到系统RAM中。CPU之间相互连接,每个内存控制器与系统的剩余部分通过高速点到点的方式互相连接(QPI快速通道互联inter主板,HyperTransport是AMD)。现在没有MCH格式的内存控制器,而被称为I/O Hub(IOH)。它只用于CPU连接到显卡/显存和ICH。
图5-6 非统一内存架构NUMA(Intel)
注意: 一个4 socket的系统,所有的CPU socket通过高速点到点的方式相互连接,但是只有一对socket能够直接连接IOH。
现代的单socket系统可以基于一个NUMA进行有效的设计,像是一个统一内存架构,因为它只有一个NUMA节点。图5-7显示了一个例子,在该图中CPU自己直接连接RAM并且和ICH一样连接到PCI。(任意早先“northbridge”的功能或是IOH设备,不会移动到CPU封装,而是移动到ICH,改名为Platform Controller Hub或PCH。)
图5-7 单socket系统
2.NUMA系统的注意事项
Non-Uniform Memory Architecture(NUMA)系统正在获得市场份额,并且被视为是典型的对称多处理器系统的自然演变。当前Linux发行版的CPU调度器非常适合NUMA系统,应用程序可能并不行。非NUMA感知的应用程序所引起的瓶颈,可以导致不确定的性能下降。最近numactl软件包中的numastat工具有助于识别NUMA架构中处理困难的进程。
为了帮助发现瓶颈,在/sys/devices/system/node/%{node number}/numastat文件中可以看到numastat工具所提供的统计数据。在numa_miss和other_node中的高值预示着可能是NUMA问题。如果你发现给一个进程分配的内存,不是存在于本地节点上(运行应用程序的处理器的节点),尝试使用renice进程改到其他节点,或使用CPU亲和力工作。
在早先的i386和x86-64系统上,CPU公平地访问所有的内存。这意味着,无论哪个CPU执行操作,对于所有内存地址的存取时间是相同的。CPU通过一个共享的前端总线(FSB)与主内存相连。这种内存架构被称为“Uniform Memory Access(UMA)”。
在当前的x86-64处理器上,不再是这种情况了。在NUMA或Non-Uniform Memory Access系统上,系统内存被分开放到不同区域里,再直接连接到特定的CPU或socket。在这种情况下,访问本地CPU的内存要比访问连接在系统上的一个远程CPU的内存快得多。
查看你的系统在node里是怎样划分的,可以使用numactl --hardware命令,需要安装numactl软件包。它会显示在哪个node中有哪些处理器及每个node使用的可利用的内存数量。在输出的底部会有一个列表表明在node之间内存访问的相关权重,值越低速度越快:
[root@zyg ~]# numactl --hardware
available: 2 nodes (0-1)
node 0 cpus: 0 2 4 6 8 10 12 14
node 0 size: 8192 MB
node 0 free: 54 MB
node 1 cpus: 1 3 5 7 9 11 13 15
node 1 size: 8179 MB
node 1 free: 844 MB
node distances:
node 0 1
0: 10 20
1: 20 10
在一个特定的node中运行一个程序,可以使用numactl命令来启动它,通过它指定CPU node或CPU、内存zone、分配内存的策略。内存分配策略包括:交错访问(被轮询划分到节点之上)、限制到特定的zone或优选某些zone。至于优选的zone,当优选的zone没有足够内存可利用时,将从其他zone分配内存。
下面是几个numactl实例。
运行bigdatabase,它的memory交错在所有的CPU:
numactl --interleave=all bigdatabase
在node 0上运行进程,所有分配的内存在node0和node1上:
numactl --cpubind=0 --membind=0,1
设置优选node 1,显示结果的状态:
numactl --preferred=1 ; numactl --show
重置共享内存文件的策略为默认的localalloc策略:
numactl --localalloc /dev/shm/file
另外还有一些有用的工具可以得到有关NUMA内存分配的详细信息。numastat实用工具可以显示多种统计,都是关于如何分配不同的NUMA node的。在每个node的基础上,/sys/devices/system/node/*/meminfo文件提供与/proc/meminfo相似的信息。
关于NUMA内存分配也可以使用一个cpuset cgroup控制,用cpuset.cpus和cpuset.mems可调参数。
NUMA可以引起一些奇怪的性能变化。如果一个应用程序从不同node得到不同的运行内存,或是如果它的内存占用不合适的本地node,性能可能会变化或难以预测。可以强制系统将所有访问交错到所有节点内存。这将导致不可预测的性能,即使应用程序不是NUMA-aware(NUMA感知的),性能也可能会比它只使用相同NUMA节点的CPU上的内存要低。这样做的一个方法是在系统的BIOS中设置node-interleave(节点交错)模式,添加选项numa=off到grub.conf中。不要禁用NUMA,当它不使用的时候在你的应用程序中它能导致不可预知的内存访问时间。
5.5 调整内存子系统
调整内存子系统是一个具有挑战性的任务。在服务器中需要持续地监控,以确认所做更改对其他子系统不会产生消极影响。如果选择修改虚拟内存参数(在/proc/sys/vm中),则建议你一次只更改一个参数,并且监控服务器是如何执行的。
记住,Linux下的大多数应用程序不会直接写入硬盘,它们通过虚拟内存写入到文件系统cache,最终将数据刷新出来。当使用IBM ServeRAID控制器或IBM TotalStorage磁盘子系统时,应尝试减少刷新的次数。通过每次刷新可以有效地增加I/O数据流。高性能的磁盘控制器能更有效地处理较大I/O数据流。
5.5.1 内存回收(设置内核交换和刷新脏数据行为)
物理内存需要时不时被回收,以防止内存填满致使系统不可用。在了解如何回收内存之前,必须首先了解表5-3所示的内存分页的不同状态。
表5-3 内存分页状态
Free 分页是有效的,可立刻分配
Inactive Clean 分页没有活跃使用,内容符合磁盘上的内容,因为它已经被写回或自读以来没有改变
Inactive Dirty 分页没有活跃使用,但是,自从磁盘上读以来分页内容已经被修改,并还没有被写回
Active 分页在活跃使用中,并不能作为一个可释放的候选者
当需要分配一个新的分页的时候,分页被标记为Inactive clean,即可以被视为空闲分页,但是如果拥有该分页的进程之后再次需要分页,将会发生一个主要页错误(major page fault)。
通过查看/proc/meminfo可以得到整个系统的内存分配的概况。我们感兴趣的行是Inactive(file)和Dirty。Anonymous page(那些与磁盘上的文件不相关的)不能轻易释放,并且需要换出到磁盘释放它们。
对于每个进程的视图可以查看/proc/PID/smaps。这个文件详述分配给一个进程的每个内存段,包含Shared/Private clean大小、脏数据内存大小。
脏数据分页必须被写到磁盘,如果分页不能释放,可能会导致内存被装满。并且由于内存的易失性(当断电时内容将丢失),这可以防止因为电源故障数据丢失。
在较早的内核中将脏数据分页写入到磁盘是通过内核线程pdflush来处理的。在较新的内核中(在RHEL 6中包含的那些)pdflush被per-BDI flush线程(BDI = Backing Device Interface)取代,Per-BDI flush线程将出现在进程列表中,如同flush-MAJOR:MINOR。
表5-4中几个内核参数可以用来控制per-BDI flush线程写入数据到磁盘。
表5-4 相关脏数据内核参数
vm.dirty_expire_centisecs 经过多久(百分之一秒)脏数据才有资格写入到磁盘。防止仅仅因为进程修改了内存的一个字节,而导致内核快速连续的对相同分页进行多次写
vm.dirty_wirteback_centisecs 内核多长时间唤醒flush线程来一次写出数据。设置为0将完全禁用周期地写回
vm.dirty_background_ratio 脏数据达到系统总内存的百分比,内核开始在后台写出数据
vm.dirty_ratio 一个进程所拥有的脏数据达到系统总内存的百分比,该进程产生写阻塞,并写出脏页
设置vm.dirty_ratio和vm.dirty_background_ratio可以取代vm.dirty_bytes和vm.dirty_ background_bytes。当达到两个内核参数中的字节数(最小值为2个分页)时在后台开始写入。
较低的ratio适合交互式的系统;较高的ratio适合少但是较大的写,这样造成的总开销较少,但是对于交互式应用程序可能会产生较高的响应时间。
1.处理内存不足(Out-of-Memory)和OOM killer
当一个次要页错误(minor page fault)发生,但是又没有空闲的分页可使用时,内核将尝试回收内存来满足请求。如果不能及时回收充足的内存,将会出现内存不足(Out-of-Memory)的情况。
默认情况下,系统会调用OOM Killer(Out-of-Memory Killer)选择杀死一个或多个进程来释放内存,以满足请求。
作为另一种代替,将sysctl vm.panic_on_oom设置为1而不是0。
注意: 一旦系统已经出现内存不足的情况,就没有更合理的选项进行恢复了。杀掉进程释放内存,放弃和杀掉系统,死锁都是可能的选择。通常情况下,如果有可能的话,最好避免让系统进入内存不足的情况。
为了确定OOM killer应该杀死哪个进程,内核为每个进程保持一个运行的不良分数(badness score),可在/proc//oom_score中查看它。
具有较高分数的进程最有可能被OOM killer杀掉。
使用许多因素来计算这个分数:虚拟内存大小(不是RSS size)、进程包括所有子进程积累的虚拟内存大小、nice值(正数的nice值得到一个较高的分数)、总共运行时间(较长的总共运行时间会减少分数)、运行的用户(root进程得到轻微的保护),如果进程直接对硬件进行访问分数会降低。
内核本身和PID 1(init)是对OOM Killer免疫的。
可以使用调整参数/proc/PID/oom_adj来手工调整oom_score。oom_adj的值从-17到15。0意味着不改变(默认),-17意味着免疫(不能杀掉),任何其他值将被用来修改oom_score,通过使用2^oom_adj乘以oom_score,使用这种方式给你的进程设置一个正数oom_adj将更有可能被杀掉。当设置一个负数的值时会有较小机会被内核终结。
注意: 强制启动OOM-Killer可以使用echo f >/proc/sysrq-trigger命令,但是记得至少会有一个进程将被杀掉。输出将被发送到dmesg。
5.5.2 调整swap
当物理内存完全被使用或系统需要额外内存时,使用swap设备。当系统上没有空闲内存可用的时候,它开始从内存中调度最少被使用的数据分页到磁盘上的swap区域。在Linux安装过程中,创建初始的swap分区,目前的指导方针是声明swap分区的大小为2倍的物理RAM。Linux 2.4内核以及之后的版本,支持swap可以达到每个分区24GB,对于32-bit系统理论最大值是8TB。swap分区应位于不同的磁盘上。
1.Swappiness
当内核想释放内存中的一个分页时,它要在两种选择之间作出权衡。它能够从进程的内存中换出一个分页,或者它能从分页cache中丢弃一个分页。为了做出这个决定,内存将执行下面的计算:
swap_tendency = mapped_ratio/2 + distress + vm_swappiness
如果swap_tendency(swap趋势)低于100,内核将从分页cache中回收一个分页;如果大于等于100,一个进程内存空间中的一部分将有资格获得交换。在这个计算中mapped_ratio是物理内存使用的百分比,distress是衡量内核在释放内存中有多少开销,它开始为0,但是如果更多尝试都需要释放内存,它将增加(最大到100)。vm_swappiness值来自于sysctl vm.swappiness。
调整vm.swappiness可能会严重地影响系统。设置vm.swappiness为100,系统将几乎总是更喜欢从page cache中回收一个page,从而将有更多的内存分页cache使用,这可以大大提高一个I/O密集型工作的性能。另一方面设置为0,强制系统尽可能少地swap。一个需要更多响应的系统中会有这样的情形,但是会增加文件系统方面的开销。
/proc/sys/vm/swappiness中的参数可以用来定义如何积极地将内存交换到磁盘上。在1.2.2节中,介绍了Linux虚拟内存管理器并讨论了在Linux中swap空间的一般使用。它指出了,Linux将一段时间内没有被访问的内存分页移动到swap空间,即使有足够的内存可以使用。可以通过更改/proc/sys/vm/swappiness中的百分比来控制这种行为,这取决于系统配置。如果不需要交换,/proc/sys/vm/swappiness应该具有一个较低的值。在内存受限的系统上运行批处理作业(进程会sleep很长一段时间)会受益于积极的交换行为。在下面的例子中可以使用echo或sysctl命令改变交换行为。
更改swappiness的行为:
[root@zyg ~]# sysctl -w vm.swappiness=100
vm.swappiness = 100
找到vm.swappiness最佳的值主要取决于系统的工作量。通过cgroups不同的swappiness能够设置不同的cgroups,使用memory cgroup-controller的memory.swappiness来进行调整。
2.最优化swap空间
swap空间的位置和数量对swap性能有很大的影响。在一个机械硬盘上,在一个磁盘片的外部边缘放置一个swap分区,将得到更好的吞吐量。在SSD存储上放置一个swap空间可以得到更好的性能,因为每个设备都有低延迟和高吞吐量。
重点: 如果使用一个SSD做swap空间,并且swap空间频繁地被使用,应确认你的设备支持相应的磨损等级并能够承受大量的写(因为这个原因,SLC-based存储可能要比MLC-based存储更受欢迎),否则,你可能会经历设备过早被磨损。
如果在初始安装之后给服务器增加更多的内存,就必须配置额外的swap空间。在初始安装之后可以有两种方法配置额外的swap空间。
□ 可以使用mkswap将磁盘上的空闲分区创建为一个swap分区。如果磁盘子系统没有空闲空间可用,这就变得困难了。在这种情况下,可以创建一个swap文件(不被分片)。
□ 如果要做出选择,优先的选择是创建额外的swap分区。这是一个性能优势,因为I/O到swap分区绕过了文件系统和所有涉及写入一个文件的开销。
另一种提高swap分区和文件性能的方法是创建多个swap分区。Linux可以利用多swap分区或文件的优势,执行并行的读和写。在创建额外的swap分区或文件之后,在/etc/fstab文件中要包含如下面的例子所示的条目:
[root@zyg ~]# vim /etc/fstab
...
/dev/sda2 swap swap defaults 0 0
/dev/sdb2 swap swap defaults 0 0
/dev/sdc2 swap swap defaults 0 0
/dev/sdd2 swap swap defaults 0 0
在正常情况下,Linux会首先使用/dev/sda2做swap分区,或使用/dev/sdb2,以此类推,直到给它分配了足够的交换空间。这意味着,如果不需要大量的swap空间,可能只使用第一个分区/dev/sda2。
将数据分散到所有可用的swap分区可以提高性能,因为所有读/写请求可以在所有选定的分区同时执行,可以使用挂载选项pri=value来说明每个使用的空间的优先级。如下面例子所示更改文件,给前3个分区分配一个较高的优先级。
修改/etc/fstab设置并行swap分区:
[root@zyg ~]# vim /etc/fstab
……
/dev/sda2 swap swap defaults,pri=5 0 0
/dev/sdb2 swap swap defaults,pri=5 0 0
/dev/sdc2 swap swap defaults,pri=5 0 0
/dev/sdd2 swap swap defaults,pri=5 0 0
swap分区的使用是从最高优先级到最低(32767是最高优先级,0是最低优先级)。给予同样优先级的前3个磁盘,会导致数据被写入到全部3个磁盘;系统是不会等待的,直到在它开始写入下一个分区之前,第一个swap被写满。系统并行使用前3个分区,性能会普遍提高。
在前3个分区被完全填满之后,如果还需要额外的空间做交换,那么将使用第4个分区。也可以让所有分区具有相同的优先级,将数据条带化存储在所有分区,但是如果一个驱动器比其他要慢,性能会降低。通常规则是,swap分区应该在可用的最快驱动器上。
重点: 虽然调整内存子系统有很好的工具,也应该尽可能避免分页移出。swap空间是不能取代物理内存的,因为存储在物理驱动器上访问时间明显要比内存慢。所以,频繁地移出分页不是一个好的行为。在尝试提高swap处理之前,确定你的服务器有足够的内存,或没有内存泄露。
一个系统应该有多少swap呢?由此有很多经验法则被提出。基于两件事情考虑你需要的swap。
第一,始终把内存中不需要的分页移开,因此物理内存可以用来做更多的事情。
第二,提供一个应急的保留区域以避免内存不足的情况。多少空间相当依赖于系统有多少物理内存,和你想在计算机上做什么。
因为很难凭经验进行计算,人们往往通过粗略的估计来设置自己的swap空间。表5-5是Red Hat提供的基本建议。
表5-5 swap空间分配(仅供参考)
系统物理内存 建议最小swap空间
4GB以内 至少2GB
4 GB至16 GB 至少4 GB
16 GB至64 GB 至少8 GB
64 GB至256 GB 至少16 GB
5.5.3 HugeTLBfs
内存管理对于使用大虚拟地址空间的应用程序来说是很有价值的。对于数据库应用程序也是非常有用的。
怎样能得知一个进程使用的内存呢?通常,当一个进程请求内存的时候,它保留虚拟内存地址,但是在第一次使用它之前不真正地映射它们到物理分页,比如top和ps两个工具在统计上是有区别的:一个是进程虚拟内存的总数量,VIRT和VSZ;一个是进程当前映射到物理内存的虚拟内存总数量,RES和RSS。一般情况下,RSS是更关键的值,因为它代表真实分配的和映射的内存。
由于每个进程保持它们自己的虚拟地址空间,因此它们需要有一个分页表,跟踪它的虚拟分页到物理分页的映射。每个虚拟分页在表上都有一个条目。问题是,进程使用的内存越多该映射表就会越大。进程在分页表上查阅一个分页映射的开销也会很大的。因此,当在分页表中查阅一个虚拟地址到物理地址映射的时候,它被缓存在一个专业的硬件中,被称为Translation Lookaside Buffer,或者TLB。它是特别的CPU缓存,通过缓存进程最近使用的分页映射来加速地址转换。因为内存易于频繁访问,这意味着如果我们访问一个相同的分页,相比较在分页表中创建一个冗长的查找,这种访问能够从TLB中更快地得到映射。
CPU的旁路转换缓冲(Translation Lookaside Buffer, TLB)是一个很小的cache,被用来存储虚拟地址到物理地址的映射信息。通过使用TLB,不必引用内存中映射虚拟地址的分页表条目,就可以执行转换。然而,为了保持转换尽可能地快,TLB通常很小。大内存应用程序超过TLB的映射能力,通常是不常见的。
旁路转换缓冲(TLB)的条目数量对于一个处理器是固定的,但是更大的分页,相对于处理器的TLB映射空间也会相应变得更大。较少的TLB条目可以指出更多的内存,这意味着会有更多的TLB命中出现。但是无论怎样,当执行上下文切换时,为了将进程调度出来,内核必须经常刷新TLB条目。
使用x86info -a命令确定一个特定系统上TLB信息,与下面的行类似:
TLB info
Data TLB: 4KB pages, 4-way associative, 64 entries
Linux内核通过hugepage机制来支持大号的分页(有时称为bigpage、largepage或hugetlbfs file system)。大多数处理器架构支持多种分页大小。IA-32架构支持4KiB、2MiB、4 MiB的分页。x86_64架构支持分页的大小:4KiB、2MiB、4MiB、1GiB。
在下面例子中所示/proc/meminfo文件中提供了关于hugetlbpage的信息:
[root@zyg ~]# cat /proc/meminfo
MemTotal: 16318924 kB
MemFree: 255068 kB
Buffers: 118856 kB
Cached: 14376168 kB
SwapCached: 33216 kB
Active: 7540192 kB
Inactive: 7133744 kB
Active(anon): 118276 kB
Inactive(anon): 61824 kB
Active(file): 7421916 kB
Inactive(file): 7071920 kB
Unevictable: 0 kB
Mlocked: 0 kB
SwapTotal: 32767992 kB
SwapFree: 26919116 kB
Dirty: 23340 kB
Writeback: 0 kB
AnonPages: 147300 kB
Mapped: 8508 kB
Shmem: 456 kB
Slab: 1222256 kB
SReclaimable: 822300 kB
SUnreclaim: 399956 kB
KernelStack: 3872 kB
PageTables: 9652 kB
NFS_Unstable: 0 kB
Bounce: 0 kB
WritebackTmp: 0 kB
CommitLimit: 40927452 kB
Committed_AS: 6242928 kB
VmallocTotal: 34359738367 kB
VmallocUsed: 313516 kB
VmallocChunk: 34350781288 kB
HardwareCorrupted: 0 kB
AnonHugePages: 94208 kB
HugePages_Total: 0
HugePages_Free: 0
HugePages_Rsvd: 0
HugePages_Surp: 0
Hugepagesize: 2048 kB
DirectMap4k: 5604 kB
DirectMap2M: 2078720 kB
DirectMap1G: 14680064 kB
HugeTLBfs特性允许应用程序使用比普通分页更大的分页,因此单个TLB条目可以映射更大的地址空间。HugeTLB条目可以大小不同。例如,在Itanium® 2系统中,hugepage可能比正常分页大1000倍。这使得TLB映射一个正常进程的1000倍虚拟地址空间,不会产生一个TLB cache未命中。为了简单起见,这个特性通过一种文件系统接口的方式展示给应用程序。
对于如何分配hugepage,可通过使用sysctl命令配置/proc/sys/vm/nr_hugepages的值,来定义hugepage的数量:
[root@zyg ~]# sysctl -w vm.nr_hugepages=512
注意: 如果有足够的空闲分页,那么将只分配被请求的分页,使用连续的内存来满足请求。为了做到这一点,经常需要在启动的时候详细说明huge pages的数量,可以通过在/etc/sysctl.conf文件中设置sysctl参数来指定。然而,如果声明大于可用RAM的huge pages则会引起kernel panic。
为了使用大型page,进程使用mmap系统调用或shmat和shmget系统调用来进行请求,如果你的应用程序通过mmap()系统调用使用huge page,则需要按照下面这样挂载一个hugetlbfs类型的文件系统:
[root@zyg ~]# mkdir /hugepages
[root@zyg ~]# mount -t hugetlbfs none /hugepages
请参考内核文档,在Documentation/vm/hugetlbpage.txt中可以了解更多信息。
1.透明的hugepage
Red Hat Enterprise Linux 6.2引入了新的内核功能,支持巨型内存分页的创建和管理,无需开发者或系统管理员的介入。这个特性被称为transparent huge pages(THP)。THP默认是启用的,它被用来映射所有的内核地址空间到单个hugepage从而减少TLB压力。它也能在为应用程序分配动态内存之前,用来映射匿名内存区域。
THP不同于标准hugepage,当它们启用的时候,通过内核动态地分配和管理。不像标准hugepage,它们也能从内存中换出。
THP可调参数在/sys中/sys/kernel/mm/redhat_transparent_hugepage目录下。/sys/kernel/mm/ redhat_transparent_hugepage/enabled可以是下面的值之一:
Always:总是使用THP
Never:禁用THP
当redhat_transparent_hugepage/enabled被设置为always或madvise时,khugepaged进程自动启动。当设置为never时自动关闭。redhat_transparent_hugepage/defrag参数使用相同的值,它控制内核是否积极地使用内存压缩更多的可以使用的hugepage。
检查整个系统THP的使用,执行下面的命令:
[root@zyg ~]# grep AnonHugePages /proc/meminfo
AnonHugePages: 94208 kB
在启动引导的时候禁用THP,可以在grub.conf中追加下面的内核命令行:
transparent_hugepage=never
重点: 在NUMA系统上,hugepage分配取决于一致地访问所有NUMA节点。但是对于数据库程序,为了最佳效率,应该只从最接近CPU的NUMA节点划出它的内存。
为了解决这个问题,并确保你的数据库程序在它的NUMA节点上能够得到足够的hugepage,分配额外的hugepage,因此当开启数据库的时候,所有的NUMA节点上应该是足够的。一旦数据库被分配了hugepage,通过调整vm.nr_hugepages sysctl,可以解除分配的不使用的额外的hugepage。另一个途径在“参考”中讨论。
/sys能提供每个NUMA节点hugepage使用的统计,帮助确定你需要保持多少hugepage
[root@zyg ~]# cat /sys/devices/system/node/node1/meminfo | grep Huge
Node 1 HugePages_Total: 0
Node 1 HugePages_Free: 0
Node 1 HugePages_Surp: 0
2.参考
/usr/share/doc/kernel-doc-*/Documentation/sysctl/vm.txt
/usr/share/doc/kernel-doc-*/Documentation/vm/hugetlbpage.txt
5.5.4 内存同页合并
当你的一些虚拟机运行完全相同的操作系统或工作量的时候,这有很高的机率,一些内存分页将有准确的相同内容。使用Kernel Samepage Merging(KSM)功能可使总共的内存使用减少,因为它可以合并那些完全相同的分页到一个内存分页中。当你在虚拟机中写这个分页时,在联机状态下它将被转变到一个新的单独的分页中。
为了使用KSM我们将使用两个服务:ksm,实际地扫描内存和合并分页;ksmtuned控制ksm是否扫描内存和如何积极扫描内存。
列出有关的KSM服务(需要安装qemu-kvm软件包):
[root@zyg ~]# chkconfig --list | grep ksm
ksm 0:off 1:off 2:off 3:on 4:on 5:on 6:off
ksmtuned 0:off 1:off 2:off 3:on 4:on 5:on 6:off
ksm能在/sys/kernel/mm/ksm中手工配置。下面的文件用来控制ksm,但是记住ksmruned将调整这些必要的设置,必要的ksmtuned是运行的:
□ Run。 当设置为1时ksm将实际扫描内存。当设置为0时,扫描被禁用。
□ pages_to_scan。 在一个周期中扫描内存分页的数量。
□ sleep_millisecs。 周期之间sleep的毫秒数。
在这个目录中也有两三个信息文件:
□ pages_shared。 被共享的物理分页数量。
□ pages_sharing。 被共享的逻辑分页数量。
□ full_scans。 到目前为止,多长时间整个内存被扫描一次。
使用ksmtuned服务手动调整ksm通常更为有用。要配置ksmtuned服务可以使用文件/etc/ksmtuned.conf:
[root@zyg ~]# cat /etc/ksmtuned.conf
# Configuration file for ksmtuned.
# How long ksmtuned should sleep between tuning adjustments
# KSM_MONITOR_INTERVAL=60
# Millisecond sleep between ksm scans for 16Gb server.
# Smaller servers sleep more, bigger sleep less.
# KSM_SLEEP_MSEC=10
# KSM_NPAGES_BOOST=300
# KSM_NPAGES_DECAY=-50
# KSM_NPAGES_MIN=64
# KSM_NPAGES_MAX=1250
# KSM_THRES_COEF=20
# KSM_THRES_CONST=2048
# uncomment the following if you want ksmtuned debug info
# LOGFILE=/var/log/ksmtuned
# DEBUG=1
为了看到ksmtuned做了什么,可以取消LOGFILE和DEBUG行的注释并重启ksmtuned:
# uncomment the following if you want ksmtuned debug info
LOGFILE=/var/log/ksmtuned
DEBUG=1
[root@zyg ~]# service ksmtuned restart
[root@zyg ~]# tail /var/log/ksmtuned
Wed Oct 15 16:33:52 CST 2014: total 7811968
Wed Oct 15 16:33:52 CST 2014: sleep 21
Wed Oct 15 16:33:52 CST 2014: thres 1562393
为了限制(或增加)允许ksm标记称为“非可交换的分页”的数量可以取消KSM_MAX_ KERNEL_PAGES这一行的注释,并设置一个数值。例如下面所示KSM_MAX_KERNEL_ PAGES=100:
[root@zyg ~]# cat /etc/sysconfig/ksm
# The maximum number of unswappable kernel pages
# which may be allocated by ksm (0 for unlimited)
# If unset, defaults to half of total memory
KSM_MAX_KERNEL_PAGES=100
[root@zyg ~]# service ksmtuned restart
当注释掉这一行或者设置为0的时候,ksm将标记多达一半的物理内存为不可交换的。不可交换的内存能增加性能,但是当分配内存的时候,代价就是缺少灵活性。例如可能有128GiB的空闲swap,但是因为大多数的内存被标记为不可交换的,它不能用来换出属于一个虚拟机的内存。
注意: 共享内存的数量可能仍旧在你配置的数量之上。当ksmtuned认为没有内存压力的时候将禁用ksm。在测试的时候,为了创造人为的内存缺乏,可以挂载一个tmpfs,并让它使用几乎所有的内存:
[root@wing ~]# cat /sys/kernel/mm/ksm/pages_shared
2908
[root@wing ~]# cat /sys/kernel/mm/ksm/pages_shared
423
5.6 调整磁盘子系统
最终,所有数据必须从磁盘检索并存储到磁盘。磁盘访问通常以毫秒计算,相比其他组件(比如内存和PCI操作,其以纳秒或微秒为单位)它至少要慢几千倍。Linux文件系统是磁盘上数据的存储和管理方法。
Linux可使用许多具有不同性能和可扩展的文件系统。除了在磁盘上存储和管理数据,文件系统也负责保证数据的完整性。较新的Linux发行版包括日志文件系统,作为默认安装的一部分。日志或日记,可防止在系统崩溃的情况下数据出现不一致。所有文件系统元数据的修改都会被保持在一个单独的日志或日记中,并在系统崩溃之后使其恢复到一致性状态。日志也提高了恢复时间,因为在系统重新启动时不需要执行文件系统检测。其他计算方面,你将发现要在性能和完整性之间进行权衡。然而,企业数据中心和企业环境中的Linux服务器,需要解决高可用性。
除了各种文件系统,Linux 2.6内核提供4种不同的I/O调度算法,可以用来为一个特定的任务定制系统。每个I/O电梯都有不同的特性,可能适合或可能不适合一个特定的硬件配置和所需的任务。虽然一些电梯宣称采用流式I/O,可它们常常在多媒体或桌面PC环境中存在,其他电梯则专注于数据库工作负载,需要低延迟访问时间。
本节我们涵盖标准文件系统的特征和调整选项,比如,在2.6内核中ReiserFS和EXT3 I/O电梯的调整。
5.6.1 安装Linux前的硬件注意事项
当前Linux发行版对于CPU速度和内存的最小化需求是有据可查的。这些操作指南还提供了完成安装所需的最小磁盘空间指导。然而,它们未能解释如何初始设置磁盘子系统。Linux服务器覆盖了多种多样的工作环境,因为服务器整合会影响数据中心。其中第一个要回答的问题是:安装的服务器具有哪些功能?
服务器的磁盘子系统是整个系统性能的主要组件。了解服务器的功能是确定I/O子系统在性能上是否有直接影响的关键。
服务器磁盘I/O是最重要的子系统的例子:
□ 文件服务器和打印服务器必须在用户与磁盘子系统之间快速移动数据。因为文件服务器的目的是传送文件到客户端,服务器必须首先读取磁盘上的所有数据。
□ 数据库服务器的最终目标是搜索和检索磁盘上存储库中的数据。即使有充足的内存,大多数数据库服务器也执行大量的磁盘I/O,将数据库记录读取到内存中,并刷新修改之后的数据到磁盘。
服务器磁盘I/O不是最重要的子系统的例子。
□ 电子邮件服务器作为电子邮件的存储库和路由器,容易产生巨大的通信负载。对于这种类型的服务器网络更加重要。
□ Web服务器负责托管的Web页面,受益于一个良好优化的网络和内存子系统。
1.驱动器的数量
磁盘驱动器的数量会明显影响性能,因为每个驱动器都有助于整个系统的吞吐量。容量的要求通常是用来确定在服务器中配置的磁盘驱动数量的唯一考虑因素。吞吐量的要求通常不很清楚或完全被忽略。磁头服务I/O请求的最大读写数量是良好的磁盘子系统的关键。
通过RAID(独立磁盘冗余阵列)技术,可以分散I/O到多个驱动器。有两个选择可用于在Linux环境下实现RAID:软件RAID和硬件RAID。除非你的服务器硬件标配了硬件RAID,否则可以用Linux发行版附带的软件RAID。如果需要,在RAID解决方案中可以增加更多的有效硬件。
如果实现硬件RAID阵列是必要的,那么对于你的系统需要一个RAID控制器。在这种情况下,磁盘子系统是由物理硬盘和控制器组成的。
提示: 一般情况下,添加驱动器是提高服务器性能最有效的手段之一。
最重要的是要记住,磁盘子系统的性能最终取决于一个给定设备能够处理的输入输出请求数量。一旦操作系统的cache和磁盘子系统的cache不能再容纳读/写请求的大小或数量,物理磁盘就必须工作。考虑下面的例子,一个磁盘驱动器每秒能够处理200个I/O。你有一个应用程序,在文件系统上执行4KB的随机位置写请求,因此不用选择流或请求合并。特定磁盘子系统的最大吞吐量现在是:
I/Os per second of physical disk * request size = maximum throughput
因此上述例子的结果是:
200 * 4 KB = 800 KB
由于物理最大值是800KB,在这种情况下提高性能的方法是,要么增加更多的物理磁盘,要么让应用程序写入较大的I/O。数据库比如DB2可以配置较大的请求,在大多数情况下这可以提高磁盘吞吐量。
2.设置分区的准则
如果是独立的磁盘,可将一个驱动器上的分区当做一组连续的块对待。今天的企业级Linux发行版默认安装,通过创建一个或多个逻辑卷,使用灵活的分区布局。
在Linux中关于最佳磁盘分区存在很大争议。如果你因为新需求或更新需求决定重新定义分区,那么单独根分区的方法可能在未来会引起问题。另一方面,太多的分区可能导致文件系统管理的问题。在安装过程中,Linux发行版可以为你创建多分区布局。
在多分区或逻辑卷上运行Linux的好处:
□ 更细粒度地提高文件系统属性安全。
例如,/var和/tmp分区具有创建属性,其允许系统上的所有用户和进程都很容易访问,容易受到恶意的访问。通过隔离这些分区到不同的磁盘,而且如果这些分区需要重建或恢复,那么这样做可以减少对系统可用性的影响。
□ 提高了数据完整性,所以磁盘故障中丢失的数据会被隔离到受影响的分区。
例如,如果系统中没有实现RAID(软件或硬件)并且服务器遭受磁盘崩溃,那么仅坏磁盘上的分区需要修复或恢复。
□ 在不影响其他多个静态分区的情况下完成新的安装或升级。
例如,如果/home文件系统没有被分离到另一个分区,则在操作系统升级中它将被覆盖,将丢失它上面存储的所有用户文件。
□ 备份过程更高效。
设计分区布局时必须考虑到备份工具。了解备份工具在分区的边界或更精细级别的操作是非常重要的,如文件系统。
表5-6列出了一些可以考虑从根中分离出来的分区,从而在你的环境中提供更大的灵活性和更好的性能。
表5-6 Linux分区和服务器环境
分区 内容和可能的服务器环境
/home 分离出/home到自己的分区对于文件服务器环境是有好处的。这是系统上所有用户的家目录,如果没有实现磁盘配额,那么分离这个目录是为了隔离用户对磁盘空间的失控使用
/tmp 如果在高性能计算环境中运行,那么在计算时需要大量的临时空间,然后完成后释放
/usr 这是放置内核源码树和Linux文档(以及大多数可执行二进制文件)的位置。/usr/local目录存储的可执行文件必须可以被系统上的所有用户访问,并且是一个很好的位置用来存储为你环境开发的自定义脚本。如果它被分离到它自己的分区,那么在升级或重新安装时通过简单地选择不需要重新格式化的分区,文件不会被重新安装
/var /var分区在邮件、网站、打印服务器环境中是非常重要的,因为它包含了这些环境的日志文件和整个系统的日志。长期的消息可以填满这个分区。如果发生这种情况,并且此分区没有从/中分离出来,则服务可能会中断。根据不同的环境,可能要进一步分离这个分区,做法是在邮件服务器上分离出/var/spool/mail,或相关系统日志的/var/log
/opt 安装的一些第三方软件产品,比如Oracle数据库服务器默认使用这个分区。如果没有分离,安装将在/下继续,如果不能分配足够的空间,可能会失败
查看更多Linux发行版如何处理文件系统标准的详情,请参考文件系统层次标准(Filesystem Hierarchy Standard)的主页:http://www.pathname.com/fhs。
5.6.2 I/O调度的调整和选择
Linux 2.6内核引入了新的I/O调度算法,以便在处理不同的I/O模式时更加灵活。系统管理员现在可以对给定硬件和软件的设计选择最适合的电梯算法。另外,每个I/O电梯算法设有一组调整选项,这可以进一步为一个特定工作负载定制系统。
1.在2.6内核中选择正确的I/O电梯算法
对于大多数服务器工作负载,典型的服务器操作中无论是Complete Fair Queuing(CFQ)电梯算法还是deadline电梯算法都是一个适当的选择,因为对于多用户多进程环境它们是优化的。企业发布版通常默认是CFQ电梯算法。然而,IBM System z上的Linux,deadline调度器要比默认电梯算法更受青睐。某些环境中选择不同的I/O电梯算法是有好处的。Red Hat Enterprise Linux 5.x和Novell SUSE Linux Enterprise Server 10 I/O调度器现在可以基于每个磁盘子系统来选择,在早先的Red Hat Enterprise Linux 4.0和Novell SUSE Linux Enterprise Server 9中是全局设定。由于每个磁盘子系统可能使用不同I/O电梯算法,管理员现在可以在磁盘子系统上隔离一个特定I/O模式(比如写入密集型的工作负载)和选择适当电梯算法。
□ 同步文件系统访问。 某些类型的应用程序需要同步执行文件系统操作。实际中数据库可能使用原始文件系统或是非常大的磁盘子系统中缓存异步磁盘访问根本不是一个选项。在这些情况下,anticipatory电梯算法通常具有最少吞吐量和最高延迟。如图5-8所示,其他3种调度器同样表现良好,I/O大小上升到大约16KB时,CFQ和NOOP电梯算法开始超过deadline电梯算法(除非磁盘访问非常频繁)。
图5-8 每个I/O电梯算法随机读性能(同步)
□ 复杂的磁盘子系统。 banchmark'显示,在高端服务器环境中NOOP电梯算法是一个有趣的选择。当使用IBM ServeRAID或TotalStorage® DS级别磁盘子系统非常复杂的配置时,缺乏排序功能成为NOOP电梯算法的优点。企业级磁盘子系统可能包含多个SCSI或FibreChannel磁盘,每个磁盘都有单独的磁头和条带化的数据。正确地预期如此复杂的子系统的I/O特性,对于I/O电梯算法是非常困难的,因此当使用NOOP I/O电梯算法的时候,你可能会常常观察到至少相同性能下开销较少。
□ 数据库系统。 由于大多数数据库工作负载的定向搜索性,当为这些工作负载选择deadline电梯算法的时候,可以实现一些性能增加。
□ 虚拟机。 不管是VMware或System z中的VM,通常通过底层硬件虚拟化层通信。所以虚拟机不知道所分配的磁盘设备是由单个SCSI设备还是由TotalStorage DS800™上FibreChannel磁盘阵列组成。虚拟化层采取对必要的I/O重新排序,并且与物理块设备进行通信。
□ CPU绑定应用程序。 虽然一些I/O调度器可以提供出色的吞吐量,但它们可能同时会产生更多系统开销。例如,CFQ或deadline电梯算法所导致的开销来自于I/O队列的积极合并和重新排序。有些时候工作负载对于磁盘子系统的性能没有太多的限制,而对CPU性能有限制。这种情况可能发生在科学工作负载或数据仓库处理非常复杂的查询。在这样的场景中NOOP电梯算法提供比其他电梯多一些的优势,如图5-9显示,因为它具有较少的CPU开销。然而还应该注意的是,当CPU开销与吞吐量相比较的时候,在大多数异步文件系统访问的模式下deadline和CFQ电梯算法仍旧是最好的选择。
图5-9 I/O电梯算法的CPU使用率(异步)
□ 单ATA或SATA磁盘子系统。如果选择使用单个物理ATA或SATA磁盘,则可以考虑使用anticipatory I/O电梯算法,重新排序磁盘写以适于单个磁头设备。
2.nr_requests的影响
2.6内核实现了可插入式的I/O调度器,还有一种方法来增加或减少发送给磁盘子系统请求的数量。使用nr_requests,就像很多其他的调整参数,没有一个最佳的设置。请求数的正确值在很大程度上取决于底层的磁盘子系统和更多的I/O工作负载的特性。nr_requests取值不同的影响也取决于你使用的不同的文件系统和I/O调度器,在图5-10和图5-11中通过两个benchmark可以很容易地看到。正如在图5-10中所指出的,通过nr_requests的不同值Deadline电梯算法比CFQ电梯算法不容易引起变化。
图5-10 nr_requests对Deadline电梯算法的影响(随机写)
图5-11 nr_requests对CFQ电梯算法的影响(随机写)
较大的请求队列可能会给写提供很多小文件的工作负载较高的吞吐量。正如在图5-11中显示的,8192的设置提供了最高的性能级别,高达16KB的I/O大小。在64KB时nr_requests分析值从64上升到8192提供大约相同的性能。然而由于I/O大小的增加,nr_requests的较小级别将在大多数情况下产生优越的性能。使用下面的命令可以改变请求的数量:
[root@zyg ~]# echo 64 > /sys/block/sdb/queue/nr_requests
当前Red Hat和Linux企业发行版提供基于每个磁盘子系统设置nr_requests的选项,这是很重要的。所以I/O访问模式可以被分离并优化调整。例如,一个数据库系统,日志分区和数据库将被存储在专用的磁盘或磁盘子系统上(比如DS3400上的一个存储分区)。在这个例子中,日志分区使用大nr_reuests是有好处的,它适应大量的小的写I/O;数据库分区使用较小的值,可能看到读I/O同128KB一样大。
提示: 要了解如何衡量和计算平均I/O大小,参考2.3.7节的内容。
3.read_ahead_kb的影响
在大的流读取情况下,增加预读buffer的大小可能会增加性能。请记住,增加这个值将不会增加大多数服务器工作负载的性能,因为这些主要是随机I/O操作。read_ahead_kb中的值定义了预读操作可以多大。存储在/sys/block//queue/read_ahead_kb中的值定义了预读操作可以达多少KB。这个值可以使用cat和echo命令进行解析和改变,如下所示:
[root@zyg ~]# cat /sys/block/sda/queue/read_ahead_kb
128
[root@zyg ~]# echo 256 > /sys/block/sda/queue/read_ahead_kb
5.6.3 文件系统的选择和调整
正如1.3节中所述,考虑到不同的工作负载和可用性特征,Linux被设计为可使用不同的文件系统。如果你的Linux发行版和应用程序允许选择不同文件系统,如果Ext、Journal File System (JFS)、ReiserFS或eXtended File System(XFS)对于计划工作负载是最佳选择,它是值得研究的。一般来说ReiserFS更适合小I/O请求,XFS和JFS被定制为面向非常大的文件系统和非常大的I/O。Ext3适用于ReiserFS和JFS/XFS之间,因为它可以适应小I/O请求,同时提供良好的多处理器扩展性。
JFS和XFS的工作负载模式最适合高端数据仓库、科研工作量、大型SMP服务器及流媒体服务器。另一方面ReiserFS和Ext3通常被用于文件、Web、邮件服务器。在图5-12中,对于创建达到64KB的较小I/O写入密集型负载,在日志模式下ReiserFS的优势会超过Ext3。然而这只适用于同步文件系统操作。
图5-12 Ext和ReiserFS之间随机写吞吐量比较(同步)
要考虑到一个选择是Ext2文件系统。由于它没有日志功能,不管是访问模式还是I/O大小,同步文件系统访问Ext2要优于ReiserFS和Ext3。因此,当性能比数据完整性重要的时候Ext2是一种选择。
在异步文件系统最常见的场景中,ReiserFS通常提供了可靠的性能,并优于Ext3默认的日志模式(data=ordered)。要注意的是,一旦从默认日志模式切换到writeback,Ext3和ReiserFS是不相上下的。如图5-13所示。
图5-13 Ext3和ReiserFS之间随机写吞吐量比较(异步)
1.使用ionice分配I/O优先级
CFQ I/O elevator的一个新特性是选择在进程级别分配优先级。使用ionice工具,它现在可以限制一个特定进程的磁盘子系统使用率。在写这篇文章的时候,使用ionice可以分配3种优先级,它们是:
□ Idle。 分配给I/O优先级为idle的进程,只有在没有其他Best-effort(尽力而为)或更高优先级的进程请求访问数据时,才给其授权访问磁盘子系统。这个设置对于任务非常有帮助,尤其当系统有空闲资源的时候,比如只运行updatedb任务。
□ Best-effort。 默认所有不要求特定I/O优先级的进程被分配到这一类。进程将继承它们各自的CPU的nice优先级为8到I/O优先级。
□ Real time。 最高可用I/O优先级是realtime,这意味着进程各自将总在给定优先级下访问磁盘子系统。real time优先级也可以设置优先级别为8。应小心使用,当给其分配一个线程real time优先级的时候,这个进程可能导致其他任务等待。
ionice工具接受以下选项:
□ -c<#> I/O优先级,1为real time,2为best-effort,3为idle。
□ -n<#> I/O优先级的数据0至7。
□ -p<#>运行任务的进程id,不使用-p任务以各自的I/O优先级启动。
下面显示了运行ionice的例子,使用ionice PID为48998的进程分配idle I/O优先级:
[root@zyg ~]# ionice -c 3 -p 48998
2.更新访问时间
Linux文件系统保存当文件被创建、更新、访问时候的记录。默认操作包括在文件读取和写入时更新最后读取时间的属性。因为写是一种开销大的操作,减少不必要的I/O可以提高整体性能。然而,在大多数情况下,禁用文件访问时间的更新将只会产生一个非常小的系能提升。
使用noatime选项挂载文件系统防止访问时间被更新。如果文件和目录的更新时间不是很关键,比如在Web服务器环境中,则管理员可以选择在/etc/fstab中使用noatime标志挂载文件系统。禁用访问时间更新的性能优势在于,写入到文件系统的范围从0到10%,文件服务器的工作负载平均为3%。
/dev/sdb1 /data ext3 defaults,data=noatime 0 0
提示: 通常一个好的建议是将/var作为一个单独的分区,并使用noatime选项挂载。
注意,在Red Hat Enterprise Linux 6.x中的挂载选项中优化atime为relatime,可以不必使用noatime。
注意,在关闭atime之前一定要确保使用该文件系统的应用程序不需要使用atime。如果需要使用atime,不要关闭,例如/tmp。
3.选择文件系统的日志模式
大多数文件系统有3种日志选项,可以使用mount命令的data选项设置。然而,Ext3文件系统日志模式对性能有很大影响,因此建议你使用这些调整选择,主要是针对Red Hat的默认文件系统:
data=journal
这个日志选项通过将文件数据和元数据全部记录为日志来提供最高的数据一致性。它也具有较高的性能开销。
data=ordered(default)
在这个模式中只记录元数据。但是保证文件数据先被写入。这是默认设置。
data=writeback
这个日志选项在数据一致性的代价下提供最快的数据访问。在保证数据一致性的前提下元数据仍被记录。然而,实际的文件数据没有进行特殊的处理,这可能导致在系统崩溃之后旧的数据会出现。应该注意的是,当使用writeback模式时这种元数据日志的实现,ReiserFS、JFS、XFS默认是可以比较的。如图5-14所示,writeback日志模式可以提高Ext3的性能,尤其是小的I/O大小。使用writeback日志的好处是当I/O大小增长时性能下降。另外要注意的是,文件系统的日志模式只影响写性能。因此,主要执行读的工作负载(例如,Web服务器)将不会从变更日志模式中受益。
图5-14 data=writeback对随机写性能的影响
有3种方法更改文件系统的日志模式。
□ 当执行mount命令的时候:
[root@zyg ~]# mount -o data=writeback /dev/sdb1 /data
•/dev/sdb1已经挂载过的文件系统
□ 在/etc/fatab的选项部分包括日志模式:
/dev/sdb1 /data ext3 defaults,data=writeback 0 0
□ 如果你想在根分区上修改默认的data=ordered选项,应更改上面列出的/etc/fatab文件,然后执行mkinitrd命令在/etc/fatab文件中扫描变更并创建一个新的镜像文件。更新GRUB或LILO指向新的镜像文件。
4.块大小
块的大小指,从驱动器中读取或写入数据的最小量,它可以对服务器的性能造成直接影响。作为原则,如果你的服务器处理大量的小文件,那么较小的块大小将更有效。如果你的服务器专用于处理大文件,则较大的块大小可能会提高性能。在已经存在的文件系统上块的大小不能在联机状态下改变,只有重新格式化才能修改当前块大小。大多数Linux发行版允许的块大小为1KB、2KB、4KB。benchmark显示,更改文件系统的块大小很难得到任何性能提高,因此,一般默认在4KB的时候是最好的。
当使用硬件RAID解决方案时,要仔细考虑,必须指定阵列的条带大小(stripe size)(或在Fibre Channel中segment(段)大小)。条带单元的大小是在阵列中的下一个驱动器上存储随后的数据之前,阵列中的一个驱动器存储数据的粒度。当前条带大小的问题是要了解一个特定应用程序执行主要请求的大小。一个硬件阵列的条带大小,需要对照文件系统的块大小,对整体磁盘性能有明显的影响。
大的条带大小可以减少磁头的寻道时间并提高吞吐量,这对于流和顺序的内容通常是有好处的,但是更多活跃的随机类型,比如在数据库服务器中,条带大小相当于记录大小执行得会更好。
5.6.4 虚拟化存储
虚拟机像物理机一样也需要存储。当给虚拟机添加一个存储的时候,必须要做3个选择:如何呈现存储到虚拟机,如何存储磁盘上的image,如何cache存储的写。
如图5-15所示呈现一个磁盘到虚拟机的选项有:IDE disk、IDE cdrom、Floppy disk和VirtIO Disk。前3个需要软件仿真,需要额外的开销,VirtIO是最快的,但是在虚拟机操作系统中需要VirtIO驱动。
图5-15 选择设备类型
Image的存储可以是在hypervisor上的本地块设备或在文件之间选择。块设备可以(一个普通分区或逻辑卷)提供最好的性能,文件给你更多的灵活性。当使用块设备的时候一些丢失的灵活性可以使用LVM补偿。如图5-16所示,当我们使用文件的时候,使用的选项有:raw(可以是ext3/ext4上的文件)、QCOW2或qed。raw文件提供最好的性能,qcow2映像更小并支持snapshot功能,qed是QEMU虚拟机的格式。
图5-16 选择存储格式
对于Cache模式可以选择default、none、writeback和writethrough。如图5-17所示。
图5-17 选择cache模式
□ default将选择最好的实际存储。
□ none完全关闭写缓存(这是默认的)。
□ wirtethrough是最安全的,写操作根本不使用缓存,数据总是直接写入磁盘。
□ writeback可以提高写操作的性能。数据不是直接被写入磁盘;而是写入缓存。
在一个libvirtd XML文件中,存储的定义是使用块。下面有2个例子,第一个是使用文件附加一个raw类型的virtIO磁盘,第二个是使用文件附加一个qcow2类型的virtIO磁盘:
5.7 调整网络子系统
当首次安装操作系统的时候,如果认为网络子系统存在瓶颈,那么应该对网络子系统进行调整。这里的一个问题可能会影响到其他子系统,例如,当数据包太小的时候,CPU使用率会受到明显的影响;如果有过多数量的TCP连接,内存使用会增加。
5.7.1 网卡绑定
通过使用bonding驱动程序,Linux内核提供网络接口聚合能力。这是一个与设备不相关的bonding驱动程序(也有特定设备的驱动程序)。bonding驱动程序支持802.3链路聚合规范,并可以实现负载均衡和容错。它实现了更高层次的可用性和性能改善。
配置一个bonding接口,首先创建一个bonding设备。在/etc/modprobe.d/中创建一个bonding.conf文件(名字不重要,但是文件名必须是以.conf结尾),包含以下内容:
alias bond0 bonding
options bonding miimon=100 mode=balance-rr
miimon是用来进行链路监测的。比如miimon=100,那么系统每100ms监测一次链路连接状态,如果有一条线路不通就转入另一条线路。
mode的值表示工作模式:
□ balance-rr或0。 数据包在round-robin模式下发送,使用bond中的所有网卡。它提供容错并基本负载均衡。
□ active-backup或1。 仅使用bond中的一个网卡。当活跃NIC出故障时,另一个网卡将接管,这个模式提供容错。
创建/etc/sysconfig/network-scripts/ifcfg-bond0并配置绑定接口:
DEVICE=bond0
TYPE=Ethernet
ONBOOT=yes
BOOTPROTO=none
IPADDR=192.168.0.213
NETMASK=255.255.255.0
分别配置bond0中的每个网卡:
[root@zyg ~]# vim /etc/sysconfig/network-scripts/ifcfg-eth1
DEVICE=eth1
TYPE=Ethernet
ONBOOT=yes
NM_CONTROLLED=no
IPV6INIT=no
USERCTL=no
BOOTPROTO=none
MASTER=bond0
SLAVE=yes
[root@zyg ~]# vim /etc/sysconfig/network-scripts/ifcfg-eth2
DEVICE=eth2
TYPE=Ethernet
ONBOOT=yes
NM_CONTROLLED=no
IPV6INIT=no
USERCTL=no
BOOTPROTO=none
MASTER=bond0
SLAVE=yes
重新启动网络后,使用ip命令查看网络接口状态:
[root@zyg ~]# ip link show dev bond0
5: bond0: <BROADCAST,MULTICAST,MASTER
,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP
link/ether 00:0c:29:fc:1c:73 brd ff:ff:ff:ff:ff:ff
[root@zyg ~]# ip link show dev eth1
3: eth1: <BROADCAST,MULTICAST,SLAVE
,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast master bond0 state UP
qlen 1000
link/ether 00:0c:29:fc:1c:73 brd ff:ff:ff:ff:ff:ff
[root@zyg ~]# ip link show dev eth2
4: eth2: <BROADCAST,MULTICAST,SLAVE
,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast master bond0 state UP
qlen 1000
link/ether 00:0c:29:fc:1c:73 brd ff:ff:ff:ff:ff:ff
也可以在proc看到bond0当前的工作状态:
[root@zyg ~]# cat /proc/net/bonding/bond0
Ethernet Channel Bonding Driver: v3.6.0 (September 26, 2009)
Bonding Mode: load balancing (round-robin)
MII Status: up
MII Polling Interval (ms): 100
Up Delay (ms): 0
Down Delay (ms): 0
Slave Interface: eth1
MII Status: up
Speed: 1000 Mbps
Duplex: full
Link Failure Count: 0
Permanent HW addr: 00:0c:29:fc:1c:73
Slave queue ID: 0
Slave Interface: eth2
MII Status: up
Speed: 1000 Mbps
Duplex: full
Link Failure Count: 0
Permanent HW addr: 00:0c:29:fc:1c:7d
Slave queue ID: 0
注意: NetworkManager在Red Hat Enterprise Linux 6中还不支持bonding。如果决定使用bonding,确保禁用NetworkManager并启用network服务。此外,连接的对端设备(比如交换机)的两个接口也要做绑定。
提示: 如果安装了kernel-doc则可以在内核文档中找到bonding的配置方式,/usr/share/doc/ `uname -r`/Documentation/networking/bonding.txt。
5.7.2 巨帧
每当一个数据包穿过网络进行传输时,数据包中都包含有协议的头部信息和所携带数据。一个典型的TCP/IP数据包报头包含一个以太网帧头、一个IP报头,和一个TCP报头。所有这些头部信息被包含在网络上所使用的最大传输单元(MTU)中。在实例中,一个普通的TCP连接使用的协议报头是40个字节。一个默认MTU是1500个字节,差不多2.7%的容量损失。
一种减少开销的方法是,切换到另一个头部信息开销更小的协议。切换tcp到udp将报头从40字节减少到28字节(小于1.9%开销,一个MTU 1500个字节),然而,这并不总是可行的。
另一个方法是增加能发送的数据包的大小(MTU)。当在1500字节的以太网标准下增加MTU的时候,该数据包被称为巨帧(Jumbo Frames)。
特别是千兆网络,较大的最大传输单元(MTU)可以提供更好的网络性能。较大MTU所面临的问题是,实际上大多数网络不支持它,一些网卡也不支持较大的MTU。如果你的目标是在千兆速度下传输大量数据(例如HPC环境),增加默认MTU大小可以带来明显的性能提升。
警告: 巨帧的典型应用为网络用途,如iSCSI和NFS。在一般用途的网络上启动巨帧时要小心,因为它可能很难保证网络上的每个单独的设备(包括你的网卡、交换机和路由器)支持巨帧并可以配置它们。官方巨帧最大的大小是9000字节,但是一些设备支持更大的帧。
在相同的40字节报头,假设一个9000字节的MTU:
40 / 9000 * 100% = 0.44 %
相比较之前的2.7%,这是重大的改善。
在/etc/sysconfig/network-scripts/ifcfg-name 中添加下面的行来配置更大的MTU:
MTU=size
下面的例子显示了一个9000字节的MTU的eth0:
[root@zyg ~]# vim /etc/sysconfig/network-scripts/ifcfg-eth0
DEVICE=eth0
HWADDR=00:0c:29:fc:1c:69
TYPE=Ethernet
UUID=38664e1d-825f-4e98-9fa5-35f6adb25aa1
ONBOOT=yes
NM_CONTROLLED=yes
BOOTPROTO=none
IPADDR=192.168.1.200
NETMASK=255.255.255.0
IPV6INIT=no
USERCTL=no
MTU=9000
[root@zyg ~]# ip addr show dev eth0
2: eth0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 9000
qdisc pfifo_fast state UP qlen 1000
link/ether 00:0c:29:fc:1c:69 brd ff:ff:ff:ff:ff:ff
inet 192.168.1.200/24 brd 192.168.1.255 scope global eth0
inet6 fe80::20c:29ff:fefc:1c69/64 scope link
valid_lft forever preferred_lft forever
5.7.3 速度与双工模式
网络吞吐量依赖于许多因素,使用的网卡、布线的类型、在一次连接中的跳数、发送的包大小,等等。提高网络性能最简单的方法之一是检测网络接口的实际速度,因为问题可能在网络组件(比如交换机或集线器)和网络接口卡之间。如下所示,不匹配会有很大的性能影响。
[root@zyg ~]# ethtool eth0
Settings for eth0:
Supported ports: [TP]
Supported link modes: 10baseT/Half 10baseT/Full
100baseT/Half 100baseT/Full
1000baseT/Full
Supports auto-negotiation: Yes
Advertised link modes: 10baseT/Half 10baseT/Full
100baseT/Half 100baseT/Full
1000baseT/Full
Advertised pause frame use: No
Advertised auto-negotiation: Yes
Speed: 1000Mb/s
Duplex: Full
Port: Twisted Pair
PHYAD: 1
Transceiver: internal
Auto-negotiation: on
MDI-X: Unknown
Supports Wake-on: g
Wake-on: d
Link detected: yes
由上可知eth0支持10Mb/s、100Mb/s、1000Mb/s链路全双功和半双功。它使用自动协商,它察觉当前设置为1000Mb/s全双功。
自动协商是以太网的一个特征,一个网卡与下一跳进程通信时协商最高速率。自动协商通常是被信任的,但偶尔它可能工作不正常。在自动协商不匹配的情况下,众多网络设备默认为100Mb半双工。如果要管理自动协商限制网卡通告的速率,则可以完全关闭自动协商手工设置一个速率。可以使用ethtool命令,检查实际线路速度和网络连接的双工设置。
注意: 大多数网络管理员认为最好的方法是添加一个网络接口,两个网卡与交换机或集线器的端口使用指定的静态速度。如果设备驱动器支持ethtool命令,则可以使用ethtool更改配置。
下面的例子显示了ethtool -s NIC OPTIONS命令,手工设置以太网选项,但是不是持久的。要持久配置,添加一行到相关的/etc/sysconfig/network-scripts/ifcfg-*文件,使用ETHTOOL_ OPTS=“OPTIONS”。关闭自动协商同时,设置一个固定的速率。使用autoneg、speed、duplex选项。
[root@zyg ~]# ethtool -s eth0 autoneg off speed 1000 duplex full
在图5-18和图5-19中从benchmark(基准测试)的结果来看,当网络速度协商不正确的时候,小数据的传输比较大数据的传输影响较小。数据传输大于1KB显示出大幅的性能影响(吞吐量下降50%~90%)。确保速度和双工的设置是正确的。
图5-18 自动协商失败导致性能下降(1Gb/s全双工)
图5-19 自动协商失败导致性能下降(100Mb/s半双工)
5.7.4 增加网络缓冲区
当涉及分配内存资源到网络buffer的时候,Linux网络协议栈处理是很谨慎的。对于现代高速网络中连接的服务器系统,增加这些值,可以使系统处理更多的网络数据包。
□ 基于系统内存自动计算出初始的整个tcp内存,可以通过下面参数找到实际的值:
/proc/sys/net/ipv4/tcp_mem
□ 通过下面参数可以设置接收socket的内存默认值和最大值到一个更高的值:
/proc/sys/net/core/rmem_default
/proc/sys/net/core/rmem_max
□ 通过下面参数可以设置发送socket的内存默认值和最大值到一个更高的值:
/proc/sys/net/core/wmem_default
/proc/sys/net/core/wmem_max
□ 通过下面参数可以调整可选内存buffers的最大值到一个更高的值:
/proc/sys/net/core/optmem_max
1.调整窗口大小
通过上面所述网络buffer的大小参数,可以调整最大窗口大小。理论上最优窗口大小可以通过使用BDP(bandwidth delay product带宽延迟乘积)获得。BDP是在传输中驻留在线路上的数据总量。使用这个简单的公式可以计算BDP:
BDP = Bandwidth (bytes/sec) * Delay (or round trip time) (sec)
为了保持网络管道是满的并且充分利用线路,网络节点应该具有可用的buffer,存储与BDP相同大小的数据。否则,发送端会停止发送数据并等待来自接收端的确认(参考1.5.2节的介绍)。
例如。在具有1毫秒延迟的千兆以太局域网中,BDP是:
125Mbytes/sec (1Gbit/sec) * 1msec = 125Kbytes
在大多数企业发行版中rmem_max和wmem_max的默认值大约是128KB,一般用途的低延迟网络环境可能是足够的。然而,如果延迟大,默认大小就可能太小了。
看另外一个例子,假设一台samba文件服务器支持来自不同地点的16个并发文件传输会话,在默认配置中,每个会话的socket buffer大小归结为8KB。如果数据传输很高这可能相对较小。
注意: 将tcp buffer设置得太大将导致出现缓冲膨胀的现象。这能严重影响发送小数据量服务(比如http或ssh)的网络速度和连接延时。
计算最大吞吐量所需要的缓冲区大小。首先,算出一个数据包的往返时间,这个时间是一个数据包从本地发送并从远端主机接收的时间。使用ping命令找到平均往返时间:
[root@zyg ~]# ping BJ-SERVER-001
PING BJ-SERVER-001 (219.168.2.38) 56(84) bytes of data.
64 bytes from BJ-SERVER-001 (219.168.2.38): icmp_seq=1 ttl=50 time=9.77 ms
64 bytes from BJ-SERVER-001 (219.168.2.38): icmp_seq=2 ttl=50 time=9.61 ms
64 bytes from BJ-SERVER-001 (219.168.2.38): icmp_seq=3 ttl=50 time=11.6 ms
64 bytes from BJ-SERVER-001 (219.168.2.38): icmp_seq=4 ttl=50 time=9.12 ms
64 bytes from BJ-SERVER-001 (219.168.2.38): icmp_seq=5 ttl=50 time=12.3 ms
^C
--- BJ-SERVER-001 ping statistics ---
5 packets transmitted, 5 received, 0% packet loss, time 4381ms
rtt min/avg/max/mdev = 9.120/10.509/12.361/1.270 ms
显示一个平均往返时间是10.509ms = 0.010594s,假设网络速度是1Gb/s:
1 Gb/s * 10.509ms = 10^9 b/s * 0.010594s = 10594000 bits * 1/8 B/b = 1324250 Bytes =1293.21 KiB
计算的结果被称为Bandwidth Delay Product或简称BDP(带宽延时积)。
如果BDP超过64KiB,那么TCP连接能利用滑动窗口。一个tcp窗口是发送到远端系统还没有被确认的数据。如果未确定的数据增长到窗口大小,发送者将停止发送直到之前的数据被确认。默认情况下,窗口最大被限制在64KiB。滑动窗口能够协商,如果两边都支持它,则允许窗口增长。如果sysctl net.ipv4.tcp_window_scaling设置为1,那么内核将尝试协商滑动窗口。如果为0滑动窗口将被禁用。
注意: 如果一个系统将处理多并发连接,则每socket缓冲区大小只需要足够大能处理一个单个的socket的BDP。
□ 设置操作系统对于多个协议队列最大发送buffer大小(wmem)和接收buffer大小(rmem)到8MB:
sysctl -w net.core.wmem_max=8388608
sysctl -w net.core.rmem_max=8388608
当它被创建的时候,分配给每个TCP socket特定的内存数量。
□ 此外,还应该使用下面命令设置发送和接收buffer。指定3个值:最小值、初始值和最大值:
sysctl -w net.ipv4.tcp_rmem="4096 87380 8388608"
sysctl -w net.ipv4.tcp_wmem="4096 87380 8388608"
第三个值必须小于等于wmem_max和rmem_max的值。然而,建议在高速高质量的网络中增加第一个值,使得TCP窗口开始于一个足够高的值。
□ 增加/proc/sys/net/ipv4/tcp_mem中的值。这3个值是指最小、压力、最大分配给TCP的内存。
限制socket bufer为较小的尺寸,结果是较小的窗口大小,导致频繁的确认数据包,低效利用。相反,指定socket buffer到较大的尺寸,结果是较大的窗口大小。
2.socket buffer大小的影响
当一台服务器处理大量并发大文件传输的时候,较小的socket buffer可能会导致性能下降。如图5-20所示,当使用较少‘socket buffer’的时候可观察到明显的性能下降。rmem_max和wmem_max较低的值限制可用的socket buffer大小,即使对方负担得起socket buffer。这会导致较小的窗口大小和大数据传输达到性能上限。虽然没有包含在此图中,在小数据(小于4KB)传输时可观察到没有明显的性能差异。
图5-20 比较4 KB和132 KB时socket buffer的影响
5.7.5 增加数据包队列
增加各种网络buffer的大小之后,建议增加允许未处理数据包的数量,使内核在丢弃数据包之前等待更长的时间。要做到这一点,编辑/proc/sys/net/core/netdev_max_backlog中的值:
[root@zyg ~]# cat /proc/sys/net/core/netdev_max_backlog
1000
5.7.6 增加传输队列长度
对每个接口增加txqueuelength参数的值在1000和20 000之间。对于高速连接进行大的均匀的数据传输特别有用。如在下面的例子中,使用ifconfig命令可以调整传输队列长度:
[root@zyg ~]# ip link show dev eth0
2: eth0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 9000 qdisc pfifo_fast state UP qlen
1000
link/ether 00:0c:29:fc:1c:69 brd ff:ff:ff:ff:ff:ff
[root@zyg ~]#
[root@zyg ~]# ip link set eth0 txqueuelen 2000
[root@zyg ~]# ip link show dev eth0
2: eth0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 9000 qdisc pfifo_fast state UP qlen
2000
link/ether 00:0c:29:fc:1c:69 brd ff:ff:ff:ff:ff:ff
5.7.7 配置offload
如1.5.3节中所述,如果支持此功能,一些网络操作可以从网络接口设备offload。可以使用ethtool命令检查当前offload配置。
使用-k选项检查offload配置:
[root@zyg ~]# ethtool -k eth0
Offload parameters for eth0:
rx-checksumming: on
tx-checksumming: on
scatter-gather: on
tcp-segmentation-offload: on
udp-fragmentation-offload: off
generic-segmentation-offload: on
generic-receive-offload: off
large-receive-offload: off
更改配置命令语法如下:
ethtool -K|--features|--offload devname feature on|off ...
例如:
[root@zyg ~]# ethtool -K eth0 sg on tso on gso off
根据网络接口设备,你选择的平台支持的offload功能可能有所不同。如果运行一个不支持的offload参数,可能会得到错误信息。
1.offload的影响
benchmark显示,CPU使用率可以通过网卡offload而降低。图5-21显示大数据量(超过32KB)导致较高的CPU使用率。大数据包可利用校验和offload,因为校验和需要计算整个数据包,所以更多处理能力被数据大小的增加所消耗。
图5-21 通过offload CPU使用率提高
然而,使用offload(如图5-22所示)会观察到轻微的性能下降。如此高的分组速率,检验和的处理在某些LAN适配器处理器上产生明显的负载。由于数据包的大小变大,每秒产生较少的数据包(因为它需要更长的时间来发送和接收所有数据),它谨慎地在适配器上进行offload校验和操作。
图5-22 通过offload吞吐量下降
当网络应用程序请求数据的时候LAN适配器可以有效地为大型帧生成请求。应用程序请求小数据块需要LAN适配器通信处理器花费更大比例的时间,为传输数据的每个字节执行开销代码。这就是为什么大多数LAN适配器不能为所有的帧大小保持完整的线速的原因。
5.7.8 Netfilter对性能的影响
由于Netfilter提供TCP/IP连接跟踪和数据包过滤功能(参考1.5.1节的介绍),在某些情况下它可能产生较大的性能影响。当连接建立的数量较高的时候,其影响是清晰可见的。图5-23所示大的连接建立数和小的连接建立数的benchmark结果。该结果清楚地说明了Netfilter的影响。
图5-23 没有应用Netfilter规则的TCP_CRR benchmark(不同数据大小)
当没有应用Netfilter规则的时候(如图5-24所示),benchmark结果表明相似的性能特点,连接建立很少发生(参考图5-27),而因为连接建立的开销,绝对吞吐量仍然不同。
图5-24 没有应用Netfilter规则的TCP_CRR benchmark(不同socket大小)
然而,当应用过滤规则的时候,可以看到相对不一致的行为(如图5-25和图5-26所示)。
图5-25 应用Netfilter规则的TCP_CRR benchmark(不同数据大小)
图5-26 应用Netfilter规则的TCP_CRR benchmark(不同socket大小)
然而,Netfilter提供数据包过滤的能力,并加强网络的安全性。它可以是安全性和性能之间的权衡。Netfilter的性能影响取决于以下因素:
□ 规则的数量
□ 规则的顺序
□ 规则的复杂性
□ 连接跟踪级别(取决于协议)
□ Netfilter内核参数配置
5.7.9 流量特性的注意事项
网络性能优化最重要的考虑因素之一是要尽可能准确地了解网络流量模式。性能变化取决于网络流量特性。
例如,图5-27和图5-28显示了使用netperf的吞吐量性能的结果,说明了不同的性能特性。唯一的不同是流量类型。图中显示了TCP_RR类型的流量和TCP_CRR类型的流量(参考3.4.5节的介绍)的结果。性能不同的主要原因是,TCP会话连接、关闭操作的开销,主要因素是Netfilter连接跟踪(参考5.7.8节的介绍)。
图5-27 netperf TCP_RR benchmark示例结果
图5-28 netperf TCP_CRR benchmark示例结果
如图5-27所显示的,在配置完全相同的情况下,即使轻微的流量特性不同,性能也会有很大变化。应熟悉以下网络流量特性和要求:
□ 事务吞吐量的要求(峰值、平均值)
□ 数据传输吞吐量的要求(峰值、平均值)
□ 延迟的要求
□ 传输数据的大小
□ 发送和接收的比例
□ 连接建立和关闭的频率或并发连接的数量
□ 协议(TCP、UDP、应用程序协议(比如HTTP、SMTP、LDAP等))
Netstat、tcpdump和wireshark是很有用的工具,由它们可以得到更准确的特性(参考2.3.11和2.3.13节的介绍)。
5.7.10 额外的TCP/IP调整
还有很多其他配置选项可以提高或降低网络性能。下面描述的参数有助于防止网络性能下降。
1.调整IP和ICMP行为
使用sysctl命令调整IP和ICMP行为。
□ 禁用以下参数防止黑客针对服务器的IP地址进行欺骗攻击:
sysctl -w net.ipv4.conf.eth0.accept_source_route=0
sysctl -w net.ipv4.conf.lo.accept_source_route=0
sysctl -w net.ipv4.conf.default.accept_source_route=0
sysctl -w net.ipv4.conf.all.accept_source_route=0
□ 这些命令配置服务器忽略来自被列出为网关机器的重定向。重定向可以被用来进行攻击,所以我们只希望允许它们来自受信任的源:
sysctl -w net.ipv4.conf.eth0.secure_redirects=1
sysctl -w net.ipv4.conf.lo.secure_redirects=1
sysctl -w net.ipv4.conf.default.secure_redirects=1
sysctl -w net.ipv4.conf.all.secure_redirects=1
□ 可以允许接口接受或不接受任何ICMP重定向。ICMP重定向是路由器传达路由信息到主机的一种机制。例如,当网关接收到来自网络中与网关连接的主机发送的网络数据报的时候,网关可以发送重定向消息给主机。网关检查路由表得到下一个网关的地址,第二个网关路由网络数据报到目标网络。使用以下命令禁用这些重定向:
sysctl -w net.ipv4.conf.eth0.accept_redirects=0
sysctl -w net.ipv4.conf.lo.accept_redirects=0
sysctl -w net.ipv4.conf.default.accept_redirects=0
sysctl -w net.ipv4.conf.all.accept_redirects=0
□ 如果服务器不充当路由器,那它不必发送重定向,所以可以禁用它们:
sysctl -w net.ipv4.conf.eth0.send_redirects=0
sysctl -w net.ipv4.conf.lo.send_redirects=0
sysctl -w net.ipv4.conf.default.send_redirects=0
sysctl -w net.ipv4.conf.all.send_redirects=0
□ 配置服务器忽略广播ping和smurf攻击:
sysctl -w net.ipv4.icmp_echo_ignore_broadcasts=1
□ 忽略所有icmp类型的数据包或ping:
sysctl -w net.ipv4.icmp_echo_ignore_all=1
□ 有些路由器发送无效响应广播帧,每个都会引起内核记录一个警告。这些响应可以被忽略:
sysctl -w net.ipv4.icmp_ignore_bogus_error_responses=1
□ 我们可使用ipfrag参数,特别是在NFS和Samba服务器中。在这里,我们可以设置用于重新组合IP碎片的最大和最小内存。当为了此目的而分配内存ipfrag_high_thresh的值(byte)时,碎片处理器将丢弃数据包,直到达到ipfrag_low_thresh。
在TCP数据包传输过程中碎片发生错误的时候,有效的数据包被存储在内存中(如同这些参数定义的),损坏的数据包会被重传。
例如,设置可用内存的范围在256MB和384MB之间,使用:
sysctl -w net.ipv4.ipfrag_low_thresh=262144
sysctl -w net.ipv4.ipfrag_high_thresh=393216
2.调整TCP行为
在这里,我们描述可以更改TCP行为的调整参数。
下面的命令可以用于调整服务器支持大量的多个连接:
□ 对于同时接收许多连接的服务器,TIME-WAIT sockets可以被新连接重新使用。其在Web服务器中非常有用,例如:
sysctl -w net.ipv4.tcp_tw_reuse=1
如果启用此命令,也应该启用TIME-WAIT sockets状态的快速回收:
sysctl -w net.ipv4.tcp_tw_recycle=1
启用这些参数,连接数量明显减少。这可以提供良好的性能,因为每个TCP传输维护一个关于每个远程客户端的协议信息的cache。在cache中存储的信息包括往返时间、最大段大小、拥塞窗口等。更详细的查看RFC 1644说明。
□ 当服务器关闭socket的时候,tcp_fin_timeout参数在FIN-WAIT-2状态下保存socket的时间。
TCP连接开始用三段同步SYN序列,结束用三段FIN序列,两者都保存数据。当为新连接释放内存的时候减少FIN序列的时间,可提高性能。但是这个值应该只有经过仔细监控之后才可以调整,因为由于死亡socket的数量,有内存溢出的风险。
sysctl -w net.ipv4.tcp_fin_timeout=30
□ 在大量并发TCP连接的服务器中问题之一是大量打开但未使用的连接。TCP有keepalive功能可以探测这些连接,默认情况下,在7200秒(2小时)后丢弃它们。对于你的服务器这个时间长度可能过长,因而可能导致内存过量使用和服务器性能下降。例如,设置为1800秒(30分钟)可能更合适:
sysctl -w net.ipv4.tcp_keepalive_time=1800
□ 当服务器负载过重或具有很多高延迟不良连接的客户端的时候,它可以导致半连接的增加。对于Web服务器这是很常见的,尤其是当有很多拨号上网用户的时候。这些半连接被存储在积压连接队列中。此值应至少设置为4096(默认是1024)。
即使你的服务器没有接收到这种类型的连接,设置此值也是非常有用的,因为它仍然可以在DoS(syn-flood)攻击中得到保护。
sysctl -w net.ipv4.tcp_max_syn_backlog=4096
□ 拒绝服务(DoS)或分布式拒绝服务(DDoS)。在syn-flood攻击中,TCP SYN cookies有助于保护服务器,它们可能对性能产生不利影响。建议只有当明确需要它们的时候,才启用TCP SYN cookies。
sysctl -w net.ipv4.tcp_syncookies=1
注意: 只有内核使用CONFIG_SYNCOOKIES编译时此命令才有效。
3.调整TCP选项
以下TCP调整选项可用于进一步调整Linux TCP协议栈:
□ 优化大量TCP流量的一种方法是选择性确认。然而,在千兆网络中SACK和DSACK可以对性能产生不利的影响。而默认情况下是启用它们,tcp_sack和tcp_dsack抵制在高速网络中优化TCP/IP性能,应该禁用。
sysctl -w net.ipv4.tcp_sack=0
sysctl -w net.ipv4.tcp_dsack=0
□ 每当一个以太网帧被转发到Linux kernel的网络堆栈时,它接收一个时间戳。这种行为对于边缘服务器是有帮助的和必要的,比如防火墙和Web服务器,但是通过禁用TCP时间戳可减少一些开销,这对后台系统可能是有好处的。
sysctl -w net.ipv4.tcp_timestamps=0
□ 我们也了解到,窗口缩放可以是扩大传输窗口的一个选择。然而,benchmark显示,系统遇到非常高网络负载的时候窗口缩放是不适合的。此外,一些网络设备不遵循RFC原则,并可能导致窗口缩放故障,建议禁用窗口缩放和手动设置窗口大小。
sysctl -w net.ipv4.tcp_window_scaling=0
5.8 限制资源使用
系统性能一直是一个受关注的话题,如何通过最简单的设置来实现最有效的性能调优,如何在有限资源的条件下保证程序的运作,限制某些用户或进程访问资源,对性能优化来说就成为了很有用的策略。例如,在一个多用户的系统上不同用户可能会同时开启进程,实际上只能确认的是,没有单个用户可以独占所有的CPU或内存。
假设有这样一种情况,当一台Linux主机上同时登录了10个人,在系统资源无限制的情况下,这10个用户同时打开了500个文档,而假设每个文档的大小有10MB,这时系统的内存资源就会受到巨大的挑战。
而实际应用的环境要比这种假设复杂得多,例如在一个嵌入式开发环境中,各方面的资源都是非常紧缺的,对于开启文件描述符的数量、分配堆栈的大小、CPU时间、虚拟内存大小,等等,都有非常严格的要求。资源的合理限制和分配,不仅仅是保证系统可用性的必要条件,也与系统上软件运行的性能有着密不可分的联系。
1.ulimit
一种限制使用系统资源的方法是通过ulimit命令。这是shell的内建命令,可用于对一个特定的shell和shell开启的子进程进行资源限制。这种机制使用较少,因为它是依赖于特定的shell实例的。
ulimit用于限制shell启动进程所占用的资源,它支持以下各种类型的限制:所创建的内核文件的大小、进程数据块的大小、shell进程创建文件的大小、内存锁住的大小、常驻内存集的大小、打开文件描述符的数量、分配堆栈的最大大小、CPU时间、单个用户的最大线程数、shell进程所能使用的最大虚拟内存。同时,它支持硬资源和软资源的限制。
作为临时限制,ulimit可以作用于通过使用其命令登录的shell会话,在会话终止时便结束限制,这并不影响其他shell会话。而对于长期的固定限制,ulimit命令语句也可以被添加到由登录shell读取的文件中,作用于特定的shell用户。
使用ulimit–a命令可以看到能够限制的资源和资源当前的状态:
[root@zyg ~]# ulimit -a
core file size (blocks, -c) 0
data seg size (kbytes, -d) unlimited
scheduling priority (-e) 0
file size (blocks, -f) unlimited
pending signals (-i) 15827
max locked memory (kbytes, -l) 64
max memory size (kbytes, -m) unlimited
open files (-n) 1024
pipe size (512 bytes, -p) 8
POSIX message queues (bytes, -q) 819200
real-time priority (-r) 0
stack size (kbytes, -s) 10240
cpu time (seconds, -t) unlimited
max user processes (-u) 15827
virtual memory (kbytes, -v) unlimited
file locks (-x) unlimited
-a,显示当前所有的limit信息。
-H,设置硬资源限制,一旦设置不能增加。ulimit - Hs 64;限制硬资源,线程栈大小为64KB。
-S,设置软资源限制,设置后可以增加,但是不能超过硬资源设置。Ulimit - Sn 32;限制软资源,32个文件描述符。
使用-t选项限制CPU时间:
[root@zyg ~]# ulimit -t 10
[root@zyg ~]# ulimit -a | grep "cpu time"
cpu time (seconds, -t) 10
[root@zyg ~]# ./zyg.sh
Killed
使用-v选项限制用户使用的虚拟内存,shell builtin命令不会受到限制,对子shell生效。
[root@zyg ~]# ulimit -v 0
[root@zyg ~]# ./zyg.sh
Killed
[root@zyg ~]# ps
Killed
[root@zyg ~]# cd /etc/
[root@zyg etc]# pwd
/etc
[root@zyg etc]# echo 111
111
使用-f选项限制创建文件大小:
[root@zyg ~]# ulimit -f 100
[root@zyg ~]# dd if=/dev/zero of=file1 bs=1024 count=100
100+0 records in
100+0 records out
102400 bytes (102 kB) copied, 0.00111363 s, 92.0 MB/s
[root@zyg ~]# dd if=/dev/zero of=file1 bs=1024 count=101
File size limit exceeded (core dumped)
2.pam_limits
使用pam_limits.so资源限制模块(提供的管理组:session),系统管理员必须首先建立一个root只读的文件(默认是/etc/security/limits.conf)。这个文件描述了超级用户想要强制限制用户和用户组的资源。uid=0的账号不会受限制。
下面的参数可以用来改变此模块的行为:
* debug -往syslog(3)写入冗长的记录.
* conf=/path/to/file.conf -指定一个替换的limits设定档.
配置文件的每一行描述了一个用户的限制,使用下面的格式:
-
domain可以是下列值:
□ 一个用户名。
□ 一个组名,语法是@group。
□ 通配符*,定义默认条目。
□ type,包括2个值:
□ hard,实行硬资源限制。这些限制由超级用户设定,由Linux内核实行,用户不能提升他对资源的需求。
□ soft,实行软资源限制。用户的限制能在软硬限制之间上下浮动。这种限制在普通用法下可以看成是默认值。
item,可以是下面其中之一:
□ core,限制core文件的大小(KB)。
□ data,最大的资料大小(KB)。
□ fsize,最大的文件尺寸(KB)。
□ memlock,最大能锁定的内存空间(KB)。
□ nofile,最多能打开的文件。
□ rss,最大的驻留程序大小(KB)。
□ stack,最大的堆栈尺寸(KB)。
□ cpu,最大的CPU时间(分钟)。
□ nproc,最多的进程数。
□ as,地址空间的限制。
□ maxlogins,用户的最多登录数。
□ priority,用户进程执行时的优先级。
要完全不限制用户(或组),可以用一个(-)(例如,“bin–”、“@admin–”)。注意,个体的限制比组限制的优先级高,所以如果你设定admin组不受限制,但是组中的某个成员被设定限制,那么此用户就会依据设置被限制。还应该注意,所有的限制设定只是每个登录的设定,它们既不是全局的,也不是永久的,只存在于会话期间。
pam_limits模块会通过syslog(3)报告它从设定当中找到的问题。
下面是一个配置文件实例:
# EXAMPLE /etc/security/limits.conf file:
# =======================================
# -
* soft core 0
* hard rss 10000
@student hard nproc 20
@faculty soft nproc 20
@faculty hard nproc 50
ftp hard nproc 0
注意: 对同一个资源的软限制和硬限制建立了用户可以从指定服务会话中得到的默认和最大允许的资源数。
使用maxlogins限制用户登录次数:
[root@zyg ~]# vim /etc/security/limits.conf
zyg hard maxlogins 2
使用nproc限制用户打开进程数:
[root@zyg ~]# vim /etc/security/limits.conf
zyg hard nproc 3
[root@zyg ~]# su - zyg
[zyg@zyg ~]$ sleep 3000 &
[1] 2306
[zyg@zyg ~]$ sleep 3000 &
[2] 2307
[zyg@zyg ~]$ sleep 3000 &
-bash: fork: retry: Resource temporarily unavailable
-bash: fork: retry: Resource temporarily unavailable
使用cpu限制用户使用CPU的时间,程序运行超过限制时间会被杀死。
[root@zyg ~]# vim /etc/security/limits.conf
zyg hard cpu 1
[zyg@zyg ~]$ ./zyg.sh
Killed
使用fsize限制用户创建文件大小。
[root@zyg ~]# vim /etc/security/limits.conf
zyg hard fsize 500
[zyg@zyg ~]$ dd if=/dev/zero of=file1 bs=1024 count=500
500+0 records in
500+0 records out
512000 bytes (512 kB) copied, 0.00246573 s, 208 MB/s
[zyg@zyg ~]$ dd if=/dev/zero of=file1 bs=1024 count=501
File size limit exceeded (core dumped)
3.cgroup
从RHEL6开始引入了一个新的更为灵活的限制系统资源访问的方法,即Control group(或简称cgroup)。Control group提供一种机制将任务(进程)和其子任务(子进程)聚合/划分到有特定行为的层次组中,在控制器中细分资源(如CPU时间、内存、磁盘I/O等),再层次化地分开。cgroup也是LXC为实现虚拟化所使用的资源管理手段,可以说没有cgroup就没有LXC。
cgroup针对一个或多个子系统将一组任务与一组参数关联在一起。
子系统是一个模块,利用cgroup提供的任务分组功能以特定的方式视其为任务组。子系统通常是一个资源控制器,调度一个资源或按cgroup应用限制,它可能是想要作用于进程组上的任何事,例如一个虚拟化子系统。
所谓的层次结构就是以树形结构对一组cgroup进行分类,这样系统中的每个任务将正确地位于层次结构中的其中一个cgroup和一组子系统中,在层次结构中每个子系统将特定的系统状态附加到每个cgroup中。每个层次结构都有一个cgroup虚拟文件系统的实例与其相结合。
在任何一个时刻都可能有多个任务cgroup的活跃层级结构。在系统中每个层次结构是所有任务的一部分。
在cgroup虚拟文件系统的一个实例中,用户级代码可以通过名称来创建和销毁cgroup,指定和查询被分配了一个任务的cgroup,列出分配给cgroup的任务的pid。这些创建和分配仅影响与cgroup文件系统实例相关的层次结构。
凭借自身,仅使用cgroup进行简单的作业跟踪。目的是将其他子系统加入到通用cgroup支持,来为cgroup提供新的属性,比如统计/限制cgroup中的进程可以访问的资源。例如,cpuset(参见Documentation/cgroups/cpusets.txt)允许你将一组CPU和一组内存节点与每个cgroup中的任务关联在一起。
如表5-7所示可以限制一些不同的子系统。
表5-7 cgroup子系统
Blkio 对块设备的I/O进行控制
Cpu 用来控制进程调度,设置进程占用CPU资源(时间片)的比重
cpuacct 使用cgroups分组任务,并统计这些任务组的CPU使用
Cpuset 提供了为一组任务分配一组CPU和内存节点的机制
devices 实现了跟踪和执行open和mknod设备文件的限制
freezer 对于批处理作业管理是很有用的,可以根据管理员的需求启动和停止任务,从而调度机器的资源
Memory 隔离并限制进程组对内存资源的使用
net_cls 使用类等级识别符(classid)标记网络数据包,可使用流量控制器(TC)为来自不同cgroups的数据包分配不同的优先级
这些子系统也被称为资源控制器或控制器。
安装kernel-doc,在Documentation/cgroups/下查看帮助。
Control group被组织成层次结构,任何单一的控制器只能是一个层次结构的一部分。在默认的RHEL配置中,每个控制器放在自己的层次结构中。
4.相互关系
□ 每次在系统中创建新层次结构时,该系统中的所有任务都是该层次结构的默认cgroup(我们称之为root cgroup,此cgroup在创建层次结构时自动创建,后面在该层次结构中创建的cgroup都是此cgroup的后代)的初始成员。
□ 一个子系统最多只能附加到一个层次结构。
□ 一个层次结构可以附加多个子系统。
□ 一个任务可以是多个cgroup的成员,但是这些cgroup必须在不同的层次结构。
□ 当系统中的进程(任务)创建子进程(任务)时,该子任务自动成为其父进程所在cgroup的成员。然后可根据需要将该子任务移动到不同的cgroup中,但开始时它总是继承其父任务的cgroup。
5.创建Control group和Control group的层次结构
方法一:使用cgcreate命令,在一个层次结构里面创建一个cgroups,可以随意地指定哪些用户能在这个cgroup中添加任务,哪些用户可以修改这个cgroup中的设置。
基本语法是:
cgreate [-t :] [-a :] -g :
例如,在cpuset层次结构中创建一个名称为zyg的cgroup,所有的管理保留给root:
[root@zyg ~]# cgcreate -g cpuset:/zyg
[root@zyg ~]# ls /cgroup/cpuset/zyg
cgroup.event_control cpuset.mem_hardwall cpuset.mems
cgroup.procs cpuset.memory_migrate cpuset.sched_load_balance
cpuset.cpu_exclusive cpuset.memory_pressure cpuset.sched_relax_domain_level
cpuset.cpus cpuset.memory_spread_page notify_on_release
cpuset.mem_exclusive cpuset.memory_spread_slab tasks
方法二:使用mkdir命令创建cgroup,移除一个cgroup可以使用rmdir或cgdelete:
[root@zyg ~]# mkdir /cgroup/memory/zyg
[root@zyg ~]# ls /cgroup/memory/zyg
cgroup.event_control memory.memsw.limit_in_bytes memory.swappiness
cgroup.procs memory.memsw.max_usage_in_bytes memory.usage_in_bytes
memory.failcnt memory.memsw.usage_in_bytes memory.use_hierarchy
memory.force_empty memory.move_charge_at_immigrate notify_on_release
memory.limit_in_bytes memory.oom_control tasks
memory.max_usage_in_bytes memory.soft_limit_in_bytes
memory.memsw.failcnt memory.stat
方法三:通过挂载一个虚拟cgroups文件系统,并指定使用的挂载控制器作为挂载选项,可以手工创建一个cgroup的层次结构:
[root@zyg ~]# mkdir /cgroup/zyg
[root@zyg ~]# mount -t cgroup -o cpuset none /cgroup/zyg
[root@zyg ~]# ls /cgroup/zyg
cgroup.event_control cpuset.memory_migrate cpuset.sched_load_balance
cgroup.procs cpuset.memory_pressure
cpuset.sched_relax_domain_level
cpuset.cpu_exclusive cpuset.memory_pressure_enabled notify_on_release
cpuset.cpus cpuset.memory_spread_page release_agent
cpuset.mem_exclusive cpuset.memory_spread_slab tasks
cpuset.mem_hardwall cpuset.mems
[root@zyg ~]# umount /cgroup/zyg
[root@zyg ~]# rmdir /cgroup/zyg
方法四:可以通过cgconfig服务持久设置层次结构和cgroup,这样在重启之后它们也是可用的。在配置文件/etc/cgconfig.conf中配置cgconfig建立cgroup层次结构:
[root@zyg ~]# vim /etc/cgconfig.conf
...
group zyg {
cpuset {
}
}
[root@zyg ~]# service cgconfig restart
Stopping cgconfig service: [ OK ]
Starting cgconfig service: [ OK ]
[root@zyg ~]# ls /cgroup/cpuset/zyg
cgroup.event_control cpuset.mem_hardwall cpuset.mems
cgroup.procs cpuset.memory_migrate cpuset.sched_load_balance
cpuset.cpu_exclusive cpuset.memory_pressure cpuset.sched_relax_domain_level
cpuset.cpus cpuset.memory_spread_page notify_on_release
cpuset.mem_exclusive cpuset.memory_spread_slab tasks
重点: 不要忘记使用chkconfig和service命令启用和启动cgconfig服务,否则这些设置将不会起作用。
6.为Control group设置限制
方法一:使用echo命令重定向一个值到相应层次结构目录中的适当的文件:
[root@zyg ~]# echo 3 > /cgroup/cpuset/zyg/cpuset.cpus
[root@zyg ~]# cat /cgroup/cpuset/zyg/cpuset.cpus
3
[root@zyg ~]# echo 0 > /cgroup/cpuset/zyg/cpuset.mems
[root@zyg ~]# cat /cgroup/cpuset/zyg/cpuset.mems
0
方法二:使用cgset命令:
[root@zyg ~]# cgset -r cpuset.cpus=2 zyg
[root@zyg ~]# cat /cgroup/cpuset/zyg/cpuset.cpus
2
方法三:在配置文件/etc/cgconfig.conf中对应的cgroup中设置,这样在重启之后它们也是可用的:
[root@zyg ~]# vim /etc/cgconfig.conf
...
group zyg {
cpuset {
cpuset.cpus=3 ;
cpuset.mems=0 ;
}
}
[root@zyg ~]# service cgconfig restart
Stopping cgconfig service: [ OK ]
Starting cgconfig service: [ OK ]
[root@zyg ~]# cat /cgroup/cpuset/zyg/cpuset.cpus
3
7.给Control Group分配进程
方法一:为一个正在运行的进程分配cgroup,可以使用几种方法。
手工echo进程的PID到相应cgroups的tasks中:
[root@zyg ~]# echo 2517 > /cgroup/cpuset/zyg/tasks
[root@zyg ~]# cat /cgroup/cpuset/zyg/tasks
2517
使用cgclassify命令:
[root@zyg ~]# cgclassify -g cpuset:/zyg 2517
[root@zyg ~]# cat /cgroup/cpuset/zyg/tasks
2517
方法二:使用cgexec命令可以为一个新的进程直接指定cgroup:
[root@zyg ~]# cgexec -g cpuset:/zyg ./zyg.sh
方法三:可以通过cgred服务,当启动程序时自动将其放置在相应的cgroup中。这需要对/etc/cgruls.conf进行配置。
/etc/cgrules.conf文件由3部分组成:
user | @group | user[:program], controllers, cgroup.
在第一部分中使用一个百分号(%)表示应用与之前一行相同的user/group/program。“*”通配符允许在第一二列使用。
可以看下面的例子,当运行zyg.sh时,将其自动放置在zyg cgroups中,使用cpuset控制器。在/etc/cgrules.conf中添加下面行:
[root@zyg ~]# vim /etc/cgrules.conf
……
*:zyg.sh cpuset zyg/
[root@zyg ~]# service cgred restart
Stopping CGroup Rules Engine Daemon... [ OK ]
Starting CGroup Rules Engine Daemon: [ OK ]
重点: 不要忘记启用和开启cgred服务使用chkconfig和service命令,编辑/etc/cgrules.conf需要运行service cgred reload。