构建高可用Linux服务器(第4版)
上QQ阅读APP看书,第一时间看更新

1.1 网站架构设计相关

在学习系统优化之前,我们应该了解一下网站架构设计的相关专业知识,这样才能更好地优化系统性能,提升网站的架构设计能力。

1.1.1 评估网站性能涉及的专业名词术语

在开始其他内容之前,我们先学习几个相关的专业名词术语,这样便于后面内容的展开,也便于大家在工作中与其他同事交流。

1. PV(Page View)

PV即访问量,中文翻译为页面浏览,代表页面浏览量或点击量,用户每刷新一次就会计算一次。PV的具体度量方法就是从浏览器发出一个对网络服务器的请求(Request),网络服务器接到这个请求后,会将该请求对应的一个网页(Page)发送给浏览器,从而产生一个PV。只要将请求发送给了浏览器,无论这个页面是否完全打开,下载是否完成,都会被计为1个PV。PV反映的是某网站页面的浏览数,所以每刷新一次也算一个PV,就是说PV与UV(独立访客)的数量成正比,但PV并不是页面的来访者数量,而是网站被访问的页面数量。

2. UV(Unique Vistor)

UV即独立访问,访问网站的一台电脑客户端为一个访客,如果以天为计量单位,程序会统计00:00至24:00这段时间内的电脑客户端,且相同的客户端只被计算一次。独立自然人访问,一个人访问记为一个UV,通过不同技术方法来记录,实际会有误差。如果企业内部通过NAT技术共享上网,那么出去的公网IP有且只有一个,这个时候在程序里面进行统计,也只能算是一个UV。

3. 并发连接数(Concurrent TCP Connections)

当一个网页被浏览,服务器就会和浏览器建立连接,每个连接表示一个并发。如果当前网站页面包含很多图片,图片并不是一个一个显示的,服务器会产生多个连接同时发送文字和图片以提高浏览速度。也就是说,网页中的图片越多,服务器的并发连接数越多,我们一般以此作为衡量单台Web机器的性能参数。现在Nginx在网站中的应用比例非常大,可以参考Nginx的活动并发连接数。

4. QPS(Query Per Second)

QPS即每秒查询率,是衡量一个特定查询服务器在规定时间内所处理流量多少的标准,在因特网上,作为域名系统服务器的机器性能通常用每秒查询率来衡量。对应Fetches/Sec,即每秒的响应请求数,也是最大吞吐能力。对于系统而言,QPS数值是一个非常重要的参数,它是综合反映系统最大吞吐能力的衡量标准。它反映的不仅是Web层面的性能,还有缓存、数据库等方面的系统综合处理能力。

5. 机房的网络质量评估

机房的网络质量可以参考下面3个标准:

1)稳定性。响应延迟,丢包率。测试方法:长时间的ping测试。测试工具有smoke-ping、mtr、ping2。

2)带宽质量。测试TCP的下载速度以及最大TCP的下载速率。测试方法:get/其他下载测试。测试工具有webbench / iperf,也可使用云测试平台。

3)接入位置。接入路由设备离骨干网的位置,接入条数越少越好。测试方法:路由跟踪。测试工具有mtr/tracert等。

参考文档:https://www.zhihu.com/question/23516866

1.1.2 CDN业务的选项

如果自己的业务网站中含有大量的图片和视频类文件,为了加快客户端的访问速度,同时减缓核心机房的服务压力并提升用户体验,建议大家在网站或系统的前端采用CDN缓存加速方案。

CDN的全称是Content Delivery Network,即内容分发网络。其目的是通过在现有的Internet中增加一层新的网络架构,将网站的内容发布到最接近用户的网络“边缘”,使用户可就近取得需要的内容,提高用户访问网站的响应速度,从而提升用户体验。CDN缓存加速方案一般有几种方式:

租赁CDN:中小型网站直接买服务即可,现在CDN已经进入按需付费的云计算模式,可以准确计算性价比。

自建CDN:这种方案的成本较高,为了保证好的缓存效果,必须在全国机房布点,并且需要自建智能Bind系统。搭建大型网站时推荐采用此方案,一般专业的视频网站或图片网站会考虑采用此方案。

1.1.3 IDC机房的选择

IDC机房的选择一般也有几种类型:

❑ 单电信IDC机房:这种业务模式比较固定,访问量也不是很大,适合新闻类网站或政务类网站。如果网站的PV流量持续增加,建议后期采用租赁CDN的方式解决非电信用户访问网站速度过慢的问题。

❑ 双线IDC机房:因为国内两大网络(电信和网通)之间存在互联互通的问题,所以电信用户访问网通网站或网通用户访问电信网站很慢,也因此产生了双线机房、双线服务器、双线服务器托管和双线服务器租用服务。双线机房实际是一个有电信、网通、联通等任意两条线路接入的机房。通过双线机房内部路由器的设置以及BGP自动路由的分析,实现电信用户访问电信线路,网通用户访问网通线路,即实现了电信网通的快速访问。

❑ BGP机房:BGP(边界网关协议)是用来连接Internet的独立系统的路由选择协议。它是Internet工程任务组制定的一个加强、完善、可伸缩的协议。BGP4支持CIDR寻址方案,该方案增加了Internet上可用IP地址的数量。BGP是为取代最初的外部网关协议EGP设计的,它也被认为是一个路径矢量协议。采用BGP方案实现双线路互联或多线路互联的机房称为BGP机房。对于用户来说,选择BGP机房可以实现网站在各运营商线路之间互联互通,使得所有互联运营商的用户访问网站都很快,也更加稳定,不用担心全国各地因线路带来访问速度快慢不一的问题,这也是传统双IP双线机房无法相比的优势。在条件允许的情况下,选择服务器租用和服务器托管时尽量选择BGP机房,可以带给用户最优的访问体验。

现在云计算服务也非常流行,目前首推的就是亚马逊云(AWS)和阿里云这两种云计算平台。

经过对业务需求的深入了解,我们在亚马逊云和阿里云之间选择了亚马逊云。

云计算服务提供的产品能让我们的研发团队专注于产品开发本身,而不是购买硬件、配置和维护硬件等繁杂的工作,还可以减少初始资金投入。我们主要使用亚马逊云的EC2/EBS/S3/Redshift服务产品,其次,Amazon EC2主机提供了多种适用于不同案例的实例类型以供选择。实例类型由CPU、内存、存储和网络容量形成不同的组合,可让我们灵活地为其选择合适的资源组合。

云计算特别适合在某些日期或某些时段流量会激增的网站,如我们从事的DSP业务的bidder集群机器,用户会集中在某时段进行竞价,因此在这段时间内使用的instance数量可能是白天的几倍甚至几十倍。也就是说,这个瞬间可能要开启很多实例处理,且处理完毕后立刻终止(EC2 Instance可以按照运行小时数进行收费)。

像笔者公司的线上系统,经常跑着很多特殊业务的Spot Instance(例如我们自行开发的爬虫系统),以小时计费,完成任务后立即终止Spot Instance,以此达到节约费用的目的。

注意

使用竞标方式获取便宜的Instance,一般在有大量、便宜、短时间使用的需求时使用。

1.2 如何根据服务器应用来选购服务器

无论物理服务器是选用IDC托管还是AWS EC2云主机(以下为了说明简单,统称为服务器),我们都要面临一个问题,那就是如何选择服务器的硬件配置。选购硬件配置时要根据我们的服务器应用需求而定,因为我们无法通过一台服务器来满足所有的需求,并解决所有的问题。在设计网站的系统架构之前,我们应该从以下方面考虑如何选购服务器:

❑ 服务器运行什么应用。

❑ 需要支持多少用户访问。

❑ 需要多大空间来存储数据。

❑ 业务的重要性。

❑ 服务器网卡。

❑ 安全。

❑ 是否安排机架合理化。

❑ 服务器的价格是否超出预算。

1. 服务器运行什么应用

这是首先需要考虑的问题,通常根据服务器的应用类型(也就是用途)决定服务器的性能、容量和可靠性需求。下面将按照负载均衡、缓存服务器、前端服务器、应用程序服务器、数据服务器和Hadoop分布式计算的常见基础架构进行讨论。

