WEB(事务型)系统软硬件生产力、可靠性,稳定性及其它质量方案(MAP/REDUCE:HADOOP)

操作系统理论毫无任何理由地“认为”分时调度优于批处理调度。

严重怀疑这是IBM的一个阴谋:即利用分时策略浪费用户的大型机资源。以便销售出去更多的当时很赚钱的大型主机。因为分时理论的提出时间正好是IBM的大型机最好卖的时候:1960s(又象是1959。反正那几年)。

WEB服务系统架构的主要目标是事务处理或请求处理(软件架构的目标驱动论认为架构并没有唯一的评价标准。因为架构的目标不同,所以评价标准也不同。这曾导致架构学研究方向的转变。因为目标不同,学界或业界自然就都没有办法得到一种通用的架构模式。还是那句话,存在的就是合理的。存在的东西就都是有用的东西。但有用的东西这么多,所以架构学就只能退缩到方法体系的范畴去搞研究了。所以说,架构界目前的研究方向是完全正确的),强调的是性能:如软件(小)系统通量,环境(大)系统通量,响应能力等指标。

这个目标不象它看上去那么难以达到。因为完全得满分的系统是不存在的(题目有多大都不知道,如何得满分。比如,一个炒股者的成绩应该要如何去衡量呢?首先,完全的满分显然是不可能的。因为未来有多少分都不知道,又如何知道满分是多少分呢?完全的满分即意味着预测未来)。但存在合格的系统

对于任何系统来讲,可用得上的资源是有限的。所以,只要我们保证了系统的每一个CPU或外部设备在时间上都被充分利用了(这是一个逻辑上的完全划分)以完成系统所接受到的任务(为完成这些任务而增加的额外的内部服务如OS的进程管理,内存管理等任务是不算的。这些是我们的成本。只能考虑缩减,不能消除),也就是说,系统的本地性能得到了最大程度的发挥(通过使用即定的作业调度策略),就是一个合格的调度(超出合格部分的系统目标可以通过对已存合格系统的简单复制来完成。简单地说,就是增加资源)。

首先需要对目标本身的标的进行定义(现行OS正因为忽视了这个阶段,才留下性能这个大BUG给我们去对付的。多道程序或多任务的实质与单任务其实区别并不大------只不过是同时运行几个程序的问题。OS的逻辑是构建一个“能”的系统,而不是一个“高能”的系统。造成这个问题的原因就是分时系统(注意一点,分时被用作OS的一个类型提出来,而不是一个调度策略提出来)。如前面提过的,分时系统------最少表面上,IBM提出或使用它的原因是大型机的资源共享---又或者,至少表面上,分时共享象是能最好地满足共享的目标------从1960年留存到今天50多年的时间,分时共享主机的环境早已荡然无存,但分时却如此深入人心。象是分时早已经解决掉所有的问题)。

面对这种情况,我只有两个字------无语。

反正,操作系统与作业有关的研究到多道程序(进程)设计以后,就嘎然而止。计算机系统的生产力研究也就到此为止。

究其原因,有可能是因为有了多道程序设计,操作系统看上去已经可以完成“所有的”任务,看不到任何需要继续发展的动力。也有可能是别的原因(如我前面所述,大公司的影响。包括IBM。或者微软。。。。。。微软在OS市场的垄断严重阻碍OS的发展早已成为既定事实。并且,这样的结论并不是对开源社区的否定。因为一个商业化的竞争环境,显然比起一个民间社区对产业进步更有帮助------并且,这很可能是为什么近年来大型公司改变对开源社区看法的根本原因------开源社区不但不会革掉他们的命,反而有可能帮助他们起死回生------这世上,难道还有什么比垄断与开源的共存更和谐的吗?)。

生产力?

OS的多道程序设计理论中的任何一种调度策略,其所消耗的处理器资源都是相等的。因为要做的工作并不会因为你使用什么策略而多一点或少一点。即,如果不考虑代码效率或OS效率的话,一个任务,不管使用哪一种进程调度策略工作量都是相等的。但工作量并不等于生产成本。处理器要工作,必须依靠内存(至少在现在的硬件体系结构下)。显然,即使在分时共享的环境下,由于存在着用户等待时间上(其实真正的执行时间也会略许区别的)的区别,不同的调度策略,所使用的内存资源是不一样的。因为用户或用户例程在多任务并发时将被迫等待,会造成内存资源消耗量的区别。注意,这里的资源消耗“量”指的是内存空间与时间的乘积。即,当我们说消耗了内存资源的时候,指的不只是空间的消耗,还包括在时间上的占用。理由很简单,假如某个程序所占用内存的时间为0,那么便可以认为内存没有被消耗过。而如果这个程序所占用内存的空间为0,自然更可以认为内存没有被消耗过了。这个还有个更恰当的比喻如我们借钱的时候经常会跟人说:“我很快就会还给你的!”。

