介绍 当分布式系统编程成为你生活中的一部分时,你需要经历一段学习曲线。这篇文章描述了一下我当前在这个领域大致属于哪个层次,并希望能为你指出足够多 的错误,从别人的错误中学习,从而使你能以最优的路径通向成功。先声明一下,我在1995年时达到第1级,我现在处于第3级。你自己属于哪一级呢? 第0级:完全一无所知 每个程序员都从这一级开始。我不会在此浪费太多口舌,因为这实在没什么太多可说的。相反,我会引用一些我曾经经历过的对话,为从未接触过分布式系统的开发者们提供一些建议。 对话1: NN:“在分布式系统中,复制是个很容易的操作,你只需要让所有的结点同时存储你要复制的东东就行了”。 另一段对话(从我记忆深处挖出来的): NN: “为了我们的第一人称射击游戏,我们得写一个自己的网络处理引擎。” 我:“为什么?” NN: “虽然已经有一些优秀的商业引擎了,但获取license的费用非常高昂,我们不想为此买单。” 我:“你之前对于分布式系统有什么经验吗?” NN:“是的,我之前写过一个套接字服务器。” 我:“你觉得你要花多久能完成这个网络引擎?” NN:“我想2周吧。保险起见,我计划用4周时间。” 好吧,有时候还是保持沉默比较好。 第1级:RPC RMI是一种非常强 大的用来构建大型系统的技术。事实上,这个技术用Java来描述的话,结合一些工作的例子可以在短短几页纸内描述清楚。RMI技术非常令人振奋,而且它很 容易使用。你可以调用你所能绑定到的任何服务器资源,而且你可以构建出分布式的网络对象。过去人们常常为构建复杂的软件系统犯难,现在RMI打开了这道大 门。 —— Peter van der Linden, Just Java(第4版, Sun Microsystems) 我先声明,我并不是说这本书很烂。我清楚的记得这本书读起来很有趣(尤其是章节之间插入的轶闻),我曾经学习Java的时候就是用的这本书(太久以 前了,简直不像在一个时空里似的)。一般情况下,我觉得作者说的挺好。他对RMI的态度就是典型的分布式系统设计的第1级水平。处于这个等级的人对统一的 对象有共同的看法。事实上,Waldo在他们著名的论文“a note on distributed computing”(1994)上曾深入描述过,这里我做下总结: 我所倡导的写分布式应用的策略可分为3个阶段。第1阶段,写这个应用时不用担心对象 存储的位置,以及它们之间的通讯如何实现。第2阶段,通过具体化对象的位置以及通讯方法来调整程序性能。第3阶段,真枪实弹的测试(网络隔离、机器宕机等 各种情况)。这里的思想就是,不管一个调用是本地的还是远程的,对程序的正确性都不会产生任何影响。 同样还是这篇论文,随后进一步挖掘了这个主题并展示了其中的问题。这个观点是错误的,而且已经错了快20年。不管如何,如果说Java RMI达成了一个目标,那就是:就算你从等式中拿掉传输协议、命名、绑定以及序列化,它还是不成立。能记得起CORBA的老程序员们同样也会记得它也是不好使的,但他们有一个借口:CORBA还在同各种底层的问题缠斗中。Java RMI将所有这些都抛开了,但使剩下的问题变得更为突出。其中有两点,第一点纯粹就是个麻烦: 网络不是透明的 让我们看看这段简单的Java RMI代码示例(同样取自Just Java一书)
想要使用天气服务的客户端需要这样做:
客户端代码需要将RemoteExceptions考虑在内。如果你想看看你究竟会遇到什么样的异常错误,可以看看那20多个子类的定义。这样你的代码就会变得丑陋,好吧,这个我们就忍了。 局部性错误 RMI的真正问题在于这些调用可能会出现局部性失败的情况。比如,调用可能会在对其他层的请求操作执行前失败,又或者请求成功了,但之后的返回值又不正确。引起这类局部性失败的原因非常多。其实,这些故障模式正是分布式系统特性的明确定义: “分布式系统就是某一台你根本意识不到其存在的计算机,它的故障会造成你的计算机无法正常使用。” —— Leslie Lamport 如果这个方法只是去检索天气预报,出现问题时你可以简单的进行重试,但如果你想递增一个计数器,重试可能会导致产生0到2次的更新,结果就不确定 了。这个解决方案应该来自幂等操作,但构建这样的操作并不总是可行的。此外,因为你决定改变方法调用的语义,那你基本上就承认了RMI与本地调用是不同 的。而这也就承认了RMI实际上是个悖论。 不论什么情况下,这种范式都是失败的。因为网络的透明度和分布式系统的架构抽象从来就是无法实现的。这也表明了某些软件所采用的方法比其他软件为此 所受到的影响更多。Scrum的一些变种方法中倾向于做原型化。原型更集中于“好的方面”(happy path),而好的方面通常都不是问题所在之处。这基本上意味着你将永远停留在第1级的水平。(不好意思,我知道这是个小小的打击) 那些脱离了第一级水平的人懂得对于需要解决的这个问题,我们要有足够的尊重。他们摒弃了网络透明化的思想,从战略性的角度来处理局部性失败的问题。 第2级:分布式算法 + 异步消息传递 + 语言级支持 OK,你已经学习了分布式计算中的悖论是什么。你决定吞下这颗子弹,然后对消息传递机制建模,以此显式地控制出现失败的情况。你将应用分为两个层次,底层负责网络和消息传递,而上层处理消息的到达,以及需要处理的各种请求。 这个上层实现了一种分布式状态机,如果你去问设计者这个状态机是用来做什么的,他们可能会这样回答你:这是建立在TCP之上的一个Multi-Paxos算法实现。 |