负载均衡端:除了网卡性能以外,它在其他方面对服务器的要求都比较低。如果选用LVS负载均衡方案,它会直接将所有的连接要求转给后端的Web应用服务器,建议选用万兆网卡;如果选用HAproxy负载均衡器,由于它的运行机制跟LVS不一样,流量必须双向经过HAproxy机器本身,因此会对CPU的运行能力有所要求,建议选用万兆网卡;如果选用AWS EC2机器,推荐使用m3.xlarge实例类型(m3类型提供计算、内存和网络资源的平衡,它是很多应用程序的良好选择)。另外,AWS官方也推出了负载均衡服务产品,即Elastic Load Balancing,它具有DNS故障转移和Auto Scalling的功能。

缓存服务器:主要是Varnish和redis,对CPU及其他方面的性能要求一般,但在内存方面的要求较多。笔者曾为了保证预算,在双核(r3.large)机器上运行了4个redis实例,AWS官方也建议将此内存优化型实例用于高性能数据库、分布式内存缓存、内存中分析、基因组装配和分析,以及SAP、Microsoft SharePoint和其他企业应用程序的较大部署。

应用服务器:因为它承担了计算和功能实现的重任,所以需要为基于Web架构的应用程序服务器(Application Server)选择足够快的服务器,另外,应用程序服务器可能需要用到大量的内存,尤其是基于Windows基础架构的Ruby、Python、Java服务器,这一类服务器至少需要使用单路至强的配置,我们线上的核心业务机器选用的是AWS c3.xlarge类型。至于可靠性问题,如果你的架构中只有一台应用服务器,那肯定需要这台服务器足够可靠,此时RAID是绝对不能忽视的选项。但如果有多台应用服务器并设计了负载均衡机制,那么便拥有了冗余功能,那就不必过于担心上述问题了。

注意

c3.xlagre EC2主机属于Compute optimized计算优化型,也就是CPU加强型。这种类型的CPU/内存比例较大,适合计算密集型业务。它包含c1和c3系列,除了较旧的两个c1系列(c1.medium和c1.xlarge)采用普通磁盘做实例存储以外,其他的(也就是c3系列)都以SSD做实例存储,其中最高档次的c3.8xlarge(32核心108个计算单元)的网络性能明确标注为10Gbps。c3系列被认为是最具性价比的类型。

特殊应用:除了用于Web架构中的应用程序以外,如果你的服务器还要处理流媒体视频编码、服务器虚拟化、媒体服务器,或者作为游戏服务器(逻辑、地图、聊天等)运行,那同样会对CPU和内存有一定的要求,至少要考虑四核以上的服务器。

公共服务:这里指的是邮件服务器、文件服务器、DNS服务器、域控服务器等。通常我们会部署两台DNS服务器互相备份,域控主服务器也会拥有一台备份服务器(专用的或非专用的),所以无须对于可靠性过于苛刻。而邮件服务器至少需要具备足够的硬件可靠性和容量大小,这主要是对邮件数据负责,因为很多用户没有保存和归档邮件数据的习惯,待其重装系统后,就会习惯性地到服务器上重新下载相应的数据。至于性能问题,应该评估用户数量后再决定。另外,考虑到它的重要性,建议尽量选择稳定的服务器系统,比如Linux或BSD系列。

数据库服务器:数据库对服务器的要求是最高的,也最重要的。一般情况下,无论你使用的是MySQL、SQLServer还是Oralce,它都需要有足够快的CPU、足够大的内存、足够稳定可靠的硬件。因此,可直接采用Dell PowerEdge R710或HP 580G5, CPU和内存方面也要尽可能最大化,如果预算充分,建议采用固态硬盘做RAID 10,因为数据库服务器对硬盘的I/O要求是最高的。

Hadoop和Spark分布式计算:这里建议选用密集存储实例—D2实例,它拥有高频率Intel Xeon E5-2676v3(Haswell)处理器、高达48TB的HDD本地存储、高磁盘吞吐量,并支持Amazon EC2增强型联网。它适合大规模并行处理数据仓库、MapReduce和Hadoop分布式计算、分布式文件系统、网络文件系统、日志或数据处理等应用。

RabbitMQ集群:Rabbit消息中间件是基于Erlang语言开发的,对内存的要求很高。这里建议选用r3.xlarge,它适合运行高性能数据库、分布式内存缓存、内存中分析、基因组装配与分析、Microsoft SharePoint以及其他企业应用程序。

更多关于AWS EC2实例类型的资料请参考:https://aws.amazon.com/cn/ec2/instance-types/

2. 服务器需要支持多少用户访问

服务器就是用来给用户提供某种服务的,所以使用这些服务的用户同样是我们需要考虑的因素,可以从下面几个具体的问题进行评估:

❑ 有多少注册用户。

❑ 正常情况下有多少用户会同时在线访问。

❑ 每天同时在线访问的最高峰值大概是多少。

一般在项目实施之前,客户会针对这些问题给出一个大致的结果,但我们要尽量设计得充分具体,同时,还要对未来的用户增长做一个尽可能准确的预测和规划。因为服务器可能需要支持越来越多的用户,所以在设计网站或系统架构时要让机器能够灵活地进行扩展。

3. 需要多大空间来存储数据

这个问题需要从两个方面来考虑,一方面是有哪些类别的数据,包括操作系统本身占用的空间、安装应用程序所需要的空间以及应用程序产生的数据、数据库、日志文件、邮件数据等,如果网站是Web 2.0的,还需计算每个用户的存储空间;另一方面是从时间轴上来考虑,这些数据每天都在增长,至少要为未来两三年的数据增长做个准确的测算,这需要软件开发人员和业务人员一起来提供足够的信息。最后,我们将计算出来的结果乘以1.5左右的系数,方便维护的时候做各种数据的备份和文件转移操作。

4. 业务有多重要

这需要根据自身的业务领域来考虑,下面举几个简单的例子,帮助大家了解这些服务器对可靠性、数据完整性等方面的要求。

❑ 如果你的服务器是用来运行一个W6ordPress博客,那么,一台酷睿服务器,1GB的内存,外加一块160GB的硬盘就足够了(如果是AWS EC2主机,可以考虑t2.micro实例类型)。就算服务器出现了一点硬件故障,导致几个小时甚至一两天不能提供访问,生活会照常继续。

❑ 如果你的服务器是用于测试平台的,那么就不会像生产环境那样对可靠性有极高的要求,你所需要做的可能只是完成例行的数据备份,若服务器宕机,只要能在当天解决完问题就可以了。

❑ 如果是一个电子商务公司的服务器,运行着电子商务网站平台,当硬件发生故障而导致宕机时,你需要对以下“危言耸听”的后果做好心理准备:投诉电话被打爆、顾客大量流失、顾客要求退款、市场推广费用打水漂、员工无事可做、公司运营陷入瘫痪状态、数据丢失。事实上,电子商务网站一般是需要365×24小时不间断运行和监控的,且具有专人轮流值守,同时要有足够的备份设备以及每天的专人检查。

❑ 如果是大型广告类或门户类网站,那么建议选择CDN系统。因为它具有提高网站响应速度、负载均衡、有效抵御DDOS攻击等特点,相对而言,每节点都会有大量的冗余。

这里其实只是简单讨论了业务对服务器硬件可靠性的要求。要全面解决这个问题,不能只考虑单个服务器的硬件,还需要结合系统架构的规划设计。

在回答了以上问题后,接下来就可以决定下面这些具体的选项了。

(1)选择什么CPU

回忆一下上面关于“服务器运行什么应用”和“需要支持多少用户访问”两个方面的考虑,这将帮助我们选择合适的CPU。毫无疑问,CPU的主频越高,其性能也就更高,换而言之,两个CPU要比一个CPU性能更好,至强(Xeon)也肯定比酷睿(Core)性能更强。但究竟怎样的CPU才是合适的呢?下面将为你提供一些常见情况下的建议。

❑ 如果业务刚刚起步,预算不是很充足,建议选择一款经典的酷睿服务器,这可以帮你节约大量成本。而且,以后可以根据业务发展的情况,随时升级到更高配置的服务器。

❑ 如果需要在一台服务器上同时运行多种应用服务,例如基于LNMP架构的Web网站,那么一个单核至强(例如X3330)或新一代的酷睿I5(双核四线程)将是最佳的选择。虽然从技术的角度来说,这不是一个好主意,但至少能够帮你节约一大笔成本。

❑ 如果服务器要运行MySQL或Oracle数据库,且目前有几百个用户同时在线,未来还会不断增长,那么你至少应该选择安装一个双四核服务器。

❑ 如果需要的是Web应用服务器,双四核基本就可以满足我们的要求了。

(2)需要多大的内存