完全一样的道理。

但是,分时或进程的出现,加上段式与页式存储,封住了所有程序员们贪婪的嘴(或者,一部分程序员仍然会讲:“我会还给你的!”------但这次没有了“很快”两个字。因为一方面内存变得很“便宜”或随便可以得到,大家都没必要太“小气”;另一方面,随需而调或者说spontaneous的调用机制使得系统变成一锅庞大无比的粥。没有人知道自己的调用到底什么时候可以返回。也没有人知道自己的指令到底会造成什么样的后果------这就是面向对象的后果。因为这种情境其实正是现实世界的最真实反映------大家都只不过“希望”它可以快点返回------这样的系统,用于现实虚拟非常合适。但并不适合任何具有明确目的的或对组织性,纪律性要求非常强的计算目标。它只适合那种最散漫的主体环境或“自然经济”。芸芸众生,不是现代社会的生产模型。现代社会的生产模型是组织化,集约化,规模化------弱肉强食!)。他们得到了几乎是“无限制”的内存空间。没有内存,开口就是了。人有多大胆,“地”有多大产。虚拟内存在把程序员从受限的地址空间中“解救”出来的同时,也把他们全部“解放”了出来。他们从此不再需要受任何局限。他们开始想写多大的程序,就写多大的程序。

可问题是,“地”真的有那么大“产”吗?程序员真的“解放”了吗?其实没有。为什么说没有呢?很多人可能会说原因是内存很贵。非也!很接近,但非也。我们解放不了的原因是,内存虽然不贵,但它也并不是不要钱的东西。它是个有价值的东西。它是有限的。它并不象操作系统/计算机系统所告诉我们的那样是无限的。想象一下,32位机的时代,要是真的有4G内存该有多好啊?现在看看吧。给你4G,你想干什么?

所以说,什么才是真的好呢?

一个进程,在任何一个时刻,其实需要的空间是有限的。给予其完全自由的内存资源控制,是一种严重的浪费。

民主是有代价的。资本主义,社会主义?现在非常清晰的一个方向就是,完全一边倒的姓资或姓社其实都有问题。这个其实不过是“存在既合理”说的第N+1次证明而已。继续的讨论其实没有任何意义。方向其实也很明确,即民主是要的,集中也是要的。两者都要扬长弃短!

所以才需要制定一个合理的内存开支策略。

那么,想做到合理开支,第一步当然是认识到并随时意识到一点:内存不是也不应该随意扩充。

即,从现在开始,我们不能再象以前一样,想要一个什么东西就 new 一个什么东西;想调用谁就调用谁。这样做的结果是放任系统进入一个未知的,有风险的,并且随时可能崩溃的状态。我们都知道状态机理论只研究有限状态机而不研究无限状态机。原因就是无限状态机的状态不收敛。这样的系统是无法预测的。计算机系统是一个目标导向的系统。它被期望永远处在受控的状态,以保证其随时提供服务的能力。

在创建新对象或调用以前,你必须得考虑你的房间到底有多么大,能“坐”下或“站”下又或再极端一点,能“塞”下多少人?不考虑这个的后果就是,要么PARTY开不成,要么房子被挤塌下了。因为你的房子并不象它的说明书中说的或经纪人曾经告诉过你的那么大。并且,即使你的内存真有那么多,以CPU的速度,要花完它,也不过是几秒钟的事情。

即然内存并不是可以随便“花”的,那么调度便是必须的(不要再跟我提进程调度------因为那不是调度。进程调度存在的原因便是让你“不调度”。How does that work out? Why and what we are discussing now?)。

要调度,就必须对系统进行划分,以得到一定的调度单元。

第一个划分是外部任务与内部任务。这个划分的目的是理清目标与途径的区别。外部任务是我们的目标。内部任务是途径。目标是调度不了的(暂时将其考虑为调度不了的。因为在环境调度的上下文中,目标其实也是可以调度的。只不过这个已经超出软件调度的范围,暂时不讨论)。我们能调度的是途径。即我们采取用来完成任务的系统组件(执行单元)。而“调度”的目标即:

1,形成一个独立于外部,与外部无关的内部生产过程(这个是我们调度的标的);

2,本地资源的充分利用(如前所述,外部资源也是可以调度的。而且调度思想与内部资源的调度是等同的。只不过因为调度环境不同,存在一些硬件相关的影响。但思路与原则还是一样的。HADOOP就是这么工作的。HADOOP眼中,是没有硬件的。硬件在我们的心中);

