Clojure(Java)和Ruby应用程序之间进行通信的最快可靠方法

14
我们有云托管(RackSpace云)的Ruby和Java应用程序,它们将按以下方式进行交互:
  1. Ruby应用程序向Java应用程序发送请求。请求包含映射结构,包含字符串、整数、其他映射和列表(类似于JSON)。
  2. Java应用程序分析数据并将回复发送给Ruby应用程序。
我们有兴趣评估以下两种消息格式(JSON、Buffer Protocols、Thrift等)以及消息传输通道/技术(sockets、message queues、RPC、REST、SOAP等)
我们的标准:
  1. 短的往返时间。
  2. 低的往返时间标准差。(我们知道垃圾回收暂停和网络使用峰值可能会影响这个值)。
  3. 高可用性。
  4. 可扩展性(我们未来可能想要有多个Ruby和Java应用程序实例交换点对点消息)。
  5. 易于调试和分析性能。
  6. 良好的文档和社区支持。
  7. 如果支持Clojure,则额外加分。
  8. 良好的动态语言支持。
您推荐哪种消息格式和传输方法的组合?为什么? 我在此处汇总了我们已经收集的一些材料供审核:
我建议选择使用Thrift作为消息格式,并使用RabbitMQ作为消息传输通道。因为Thrift文件定义语言简单易懂,具有极高的性能,并支持多种编程语言。而RabbitMQ则是一个可靠、可扩展、高可用、易于使用和部署的消息代理平台,它支持多种消息传输模式,如发布/订阅、点对点和RPC。
  • Thrift和Protocol Buffers的比较
  • Protocol Buffers RPC功能的谬论
  • 在AMQP(消息队列)上下文中讨论RPC
  • 比较分布式系统中的RPC和消息传递(pdf)
  • 从消息传递粉丝的角度批评RPC
  • 从Ruby程序员的角度概述Avro
  • 从Ruby程序员的角度概述Thrift
  • 从Java程序员的角度概述Thrift
  • 介绍MessagePack
  • 动态语言爱好者介绍BERT
  • 消息队列评估笔记
  • ZeroMQ和Clojure

  • 你真的想要可靠性吗(从标题中)?在你所谈论的消息类别的背景下,这意味着消息永远不会丢失(可能还意味着它们按发送顺序传递),这是非常昂贵的。当然,在这里的可靠性是指抵御像挖掘机攻击(即网络或电力基础设施的物理破坏)等事情的能力。我更喜欢及时交付并使应用程序对故障具有抵抗力,因为这更容易... - Donal Fellows
    嗨,我们希望系统具有相当不错的可靠性,但不关心按顺序传递。我们的系统可以容忍偶尔的故障,尽管保持故障率相当低是很重要的。 - jkndrkn
    4个回答

    3
    我们决定选择BSON而不是RabbitMQ。我们喜欢BSON对异构集合的支持和无需预先指定消息格式的特点。我们不介意它具有较差的空间使用特性和可能比其他消息格式更差的序列化性能,因为我们的应用程序中的消息传递部分不会成为瓶颈。看起来并没有编写一个好的Clojure接口来直接操作BSON对象,但希望这不是问题。如果我们决定BSON不能满足我们的需求,我会修改这篇文章。
    我们选择RabbitMQ主要是因为我们已经在一个需要高吞吐量和可用性的系统中使用它。
    如果消息传递成为瓶颈,我们将首先查看BERT(被拒绝,因为它目前似乎没有Java支持),然后是MessagePack(被拒绝,因为似乎没有大量使用它的Java开发人员社区),然后是Avro(被拒绝,因为它需要您预先定义消息格式),然后是Protocol Buffers(因为需要额外的代码生成步骤和缺少异构集合而被拒绝),最后是Thrift(因为与Protocol Buffers提到的原因相同而被拒绝)。
    我们可能希望使用简单的RPC方案而不是使用消息队列,因为我们的通信方式基本上是同步点对点的。
    谢谢大家的意见!
    更新:这里是project.cljcore.clj,演示了如何将Clojure maps转换为BSON并重新转换回来:
    ;;;; project.clj
    (defproject bson-demo "0.0.1" :description "BSON演示" :dependencies [[org.clojure/clojure "1.2.0"] [org.clojure/clojure-contrib "1.2.0"] [org.mongodb/mongo-java-driver "2.1"]] :dev-dependencies [[swank-clojure "1.3.0-SNAPSHOT"]] :main core)
    ;;;; core.clj (ns core (:gen-class) (:import [org.bson BasicBSONObject BSONEncoder BSONDecoder]))
    (defonce *encoder* (BSONEncoder.))
    (defonce *decoder* (BSONDecoder.))
    ;; XXX不接受关键字参数。先将map中的clojure.lang.Keyword转换为java.lang.String。 (defn map-to-bson [m] (->> m (BasicBSONObject.) (.encode *encoder*)))
    (defn bson-to-map [^BasicBSONObject b] (->> (.readObject *decoder* b) (.toMap) (into {})))
    (defn -main [] (let [m {"foo" "bar"}] (prn (bson-to-map (map-to-bson m)))))

    2
    我没有亲身经历过,但我知道Flightcaster正在使用JSON消息传递将其后端Clojure分析引擎与前端Rails应用程序链接起来,这对他们似乎很有效。以下是文章链接(在最后出现):Clojure and Rails - the Secret Sauce Behind FlightCaster。希望这可以帮到你。--Mike

    嗨Mike。很好的文章。结果我的队友们已经非常熟悉那个用例^_^ 我不确定那里描述的Ruby/Clojure互操作是否是关键的速度敏感路径的一部分。 - jkndrkn

    2
    我对此方面没有经验,但我会提供这个可能有用的猜测。
    • ZeroMQ 提供点对点消息传递,包括各种类型的网络拓扑结构。消息由任意二进制值组成 - 因此您只需要一种二进制序列化格式来处理您的结构化消息。

    • BSONProtoBuffersBERT 提供将任意数据结构(数字、字符串、顺序数组、关联数组)序列化为二进制值的功能。

    GitHub 发明了 BERT 以加快 RCP;BSON 是由 MongoDB (或10gen) 发明的出于同样的原因;ProtoBuffers 同样是由 Google 发明的。


    谢谢,我们系统中已经使用了RabbitMQ,可以考虑直接使用它来代替RPC解决方案进行消息传递。到目前为止,看起来我们会选择使用Apache Thrift、Protocol Buffers或者MessagePack进行序列化。Apache Avro也是一个可能的选择。 - jkndrkn
    如果您已经部署了像RabbitMQ这样的消息总线,那么在需要消息传递时重复使用它可能是有意义的。否则,ZeroMQ可能更合适,因为它可能更容易部署:它是一个直接用于应用程序组件内部的消息传递库,并且不需要部署任何单独的基础设施。我添加了这个评论,以防其他人有同样的问题,但没有部署RabbitMQ。 - yfeldblum

    1

    我相信协议缓冲区比JSON更快,更高效(上次我检查时,它大约快了40倍,但我没有在Ruby中尝试过,所以结果可能会有所不同)。


    在我的情况下,ProtoBuffs与JSON相比较,但当时并没有使用Jackson(我想我使用的是jsonlib),而且自那时以来,ProtoBuff Java库也一定有所发展。 - mpenet
    网络RTT通常是主导因素,有效载荷大小才是真正重要的。经过gzip压缩的JSON与协议缓冲区的大小相当,所以我认为两者都可以。 - Kevin

    网页内容由stack overflow 提供, 点击上面的
    可以查看英文原文,
    原文链接