同样,“服务器运行什么应用”和“需要支持多少用户访问”两方面的考虑也将帮助我们选择合适的内存容量。与CPU相比,笔者认为内存(RAM)才是影响性能的最关键因素。因为在相当多正在运行的服务器中,CPU的利用率一般为10%~30%,甚至更低。但我们发现由于内存容量不够导致服务器运行缓慢的案例比比皆是,如果服务器不能分配足够的内存给应用程序,应用程序就需要通过硬盘接口交换读写数据了,这将导致网站慢得令人无法接受。内存的大小主要取决于服务器的用户数量,当然也和应用软件对内存的最低需求和内存管理机制有关,所以,最好由你的程序员或软件开发商给出最佳的内存配置建议。下面同样给出了一些常见应用环境下的内存配置建议:

❑ 无论是Apache或Nginx服务器,一般情况下Web前端服务器不需要配置特别高的内存,尤其是在集群架构中,4GB的内存就已经足够了。如果用户数量持续增加,我们才会考虑使用8GB或更高的内存。单Apache Web机器,在配置了16GB内存后,可以抗6000个并发链接数。

❑ 对于运行Tomcat、Resin、WebLogic的应用服务器,8GB内存应该是基准配置,更准确的数字需要根据用户数量和技术架构来确定。

❑ 数据库服务器的内存由数据库实例的数量、表大小、索引、用户数等决定,一般建议配置16GB以上的内存,笔者公司在许多项目方案中使用了24GB~48GB的内存。

❑ 诸如Postfix和Exchange这样的邮件服务器对内存的要求并不高,1GB~2GB就可以满足了。

❑ 还有一些特殊的服务器,需要为之配置尽可能高的内存容量,比如配置有Varnish和Memcached的缓存服务器等。

❑ 若是只有一台文件服务器,1GB的内存可能就足够了。

事实上,由于内存技术在不断提高,价格也在不断降低,因此才得以近乎奢侈地讨论4GB、8GB、16GB这些曾经不可想象的内存容量。然而,除了花钱购买内存来满足应用程序的“贪婪”之外,系统优化和数据库优化仍然是我们需要重视的问题。

(3)需要怎样的硬盘存储系统

硬盘存储系统的选择和配置是整个服务器系统里最复杂的一部分,需要考虑硬盘的数量、容量、接口类型、转速、缓存大小,以及是否需要RAID卡、RAID卡的型号和RAID级别等问题。甚至在一些高可靠性高性能的应用环境中,还需要考虑使用怎样的外部存储系统(SAN、NAS或DAS)。下面归纳一下服务器的硬盘Raid卡的特点:

❑ 如果是用做缓存服务器,比如Varnish或Redis,可以考虑用RAID 0;

❑ 如果是跑Nginx+FastCGI或Nginx等应用,可以考虑用RAID 1;

❑ 如果是内网开发服务器或存放重要代码的服务器,可以考虑用RAID 5;

❑ 如果是跑MySQL或Oracle等数据库应用,可以考虑用固态硬盘做RAID 5或RAID 10。

5. 网卡性能方面的考虑

如果你的基础架构是多服务器环境,而且服务器之间有大量的数据交换,那么建议你为每台服务器配置两个或更多的网卡,一个用于对外提供服务,另一个用于内部数据交换。因为现在项目外端都置于防火墙内,所以很多时候单网卡就足够了。而比如LVS+Keepalived这种只用公网地址的Linux集群架构,对网卡的速率要求很高,建议大家选用万兆网卡。

如果我们采用的是AWS EC2云主机环境,单纯以EC2作为LVS或HAproxy意义不大。如果大家经常使用AWS EC2机器,应该注意到AWS将机器的网卡性能分成三种级别,即Low、Moderate、 High,那么这三个级别是什么情况呢?虽然AWS没有带宽限制,但是由于多虚拟机共享HOST物理机的网络性能和I/O性能,单个虚拟机的网络性能不是特别好度量,不过大概是这样:Low级别的是20MBps, Moderate级别的是40MBps, High级别的能达到80MBps~100MBps。从上面分析的情况可以得知,单台AWS EC2主机作为网站的负载均衡入口,容易成为网站的瓶颈。这个时候可以考虑使用AWS提供Elastic Load Balancing的产品,它可以在云中的多个Amazon EC2实例间自动分配应用程序的访问流量,相当于将网站的流量分担到了多台机器上。它可以让我们实现更高水平的应用程序容错性能,从而无缝提供分配应用程序流量所需的负载均衡容量。

6. 服务器安全方面的考虑

由于目前国内的DDoS攻击是比较普遍,建议给每个项目方案和自己的电子商务网站配备硬件防火墙,比如Juniper、Cisco等。当然,这个问题也是网站后期运营维护需要考虑的,这里只是想让大家有个概念性的认识。此外,建议租赁CDN服务,这样万一不幸遭遇恶意的DDoS流量攻击,CDN能够帮助抵挡部分流量。

7. 根据机架数合理安排服务器的数量

这个问题应该在项目实施前就准备好,选择服务器时应该明确服务器规格,即到底是1U、2U、还是4U,到底有多少台服务器和交换机,应该如何安排,毕竟机柜只有42U的容量。在小项目中这个问题可能无关紧要,但在大型项目的实施过程中,这个问题就很突出了,我们应该根据现有或额定的机架数目确定到底应该选择多少台服务器和交换机。

8. 成本考虑:服务器的价格问题

无论是公司采购时,还是在项目实施过程中,这都是重要的问题。笔者的方案经常被退回,理由就是超出预算。尤其在一些小项目,预算更吃紧。之前笔者经常面对的客户需求是为证券类资讯网站设计方案,只要求网站在周一至周日的早上九点至下午三点期间不出问题即可,并不需要做复杂的负载均衡高可用。所以这时候笔者会做成单Nginx或Haproxy,后面接两台Web应用服务器。可如果是做中大型电子商务网站,在服务器成本上的控制就尤其重要了。事实上,我们经常出现的问题是,客户给出的成本预算有限,而我们的应用又需要比较多的服务器,这时候,我们不得不设计另外一套最小化成本预算方案来折中处理。

以上8个方面就是我们在采购服务器时需要注意的因素,在选择服务器的组件时要有所偏重,然后根据系统或网站架构来决定服务器的数量,尽量做到服务器资源利用的最大化。在控制方案成本的同时,要做到最优的性价比。

1.3 硬件对Linux性能的影响

毋庸置疑,服务器的硬件会对Linux性能产生关键性的影响,其中,如服务器的CPU、内存及硬盘都会影响单机的性能。

1. CPU

CPU是操作系统稳定运行的根本,CPU的速度与性能在很大程度上决定了系统整体的性能,因此,CPU数量越多、主频越高,服务器性能也就相对越好。就笔者目前跑的应用来看,确实有因为CPU性能达不到要求造成业务出现问题的情况。

2. 内存

内存的大小也是影响Linux性能的一个重要因素,内存太小,系统进程将被阻塞,应用也将变得缓慢,甚至失去响应;内存太大,导致资源浪费。Linux系统采用了物理内存和虚拟内存两种方式,虚拟内存虽然可以缓解物理内存的不足,但是占用过多的虚拟内存,应用程序的性能将明显下降,要保证应用程序的高性能运行,物理内存一定要足够大,但是过大的物理内存,会造成内存资源浪费,例如,在一个32位处理器的Linux操作系统上,超过8GB的物理内存都将被浪费。因此,要使用更大的内存,建议安装64位的操作系统,同时开启Linux的大内存内核支持。由于处理器寻址范围的限制,在32位Linux操作系统上,应用程序单个进程最大只能使用4GB的内存,这样一来,即使系统有更大的内存,应用程序也无法做到物尽其用,解决的办法就是使用64位处理器,安装64位操作系统。在64位操作系统下,可以满足所有应用程序对内存的使用需求,几乎没有限制。

3. 磁盘I/O性能

磁盘的I/O性能直接影响应用程序的性能,在一个有频繁读写的应用中,如果磁盘I/O性能得不到满足,就会导致应用停滞。好在现今的磁盘都采用了很多方法来提高I/O性能,比如常见的磁盘RAID技术。

RAID(磁盘阵形)通过将多块独立的磁盘(物理硬盘)按不同方式组合起来形成一个磁盘组(逻辑硬盘),从而提供比单个硬盘更高的I/O性能和数据冗余。通过RAID技术组成的磁盘组就相当于一个大硬盘,用户可以对它进行分区格式化、建立文件系统等操作,跟单个物理硬盘一模一样,唯一不同的是RAID磁盘组的I/O性能比单个硬盘要高很多,同时在数据的安全性方面也有很大提升。