3,解决高峰问题。根据相关研究,峰值一般在平均值的8-10倍。而且,这还只是个一般的数据。意思是更极端的情况不排除级数式的负荷增长。

4,用户满意的响应延迟。

第二个划分是系统内部的工作元素。

这个涉及到系统的任务模型。即系统的生产计划。根据前面讨论过的,调度的目的是本地性能最优化。本地只有三种资源:CPU周期,内存资源(内存容量*时间),I/O资源。

CPU周期的充分利用很容易,只要剪除了重复代码,使得所有周期都在做有意义的事情,CPU周期这个资源就算是得到了充分的利用。无需再进行任何优化(有的话,暂时将其归为CPU本身的技术优化。如果真这么干,那么不优化就是最好的优化。因为CPU优化时假设的是通用型应用或领域型应用。太特殊的应用或代码,是很难得到那些芯片巨头的青睐的。)。

内存资源是最大的系统性能变化因子。我们知道,只要有内存,系统(CPU)就可以继续工作。所以,系统执行引擎的内存模型是很重要。目前的栈模型与堆模型显然都是存在问题的。首先,堆模型除了在一些智能程序如推理,学习,神经网络或领域分析建模中,显然不适合事务型的系统(事务系统不喜欢长期占据内存的例程或对象。除非是“自己人”);而栈模型除了在一些紧耦合的系统如TCP/IP协议栈,其它一些层状系统(不是目前普遍应用分层架构的那些系统。因为应用分层架构的系统并不一定适合分层。而应该分层的又不一定得到了分层。层状系统指的是那些应该分层的系统。不管有没有得到分层)中,显然是一种极其浪费的内存模型(想象一下现在业界主流提倡的N层理论。假设10个层。那么系统内存最少被浪费一半------其实不止。因为底层的I/O操作需要相当长的时间来完成。如,假设I/O的时间开销仅10倍于其它层。那么在栈式模型下整个内存的开销将被浪费(10*10-9-10)/19=4)倍。

而且内存资源最大的问题是,它的投入产出比并不是线性的。因为一旦内存不够,系统将启用虚拟内存。而虚拟内存的启用,根据前面的分析,很可能本身就是由I/O操作引起的。于是形成典型的以己之茅,刺己之盾。特别是在WEB应用中,请求来得非常快,一张吉比特的网卡就足以吞没整个存储系统。象所有大灾难一样,当面对这种情况时,唯一的希望便是向老天祈褥灾难快点过去(或者重启系统)。

解决栈模型问题的最佳手段是分而治之------将原来的“大”栈分为多上“小”栈。这些“小”栈可以用来完成一些阶段性的内部作业,以产生一些中间结果。而作业之间则通过这些中间结果进行工作对接。这样一来,虽然总的内存需求量没有变,但作业在(必需的)内存驻留的时间却大大减少了。因为,每一个子作业在内存的驻留时间从原来的从整个作业开始到整个作业结束缩减到从当前子作业开始到当前子作业结束即产生中间结果之间的长度---很明显,整个作业结束的时间比起当前作业结束的时间要长得多。这一点在大型分层系统中尤为突出---这个问题的根源在于“同步调用”机制本身。可以想象一个一千个调用的事务。这样的调用并不是不可能的。比如在Web上进行一个同步的Web Service链调用。每一个调用必须等到后面所有调用全部返回以后才能从内存或系统退出。相对于本地即同地址空间调用,在Web调用的情况下,这意味着浪费的将不仅是内存,还有本地的网络资源,或其它抽象级别再高的资源如进程资源,服务资源等。在这之前,系统必须允许其一直驻留在内存,因为内存保留了这个事务的状态。这些状态一旦被清除掉事务将无法继续。当这种调用被应用到系统边界上时,出现了严重的IO问题,最终导致AIO的被提出。于是大家都以为我们所遇到的问题不过是个I/O问题。正是这个认识严重阻碍了对躺在那里好久的真正问题的发现。而付出的只不过是一些保存中间结果或所谓“消息”的内存空间(见SEDA相关资料)。

底层I/O可能浪费(因为同步等待而导致被闲置的,但却又不能被其它任务或系统利用的内存资源---注意,不是内存空间。是资源。因为资源=空间*时间)的内存资源数量近似估计为:

(全部调用需要的内存空间-底层IO调用需要的内存空间)*底层IO调用需要的时间

