最近在做提高资源使用效率的项目,有一些思考和大家分享一下。提高资源使用效率可以从很多方面下手,比如以下几个方面都有很多工作可以做:
改进工作流程
提高员工工作效率
提高服务器资源使用率
提高软件性能
这里只关注如何提高服务器的资源使用率。
除非业务处于高速发展期,新增流量带来的收益远大于新增服务器的成本,否则公司财务和部门大佬们就会开始关注服务器的资源使用率了。在新机器采购订单提交到财务部门后,你需要有理由说明,为什么现有服务器的使用率这么低,你仍然需要订购服务器来支撑X%的流量增长?
为什么服务器的资源使用率这么低?
为了把这个问题解释清楚,让我们先定义一个概念:
***可用资源使用率:整体计算资源中,可用于满足业务需求的***计算资源的占比。
这个***可用资源使用率适用于单个服务器,也适用于整个集群。最重要的一点是,这个值远小于100%,而且一般服务器/集群的资源使用率远小于***可用资源使用率。
***可用资源使用率主要受以下两个因素限制:
冗余策略
这是***个硬性指标,假设你的冗余策略是N+X,那么你的业务可用达到的***可用资源使用率为:N/(N+X)。
以N+1为例,这允许你的业务有一个***的集群挂掉而不影响服务,理想情况下是你的每个集群规模都一样大,挂掉任何一个损失都是一样的,如果N=3,这时你的***可用资源使用率为3/(3+1)=75%。注意这个值是假设你的每个集群规模都一样大,实际中往往不是这样的,所以你的***可用资源使用率会小于75%!
随着N的变大,***可用资源使用率也会提高,如果N=7,那么你的***可用资源使用率为7/(7+1)=87.5%。但是当N变的很大时,***可用资源使用率带来的收益会被运维成本的增加大幅削减。
响应时间
这是第二个硬性指标,响应时间会影响冗余策略的制定,但是这里我们不展开讨论,将来有机会再详细介绍。响应时间的大小会很大程度上制约***可用资源使用率,为什么呢?在同样流量的情况下,根据排队论,不同的响应时间和服务队列(对应到CPU,或者机器)对应着不同的***资源使用率。
Utilizationcurve
假设你的业务由一个程序提供,这个程序每个副本需要16个CPU,那么根据排队论,为了能够在指定时间内完成业务请求,***的资源使用率大约是81%。
加上冗余策略,还是以前面的N+1,N=3为例,该业务的***可用资源使用率是75%*81%=61%。
这个***可用资源使用率只是一个理论上限,实际上业务可以达到的资源使用率还受到很多其他因素影响,导致其最终使用率会远小于这个理论值。
软件性能问题
软件的代码编写质量太差,参数设置不合理等都会影响资源的使用率,使得业务要在预定的响应时间返回结果,必须要保持较低的资源使用率。
组件间资源使用率差异
前面提到了,根据排队论对性能的影响,不同的组件副本使用不同的CPU个数,导致的不同组件的***可用资源使用率不同,进一步降低了总体资源使用率。
备用机器资源
为了应对临时的机器维修,突发业务需求,业务会有额外的备用机器,这些备用机器一般会放在业务线自己的池子里面,会进一步的降低总体的资源使用率。
资源使用率计算方法
不同的资源使用率计算方法,会对外呈现不同的资源使用率,历史平均使用率还是百分位使用率,是截然不同的两个结果。
如何提高服务器的资源使用率?
前面提到了,对于一个N+1,N=3的业务,理论上***可用资源使用率仅能达到61%,而实际中却比61%小很多,能达到40%就很不错了,那么如何从技术上来提高资源使用率,使其进一步的接近理论上限呢?
简单容易实现的:
多线程更好的利用多核机器
根据排队论,增加单个程序副本的CPU数目,可以有效提高资源使用率。
4CPUvs.16CPU
但是当线程过多时,会带来contention等问题,以及NUMA架构带来的远程内存访问都会影响资源使用率的提高。这里需要权衡,而不能一味的增加CPU和线程数目。
同一服务器上运行多个应用
既然一个程序不能***化的利用一台服务器的资源,那我们可以放多个不同的程序上去,通过共享来提高资源使用率。这个方法非常有效,但是也有它自己的问题,后面我们会提到。
增大响应时间
随着资源使用率的提高,应用的响应时间会变长,如果在满足现有业务需求的情况下,并不需要太快的响应时间,可以考虑通过增大响应时间来获得更高的资源使用率。当然,这个方法是实际操作中使用的很少,因为响应时间增大很容易,但是要降低非常非常的难!
复杂实现难度高的:
资源分层
这其实也是通过共享资源来提高使用率,不同于直接在某台服务器上运行多个程序,资源分层以后可以针对不同的层级提供不同的服务质量保证,例如保证高优先级程序的资源使用,当出现资源短缺时低优先级程序可以等待。
资源超卖
即使是通过分层的资源来提高使用率,不同的高优先级程序同时运行在一台服务器上也不会同时处理峰值流量,利用这个特点,可以对计算资源超卖,来进一步提高资源使用率。
举个简单例子:服务器S有48个CPU,3个程序运行在这台服务器上,分别请求了24,16和8个CPU,但是由于不同时处理峰值流量,在任意时刻该服务器的CPU使用率都不超过32个CPU,那么资源超卖就运行对剩余的16个CPU进行再次售卖。
提高资源使用率会带来哪些问题和挑战?
提高资源使用率有很多好处,但是事情都有两面性,随之而来的也有很多问题和挑战。
装箱问题(binpacking)
当有很多不同大小的应用,要运行在一组服务器上时,装箱问题会降低资源的使用率。比如有100个应用总计需要1000个CPU,理论上只需要209台48核的服务器,但是实际上由于装箱问题,会需要250台服务器。所以,解决装箱问题是和资源共享伴生的一个技术难题。
隔离问题(badneighbours)
不同的应用有不同的特点,有IO密集型的也有CPU密集型的,有对延迟要求很高的也有只关心吞吐量的,这些不同的应用运行在同一台服务器上,不可避免的对彼此产生影响,尤其是在机器的资源使用率较高的情况下。如何降低彼此的影响也是一个很难的课题。因为如果不能很好的隔离影响,应用则会选择要么单独运行要么申请更多的资源,从而导致资源使用率很低。
核算问题(resourceaccounting)
核算问题只存在于超卖的资源上,因为超卖的资源只能提供较低的服务质量保证,所以价格一定会更便宜,但是依然需要准确的衡量。
如何衡量提升资源使用率是否成功?
首先要保证的是,不能降低业务的稳定性和可靠性;其次是带来的收益要大于成本;必须是一个持久的过程,而不是短暂的。
要权衡带来的收益和成本,也许提升X%的资源使用率会增加YY毫秒的请求延迟,由此带来的收入损失可能远远大于X%的提升带来的收益。再有就是使用率的提升可能伴随着运维成本的暴增,这些都是需要衡量然后取舍的。
结束语
提高服务器资源使用率,是一个跨越部门和技术边界的问题:首先要确保的是最小化对业务的影响,通过准确的衡量系统计量应用对资源的使用情况,利用底层基础设施实现资源共享并最小化隔离问题,从而***程度的利用已有计算资源。