根据磁盘组合方式的不同,RAID可以分为RAID 0、RAID 1、RAID 2、RAID 3、RAID 4、RAID 5、RAID 6、RAID 7、RAID 0+1、RAID 10等级别,常用的RAID级别有RAID 0、RAID 1、RAID 5、RAID 10,这里进行简单介绍。

❑ RAID 0:通过把多块硬盘粘合成一个容量更大的硬盘组,提高了磁盘的性能和吞吐量。这种方式成本低,要求至少两个磁盘,但是没有容错和数据修复功能,因而只能用在对数据安全性要求不高的环境中。

❑ RAID 1:也就是磁盘镜像,通过把一个磁盘的数据镜像到另一个磁盘上,最大限度地保证磁盘数据的可靠性和可修复性,具有很高的数据冗余能力,但磁盘利用率只有50%,因而成本最高,多用在保存重要数据的场合。

❑ RAID 5:采用了磁盘分段加奇偶校验技术,从而提高了系统可靠性,RAID5读出效率很高,写入效率一般,至少需要3块盘。允许一块磁盘故障,而不影响数据的可用性。

❑ RAID 10:把RAID 1和RAID 0技术结合起来就成了RAID 10,至少需要4个硬盘。此种方式的数据除分布在多个盘上外,每个盘都有其镜像盘,提供全冗余能力,同时允许一个磁盘故障,而不影响数据可用性,并具有快速读/写能力。

通过了解各个RAID级别的性能,可以根据应用的不同特性,选择适合自身的RAID级别,从而保证应用程序在磁盘方面达到最优性能。另外,固态硬盘(SSD)的磁盘IO性能比SAS磁盘优异很多,可以考虑用SSD磁盘要代替普通的SAS磁盘。

4. 网络宽带

Linux系统下的各种应用一般都是基于网络的,因此网络带宽也是影响性能的一个重要因素,低速、不稳定的网络将导致网络应用程序的访问阻塞,而稳定、高速的网络带宽可以保证应用程序在网络上畅通无阻地运行。幸运的是,现在的网络一般都是千兆带宽或光纤网络,带宽问题对应用程序性能造成的影响也在逐步降低。

1.4 CentOS 6.8 x86_64最小化安装后的优化

购买服务器以后要做的第一件事就是安装操作系统,这里推荐CentOS 6.8 x86_64,安装系统时要选择最小化安装(不需要图形),大家在用服务器时记得一个原则,系统安装的应用程序包越少,服务器越稳定。至于服务器单机性能调优,应本着稳定安全的原则,尽量不要改动系统原有的配置(CentOS系统自身的文件和内存机制就很优秀),以下配置优化部分也适合Amazon Linux系统,大家可以对比参考。

1.4.1 系统的基础优化

建议对CentOS 6.8系统做如下的基础优化,比如更新yum源提升速度,关闭不必要开启的服务等。

1. 更新yum官方源

CentOS 6.8系统自带的更新源速度较慢,想必各位都有所感受。为了让CentOS 6.8系统使用速度更快的yum更新源,运维人员都会选择更换源,笔者一般会选择网易的更新源,详细步骤如下所示。

1)下载repo文件,命令如下所示:

        wget http://mirrors.163.com/.help/CentOS6-Base-163.repo

2)备份并替换系统的repo文件,命令如下所示:

        cd /etc/yum.repos.d/
        mv CentOS-Base.repo CentOS-Base.repo.bak
        mv CentOS6-Base-163.repo CentOS-Base.repo

3)执行yum源更新,如下。

        yum clean all #清除yum缓存
        yum makecache #重建缓存
        yum update    #升级Linux系统

增加epel源,详细步骤如下。

1)下载rpm文件并进行安装,命令如下:

        wget http://dl.fedoraproject.org/pub/epel/6/x86_64/epel-release-6-8.noarch.rpm
        rpm -ivh epel-release-6-8.noarch.rpm

2)安装yum-priorities源优先级工具,命令如下:

        yum install yum-priorities

yum-priorities源优先级工具是yum-plugin-priroites插件,用来给yum源分优先级。比如说系统存在官方源、epel、puppetlabs三个yum源,三个yum源中可能含有相同的软件,yum管理器为了分辨更新系统或者安装软件的时候用哪个yum源的软件,则会用上该工具。

如果说,设置官方的yum源优先级最高,epelyum源第二,puppetlabs第三(用1到99来表示,1最高),那在安装程序的时候,就会先寻找官方的yum源,如果源里面有需要的程序,那就停止寻找,直接安装找到的,如果没有找到,则依次寻找epel和rpmfusion的源。如果说三个yum源都含有同一个软件,那就安装优先级最高的yum源中的程序。添加优先级的过程比较简单,只需要编辑对应的repo文件,在文件最末添加如下内容即可:

        priority=对应优先级数字

注意,要想开启yum源优先级功能,确保priorities.conf文件里面有如下内容,需要先打开此文件,打开的命令如下:

        vim /etc/yum/pluginconf.d/priorities.conf

确保文件里面包含如下内容:

        [main]
        enabled=1

2. 关闭不需要的服务

众所周知,服务越少,系统占用的资源就会越少,所以建议大家把不需要的服务关闭掉,这样做的好处是减少内存和CPU资源占用。首先可以看下系统中存在着哪些已经启动的服务,查看命令如下:

        ntsysv

下面列出需要启动的服务,未列出的服务根据实际情况关闭:

❑ crond:自动计划任务。

❑ network:Linux系统的网络服务,这个非常重要,不开启此服务的话,服务器是不能联网的。

❑ sshd:OpenSSH服务器守护进程。

❑ rsyslog:Linux的日志系统服务,必须要启动。

3. 关闭不需要的TTY

可用vim编辑器打开vim /etc/init/start-ttys.conf文件,文件内容如下所示:

        start on stopped rc RUNLEVEL=[2345]
        env ACTIVE_CONSOLES=/dev/tty[1-6]
        env X_TTY=/dev/tty1
        task
        script
            . /etc/sysconfig/init
            for tty in $(echo $ACTIVE_CONSOLES) ; do
                [ "$RUNLEVEL" = "5" -a "$tty" = "$X_TTY" ] && continue
                initctl start tty TTY=$tty
            done
        end script

这段代码会使init打开6个控制台,可分别用ALT+F1到ALT+F6进行访问。此6个控制台默认都驻留在内存中,用ps aux命令就可以看到,如下:

        ps aux | grep tty | grpe -v grep

命令显示结果如下所示:

        root   1118 0.0 0.1  4064  596 tty1   Ss+ 13:14  0:00
        /sbin/mingetty /dev/tty1
        root   1120 0.0 0.1  4064  596 tty2   Ss+ 13:14  0:00
        /sbin/mingetty /dev/tty2
        root   1122 0.0 0.1  4064  596 tty3   Ss+ 13:14  0:00
        /sbin/mingetty /dev/tty3
        root   1124 0.0 0.1  4064  596 tty4   Ss+ 13:14  0:00
        /sbin/mingetty /dev/tty4
        root   1126 0.0 0.1  4064  600 tty5   Ss+ 13:14  0:00
        /sbin/mingetty /dev/tty5
        root   1128 0.0 0.1  4064  600 tty6   Ss+ 13:14  0:00
        /sbin/mingetty /dev/tty6

事实上没有必要使用这么多TTY,那如何关闭不需要的进程呢?

通常保留两个控制台就可以了,打开/etc/init/start-ttys.conf文件,注意以下代码内容:

        env ACTIVE_CONSOLES=/dev/tty[1-6]

将[1-6]修改为[1-2],然后打开/etc/sysconfig/init文件,注意以下代码内容:

        ACTIVE_CONSOLES=/dev/tty[1-6]

将[1-6]修改为[1-2],并重启机器即可,我们依旧使用ps aux命令查看tty个数,如下所示:

        root   1105 0.0 0.1  4064  600 tty1   Ss+ 13:48  0:00
        /sbin/mingetty /dev/tty1
        root   1107 0.0 0.1  4064  600 tty2   Ss+ 13:48  0:00
        /sbin/mingetty /dev/tty2

4. 对TCP/IP网络参数进行调整

调整TCP/IP网络参数可以加强抗SYN Flood的能力,命令如下所示:

        echo 'net.ipv4.tcp_syncookies = 1' >> /etc/sysctl.conf
        sysctl -p

5. 修改SHELL命令的history记录个数

用vim编辑器打开/etc/profile文件,关注HISTSIZE =1000:

        vi /etc/profile

