如何解决有限的资源和运算能力分配问题

近日在工作上遇到这么一个问题,我们公司的应用在现场服务器环境中运行中,发现了一些问题,比如一个完整产品的某个模块处理数据的进度在产品升级后变得较之前缓慢,甚至在刷新数据方面完全失效,进而导致前台报表没有展示出近期的业务数据。在解决开始阶段,就遇到了现场的数据库超过最大连接数的情况,所以无法对失效的数据库对象进行更新等操作。无奈之下,现场运维同事就协助对数据库进行了重启,重启之后,数据库恢复服务。紧接着,主管召集大家开会,探讨针对这些运行中的问题的解决方案,一番讨论之后,结果,解决方案全是针对程序的逻辑处理过程的优化,其实这样的优化,相对目前版本来说,从程序层面来讲,理论上完全可以改善目前所暴露的问题。但是有这么一个信息,就是这次服务器上部署了多个应用,而且数据库也是公用的,这就自然而然地产生这么一个问题,产品在公司发布前,实验室的测试环境是一台服务器和专用数据库,结果没有测出某模块处理数据进度比预期慢的问题;而产品实际的运行环境中有数个应用在运行,准确地讲,是多个应用在共享有限的服务器资源和数据库的运算能力,从而产生了目前所出现的这个问题。

从问题表面上,可以这么简单地理解,就是因为程序运行所需要的资源出现了紧缺,所以在完成任务的过程中出现了异常。那么应用们在运行中,是如何争夺资源和运算能力,这些有限的服务器资源和数据库的计算能力又是如何分配给应用的呢?应用以目前的水平,在拥有多少资源和运算能力下,可以很稳定地运行呢?如何这个问题可以得到一个准确的回答,那么优化方案方面结合程序范围的解决方案的话,应该就是一个相得益彰,相当有成效的优化。这就是我今天想请教大家的问题?谢谢大家

[该贴被admin于2011-12-23 09:21修改过]

2011年12月22日 15:03 "@KenWT"的内容
那么应用们在运行中,是如何争夺资源和运算能力,这些有限的服务器资源和数据库的计算能力又是如何分配给应用的呢?应用以目前的水平,在拥有多少资源和运算能力下,可以很稳定地运行呢? ...

这个问题实际就是我们经常讨论的软件可伸缩性Scalable或可扩展性问题。

第一步:应用服务器和数据库服务器的资源和计算能力没有均衡分布,你这个案例是几乎负载都集中到数据库上了,而应用服务器闲置,解决这个一现象可以通过在应用服务器中引入缓存的方式。

第二步:如果应用服务器的缓存丢失率高,说明应用服务器和数据库服务器负载都很高,那么我们可以在应用服务器和数据库服务器之间引入分布式缓存如memcached。

现在架构是:
client -- > 应用服务器 (in-memory Cache) ---> memcached ---->DB

下一步就是引入云计算技术:
云计算有两种方式:一种是自己引入云计算组件,做私有云:比如对于一些复杂计算耗费CPU且频繁调用的报表计算,比如数据仓库挖掘等可以使用云计算Hadoop;对于爆炸增长的大数据量引入NoSQL等等。

另外一种是租用现有的云计算平台,租用公有云,比如Google和Amazon。


2011年12月22日 18:18 "@banq"的内容
这个问题实际就是我们经常讨论的软件可伸缩性Scalable或可扩展性问题。 ...


帮主,您好,首先对您的回复表示感谢。您讲得可伸缩和扩展性问题,这方面的理论,我目前尚且略知一二。不过我认为您的答复并没有正面回答我所关心的核心问题,那就是部署在服务器上运行中的应用们是如何相互争夺资源的?有点类似多线程的调度(要么虚拟机管理调度,要么操作系统负责),可是应用们获取运行时所需资源的多与少,这个地方的调度管理究竟是由谁,什么规则来调度呢?希望大家多多讨论,谢谢

2011年12月22日 22:52 "@KenWT"的内容
部署在服务器上运行中的应用们是如何相互争夺资源的 ...

首先:编程时尽量避免多线程的资源争夺,多线程有一个致命问题是资源争夺,那么难免使用锁,这些都是导致资源利用率下降的根本原因,因此,在目前多线程编程中,尽量使用不变性,或者直接使用缺省是不变性的语言Scala。这些都能避免资源纠结与争夺。

