关于我们

质量为本、客户为根、勇于拼搏、务实创新

< 返回新闻公共列表

高性能服务器之性能调优

发布时间:2021-04-12 14:37:51

让咱们先来说说怎么什么是体系功能。这个界说十分要害,假如咱们不清楚什么是体系功能,那么咱们将无法定位之。我见过许多朋友会觉得这很简略,可是仔细一问,其实他们并没有一个比较体系的办法,所以,在这儿我想告诉咱们怎么体系地来定位功能。 总体来说,体系功能便是两个事:

  1. 一般来说,一个体系的功能遭到这两个条件的束缚,缺一不可。比方,我的体系能够顶得住一百万的并发,可是体系的推迟是2分钟以上,那么,这个一百万的负载毫无意义。体系推迟很短,可是吞吐量很低,相同没有意义。所以,一个好的体系的功能测验必定遭到这两个条件的一起作用。 有经验的朋友必定知道,这两个东西的一些联系:
    • 二、体系功能测验

      • 其次,开发功能测验东西,一个东西用来制作高强度的Throughput,另一个东西用来丈量Latency。关于怎么丈量Latency,你能够在代码中丈量,可是这样会影响程序的履行,而且只能测验到程序内部的Latency,真实的Latency是整个体系都算上,包括操作体系和网络的延时,你能够运用Wireshark来抓网络包来丈量。这两个东西详细怎么做,这个还请咱们自己思考去了。
      • 再多说一些,
        • 关于功能测验,咱们还需求界说一个时间段。比方:在某个吞吐量上继续15分钟。由于当负载到达的时分,体系会变得不安稳,当过了一两分钟后,体系才会安稳。其他,也有或许是,你的体系在这个负载下前几分钟还表现正常,然后就不安稳了,乃至垮了。所以,需求这么一段时间。这个值,咱们叫做峰值极限。
        • 功能测验有许多很复要的东西,比方:burst test等。 这儿不能一一详述,这儿只说了一些和功能调优相关的东西。总归,功能测验是一细活和累活。
        • 有了上面的衬托,咱们就能够测验到到体系的功能了,再调优之前,咱们先来说说怎么找到功能的瓶颈。我见过许多朋友会觉得这很简略,可是仔细一问,其实他们并没有一个比较体系的办法。

          首先,当咱们体系有问题的时分,咱们不要急于去查询咱们代码,这个毫无意义。咱们首要需求看的是操作体系的陈述。看看操作体系的CPU运用率,看看内存运用率,看看操作体系的IO,还有网络的IO,网络链接数,等等。Windows下的perfmon是一个很不错的东西,Linux下也有许多相关的指令和东西,比方:vmstat, sar, iostat, top, tcpdump等等 。经过调查这些数据,咱们就能够知道咱们的软件的功能根本上出在哪里。比方:

          2)然后,咱们能够看一下IO大不大,IO和CPU一般是反着来的,CPU运用率高则IO不大,IO大则CPU就小。关于IO,咱们要看三个事,一个是磁盘文件IO,一个是驱动程序的IO(如:网卡),一个是内存换页率。这三个事都会影响体系功能。

          4)假如CPU不高,IO不高,内存运用不高,网络带宽运用不高。可是体系的功能上不去。这阐明你的程序有问题,比方,你的程序被堵塞了。或许是由于等那个锁,或许是由于等某个资源,或者是在切换上下文。

          3.2)运用Profiler测验

          咱们要点调查运转时间最多,调用次数最多的那些函数和指令。这儿留意一下,关于调用次数多可是时间很短的函数,你或许只需求轻微优化一下,你的功能就上去了(比方:某函数一秒种被调用100万次,你想想假如你让这个函数进步0.01毫秒的时间 ,这会给你带来多大的功能)

          1)在你的代码中自己做核算,运用微秒级的计时器和函数调用核算器,每隔10秒把核算log到文件中。

          终究再说一点,关于功能测验,不同的Throughput会呈现不同的测验成果,不同的测验数据也会有不同的测验成果。所以,用于功能测验的数据十分重要,功能测验中,咱们需求观测验不同Throughput的成果

          下面这些东西是我所经历过的一些问题,或许并不全,或许并不对,咱们能够弥补纠正,我纯属抛砖引玉。关于体系架构方面的功能调优,咱们可移步看一下,关于Web方面的一些功能调优的东西,咱们能够看看一文中的功能一章。我在这儿就不再说规划和架构上的东西了。


        • 用空间换时间。各种cache如CPU L1/L2/RAM到硬盘,都是用空间来换时间的战略。这样战略根本上是把核算的进程一步一步的保存或缓存下来,这样就不必每次用的时分都要再核算一遍,比方数据缓冲,CDN,等。这样的战略还表现为冗余数据,比方数据镜象,负载均衡什么的。
        • 简化代码。最高效的程序便是不履行任何代码的程序,所以,代码越少功能就越高。关于代码级优化的技能大学里的教科书有许多示例了。如:削减循环的层数,削减递归,在循环中少声明变量,少做分配和释放内存的操作,尽量把循环体内的表达式抽到循环外,条件表达的中的多个条件判断的次序,尽量在程序启动时把一些东西准备好,留意函数调用的开支(栈上开支),留意面向目标言语中暂时目标的开支,当心运用异常(不要用异常来检查一些可接受可疏忽并常常产生的过错),…… 等等,等等,这连东西需求咱们十分了解编程言语和常用的库。
        • 总归,
        • 依据2:8准则来说,20%的代码耗了你80%的功能,找到那20%的代码,你就能够优化那80%的功能
        • 。 下面的一些东西都是我的一些经验,我只例举了一些最有价值的功能调优的的办法,供你参阅,也欢迎弥补。

        • 一个是过滤算法,体系需求对收到的恳求做过滤,咱们把能够被filter in/out的东西装备在了一个文件中,原有的过滤算法是遍历过滤装备,后来,咱们找到了一种办法能够对这个过滤装备进行排序,这样就能够用二分折半的办法来过滤,体系功能增加了50%。
        • 分而治之和预处理。曾经有一个程序为了生成月报表,每次都需求核算很长的时间,有时分需求花将近一整天的时间。所以咱们把咱们找到了一种办法能够把这个算法发成增量式的,也便是说我每天都把当天的数据核算好了后和前一天的报表兼并,这样能够大大的节省核算时间,每天的数据核算量只需求20分钟,可是假如我要算整个月的,体系则需求10个小时以上(SQL句子在大数据量面前功能成级数性下降)。这种分而治之的思路在大数据面前对功能有很帮助,就像merge排序相同。SQL句子和数据库的功能优化也是这一战略,如:运用嵌套式的Select而不是笛卡尔积的Select,运用视图,等等。


      • 字符串操作。这是最费体系功能的事了,无论是strcpy, strcat仍是strlen,最需求留意的是字符串子串匹配。所以,能用整型最好用整型。举几个比方,第一个比方是N年前做银行的时分,我的搭档喜爱把日期存成字符串(如:2012-05-29 08:30:02),我勒个去,一个select  where between句子适当耗时。另一个比方是,我曾经有个搭档把一些状况码用字符串来处理,他的理由是,这样能够在界面上直接显示,后来功能调优的时分,我把这些状况码全改成整型,然后用位操作查状况,由于有一个每秒钟被调用了150K次的函数里面有三处需求检查状况,经过改进以后,整个体系的功能上升了30%左右。还有一个比方是,我曾经从事的某个产品编程规范中有一条是要在每个函数中把函数名界说出来,如:const char fname[]=”functionName()”, 这是为了好打日志,可是为什么不声明成 static类型的呢?
      • 内存分配。不要小看程序的内存分配。malloc/realloc/calloc这样的体系调十分耗时,尤其是当内存呈现碎片的时分。我曾经的公司出过这样一个问题——在用户的站点上,咱们的程序有一天不呼应了,用GDB跟进去一看,体系hang在了malloc操作上,20秒都没有返回,重启一些体系就好了。这便是内存碎片的问题。这便是为什么许多人诉苦STL有严峻的内存碎片的问题,由于太多的小内存的分配释放了。有许多人会以为用内存池能够处理这个问题,可是实际上他们仅仅从头发明了Runtime-C或操作体系的内存管理机制,彻底杯水车薪。当然处理内存碎片的问题仍是经过内存池,详细来说是一系列不同尺度的内存池(这个留给咱们自己去思考)。当然,少进行动态内存分配是最好的。提到内存池就需求说一下池化技能。比方线程池,衔接池等。池化技能关于一些短作业来说(如http服务) 适当适当的有用。这项技能能够削减链接树立,线程创立的开支,然后进步功能。
      • 言语和代码库。咱们要熟悉言语以及所运用的函数库或类库的功能。比方:STL中的许多容器分配了内存后,那怕你删除元素,内存也不会收回,其会形成内存走漏的假像,并或许形成内存碎片问题。再如,STL某些容器的size()==0  和 empty()是不相同的,由于,size()是O(n)杂乱度,empty()是O(1)的杂乱度,这个要当心。Java中的JVM调优需求运用的这些参数:-Xms -Xmx -Xmn -XX:SurvivorRatio -XX:MaxTenuringThreshold,还需求留意JVM的GC,GC的霸气咱们都知道,尤其是full GC(还收拾内存碎片),他就像“恐龙特级克赛号”相同,他运转的时分,整个国际的时间都中止了。

      关于网络调优,尤其是TCP Tuning(你能够以这两个要害词在网上找到许多文章),这儿面有许多许多东西能够说。看看Linux下TCP/IP的那么多参数就知道了(趁便说一下,你或许不喜爱Linux,可是你不能否认Linux给咱们了许多能够进行内核调优的权利)。强烈建议咱们看看这本书。我在这儿只讲一些概念上的东西。

      咱们知道TCP链接是有许多开支的,一个是会占用文件描述符,另一个会开缓存,一般来说一个体系能够支撑的TCP链接数是有限的,咱们需求清楚地认识到TCP链接对体系的开支是很大的。正是由于TCP是耗资源的,所以,许多进犯都是让你体系上呈现许多的TCP链接,把你的体系资源耗尽。比方著名的SYNC Flood进犯。


      1

      2

      3

      net.ipv4.tcp_keepalive_probes = 5

      net.ipv4.tcp_keepalive_intvl = 20

      net.ipv4.tcp_fin_timeout = 30



      1

      2

      net.ipv4.tcp_tw_reuse=1

      net.ipv4.tcp_tw_recycle=1


      TCP还有一个重要的概念叫RWIN(TCP Receive Window Size),这个东西的意思是,我一个TCP链接在没有向Sender发出ack时能够接收到的最大的数据包。为什么这个很重要?由于假如Sender没有收到Receiver发过来ack,Sender就会中止发送数据并会等一段时间,假如超时,那么就会重传。这便是为什么TCP链接是牢靠链接的原因。重传还不是最严峻的,假如有丢包产生的话,TCP的带宽运用率会马上遭到影响(会盲目折半),再丢包,再折半,然后假如不丢包了,就逐步康复。相关参数如下:

      一般来说,理论上的RWIN应该设置成:吞吐量  * 回路时间。Sender端的buffer应该和RWIN有相同的巨细,由于Sender端发送完数据后要等Receiver端承认,假如网络延时很大,buffer过小了,承认的次数就会多,所以功能就不高,对网络的运用率也就不高了。也便是说,关于推迟大的网络,咱们需求大的buffer,这样能够少一点ack,多一些数据,关于呼应快一点的网络,能够少一些buffer。由于,假如有丢包(没有收到ack),buffer过大或许会有问题,由于这会让TCP重传一切的数据,反而影响网络功能。(当然,网络差的状况下,就别玩什么高功能了) 所以,高功能的网络重要的是要让网络丢包率十分十分地小(根本上是用在LAN里),假如网络根本是可信的,这样用大一点的buffer会有更好的网络传输功能(来来回回太多太影响功能了)。

      B)UDP调优

      再多说一下,运用Socket编程的时分,你能够运用setsockopt() 设置 SO_SNDBUF/SO_RCVBUF 的巨细,TTL和KeepAlive这些要害的设置,当然,还有许多,详细你能够检查一下Socket的手册。

      C)网卡调优

      D)其它网络功能

      其他,关于一些和DNS Lookup的体系调用要当心,比方:gethostbyaddr/gethostbyname,这个函数或许会适当的费时,由于其要到网络上去找域名,由于DNS的递归查询,会导致严峻超时,而又不能经过设置什么参数来设置time out,对此你能够经过装备hosts文件来加快速度,或是自己在内存中管理对应表,在程序启动时查好,而不要在运转时每次都查。其他,在多线程下面,gethostbyname会一个更严峻的问题,便是假如有一个线程的gethostbyname产生堵塞,其它线程都会在gethostbyname处产生堵塞,这个比较反常,要当心。(你能够试试GNU的gethostbyname_r(),这个的功能要好一些) 这种到网上找信息的东西许多,比方,假如你的Linux运用了NIS,或是NFS,某些用户或文件相关的体系调用就很慢,所以要当心。

      A)I/O模型

      第一种,同步堵塞式I/O,这个不说了。

      第三种,关于select/poll/epoll这三个是I/O不堵塞,可是在事件上堵塞,算是:I/O异步,事件同步的调用。

      第四种由于没有任何的堵塞,无论是I/O上,仍是事件告诉上,所以,其能够让你充分地运用CPU,比起第二种同步无堵塞优点便是,第二种要你一遍一遍地去轮询。Nginx之所所以高效,是其运用了epoll和AIO的办法来进行I/O的。

      a)一个是WriteFile体系调用,这个体系调用能够是同步堵塞的,也能够是同步无堵塞的,关于看文件是不是以Overlapped翻开的。关于同步无堵塞,需求设置其终究一个参数Overlapped,微软叫Overlapped I/O,你需求WaitForSingleObject才干知道有没有写完结。这个体系调用的功能可想而知。

      c)然后是IOCP – IO Completion Port,IOCP会把I/O的成果放在一个行列中,可是,侦听这个行列的不是主线程,而是专门来干这个事的一个或多个线程去干(老的渠道要你自己创立线程,新的渠道是你能够创立一个线程池)。IOCP是一个线程池模型。这个和Linux下的AIO模型比较相似,可是完成办法和运用办法彻底不相同。

      B)多核CPU调优


    • 关于Windows来说,咱们能够经过“使命管理器”中的“进程”而中右键菜单中的“设置相关性……”(Set Affinity…)来设置并约束这个进程能被运转在哪些核上。
    • 多核CPU还有一个技能叫

    • 技能(Non-Uniform Memory Access)。传统的多核运算是运用SMP(Symmetric Multi-Processor )形式,多个处理器共享一个会集的存储器和I/O总线。所以就会呈现一致存储器拜访的问题,一致性一般意味着功能问题。NUMA形式下,处理器被划分成多个node, 每个node有自己的本地存储器空间。关于NUMA的一些技能细节,你能够检查一下这篇文章《
    • numactl 》,在Linux下,对NUMA调优的指令是:
    • 。如下面的指令:(指定指令“myprogram arg1 arg2”运转在node 0 上,其内存分配在node 0 和 1上)
    • 当然,上面这个指令并欠好,由于内存跨越了两个node,这十分欠好。最好的办法是只让程序拜访和自己运转相同的node,如:
      C)文件体系调优

      接下来,咱们就能够调优文件体系装备了,关于Linux的Ext3/4来说,几乎在一切状况下都有所帮助的一个参数是封闭文件体系拜访时间,在/etc/fstab下看看你的文件体系 有没有noatime参数(一般来说应该有),还有一个是dealloc,它能够让体系在终究时间决议写入文件产生时运用哪个块,可优化这个写入程序。还要注间一下三种日志形式:data=journal、data=ordered和data=writeback。默认设置data=ordered提供功能和防护之间的最佳平衡。

      这儿介绍一个Linux下的检查I/O的指令—— iotop,能够让你看到各进程的磁盘读写的负载状况。

      4.5)数据库调优

      A)数据库引擎调优


    • 数据库的锁的办法。这个十分十分地重要。并发状况下,锁是十分十分影响功能的。各种阻隔等级,行锁,表锁,页锁,读写锁,业务锁,以及各种写优先仍是读优先机制。功能最高的是不要锁,所以,分库分表,冗余数据,削减一致性业务处理,能够有用地进步功能。NoSQL便是献身了一致性和业务处理,并冗余数据,然后达到了散布式和高功能。
    • 数据库的存储机制。不但要搞清楚各种类型字段是怎么存储的,更重要的是数据库的数据存储办法,是怎么分区的,是怎么管理的,比方Oracle的数据文件,表空间,段,等等。了解清楚这个机制能够减轻许多的I/O负载。比方:MySQL下运用show engines;能够看到各种存储引擎的支撑。不同的存储引擎有不同的侧要点,针对不同的业务或数据库规划会让你有不同的功能。
    • 数据库的散布式战略。最简略的便是仿制或镜像,需求了解散布式的一致性算法,或是主主同步,主从同步。经过了解这种技能的机理能够做到数据库级其他水平扩展。

    关于SQL句子的优化,首先也是要运用东西,根本上来说,一切的RMDB都会有这样的东西,来让你检查你的应用中的SQL的功能问题。 还能够运用explain来看看SQL句子终究Execution Plan会是什么样的。

    下面我依据我有限的数据库SQL的常识说几个会有功能问题的SQL:

    • 索引。关于索引字段,最好不要在字段上做核算、类型转化、函数、空值判断、字段衔接操作,这些操作都会损坏索引原本的功能。当然,索引一般都呈现在Where或是Order by字句中,所以对Where和Order by子句中的子段最好不要进行核算操作,或是加上什么NOT之类的,或是运用什么函数。
    • JOIN操作。有人说,Join表的次序会影响功能,只要Join的成果集是相同,功能和join的次序无关。由于后台的数据库引擎会帮咱们优化的。Join有三种完成算法,嵌套循环,排序归并,和Hash式的Join。(MySQL只支撑第一种)
    • 仍是那句话,详细要看什么样的数据,什么样的SQL句子,你才知道用哪种办法是最好的。
      • 字符串。正如我前面所说的,字符串操刁难功能上有十分大的恶梦,所以,能用数据的状况就用数字,比方:时间,工号,等。
      • 其它
        • 不要select *,而是明确指出各个字段,假如有多个表,必定要在字段名前加上表名,不要让引擎去算。
        • 不要用Having,由于其要遍历一切的记载。功能差得不能再差。
        • 尽或许地运用UNION ALL  取代  UNION。
        • 索引过多,insert和delete就会越慢。而update假如update多数索引,也会慢,可是假如只update一个,则只会影响一个索引表。
        • 等等。


/template/Home/News/PC/Static
var _hmt = _hmt || []; (function() { var hm = document.createElement("script"); hm.src = "https://hm.baidu.com/hm.js?3055b648e71c7d34d18c96db95a87337"; var s = document.getElementsByTagName("script")[0]; s.parentNode.insertBefore(hm, s); })();
客服中心
点击二维码下边按钮可通过微信联系客服进行沟通
QICQ支持
处理:机器咨询,产品优惠,售后处理服务器状态异常等,10分钟内响应
微信支持
工单服务
提交工单:在线工单入口
工单处理:网络延时,机器状态异常,网站备案等,10分钟内响应
投诉/合作
滥用举报:abuse@wuyouyun.com
商务合作:business@wuyouyun.com
服务投诉:微信处理入口
处理:投诉,建议,代理,大客户,我们会全力以赴满足您的服务请求