找到HISTSIZE=1000后,将其改为HISTSIZE=100(这条可根据实际工作环境而定)。

不需要重启系统就可让其生效,如下所示:

        source /etc/profile

6. 定时校正服务器的时间

我们可以定时校正服务器的时间,命令如下所示:

        yum install ntp
        crontab -e

加入一行:

        */5 * * * * /usr/sbin/ntpdate ntp.api.bz>>/dev/null 2>&1

调试crontab时间可以参考工具https://crontab.guru

ntp.api.bz是一组NTP服务器集群,之前是6台服务器,位于上海电信;现在是3台服务器,分散到上海和浙江电信,可用dig命令查看:

        dig ntp.api.bz

命令显示结果如下所示:

        ; <<>> DiG 9.8.2rc1-RedHat-9.8.2-0.62.rc1.el6_9.1 <<>> ntp.api.bz
        ;; global options: +cmd
        ;; Got answer:
        ;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 61931
        ;; flags: qr rd ra; QUERY: 1, ANSWER: 5, AUTHORITY: 2, ADDITIONAL: 2
        ;; QUESTION SECTION:
        ;ntp.api.bz.                      IN      A
        ;; ANSWER SECTION:
        ntp.api.bz.                600     IN      CNAME   time.asia.apple.com.
        time.asia.apple.com.      3172    IN      CNAME   time-ios.g.aaplimg.com.
        time-ios.g.aaplimg.com.   600     IN      A       17.253.84.125
        time-ios.g.aaplimg.com.   600     IN      A       17.253.84.253
        time-ios.g.aaplimg.com.   600     IN      A       17.253.72.243
        ;; AUTHORITY SECTION:
        g.aaplimg.com.            31      IN      NS      a.gslb.aaplimg.com.
        g.aaplimg.com.            31      IN      NS      b.gslb.aaplimg.com.
        ;; ADDITIONAL SECTION:
        a.gslb.aaplimg.com.       28200   IN      A       17.253.201.8
        b.gslb.aaplimg.com.       60802   IN      A       17.253.206.8
        ;; Query time: 30 msec
        ;; SERVER: 192.168.1.1#53(192.168.1.1)
        ;; WHEN: Sun Apr 23 09:43:192017
        ;; MSG SIZE  rcvd: 211

7. 停止IPv6网络服务

在CentOS 6.8默认的状态下,IPv6是被启用的,可用如下命令查看:

        lsmod | grep ipv6

命令显示结果如下:

        nf_conntrack_ipv6       8748   2
        nf_defrag_ipv6         11182   1 nf_conntrack_ipv6
        nf_conntrack           79357   2 nf_conntrack_ipv6, xt_state
        ipv6                   321422  23 ip6t_REJECT, nf_conntrack_ipv6, nf_defrag_ipv6

有些网络和应用程序还不支持IPv6,因此,禁用IPv6可以说是一个非常好的选择,以此加强系统的安全性,提高系统的整体性能。不过,首先要确认一下IPv6是否处于被启动的状态,命令如下:

        ifconfig -a  ← 列出全部网络接口信息

命令结果如下所示:

        eth0      Link encap:Ethernet  HWaddr 00:16:3E:7F:67:C3
                  inet addr:192.168.1.207  Bcast:192.168.1.255  Mask:255.255.255.0
                  inet6 addr: fe80::216:3eff:fe7f:67c3/64 Scope:Link
                  UP BROADCAST RUNNING MULTICAST  MTU:1500  Metric:1
                  RX packets:405835 errors:0 dropped:0 overruns:0 frame:0
                  TX packets:197486 errors:0 dropped:0 overruns:0 carrier:0
                  collisions:0 txqueuelen:1000
                  RX bytes:327950786 (312.7 MiB)  TX bytes:17186162 (16.3 MiB)
                  Interrupt:24
        lo        Link encap:Local Loopback
                  inet addr:127.0.0.1  Mask:255.0.0.0
                  inet6 addr: ::1/128 Scope:Host
                  UP LOOPBACK RUNNING  MTU:16436  Metric:1
                  RX packets:0 errors:0 dropped:0 overruns:0 frame:0
                  TX packets:0 errors:0 dropped:0 overruns:0 carrier:0
                  collisions:0 txqueuelen:0
                  RX bytes:0 (0.0 b)  TX bytes:0 (0.0 b)

然后修改相应配置文件,停止ipv6,命令如下:

        echo "install ipv6 /bin/true" > /etc/modprobe.d/disable-ipv6.conf
        #每当系统需要加载IPv6模块时,强制执行/bin/true来代替实际加载的模块
        echo "IPV6INIT=no" >> /etc/sysconfig/network-scripts/ifcfg-eth0
        #禁用基于IPv6网络,使之不会被触发启动

注意

如果关闭ipv6选项,在安装LVS服务的机器上面运行ipvsadm会出现如下报错:

FATAL: Error inserting ip_vs (/lib/modules/2.6.32-573.7.1.el6.x86_64/kernel/net/netfilter/ipvs/ip_vs.ko): Unknown symbol in module, or unknown parameter (see dmesg) Can't initialize ipvs: Protocol not available

Are you sure that IP Virtual Server is built in the kernel or as module?

所以此选项的优化应该根据实际情况来定,如果有需要安装LVS服务的机器建议略过此项优化。

8. 调整修改文件描述符限制

在Linux系统中,所有东西都可以看成是文件,文件又可分为普通文件、目录文件、链接文件和设备文件。文件描述符是内核为了高效管理已被打开的文件所创建的索引,是一个非负整数(通常是小整数),用于指代被打开的文件,所有执行I/O操作的系统调用都通过文件描述符。程序刚刚启动的时候,0是标准输入,1是标准输出,2是标准错误。如果此时去打开一个新的文件,它的文件描述符会是3。大家在运行Linux系统下的服务应用时(例如Squid服务),打开的文件太多就会提示“Too many open files”,出现这句提示的原因是程序打开的文件连接数量超过系统设定值。这主要是因为文件描述符是系统的一个重要资源,虽然说系统内存有多少就可以打开多少的文件描述符,但是在实际实现过程中内核会做相应的处理,一般最大打开文件数会是系统内存的10%(以KB来计算)(称之为系统级限制,比如4G内存的机器可以为419430),查看系统级别的最大打开文件数可以使用sysctl -a | grep fs.file-max命令查看。与此同时,内核为了不让某一个进程消耗掉所有的文件资源,它也会对单个进程最大打开文件数做默认值处理(称之为用户级限制),默认值一般是1024,可以使用ulimit -n命令查看。

如何修改文件描述符限制(也称之文件最大打开数)的值呢?我们可以参考下面的步骤。

1)修改用户级限制

在/etc/security/limits.conf文件里添加如下内容:

        * soft nofile 65535
        * hard nofile 65535

注意

soft的数值应该是小于或等于hard值,soft的限制不能比hard限制高。

2)修改系统限制可以把fs.file-max=419430添加到/etc/sysctl.conf中,使用sysctl -p即不需要重启系统也可生效,具体步骤如下所示:

        echo "fs.file-max=419430" >> /etc/sysctl.conf
        sysctl -p

用户级限制:ulimit命令看到的是用户级的最大文件描述符限制,也就是说每一个用户登录后执行的程序占用文件描述符的总数不能超过这个限制。

系统级限制:sysctl命令和proc文件系统中查看到的数值是一样的,这属于系统级限制,它是限制所有用户打开文件描述符的总和。

另外,ulimit -n命令并不能真正看到文件的最大文件打开数,可用如下脚本查看:

        #! /bin/bash
        for pid in 'ps aux |grep nginx |grep -v grep|awk '{print $2}''
        do
        cat /proc/${pid}/limits |grep 'Max open files'
        done

在线上环境找一台CMS业务机器执行此脚本,显示结果如下所示:

        Max open files             65535                 65535                 files
        Max open files             65535                 65535                 files
        Max open files             65535                 65535                 files
        Max open files             65535                 65535                 files
        Max open files             65535                 65535                 files
        Max open files             65535                 65535                 files
        Max open files             65535                 65535                 files
        Max open files             65535                 65535                 files
        Max open files             65535                 65535                 files
        Max open files             65535                 65535                 files

9. 正确启动网卡