其次:无论微观如何争夺调度,我们也需要在宏观整体进行调度。在程序中多引入异步,异步可能到来最终一致性,这些都需要根据情况选用,尽量避免或缩小事务或数据库锁JDBC等锁定资源的使用范围。

这里有一个消耗资源大小或耗费性能的排列:
基于内存异步事件 ---> 内存锁 --->事务锁 --->数据库锁。
越是后面,性能越差,可伸缩性越差,资源利用帅越差,闲置率越高。

这里比较一下异步和通常同步,也就是你们现在架构的区别:
同步情况下:当你发出请求必然有一个响应结果,但是你可能接着还需要继续其他更多处理,不是立即用到这个响应结果。
这样,你不必发出请求后,就在那里傻等响应结果,而是继续做你其他更多处理,直到需要它时才过来取。
生活中排队,你去买两样东西,一样东西需要排队,那么先买不需排队的,再过来买。

等待时线程会闲置,会消耗系统资源。对于一个高交互量的系统,线程闲置数= arrival_rate * processing_time。如果arrival_rate很高,闲置数将非常高,系统工作在一个非常无效率的状态。

我上面的一个帖子是提出了解决办法,这个帖子是解释了原因,希望能够帮助到你。

在自己测试环境自己的软件是正常的,而到生产现场则不正常,这个现象非常普遍,主要是我们以前只考虑功能,没有过多考虑运营复杂状况,还有测试部门对生产现场的数据采样没有跟上,能够尽量模拟生产现场,其实最终结的办法是Event Sourcing,使用一个NoSQL将所有用户操作事件日志保留下来,然后在调试环节回放。

只有采集数据接近现实,你就能通过调试判断:应用以目前的水平,在拥有多少资源和运算能力下,可以很稳定地运行。

如果你觉得这样的数据难以获取,那么就采取可扩展的云架构,通过虚拟化技术和自动伸缩扩展功能,随着你的资源和运算能力多少,自动调配资源。
[该贴被banq于2011-12-23 09:19修改过]

感觉LZ的几个问题处于猜测阶段,需要有手段验证你的问题。
1.多个应用部署到同一个服务器,是否因为应用服务器满负荷(同服务器的其它应用占用很多)导致你得产品运行慢。
2.共用一个数据库,由于其它应用占用数据库资源过大导致数据查询、处理速度慢,从而导致你得产品慢。

对于第1个问题,可以通过监控服务器 硬盘、CPU等情况确定服务器是否满负荷了?对于第2个问题,可以通过监控数据库运行的SQL语句,SQL语言运行的效率,服务器运行的效率来判别是否数据库满负荷。

如果是以上2个问题导致的,那么就只能增加服务器解决或者移走其它应用。

但是,在验证上面2个问题之前,你是否确认你得产品在生产环境下是正常的。是否跟踪过你的产品处理过程每个环节,是否有调试每个环境处理的时间,性能等情况?

首先多谢楼上两位热心道友的回复!不客气地说,你们的答案我都不满意(请原谅我这么说,也许有些不礼貌),为什么说不赞同呢?因为我觉得你们还是没有深层次分析问题,帮主给的回复过于高深宏观,但是缺乏针对性深入性,而最后回复的这位道友,则完全是停于表面,其实你完全不必在乎我是推测或者猜测,面对这个问题,你完完全全可以客观认真地以自我的形式来分析这个问题,面对同一个问题,应该完完全全拿出自己的分析来交流。而在此我真正想要的回复是一定层面的深入透彻的分析,分析透了,问题自然迎刃而解。

在此稍微说点题外话,其实,大家在遇到问题的时候,我感觉往往过于着急得到答案,其实这完全是不符合真正意义编程的风格的,问题的提出源自深入的思考,问题的解决绝对百分之九十九是分析,分析透了,解决自然不成问题。点到为止,我不想做一个大嗓门扯“大道理”的人,我还是鼓起勇气重拾C吧,不了解底层的程序员得真实地面对自己的提升瓶颈了,我给自己列好了一个长长的书目,你呢?大家多努力吧,谢谢。

呵呵。。。LZ,其实banq给你指出的是一条明路,但你显然没有听进去。你与其去看C,不如好好把这个论坛里的帖子好好地研读一番,也许更有收获。
另外,不要一出问题就老拿基础说事。不要动不动就拿C说事,如果那样我还可以建议你重拾汇编,那样的效率更高。

噢,看来LZ的问题很高深啊!还不是一般人难解决。


[该贴被BinnyJ于2011-12-25 20:09修改过]

