REST(Representational State Transfer) 曾经被误解为只是CRUD(增删改查),从这个层面上,好像REST只是和RPC一个层面的东西,没有什么了不起,其实这些都是对REST误读。 理解REST需要从系统集成整合以及架构的伸缩性方面入手,这方面有一篇很重要的REST博文: I finally getREST. Wow. http://www.pluralsight.com/community/blogs/tewald/archive/2007/04/26/46984.aspx 作者认为:每个通讯协议都有一个状态机,当你使用RPC时,你要做些方法来改变通讯的状态,但是这些状态是封装在服务器端或客户端的专门通讯模块中,比如通过Hessian/SOAP等Proxy技术进行RPC调用,虽然可以在客户端很方便地象调用本地服务一样,缺点总是伴随优点到来,由于Proxy封装了客户端和服务器的通讯,就很容易让客户端和服务器紧耦合。 这其实是C/S架构的一个本质问题,而B/S架构通过简单的浏览器则解耦了客户端和服务器的耦合,别小看丑丑的浏览器,特别是当初还没有AJAX辅助时,浏览器被很多传统C/S讥笑和不屑,但是他们不知道B/S架构后面蕴含的深刻朴实的设计道理,是真正大道至简。所以,当我们重新回归RIA富客户端代表的C/S架构时,必须吸取Web架构的本质优点,这样才是螺旋式上升。 回归话题,由于传统架构隐藏了通讯模块进而发生了紧耦合,而REST最大作用则是将通讯状态以URI显式表现出来,也就是将通讯状态的透明性,这样做最大的好处就可以在通讯环节引入伸缩性。 REST核心思想就是:以URI形式将状态机表现为动态的节点图,我们就能引入动态负载平衡dynamic load-balancing, 数据重导向data-directed-routing, versioning 等其他正常的Web底层设计架构Web infrastructure,从而使客户端和服务器之间服务器之间享受Web架构的好处。 谈到系统集成,SOAP/Web服务/SOA被厂商吹嘘了很多年,很多应用也在使用SOAP,SOAP和REST无疑是相互竞争的,SOA其实也是一种的RPC,是一种基于XML的RPC,因此,同样存在通讯状态隐藏的致命问题。 上述博客作者写了另外一篇文章来比较(http://www.pluralsight.com/community/blogs/tewald/archive/2007/04/27/47031.aspx) 比如,两个城市之间航班看成一个协议,这个协议有下面几个状态: <ready> - searched (查询) - retrieved details (获得细节) - reserved (预订) 通过URI表现出来是: <none> - http://quuxTravel.com/searched - ??? depends on previous state - ??? depends on previous state 客户端通过get方式http://quuxTravel.com/searched?src=London&dest=NYC进行查询,得到结果如下: <itineraries> <itinerary src=“London“ dest=“NYC“ price=“400.03“> <getDetails uri=“http://quuxTravel.com/details?itinerary=402“ /> <reserve uri=“http://reservations.bookingsunlimited.com/quuxTravel?itinerary=402“ /> </itinerary> <itinerary src=“London“ dest=“NYC“ price=“109.88“> <getDetails uri=“http://quuxTravel.com/details?itinerary=219“ /> <reserve uri=“http://reservations.bookingsunlimited.com/quuxTravel?itinerary=219“ /> </itinerary> </itineraries> 客户端目前处于“查询”状态,通过遍历上述itineraries旅游线路结果集合,寻找出最便宜的一家,如果用户想查询一个不在上述结果的信息比如飞行总体时间,他能通过上述结果属性getDetails/@uri中保存的URI信息再次GET获得,这样就会切换到 retrieved details状态。然后又会回到searched状态。 当用户选择一条路线后,通过保存在reserve属性中的URI值就进入 reserved状态,客户端得到一些reserved方面的信息,至此,整个业务算完成了。 如果使用RPC如何来完成呢?我们必须创建一个接口如下: interface IFlightSystem { Itineraries Search(string src, string dest); Details GetDetails(int itineraryId); Confirmation Reserve(itineraryId); } 客户端可以通过调用这个接口的几个方面来完成上述一些业务. 在这里,接口表达了和前面REST同样的协议,所不同的是, RPC客户端依赖服务器端这个接口,也就是两者通过接口耦合了,更致命的是:searched (查询) retrieved details (获得细节) reserved三个状态耦合到同一个服务器中,如果我们想将这三个状态分离分散到多台服务器上,除非重写服务器端代码,否则无能为力。 而在前面REST调用中,每个状态都是通过URI重新定位,这样,我们可以在这三个状态中引入伸缩性,比如searched状态的URI在A服务器,而retrieved details的URI则是B服务器的网址,而reserved的URI则是c服务器,看看我们的业务不再是铁板一块了。 这就是REST本质魅力,REST和RPC/SOAP本质区别是透明性。REST透明性可以让我们以更细粒度引入伸缩性,这样以REST为主要形式可以组建一个分布式的大型架构,而这个目的恰恰是重量解决方案SOA提出的目标,现在我们有了另外一个轻量的选择。 A terabyte cache with the RESTful Ehcache Server 使用RESTful EhCache服务器实现TB级级别缓存 http://gregluck.com/blog/archives/2008/08/_the_restful_eh.html 使用RESTful接口实现数据分区(也可以称为通常的数据库分离),一个最大的ehcache可以有20GB内存,而最大的磁盘存储是100Gb. 使用数据分区将这些节点组合在一起,可以得到更大的内存,50个节点X 20GB可以得到1TB。 非冗余的一个设计: 带客户端Hash的设计,代码如下: String[] cacheservers = new String[]{"cacheserver0.company.com", "cacheserver1.company.com", "cacheserver2.company.com", "cacheserver3.company.com", "cacheserver4.company.com", "cacheserver5.company.com"}; Object key = "123231"; int hash =Math.abs(key.hashCode()); int cacheserverIndex = hash % cacheservers.length; String cacheserver = cacheservers[cacheserverIndex] 图示: 有趣的是,一些内容交换的负载均衡器可以使用某种形式的正则表达式可以实现URI路由,如下代码所示,所以,你可以不选择上面客户端Hash散列实现分割的方式来实现负载平衡器。 /ehcache/rest/sampleCache1/a1 =>cluster1 /ehcache/rest/sampleCache1/a2 =>cluster2 当然,更复杂的是使用F5负载平衡器,还可以使用TCL创建iRules,但是比正则表达式要复杂。F5的URI hashing iRule见: http://devcentral.f5.com/Default.aspx?tabid=63&PageID=153&ArticleID=135&articleType=ArticleView 个人建议:图中Cluster组可以使用Terracotta,可自动整合Ehcache,对程序无侵入性,更新性能好于memcached,比JMS JGroups要高级多。 相关文章: REST是什么? http://www.jdon.com/jivejdon/thread/36520.html