大家配置CentOS 6.8的网卡IP地址时,最容易忽略的一项就是CentOS系统启动时未启动网卡,其后果很明显,那就是你的Linux机器永远没有IP地址。下面是一台线上环境服务器网卡文件/etc/sysconfig/network-scripts/ifcfg-eth0文件的配置内容。

        DEVICE=eth0
        BOOTPROTO=static
        HWADDR=00:14:22:1B:71:20
        IPV6INIT=no
        IPV6_AUTOCONF=yes
        ONBOOT=yes   →此项一定要记得更改为yes,它会在系统引导就启动你的网卡设备
        NETMASK=255.255.255.192
        IPADDR=203.93.236.146
        GATEWAY=203.93.236.129
        TYPE=Ethernet
        PEERDNS=yes   →允许从DHCP处获得的DNS覆盖本地的DNS
        USERCTL=no    →不允许普通用户修改网卡

10. 关闭写磁盘I/O功能

Linux文件默认有3个时间,如下所示:

❑ atime:对此文件的Access(访问)时间。

❑ ctime:此文件inode发生Change(状态变化)的时间。

❑ mtime:此文件的Modify(修改)时间。

我们可以用stat命令查看文件的这些相关时间,如下所示:

        stat install.log

命令显示结果如下所示:

        File: "install.log"
          Size: 46503      Blocks: 104        IO Block: 4096   普通文件
        Device: 802h/2050d Inode: 786434      Links: 1
        Access: (0644/-rw-r--r--)  Uid: (  626/    yucy)   Gid: (  626/    yucy)
        Access: 2015-09-08 19:02:49.838428672 +0800
        Modify: 2014-12-15 12:05:12.808264055 +0800
        Change: 2015-07-06 11:05:22.731778396 +0800

如果有多个小文件(比如Web服务器的页面上有多个小图片),通常就没有必要记录文件的访问时间了,这样可以减少写磁盘的I/O,可这要如何配置呢?

首先,修改文件系统的配置文件/etc/fstab,然后,在包含大量小文件的分区中使用noatime和nodiratime这两个命令。

例如:

        /dev/sda5 /data/pics ext3 noatime, nodiratime 0 0

这样文件被访问时就不会再产生写磁盘的I/O了。

11. 修改SSH登录配置

SSH服务配置优化,请保持机器中至少有一个具有sudo权限的用户,下面的配置会禁止root远程登录,代码内容如下所示:

        sed -i 's@#PermitRootLogin yes@PermitRootLogin no@' /etc/ssh/sshd_config
        #禁止root远程登录
        sed -i 's@#PermitEmptyPasswords no@PermitEmptyPasswords no@'
        /etc/ssh/sshd_config #禁止空密码登录
        sed -i 's@#UseDNS yes@UseDNS no@' /etc/ssh/sshd_config
        /etc/ssh/sshd_config #关闭SSH反向查询,以加快SSH访问速度

12. 增加具有sudo权限的用户

添加用户的步骤和过程比较简便(这里略过),由于系统已经禁止了root远程登录,因此需要一个具有sudo权限的admin用户,权限跟root相当,这里用visudo命令,在打开的文件内容里找到如下内容:

        ## Allow root to run any commands anywhere
        root    ALL=(ALL)       ALL

然后添加如下内容:

        yhc   ALL=(ALL)       ALL

如果在进行sudo切换时不想输入密码,可以做如下更改:

        yhc  ALL=(ALL) NOPASSWD:ALL

1.4.2 优化Linux下的内核TCP参数以提高系统性能

内核的优化跟服务器的优化一样,本着稳定安全的原则。下面以Squid服务器为例进行说明,待客户端与服务器端建立TCP/IP连接后就会关闭SOCKET,服务器端连接的端口状态也就变为TIME_WAIT了。那是不是所有执行主动关闭的SOCKET都会进入TIME_WAIT状态呢?有没有什么情况使主动关闭的SOCKET直接进入CLOSED状态呢?答案是主动关闭的一方在发送最后一个ACK后就会进入TIME_WAIT状态,并停留2MSL(报文最大生存)时间,这是TCP/IP必不可少的,也是“解决”不了的。

TCP/IP设计者如此设计,主要原因有两个:

❑ 防止上一次连接中的包迷路后重新出现,影响新的连接(经过2MSL时间后,上一次连接中所有重复的包都会消失)。

❑ 为了可靠地关闭TCP连接。主动关闭方发送的最后一个ACK(FIN)有可能会丢失,如果丢失,被动方会重新发FIN,这时如果主动方处于CLOSED状态,就会响应RST而不是ACK。所以主动方要处于TIME_WAIT状态,而不能是CLOSED状态。另外,TIME_WAIT并不会占用很大的资源,除非受到攻击。

在Squid服务器中可输入查看当前连接统计数的命令,如下所示:

        netstat -n | awk '/^tcp/ {++S[$NF]} END{for(a in S) print a, S[a]}'

命令显示结果如下所示:

        LAST_ACK 14
        SYN_RECV 348
        ESTABLISHED 70
        FIN_WAIT1229
        FIN_WAIT2 30
        CLOSING 33
        TIME_WAIT 18122

命令中的含义分别如下:

❑ CLOSED:无连接是活动的或正在进行中。

❑ LISTEN:服务器在等待进入呼叫。

❑ SYN_RECV:一个连接请求已经到达,等待确认。

❑ SYN_SENT:应用已经开始,打开一个连接。

❑ ESTABLISHED:正常数据传输状态。

❑ FIN_WAIT1:应用说它已经完成。

❑ FIN_WAIT2:另一边已同意释放。

❑ ITMED_WAIT:等待所有分组死掉。

❑ CLOSING:两边同时尝试关闭。

❑ TIME_WAIT:另一边已初始化一个释放。

❑ LAST_ACK:等待所有分组死掉。

也就是说,这条命令可以把当前系统的网络连接状态分类汇总。

在Linux下高并发的Squid服务器中,TCP TIME_WAIT套接字数量经常可达两三万,服务器很容易被拖死。不过,可以通过修改Linux内核参数来减少Squid服务器的TIME_WAIT套接字数量,命令如下:

        vim /etc/sysctl.conf

然后,增加以下参数:

        net.ipv4.tcp_fin_timeout = 30
        net.ipv4.tcp_keepalive_time = 1200
        net.ipv4.tcp_syncookies = 1
        net.ipv4.tcp_tw_reuse = 1
        net.ipv4.tcp_tw_recycle = 1
        net.ipv4.ip_local_port_range = 1000065000
        net.ipv4.tcp_max_syn_backlog = 8192
        net.ipv4.tcp_max_tw_buckets = 5000

简单说明上面参数的含义:

❑ net.ipv4.tcp_syncookies=1表示开启SYN Cookies,当出现SYN等待队列溢出时,启用cookie来处理,可防范少量的SYN攻击,默认为0,表示关闭;

❑ net.ipv4.tcp_tw_reuse=1表示开启重用,即允许将TIME-WAIT sockets重新用于新的TCP连接,默认为0,表示关闭;

❑ net.ipv4.tcp_tw_recycle=1表示开启TCP连接中TIME-WAIT sockets的快速回收,默认为0,表示关闭;

❑ net.ipv4.tcp_fin_timeout=30表示如果套接字由本端要求关闭,这个参数决定了它保持在FIN-WAIT-2状态的时间;

❑ net.ipv4.tcp_keepalive_time=1200表示当keepalive启用时,TCP发送keepalive消息的频度默认是2小时,改为20分钟;

❑ net.ipv4.ip_local_port_range=1000065000表示CentOS系统默认向外连接的端口范围。默认值很小,这里改为10000到65000。建议这里不要将最低值设得太低,否则可能会占用正常的端口。

❑ net.ipv4.tcp_max_syn_backlog=8192表示SYN队列的长度,默认为1024,加大队列长度为8192,可以容纳更多等待连接的网络连接数。

❑ net.ipv4.tcp_max_tw_buckets=5000表示系统同时保持TIME_WAIT套接字的最大数量,如果超过这个数字,TIME_WAIT套接字将立刻被清除并打印警告信息,默认为180000,改为5000。对于Apache、Nginx等服务器,前面介绍的几个的参数已经可以很好地减少TIME_WAIT套接字数量,但对于Squid来说效果不大,有了此参数就可以控制TIME_WAIT套接字的最大数量,避免Squid服务器被大量的TIME_WAIT套接字拖死。

执行以下命令使内核配置立马生效:

        /sbin/sysctl -p

如果是用于Apache或Nginx等Web服务器,则更改以下几项即可:

        net.ipv4.tcp_syncookies=1
        net.ipv4.tcp_tw_reuse=1
        net.ipv4.tcp_tw_recycle = 1
        net.ipv4.ip_local_port_range = 1000065000

