一. Java 的不足
如何构建一个分布式可扩展的Java服务器?首先我们要非常了解Java构建网络应用的优点及不足之处。
Java网络架构的基础是RMI远程调用。RMI是一种成熟稳定方便的应用,它的不足主要有

1) 没有安全隔离机制,一段代码的不稳定会造成整个node failure
2) 没有接管及远程监控机制,失败不能由另外一个程序或另外一个节点接管
3) RMI是C/S结构,通常是一对一, Client无法选择多个Server,无法切换Server,无法转移Server,如下一个典型的 Java RMI Spring配置

<bean id="timDemoService" class="org.springframework.remoting.rmi.RmiProxyFactoryBean">
    <property name="serviceUrl" value="rmi://server:1199/fooService"/>
    <property name="serviceInterface" value="com.foo.TimDemoService"/>
</bean>

上面的 timDemoService在JVM系统启动时候就加载,client/server就已经固定。
4) RMI是单向的,只能 client 调用 server, Server 调用 Client需要另外配置一套(即Server变成另外一个场景的client),不能共享同一个连接。

二. 传统的 RPC 都是错误的
因此最近有一种观点就说RPC都是错误的,下文中提到的RPC都可以理解成包含Java RMI

"but for normal languages, RPC creates more problems than it solves."
    -- Steve Vinoski

来源:(
原文中文版)
其主要论点就是说RPC最大的问题就是把远程调用做得象本地调用。但是,远程调用并不是本地调用,它的异常和错误及其他很多方面是截然不同的。传统的RPC调用忽略了local与remote的区别,因此在大型项目里面混淆了这两者调用区别的应用通常会造成性能问题。

三. Erlang的优势
跟传统的 RPC 相对比,Erlang 的主要优点包括

1) 2个process互为关联(link),一个crash,另外一个自动接管。
2) RPC就是message send/receive(严格的讲Erlang里面没有RPC), 可以很方便增加error handling, 而且 error handling 可以放在远程,这样更适合网络架构,因为local error handling在本机发生故障时候毫无意义。
3) message receive可以增加timeout,不会阻塞在某个地方
4) 其他场景,如Node X调用Node Y, Node Y执行业务之后把结果返回给Node Z, 传统RPC无法处理

四. Java中一些替代思路
1) RMI 也可以设置 timeout,因为底层无非都是基于Socket
2) RMI也可以实现无单点故障及负载均衡,参看
Clustered Remoting For Spring Framework Cluster4Spring 支持一对多调用,动态发现服务(dynamic services discovering)及远程错误监控, The Server Side 上有更多深入的讨论
3) 分布式内存共享
Coherence Data Grid, Openfire Cluster 就用了这个模块,不过这个框架不是开源的。
4) 分布式内存共享
Terracotta,这是一个开源的,Scala会采用这个
5) JGroups 可靠的组播服务,集群通讯首选的工具库,在其他语言无类似替代产品。JGroups介绍可参看前文
JGroups 简介、适用场合、配置、程序例子Demo等完全使用指南
6) Concurrent, Erlang中有轻量级的process, Java7中会有Doug Lea主导的fork/join
不过 Erlang里面还有Java中暂时无法替代的优势, 如Immutable变量, 无共享内存,Process交换数据通过消息传递实现等,这些特性在多核CPU下具有先天优势,相关资料也很多,就不这里重复了。
 
2008-07-24 00:00

Building Scalable Web Sites一书大家基本上都是冲着Flickr和Cal Henderson首席架构师的名头去的,最近看到有中文版了就订了一本。书中全部代码用PHP为例,但其实跟PHP关系不大。书中实用的章节不多,先看了远程服务一章。

1. 使用远程服务的第一原则是不能依赖远程服务,另外一方面远程服务要考虑冗余性。
在我理解,远程服务有几类:
1) 远程API,如XML-RPC, HTTP接口, Message Queue。
这个是业务相关的,Failure怎样做要程序自身考虑了。
2) DB存储类,如MySQL, NFS。
MySQL可用主从或MySQL proxy, NFS不知道,不稳定,关键业务用的场合不多。
3) Cache, 如Memcached,
Memcache默认可以分布多个,Failure怎样处理?我觉得如果cache失效对系统影响比较大的话可以写2份,否则就立即启用备用cache。

书中还提到一个TCO的概念,在某个场合,靠人力去优化还是加硬件,哪个成本更低?

2. 异步系统。
异步系统也是我感兴趣的地方,任何一大型的系统,都会有不少异步的设计。
书中提到一种Ticket模型:
 


图片来源:(
books.google.com)

Ticket异步模型除了书中介绍的用来转换图片服务的场景之外,我举一个我理解的例子。
用在IM里面比如在群中发送图片功能。
1) 发送方发送/粘贴图片,立即显示发送完毕
2) 群中所有接收方立即显示接收到图片(只是个Ticket)
3) 系统实际上处于发送方上传图片中
4) 同时群中用户拿ticket去要图片(轮询or通知)。
5) 发送方上传完毕
6) 接收方凭Ticket获取到图片最终资源显示。
这个场景理论上就是和Ticket模型相似,但在实际操作上群图片还有更多细节考虑。

3. 使用轻量级协议
HTTP和XML被过量使用,某些高访问场合未必是最好的选择。
这就是Flickr为什么要使用自己的存储服务和协议。
但这个问题是双面的,首先作者强调,“大多数场合,自行开发协议是糟糕的主意”。Flickr也尝试过NFS和scp。(这也是为什么gtalk选用XMPP)

另外翻译版源代码排版比较差,空行缩进行距等细节未注意,跟我们开发人员写的Word文档排版有得一比。