之所以这么算,是因为对于 全部调用需要的内存空间-底层IO调用需要的内存空间 来说,时长为 底层IO调用需要的时间 的等待过程是毫无必要的(有极少数情况下必要,这里不考虑那种情况)。没有必要的等待,当然会引起浪费!想象一下你坐在餐厅的桌子旁边等待你的食物,在你点的食物被端上来以前,那张桌子在你等待的这段时间里被浪费了。正确的操作可以是你点菜,然后把桌子让开,让别人也可以点菜。这样可以加快餐馆整体上的利用效率。这样,一旦厨房完成当前的工作,不会因为没活干而空转而重复之前的问题。。。。。。这个案例如果继续进行分析,完全可以从中导出下面所讨论的系统调度策略,或称资源利用计划(又或计算机系统ERP)。但这样做太辛苦,理解上需要反复地在桌子与内存之间进行思维比拟。后面的思路更简单明了一点。

另外,从这个计算公式很容易看出,底层以上调用需要的内存空间越大,浪费的内存资源越多。假如底层以上没有调用或不需要内存,那么基本上可以认为没有被浪费的内存资源

而关于中间结果有一个很能够帮助理解的例子就是尾递归。根据资料显示,很多编译器都具有优化这种递归的能力。因为这样的递归可以被转化成循环(循环与递归是不同的)来实现/编译。

SEDA是个很好,很简洁的执行框架,但是它有一个很大的问题------调度------没有解决。

或者说,其仅提供了一种调度------即顺序执行。这是个不可原谅的错误。因为阶段与语句一样,存在着一个流程的问题。程序本身就是一种调度,所以才能够提供服务(一直往下跑的程序是很少的。所以处理器中才有跳转指令的存在)。不管它的单元是语句还是组件。调度都是必须的。现在出现的ESB,规则引擎,工作流等流程技术都具有调度的能力。一个没有调度能力的执行框架,是没有任何用处的。SEDA的指导说其目标是提供一个简单的分阶段事件驱动执行架构,调度由阶段自己完成。这个框架是由一个学生提出来的。我们知道学院派的东西的特点:很优秀,很烂。

他们提出的东西,总是能让你没话说!

我研究SEDA这么多年,真的不太想否定它。但该SAY NO的时候还是得SAY NO。

排除了SEDA,重新回到函数式编程。研究了一大堆语言如ErLang,Stackless Python,Scala,F#,Ruby On Rails,甚至重新研究了一下java,发现还是吹的成份比较多。真正能拿来做企业应用的,总觉得有点差距(我对FP的了解可能还非常肤浅,但根据网上所传美国一个大学教授所教导它的学生的话:闭包就是带有数据的函数,对象就是带有函数的数据。白猫黑猫,抓到耗子就是好猫。本文的结果也从很大程度上证明了好东西不一定要艰涩。不过话说回来,FP到底行不行,还得走着瞧)。难道一定要用Map/Reduce?

于是回头再研究Hadoop的Map/Reduce,发现其远远不止函数式编程那么简单。

一个最有说服力的例子是,它连调度都做成了插件。只能说,野心悖悖。野心悖悖啊!

年纪不太轻的人,大多不大喜欢所谓“大道至简”的东西。觉得那是对智慧的污辱。看了Map/Reduce,才发现,矛盾在这里得到了统一。即,事物的复杂性与简单性,本就是个对立统一面。由简入繁,由繁入简。

比如,初看SEDA,你会发现它的思想是多么地单纯,却又多么地有效(对于以事务处理为目标的系统架构)。SEDA的分阶段事件驱动,其实就是一种流水线思想,完全取自制造业的生产(资源)计划理论(流水线思想本来就是ERP理论中的一个部分)。然而,水只能有一个方向,所以流水线是个单向流程。而且流水线的速度是由其中最慢的那个工位(阶段)负责的。SEDA的理论对这个问题的解决办法是自治。让阶段自己去处理协作的问题。这样一来很显然,SEDA的简单来自于的是它所偷掉的懒(象很多别的流量系统一样)。如公路交通系统与计算机网络。这些系统在初步的设计中都没有(充分)考虑过流量问题(同样的,大部分设计都这样。因为学界一直在采用错误的思路:环境上下文---问题域---解决方案。这是一种完全平面化,静态化的思路,把时间这个关键因子完全排除在外。任何系统,刚开始考虑的都是“能”不能的问题,而不是“高能”。思路总是从现有问题开始的------还好有问题的存在,不然人们根本就不会思考,与时间完全无关。殊不知我们一直在用静态的方法去解决时变系统的问题,不落下顽疾,才怪!),从而导致后期应用出现大量的难以解决的性能问题(重新设计当然能部分解决。但如从一开始就有详细的调研,结果肯定要好很多)。

 

你可能感兴趣的:(hadoop,调度,批处理,MAP/REDUCE,分时共享)