执行以下命令使内核配置立马生效:

        /sbin/sysctl -p

如果是Postfix邮件服务器,则建议内核优化方案如下:

        net.ipv4.tcp_fin_timeout = 30
        net.ipv4.tcp_keepalive_time = 300
        net.ipv4.tcp_tw_reuse = 1
        net.ipv4.tcp_tw_recycle = 1
        net.ipv4.ip_local_port_range = 1000065000
        kernel.shmmax = 134217728

执行以下命令使内核配置立马生效:

        /sbin/sysctl -p

当然,这些都只是最基本的更改,大家还可以根据自己的需求来更改内核的设置,同样也要本着服务器稳定为最高原则,如果服务器不稳定的话,一切工作和努力都是白费。如果以上优化仍无法满足工作要求,则可能需要定制你的服务器内核或升级服务器硬件。

1.4.3 CentOS 6.8 x86_64系统最小化安装优化脚本

CentOS 6.8 x86_64系统最小化优化脚本,大家注意,下文中有中文注释内容,如果是放在线上运行时需要格外留意,脚本内容如下所示:

        #! /bin/bash
        #系统基础升级,建议以root执行
        #必须使用root才能执行此脚本
        if [ $USER ! = "root" ]; then
            echo "需要使用sudo才能使用本脚本"
            exit 1
        fi
        cd /usr/local/src
        wget http://mirrors.163.com/.help/CentOS6-Base-163.repo
        cd /etc/yum.repos.d/
        mv CentOS-Base.repo CentOS-Base.repo.bak
        cp /usr/local/src/CentOS6-Base-163.repo ./CentOS-Base.repo
        yum clean all #清除yum缓存
        yum makecache #重建缓存
        yum update -y  #升级Linux系统
        cd ../
        #添加epel外部yum扩展源
        cd /usr/local/src
        wget http://dl.fedoraproject.org/pub/epel/6/x86_64/epel-release-6-8.noarch.rpm
        rpm -ivh epel-release-6-8.noarch.rpm
        #安装gcc基础库文件以及sysstat工具
        yum -y install gcc gcc-c++ vim-enhanced unzip unrar sysstat
        #配置ntpdate自动对时
        yum -y install ntp
        echo "01 01 * * * /usr/sbin/ntpdate ntp.api.bz   >> /dev/null 2>&1" >> /etc/crontab
        /usr/sbin/ntpdate ntp.api.bz
        service crond restart
        #配置文件的ulimit值
        ulimit -SHn 65534
        echo "ulimit -SHn 65534" >> /etc/rc.local
        cat >> /etc/security/limits.conf << EOF
        *                   soft    nofile           65535
        *                   hard    nofile           65535
        EOF
        echo "fs.file-max=419430" >> /etc/sysctl.conf
        #基础系统内核优化
        cat >> /etc/sysctl.conf << EOF
        net.ipv4.tcp_syncookies = 1
        net.ipv4.tcp_syn_retries = 1
        net.ipv4.tcp_tw_recycle = 1
        net.ipv4.tcp_tw_reuse = 1
        net.ipv4.tcp_fin_timeout = 1
        net.ipv4.tcp_keepalive_time = 1200
        net.ipv4.ip_local_port_range = 1000065535
        net.ipv4.tcp_max_syn_backlog = 16384
        net.ipv4.tcp_max_tw_buckets = 36000
        net.ipv4.route.gc_timeout = 100
        net.ipv4.tcp_syn_retries = 1
        net.ipv4.tcp_synack_retries = 1
        net.core.somaxconn = 16384
        net.core.netdev_max_backlog = 16384
        net.ipv4.tcp_max_orphans = 16384
        EOF
        /sbin/sysctl -p
        #禁用control-alt-delete组合键以防止误操作
        sed -i 's@ca::ctrlaltdel:/sbin/shutdown -t3-r now@#ca::ctrlaltdel:/sbin/shutdown
            -t3-r now@' /etc/inittab
        #关闭SElinux
        sed -i 's@SELINUX=enforcing@SELINUX=disabled@' /etc/selinux/config
        #关闭iptables
        service iptables stop
        chkconfig iptables off
        #ssh服务配置优化,请保持机器中至少有一个具有sudo权限的用户,下面的配置会禁止root远程登录
        sed -i 's@#PermitRootLogin yes@PermitRootLogin no@' /etc/ssh/sshd_config
        #禁止空密码登录
        sed -i 's@#PermitEmptyPasswords no@PermitEmptyPasswords no@' /etc/ssh/sshd_config
        #禁止SSH反向解析
        sed -i 's@#UseDNS yes@UseDNS no@' /etc/ssh/sshd_config /etc/ssh/sshd_config
        service sshd restart
        #禁用ipv6地址,根据实际需求设置,如果需要安装lvs服务的机器,建议保留此选项
        echo "install ipv6 /bin/true" > /etc/modprobe.d/disable-ipv6.conf
        #每当系统需要加载IPv6模块时,强制执行/bin/true来代替实际加载的模块
        echo "IPV6INIT=no" >> /etc/sysconfig/network-scripts/ifcfg-eth0
        #禁用基于IPv6网络,使之不会被触发启动
        chkconfig ip6tables off
        #vim基础语法优化
        cat >> /root/.vimrc << EOF
        set number
        set ruler
        set nohlsearch
        set shiftwidth=2
        set tabstop=4
        set expandtab
        set cindent
        set autoindent
        set mouse=v
        syntax on
        EOF
        #精简开机自启动服务,安装最小化服务的机器初始可以只留crond|network|rsyslog|sshd这四个服务
        for i in 'chkconfig --list|grep 3:on|awk '{print $1}''; do chkconfig --level 3 $i
            off; done
        for CURSRV  in crond rsyslog sshd network; do chkconfig --level 3 $CURSRV on; done
        #重启服务器
        reboot

1.4.4 Linux下CPU使用率与机器负载的关系与区别

笔者曾接触一个案例:线上的bidder业务机器,在业务最繁忙的一段周期内,发现Nginx单机并发活动连接数超过2.8万,机器负载UPTIME值(基本上不到4,报警系统没有发送报警邮件和短信)。Nginx+Lua服务都是正常的,网卡流量并没有打满,但流量就是怎么也打不进去。经过深入观察,发现这段时期内每台机器CPU的利用率都已经很高了,基本维持在99%左右,这种情况应该是CPU资源耗尽导致不能继续提供服务。所以这里也研究下CPU负载和CPU利用率这两个概念的关系与区别。

CPU负载和CPU利用率虽然是不同的两个概念,但它们的信息可以在同一个top命令中显示。CPU利用率显示的是程序在运行期间实时占用的CPU百分比,而CPU负载显示的是一段时间内正在使用和等待使用CPU的平均任务数。CPU利用率高,并不意味着负载就一定大。

网上有篇文章给出了一个有趣的比喻,即通过打电话来说明两者的区别,下面笔者按自己的理解阐述一下。

某公用电话亭,有一个人在打电话,四个人在等待,每人限定使用电话一分钟,若有人一分钟之内没有打完电话,只能挂掉电话去排队等待下一轮。电话在这里就相当于CPU,而正在或等待打电话的人就相当于任务数。

在电话亭使用过程中,肯定会有人打完电话走掉,有人没有打完电话而选择重新排队,更会有新增的人在这儿排队,这个人数的变化就相当于任务数的增减。为了统计平均负载情况,我们5秒钟统计一次人数,并在第1、5、15分钟的时候对统计情况取平均值,从而形成第1、5、15分钟的平均负载。有的人拿起电话就打,一直打完1分钟,而有的人可能前三十秒在找电话号码,或者犹豫要不要打,后三十秒才真正在打电话。如果把电话看作CPU,人数看作任务,我们就说前一个人(任务)的CPU利用率高,后一个人(任务)的CPU利用率低。

当然,CPU并不会在前三十秒工作,后三十秒歇着,只是说,有的程序涉及大量的计算,所以CPU利用率就高,而有的程序牵涉计算的部分很少,CPU利用率自然就低。但无论CPU的利用率是高是低,跟后面有多少任务在排队都没有必然关系。

CPU负载为多少才算比较理想呢?对此一直存在争议,各有各的说法,个人比较赞同CPU负载小于等于0.5算是一种理想状态。