2011年12月24日 14:03 "@flyzb"的内容
呵呵。。。LZ,其实banq给你指出的是一条明路,但你显然没有听进去。你与其去看C,不如好好把这个论坛里的帖子好好地研读一番,也许更有收获。 ...

我觉得大家是不是都没明白楼主的意思呢?
楼主想要的应该是:"想知道操作系统是如何对资源进行分配,它为什么要这么分配,运算能力又是如何分配的,分配的规则是什么?"
而不是问大家这些问题要如何解决.

2011年12月25日 23:38 "@ronalfei"的内容
我觉得大家是不是都没明白楼主的意思呢?
楼主想要的应该是:"想知道操作系统是如何对资源进行分配,它为什么要这么分配,运算能力又是如何分配的,分配的规则是什么?"
而不是问大家这些问题要如何解决. ...


ronalfei同学说得对。这就是我关心的核心问题,大家多多讨论,我不着急,有什么新的想法,我也会及时发帖子说明的,谢谢大家

2011年12月25日 23:38 "@ronalfei"的内容
想知道操作系统是如何对资源进行分配,它为什么要这么分配,运算能力又是如何分配的,分配的规则是什么 ...

我不反对探究底层机制,Disruptor也是因为LMAX团队研究到CPU的缓存后才发现64字节特性。据我所知,不同的操作系统和硬件,支持不同的策略的资源分配和运算,比如Java中常讲的CAS一般需要底层操作系统支持,可在这方面研究,推荐这个帖子:The Art of Multiprocessor Programming多线程编程艺术

不过因为操作系统对资源的调配就是我们了解了,很多时候我们无法干预控制,操作系统提供那么多的多线程可能难以编写使用,所以,业界就产生了另外两个方向:一是回避内部,转向外部,通过增加服务器水平扩展Scalable;另外一种不使用多线程,而是使用单线程,比如Node.js。这些问题讨论可见我这个新帖:Why AsyncFP 引起的一场争论
[该贴被banq于2011-12-28 09:52修改过]

首先,谢谢帮主的回复。而且这种风格是我非常喜欢回复。就是我只给你一个我的指向,在我并没有完完全全理解你的问题之前或者没有百分百完全类似的经历经验的时候,告诉你应该读些什么书,或许会让你对该问题有进一步理解和帮助。

其次,我还想说的是,其实这个话题真的有点意思,初接触Java的时候,就在很多地方听过这么一句话,java是一种健壮的开发语言,虽然这个健壮有一些共性的理解,比如说异常处理机制等。但是其实我提的这个问题,应该可以算对健壮性的一个拓展的解决吧,比如你我他,咱们三个应用在同一个服务器上跑,公用一个数据库,如果说我比较“健壮”的话,和操作系统服务器数据库的关系还比较“铁”的话,按照这个逻辑,我一个人吃一碗饭,或者咱们三个人吃一碗饭,我都不用担心自己会吃不饱。近而可以联想到,程序的可靠性是不是大大增强,环境及时发生了预想的若干变化,我都有自身的适应能力,以保证我的任务始终都能顺利完整地完成呢?其实很多时候,我们都习惯于一遇到问题,赶紧从我们的程序里找问题,这当然也无可厚非,但是程序是否能很好地完成自己的使命任务,显然并不完完全全都取决于它自身,它也有自己的委屈和苦衷,也希望自己霸道一点,不变应万变。要达到这个期望目的,这个方向我个人觉得值得大家进一步探讨钻研。共勉吧,谢谢大家。

2011年12月28日 10:35 "@KenWT"的内容
该可以算对健壮性的一个拓展的解决吧,比如你我他,咱们三个应用在同一个服务器上跑,公用一个数据库,如果说我比较“健壮”的话,和操作系统服务器数据库的关系还比较“铁”的话,按照这个逻辑, ...

问题就出在“健壮”上面,由于健壮稳定需要,就特别耗资源和时间。你见到比较铁的哥们儿要多说几句话吧,这就耽误时间没空招待新来的其他朋友。

以TCP和UDP比较,TCP比UDP健壮,但是UDP要轻量性能高,UDP可以通过反复来避免健壮问题。
[该贴被banq于2011-12-28 17:10修改过]

最近读了一本书《深入理解Java虚拟机》,该书第五部分是高效并发,这块内容对于该贴话题提出的问题有一定得帮助理解的作用,有兴趣的道友,不妨看看
[该贴被KenWT于2012-01-13 13:26修改过]