V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
jwfing
V2EX  ›  程序员

XMPP 协议适合用来做移动 IM 么

  •  6
     
  •   jwfing · 2014-09-02 10:26:06 +08:00 · 21428 次点击
    这是一个创建于 3736 天前的主题,其中的信息可能已经有所发展或是发生改变。

    XMPP 协议是什么

    XMPP(Extensible Messaging and Presence Protocol,前称Jabber)是一种以 XML 为基础的开放式实时通信协议,关于它的协议细节,网上已经有太多分析文章,我这里就不再赘述(而且,我也不可能比别人解释的更清楚)。简单来看这个协议,我们只需要知道:

    1,XMPP 的三种基本角色:客户端、服务器和网关,通信能够在这三者的任意两个之间双向发生。服务器端同时承担了客户端信息记录、连接管理和信息路由的功能。网关则承担着与异构系统的互联互通功能。在 RFC 3920 XMPP Core 中对 XMPP 网络结构有一个描述:
    <pre>
    C1—-S1—S2—C3
    |
    C2—-+–G1===FN1===FC1
    </pre>
    这里 C1,C2,C3 表示 XMPP 客户端;S1,S2 表示 XMPP 服务器;G1 表示网关,用来负责 XMPP 协议和外部聊天协议的转换;FN1 表示外部消息网络的服务器,FC1 表示外部网络客户端。

    大家可能会奇怪,这里为什么需要一个网关呢。这要从 XMPP 的来源说起。1996 年 Mirabilis 公司推出了世界上第一个即时通信系统 ICQ,不到 10 年,IM 就成了最流行的应用之一,MSN、Gtalk、雅虎即时通、AIM、Adium、Pidgin 等各种软件如雨后春笋般涌现,但是这些服务之间没有统一的标准,不能互联互通,XMPP 的设计目的就是为了实现整个及时通信服务协议的互通,让 IM 成为继 WEB 和 Email 之后的互联网第三大服务。

    2,XMPP 的消息格式。

    XMPP 协议的所有消息都是 XML 格式的,这是 XMPP 协议的另一个充满历史意味的选择,想当年 SOA / SOAP 一时间爆发起来,很多消息交换协议都采用了 XML 格式,但是不想 XML 很快就成了「大数据」的代名词。在 RFC 3920 XMPP Core 中定义了两个基础概念,XML Stream 和 XML Stanza,XML Stream 是两个节点之间进行数据交换的容器,它定义了顶层的XML节点 <stream>;XML Stanza 则定义了实体消息的具体语义单元,在 XMPP 中定义了 3 个顶层消息:

    2.1 Presence
    用于确定用户的状态。消息结构举例如下(每个 XML 的 node 还会有很多其他 attribute,为了简单起见这里省略,下同):
    <presence from=“[email protected]/contact” to=“[email protected]/contact”>
    <status>online</status>
    </presence>

    2.2 Message
    用于在两个用户之间发送消息。消息结构举例如下:
    <message from=“[email protected]/contact” to=“[email protected]/contact” type=“chat”>
    <body>hello</body>
    </message>

    2.3 IQ
    信息/请求,是一个请求-响应机制,管理XMPP服务器上两个用户的转换,允许他们通过相应的XML格式进行查询和响应。
    <iq from=“[email protected]/contact” id=“id11” type=“result”>
    </iq>

    3,XMPP 的交互流程。
    XMPP 通过 TCP 传输了什么内容?在 QQ 里面,消息是使用二进制形式发送的,在 MSN 里面是采用纯文本指令加参数加换行符的形式发送的,而 XMPP 传输的即时通讯指令与他们相仿,只是协议的形式变成了 XML 格式的纯文本,这让解析更容易,方便了开发和查错,但是也带来了数据负载过重的缺点,而被人广为诟病。

    XMPP 聊天的过程如下:

    • 所有从一个 client 到另一个 client 的消息和数据都要经过 XMPP Server;
    • client1 连接到Server;
    • server 利用本地目录系统的证书对其认证;
    • client1 指定 client2 目标地址,让 server 告知 client2 目标状态;
    • server 查找,连接并进行互相认证;
    • client1 和 client2 进行交互。

    XMPP 系统实测

    XMPP 协议的最主要的一点就是开放,不管是协议、客户端,还是 Server 端,都有成熟的实现方案。为了实际感受 XMPP 协议的聊天过程,我使用 asmack library + OpenFire 服务器搭建了一套完整的测试环境。

    OpenFire 采用 Java 开发,是一个基于 XMPP 协议 的开源的实时协作服务器,它的安装和使用都非常简单,自带有一个内置的存储数据库(当然,你也可以使用独立数据库如Mysql等),并利用 Web 进行管理。其他类似的开源系统还有很多,eJabber、Tigase 也经常被用到。但是根据我们之前的经验,这些开源系统能支持的并发连接数都不高,要是有超过10万的用户同时连上来,对它们来说就快达到单机的瓶颈了,这时候一般都需要水平拆分,但是拆分之后服务器之间的 session 同步负担会大幅加重,对于性能又带来不小的抵消。所以这些系统大都被拿来做研究和测试用,很少见到大规模在生产环境中使用的。

    好吧,我们还是来实际聊聊看。为了体现真实性,选取了程序员圈子里面较大概率可能发生的几段典型对话:

    • Case1-搭讪
      猿:你吃饭了吗?
      MM:吃了
      猿:你在干什么呢?
      MM:上网
      猿:你那天气好吗?
      MM:还可以
      猿:你最近忙吗?
      MM:不忙
      猿:。。。。
      猿:哦,这样啊,我就想知道你在干什么,那你继续忙吧,拜拜
      MM:拜拜

    • Case2-请教
      A:嘿 //是什么意思啊?
      B:嘿.
      A:呃 我问你//是什么意思?
      B:问吧.
      A:我刚才不是问了么?
      B:啊?
      A:你再看看记录…
      B:看完了.
      A:……所以//是啥?
      B:所以什么?
      A:你存心耍我呢吧?
      B:没有啊 你想问什么?

    • Case3-约会
      女:你能让这个论坛的人都吵起来,我今晚就跟你走.
      某猿:PHP是最好的语言!
      论坛一下炸翻了天,女:i服了u,我们走吧,你想干啥都行.
      某猿:今天不行,我一定要说服他们,PHP必须是最好的语言
      某女:…….

    • Case4-借钱
      A:哥们儿,有钱吗?
      B:有
      A:借我点呗?
      B:啊?你说什么?
      A:借我点呗?
      B:不是,上一句?
      A:有钱吗?
      B:没有
      A:晕,程序重新请求一下,结果还不一样了!

    实际结果如下,我在 Nexus5 上面运行一个 IM app,连接上我自己搭建的 openfire 服务器,然后模拟了上面几段对话,在几个参与者的前提下,消息实时性还挺好,但在系统设置-》网络流量中看到,整个聊天过程中该 app 消耗掉的网络流量高达 36KB,聊天记录的文本文件大小为 8KB,也就是说网络流量的 70% 都消耗在 XMPP 协议层了,这个数字正好吻合了维基百科上吐槽的数据冗余率。

    最后测试下来看,我个人感觉是,对于移动互联网来说,省电、省流量是所有底层服务的一个关键技术指标,XMPP协议看起来已经落后移动互联网了。

    41 条回复    2015-10-25 00:01:35 +08:00
    erylee
        1
    erylee  
       2014-09-02 10:40:32 +08:00
    嗯,个人觉得XMPP不适合,我们在开发SLIMPP,GitHub项目: https://github.com/slimpp/
    chmlai
        2
    chmlai  
       2014-09-02 10:57:36 +08:00   ❤️ 1
    @erylee 你这个基于 MQTT 的好像不错, 可以问问现在是开发到什么状态了吗?, 留意下;
    ioth
        3
    ioth  
       2014-09-02 11:12:02 +08:00
    关注,现在要做一个。
    ahu
        4
    ahu  
       2014-09-02 11:16:03 +08:00
    注册了下,貌似还不能用
    erylee
        5
    erylee  
       2014-09-02 11:19:44 +08:00
    @chmlai 基础协议刚开发完,比如iOS的CocoaMQTT, erlang的mqtt server。现在开发Android的一个Demo,0.1版本应该在10月发布,然后迭代协议到1.0
    a2z
        6
    a2z  
       2014-09-02 11:22:16 +08:00
    XMPP用的XML,overhead太大了,大部分情况下结构描述比信息本身都大,非常不适合在流量有限的移动环境中使用。
    erylee
        7
    erylee  
       2014-09-02 11:28:52 +08:00
    @ahu 嗯,那个是协议开放站点,还只有web部分,手机端刚开始不久
    caoyue
        8
    caoyue  
       2014-09-02 11:40:47 +08:00
    XMPP 协议确实非常蛋疼,但是好处是足够完善,实现也很多,适合快速开发
    allenforrest
        9
    allenforrest  
       2014-09-02 11:47:18 +08:00   ❤️ 1
    SIP 也一样,开销非常大。

    但我还是很推崇 XMPP,优势在协议完备性、各种实现的成熟度等等方面。

    可以考虑在实现层面做一下改造,将 XMPP 报文在底层 TCP 传输时做一次编解码,转换成自定义的二进制格式,只需要改造一下 smack 库和 openfire 源码部分,对于上层应用开发来说完全透明,原来 smack 怎么用还是怎么用。

    底层编码后的冗余数据大大减少,节省流量和功耗。

    另外,考虑 XMPP 各种协议扩展较多,我们只需要针对最常用、最频繁的 XMPP 报文做编解码即可,其他不常用的仍然维持现有文本格式,对流量的贡献可控。
    est
        10
    est  
       2014-09-02 11:49:45 +08:00
    XMPP非常烂。离开了libjingle2的XMPP在桌面上都是一坨废物。
    lithiumdroid
        11
    lithiumdroid  
       2014-09-02 11:52:54 +08:00
    丰总,你还在写代码吗丰总
    huoxiaochai
        12
    huoxiaochai  
       2014-09-02 13:00:54 +08:00   ❤️ 1
    MQTT 值得你拥有!
    jwfing
        13
    jwfing  
    OP
       2014-09-02 14:30:56 +08:00
    @lithiumdroid 哈哈,写啊,我们公司工程师都写代码的。
    jwfing
        14
    jwfing  
    OP
       2014-09-02 14:31:46 +08:00   ❤️ 1
    推荐大家考察一下我们推出的聊天服务: https://avoscloud.com/features/realtime-messaging.html
    shawngao
        15
    shawngao  
       2014-09-02 14:43:29 +08:00
    哈哈,话说听了上期的teahour,说到AVOS就你一个在做IM,是这样吗?
    @jwfing
    jwfing
        16
    jwfing  
    OP
       2014-09-02 14:58:35 +08:00
    @shawngao 不是不是,我们有一个「小团队」在做 IM,主要负责的工程师是 https://twitter.com/Sunng
    shawngao
        17
    shawngao  
       2014-09-02 15:04:44 +08:00
    @jwfing 这样啊,那顺便了解一下你们的IM用C/C++、Golang或者其他?这方面我也是比较感兴趣的,所以想特别了解一下。
    pi1ot
        18
    pi1ot  
       2014-09-02 16:04:49 +08:00
    xml上面zip一下应该会有改善吧
    jwfing
        19
    jwfing  
    OP
       2014-09-02 16:08:23 +08:00   ❤️ 1
    @shawngao 我们服务器端是用 Clojure 写的,整个 AVOS Cloud(http://avoscloud.com) 的后端和网站,都是 Clojure 写出来的:)
    shawngao
        20
    shawngao  
       2014-09-02 16:47:27 +08:00
    @jwfing 对的,只是没想到IM也用Clojure, 感谢分享。
    hussion
        21
    hussion  
       2014-09-02 17:00:03 +08:00
    关注,我们暂时用socket.io实现,也在寻找比较靠谱的协议
    railgun
        22
    railgun  
       2014-09-02 17:15:15 +08:00   ❤️ 1
    不适合,首先传输用的是XML,构造和解析复杂,传输冗余大。
    另外,它对不稳定的移动网络不友好,经常会发生丢消息的情况。
    我认为成熟的移动IM,(或者根本不应该叫IM,移动网络的特点本身就决定了它不适合做即时通讯)应该同时兼容socket和HTTP,网络好的时候用socket保证实时性,网络差的时候用HTTP保证可靠性。
    还有一个血的教训是,不要让它负责除了聊天之外的其他任何事情,好友关系处理、用户资料设置什么的,最好都自己另外弄一套。XMPP自带的扩展和传输都很麻烦
    guoyang
        23
    guoyang  
       2014-09-02 18:44:31 +08:00 via iPhone
    作为一个趟过该浑水的人,我觉得自己搞私有协议远比xmpp好,因为用了之后你会发现里面的很多本来是好的东西,最后却变成了负担!特别对于移动网络
    erylee
        24
    erylee  
       2014-09-02 19:08:48 +08:00
    @railgun 非常有道理,我们直接JSON/HTTP+MQTT混合,网络好用MQTT推送,网络差通过HTTP同步。协议层面尽量支持Sync Pull和PUSH混合。
    jwfing
        25
    jwfing  
    OP
       2014-09-02 19:29:43 +08:00
    wenbinwu
        26
    wenbinwu  
       2014-09-02 19:52:25 +08:00
    hipchat?
    llbgurs
        27
    llbgurs  
       2014-09-02 20:03:15 +08:00
    可以看看我们的服务,基于mqtt的 yunba.io https://github.com/yunba
    icyalala
        28
    icyalala  
       2014-09-02 20:48:41 +08:00   ❤️ 1
    XMPP太重,如果需求不复杂,socket.io自己定义下协议就够用了。
    jwfing
        29
    jwfing  
    OP
       2014-09-02 21:12:45 +08:00
    @icyalala 嗯,AVOS Cloud的聊天服务就是自定义协议,并且也支持socket.io,最后我们的体会是根本不需要那些「开放」且「重量级」的协议!
    usufu
        30
    usufu  
       2014-09-03 09:00:48 +08:00
    有没有支持视频聊天的协议?除了xmpp扩展以外?
    pi1ot
        31
    pi1ot  
       2014-09-03 12:56:25 +08:00
    文本沟通的话IRC协议就够了,只是IRC更面向群聊。
    wupher
        32
    wupher  
       2014-09-03 14:01:11 +08:00
    不适合。协议设计比较臃肿,XMPP协议最初设计时也没考虑移动端。
    <message>本身是可丢弃的,掉了也就掉了。使用XMPP一般考虑的是服务端客户端有开源实现可抄,二来就是开放性了。
    就现有开源实现来说,Erlang的那个ejabberd实现不太清楚,其它openFire, jabberd2感觉上量都有问题。群消息更是大深坑。
    文件传输与音视频这块,其实XMPP也就负责握个手,该怎么走RTCP,到时还得怎么走。
    量少浅尝可以,量大最终会开始动手改造。

    倒是阅读XMPP协议蛮有趣的,没想到里面有这么多纯搞笑协议的RFC。比如XMPP-二进制版。
    jwfing
        33
    jwfing  
    OP
       2014-09-03 17:18:58 +08:00
    @wupher +1 openfire/ejabberd能支持的并发连接都比较有限
    gfh110
        34
    gfh110  
       2014-09-03 17:45:08 +08:00   ❤️ 1
    大家应该看下xmpp产生的历史。当时它的目标是提供一种通用的协议来试不同厂商的im可以互相通信。
    它的性能并不好,而且因为是xml协议并不适用目前国内还对流量敏感的用户,并发量也上不去
    citysofa
        35
    citysofa  
       2014-09-03 17:50:45 +08:00
    不适合
    siteshen
        36
    siteshen  
       2014-09-03 18:42:36 +08:00
    坐等IM开源……
    popatry
        37
    popatry  
       2014-09-04 01:56:13 +08:00   ❤️ 1
    > 整个聊天过程中该 app 消耗掉的网络流量高达 36KB,聊天记录的文本文件大小为 8KB,也就是说网络流量的 70% 都消耗在 XMPP 协议层了,这个数字正好吻合了维基百科上吐槽的数据冗余率。

    首先,其实浪费的带宽并没有你想象那么高比例。因为你没有考虑IP层和TCP层的带宽占用。我估计这种短小聊天信息如果有8KB,那么TCP/IP包头加起来恐怕也有10KB到20KB了。那么算上这些带宽占用,XMPP协议层占用的带宽也就在50%左右了。

    其次,XMPP基于XML协议层格式繁琐,但信息量并不高,所以如果要压缩,那么压缩率就会很高。XMPP协议通常要通过TLS加密,可以启用TLS压缩选项。

    最后,无论使用任何协议,文本聊天都不会占用很多带宽,稍微浪费一点,问题不大。
    yunbaIO
        38
    yunbaIO  
       2014-09-04 11:24:47 +08:00   ❤️ 1
    不适合。虽然说XMPP本身是一个非常完整的协议,而且扩展性相当好,也有一些很好的Broker。但它并不适合用来做移动IM。其中一个劣势@jwfing 已经提到,就是它本身协议承载数据比例太低,差不多70%的流量都是消耗在标签上。另一个麻烦的问题就是它的延迟大。我们试验过用XMPP来做一个简单的Connect和用户认正,不仅要用1K的流量,还需要5-7次的交互,换句话说,一个登录就是秒级的延迟(移动互联网一个环回大概就是400、500毫秒)。另一个缺点就是XMPP的编解码也是很重,因为它是纯文本的解析器,你要用纯文本去做,不管是编码还是解码都是比较重的,在移动环境下合适。


    推荐用MQTT协议,它是二进制协议,而且本身非常精简,做移动网络环境下做IM非常合适,省电省流量。它的做法是一个订阅/发布系统,拿到权限的人就可以往频道里发消息,任何在这个频道里的人就可以收到。MQTT还是开放协议,有很多开源实现,可以用它的开源实现搭个环境来玩一玩。另外很重要的一点就是它的扩展很方便,它原来就留了两个两个命令字,再加上它协议头本身很轻,在它的扩展命令字上做一些简单的事情就可以扩展出很多命令字。


    我们云巴yunba.io是基于MQTT协议做双向消息实时推送,也支持Socket.io。开发者可以使用云巴,快速搭建包括移动IM以内的各类型实时应用。可以稳定支持千万级亿级海量用户。我们设立多处主干机房,全国范围内消息延迟在0.2s以内。

    我们也投入了大量时间精力研究实践实时海量数据通讯、统计、存储等问题。之前创始人还在ArchSummit上就这方面做了的分享,题目就是实时系统架构和实践,有兴趣的可以戳http://t.cn/RhUxmwN看视频,全程干货,当时也提到了协议选择的问题。

    对了,还有一个基于云巴产品开发的移动IM开源Demo,或许有用哈,Github地址http://t.cn/RPxwZjQ
    loddit
        39
    loddit  
       2014-09-05 09:08:28 +08:00
    之前用过一阵子XMPP,感觉除了大家提到的XML冗余之外,还有一些限制它适用性的地方。
    最主要就是它有一下自己的业务设计,比如加入room需要客户端发送presence,需要先主动获取 roster 才能获取好友状态的更新。叫

    一般来讲采用 XMPP 主要的好处就是可以直接使用很多开源的产品。但是因为本身也算比较复杂,这些产品上做一些自己的定制就没那么容易。

    在移动端我不熟悉,我觉得如果使用第三方的平台实现实时通信可能是比较快速的选择。

    ps ejabberd 是比较有名的 erlang 实现,实现的xmpp协议比较全,而且性能貌似是目前最好的吧? 不如 openFire 吗?
    Wichna
        40
    Wichna  
       2015-07-27 13:10:47 +08:00
    好老的文了。很不错,顶一下。
    zonghua
        41
    zonghua  
       2015-10-25 00:01:35 +08:00
    @icyalala 可是是 openfire 等服务端有现成的消息系统,自己通过其他协议实现还要很多工作要做,小项目做这么多不现实。
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   实用小工具   ·   2985 人在线   最高记录 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 28ms · UTC 13:44 · PVG 21:44 · LAX 05:44 · JFK 08:44
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.