不管某个CPU的性能有多好,1秒能处理多少任务,我们可以认为它无关紧要,虽然事实并非如此。在评估CPU负载时,我们只以5秒为单位来统计任务队列长度。如果每隔5秒钟统计的时候,发现任务队列长度都是1,那么CPU负载就为1。假如我们只有一个单核的CPU,负载一直为1,意味着没有任务在排队,这种情况还不错。还是以上面提到的bidder业务机器为例,都是四核机器,每个内核的负载为1的话,总负载则为4。也就是说,如果那些bidder服务器的CPU负载长期保持在4左右,还是可以接受的。

CPU使用率到多少才算比较理想呢?

笔者这里建议大家统计%user+%system的值,如果长期大于85%的话,就可以认为系统的CPU过重,这个时候可以考虑添加物理CPU或增添业务集群机器了。比较偷懒的做法是统计CPU的%idle(空闲)值,如果过小的话正好从侧面说明系统CPU利用率过高了。

附上其统计CPU使用率的Shell脚本,如下所示:

        #! /bin/bash
        # Nagios return codes
        STATE_OK=0
        STATE_WARNING=1
        STATE_CRITICAL=2
        STATE_UNKNOWN=3
        # Plugin parameters value if not define
        LIST_WARNING_THRESHOLD="70"
        LIST_CRITICAL_THRESHOLD="80"
        INTERVAL_SEC=1
        NUM_REPORT=1
        CPU_REPORT='iostat -c $INTERVAL_SEC $NUM_REPORT | sed -e 's/, /./g' | tr -s ' '
            '; ' | sed '/^$/d' |tail -1'
        CPU_REPORT_SECTIONS='echo ${CPU_REPORT} | grep '; ' -o | wc -l'
        CPU_USER='echo $CPU_REPORT | cut -d "; " -f 2'
        #CPU_NICE='echo $CPU_REPORT | cut -d "; " -f 3'
        CPU_SYSTEM='echo $CPU_REPORT | cut -d "; " -f 4'
        # Add for integer shell issue
        CPU_USER_MAJOR='echo $CPU_USER | cut -d "." -f 1'
        CPU_SYSTEM_MAJOR='echo $CPU_SYSTEM | cut -d "." -f 1'
        #CPU_IOWAIT_MAJOR='echo $CPU_IOWAIT | cut -d "." -f 1'
        #CPU_IDLE_MAJOR='echo $CPU_IDLE | cut -d "." -f 1'
        #CPU_VMSTAT_R='vmstat 1 4 | sed -n '3, $'p  | awk 'BEGINE{SUM=0} {SUM += $1} END
            {print SUM/4}' '
        CPU_UTILI_COU='echo ${CPU_USER} + ${CPU_SYSTEM}|bc'
        CPU_UTILI_COUNTER='echo $CPU_UTILI_COU | cut -d "." -f 1'
        # Return
        if [ ${CPU_UTILI_COUNTER} -lt ${LIST_WARNING_THRESHOLD} ]
        then
            echo "OK - CPUCOU=${CPU_UTILI_COU}% | CPUCOU=${CPU_UTILI_COU}%;80;90"
            exit ${STATE_OK}
        fi
        if [ ${CPU_UTILI_COUNTER}  -gt  ${LIST_WARNING_THRESHOLD}  -a  ${CPU_UTILI_COUNTER}
              -lt ${LIST_CRITICAL_THRESHOLD} ]
        then
            echo  "Warning  -  CPUCOU=${CPU_UTILI_COUNTER}%  |  CPUCOU=${CPU_UTILI_
                COUNTER}%;80;90"
            exit ${STATE_WARNING}
        fi
        if [ ${CPU_UTILI_COUNTER} -gt ${LIST_CRITICAL_THRESHOLD} ]
        then
            echo  "Critical  -  CPUCOU=${CPU_UTILI_COUNTER}%  |  CPUCOU=${CPU_UTILI_COUNTER}
                %;80;90"
            exit ${STATE_CRITICAL}
        fi

1.5 服务器调优实际案例

下面笔者用自己的经历以及工作的业务平台跟大家说明真实工作场景下服务器的实际调优案例。

笔者的海外DSP业务群机器采用的是AWS云计算平台,基于业务的复杂性,所以系统基本属于高并发高负载运行。为了系统的稳定,机器上线之前暂时做了一些基础的系统内核优化,并且在CPU和内存硬件方面做了提升加强,基础的内核优化配置文件如下所示:

        # Kernel sysctl configuration file for Red Hat Linux
        # For binary values, 0 is disabled, 1 is enabled.  See sysctl(8) and
        # sysctl.conf(5) for more details.
        # Controls IP packet forwarding
        net.ipv4.ip_forward = 0
        # Controls source route verification
        net.ipv4.conf.default.rp_filter = 1
        # Do not accept source routing
        net.ipv4.conf.default.accept_source_route = 0
        # Controls the System Request debugging functionality of the kernel
        kernel.sysrq = 0
        # Controls whether core dumps will append the PID to the core filename.
        # Useful for debugging multi-threaded applications.
        kernel.core_uses_pid = 1
        # Controls the use of TCP syncookies
        net.ipv4.tcp_syncookies = 1
        net.ipv4.tcp_max_syn_backlog = 4096
        net.core.somaxconn = 2048
        net.ipv4.tcp_timestamps = 1
        net.ipv4.tcp_tw_recycle = 1
        # Disable netfilter on bridges.
        net.bridge.bridge-nf-call-ip6tables = 0
        net.bridge.bridge-nf-call-iptables = 0
        net.bridge.bridge-nf-call-arptables = 0
        # Controls the default maxmimum size of a mesage queue
        kernel.msgmnb = 65536
        # Controls the maximum size of a message, in bytes
        kernel.msgmax = 65536
        # Controls the maximum shared segment size, in bytes
        kernel.shmmax = 68719476736
        # Controls the maximum number of shared memory segments, in pages
        kernel.shmall = 4294967296

但系统上线后流量骤增,经常会出现“TCP:too many orphaned sockets”的情况,具体表现为系统日志用dmesg排错时,发现大量的“TCP:too many orpharned sockets”信息,如下所示:

        [13257987.555864] TCP: too many orphaned sockets
        [13257987.559244] TCP: too many orphaned sockets
        [13257987.562524] TCP: too many orphaned sockets
        [13257988.576104] TCP: too many orphaned sockets
        [13257988.576117] TCP: too many orphaned sockets
        [13257988.576119] TCP: too many orphaned sockets
        [13257988.576122] TCP: too many orphaned sockets
        [13257989.088095] TCP: too many orphaned sockets
        [13257989.090621] TCP: too many orphaned sockets
        [13257989.600115] TCP: too many orphaned sockets

所以需要对系统内核做些优化调整以应对更大并发流量的冲击,修改其内核文件并增加内容,如下所示:

        net.ipv4.tcp_rmem = 4096409616777216
        net.ipv4.tcp_wmem = 4096409616777216
        net.ipv4.tcp_mem = 78643220971523145728
        net.ipv4.tcp_max_orphans = 131072

执行以下命令使内核配置立即生效:

        /sbin/sysctl -p

主要看这几项:

❑ net.ipv4.tcp_rmem:用来配置读缓冲的大小,三个值,第一个是这个读缓冲的最小值,第三个是最大值,中间的是默认值。我们可以在程序中修改读缓冲的大小,但是不能超过最小值与最大值。为了使每个socket所使用的内存数最小,笔者此处设置的默认值为4096。

❑ net.ipv4.tcp_wmem:用来配置写缓冲的大小。读缓冲与写缓冲的大小直接影响到socket在内核中内存的占用。

❑ net.ipv4.tcp_mem:配置TCP的内存大小,其单位是页,而不是字节。当超过第二个值时,TCP进入pressure模式,此时TCP尝试稳定其内存的使用,当小于第一个值时,就退出pressure模式。当内存占用超过第三个值时,TCP就拒绝分配socket了,使用dmesg命令查看,会打出很多的日志“TCP: too many of orphaned sockets”。

❑ net.ipv4.tcp_max_orphans:这个值也要设置一下,表示系统所能处理不属于任何进程的socket数量,当我们需要快速建立大量连接时需要关注这个值。当不属于任何进程的socket的数量大于这个值时,使用dmesg命令会看到“TCP:too many of orphaned sockets”。

1.6 小结

本章介绍了系统架构设计的相关专业术语,以及关于IDC机房物理服务器和AWC EC2类型实例的选择,还介绍了CentOS 6.8 x86_64系统的最小化安装后的优化,最后笔者跟大家分享了实际工作平台上真实案例系统的优化。这些工作都是系统架构设计的基础,希望大家能够掌握此章内容,这对于我们今后的工作会有很大的帮助。