AVOS Cloud目前还在用Ejabberd做Android的消息推送服务。当时选择Ejabberd,是因为Ejabberd是一个发展很长时间的XMPP实现,并且基于Erlang,设想能在我们自主研发的Push Server起来之间顶上一段时间。

我们自主研发的Push Server预计本月中旬就上线了。但是Ejabberd却先顶不住了。Ejabberd做推送,本身就有劣势,比如XMPP协议的冗余,XMPP协议本来就是IM协议,对推送这个简单的场景还是太复杂了一些。Ejabberd Cluster对于IM这样的场景很有优势,对于一个Ejabberd Cluster内机器来说,A用户连在A服务器,B用户连在B服务器,两者之间的通讯,Ejabberd都帮你处理了,会自动路由AB之间的消息。Ejabberd会在整个Cluster内每个节点维护session数据,每次session的变更都会在节点之间复制。但是对于推送服务来说,没有刚才提到的AB用户的通讯问题,都是服务端往client推送数据,client没有上行的数据,这个session维护的代价反而是没有必要了。

因此,使用Ejabberd推送的第一条优化手段: 不使用Ejabberd Cluster。反而采用多个独立节点的结构,每个节点之间都是独立,不组成集群。因为节点之间独立,用户数据却还需要共享,那么放弃mnesia,而采用odbc数据库的方式存储用户数据就成为自然的选择了。

那么在采用多节点之后,会出现一个问题?推送服务怎么知道应该往哪个节点推送消息,换句话说,推送服务怎么知道要推送的设备连在哪台服务器上?我们的解决办法是引入一个Router服务,它来告诉推送服务和终端设备链接到哪台服务,采用一致性哈希算法来分配连接,减少节点变更带来的影响。最后,我们使用一个简陋但是简单的办法来感知节点是否有效。这个简陋的办法就是使用crontab脚本每隔几秒向router服务发送该机器上ejabberd端口处于ESTABLISHED或LISTEN状态的链接数(netstat命令)。

优化第二条:将数据库服务跑在单独的服务器上。我们使用MySQL,MySQL的优化这里就不提了,innodb配置参数,并发线程、事务级别等等。最好也对数据库做个异步slave备份。

优化第三条,去除不必要的module,我们只用到ejabberd的数据下行和用户账户管理功能,其他模块都可以去掉,下面是一个可以去掉的模块清单:

mod_caps
mod_pubsub
mod_vcard_odbc
mod_roster_odbc
mod_privacy_odbc
mod_proxy65
mod_disco
mod_echo
mod_http_fileserver
mod_shared_roster
mod_service_log
mod_irc
mod_muc
mod_vcard_odbc
mod_adhoc
mod_configure
mod_last

如果你想记录每个账户最后一次连接的时间,可以保留mod_last模块,使用odbc方式记录。

优化第四点,ejabberd.cfg的参数优化(一般在/etc/ejabberd/ejabberd.cfg),包括:

  • loglevel, 建议设置成3,只打印warn级别以上日志。
  • listen模块,ejabberd_c2s的backlog参数,设置TCP backlog队列长度,建议设置得大一些。因为移动网络下,连接断开重连相对频繁,backlog队列较大可以保证服务端的连接accept能力。
  • shaper模块,设置流量控制,默认的normal是1.000 B/s远远不能满足需求。
  • max_fsm_queue参数,控制出队消息队列长度,建议不要设置(undefined),或者设置得较大。
  • odbc相关参数: odbc_pool_size控制连接池大小,设置大一些没关系。odbc_keepalive_interval检测连接是否存活,跟MySQL的wait_timeout保持一致,odbc_start_interval设置重连间隔,默认即可。
  • 权限控制(Access)相关参数:max_user_offline_messages设置最大保存的离线消息数目,根据你的应用需要,设置一个合理的值,我们是设置成5。max_user_sessions设置每个用户最多登录的session数目,建议设置小于等于2,防止重复登录。rigister权限控制给admin使用,预先创建一批admin账号,授予创建用户的权限。每个设备用一个uuid标示,通过这些admin账号注册到ejabberd上。

优化第五条,erlang运行时参数优化(一般在/etc/default/ejabberd文件):

  • POLL=true,开启网络层启用Polling,linux一般是epoll,BSD系统是kqueue。编译Erlang的时候必须设置启用才能启用此选项。
  • SMP=auto|enable,设置成auto或者enable,测试表明,启用SMP在多核机器上能极大地改善吞吐量。
  • ERL_MAX_PORTS,每个TCP链接都将耗费2到3个的erlang port,因此这个参数也设置得大一些,>=30万。
  • PROCESSES,进程数目尽管设置得大一些,最好是ERL_MAX_PORTS的数倍。
  • ERL_MAX_ETS_TABLES: ets表数目,如果日志中看到too many db tables的时候,可以增大此参数,默认1400。

优化第六条,TCP内核参数的优化,注意下列参数:

net.ipv4.tcp_syncookies=1
net.ipv4.tcp_tw_reuse=1
net.ipv4.tcp_tw_recycle=0
net.ipv4.tcp_timestamps=1
net.ipv4.tcp_max_syn_backlog=65535
net.ipv4.tcp_fin_timeout=30

具体含义请自行Google,切记,不要同时开启tcp_tw_recycle字段和tcp_timestamps字段,建议开启tcp_timestamps,原因参考雕梁哥的这篇博客

如果有开启防火墙iptables,还需要注意net.netfilter.nf_conntrack_max参数,这是用来限制防火墙跟踪链接的状态表的大小,对于推送服务来说保持大量长连接是很容易超过默认的65535的,如何配置请参考这篇文章

最后,更多的优化手段,其实就需要深入ejabberd源码了,比如存储的优化,使用redis作为离线消息存储等;erlang语言和vm层面的优化,系统层面的优化(CPU绑定、内核参数进一步调整等)。这就超过我目前的能力范围了,我们的新推送服务基于Netty和Clojure开发,以后应该不会再跟ejabberd打交道了。整体上来说,ejabberd作为一个早期推送方案,支撑百万级别的推送是没有问题的,虽然可能成本会稍微高了一些。

Ejabberd作为推送服务的优化手段的更多相关文章

  1. Ejabberd作为推送服务的优化手段(转)

    AVOS Cloud目前还在用Ejabberd做Android的消息推送服务.当时选择Ejabberd,是因为Ejabberd是一个发展很长时间的XMPP实现,并且基于Erlang,设想能在我们自主研 ...

  2. Netty系列之Netty百万级推送服务设计要点

    1. 背景 1.1. 话题来源 最近很多从事移动互联网和物联网开发的同学给我发邮件或者微博私信我,咨询推送服务相关的问题.问题五花八门,在帮助大家答疑解惑的过程中,我也对问题进行了总结,大概可以归纳为 ...

  3. Netty_Netty系列之Netty百万级推送服务设计要点

    1. 背景 1.1. 话题来源 最近很多从事移动互联网和物联网开发的同学给我发邮件或者微博私信我,咨询推送服务相关的问题.问题五花八门,在帮助大家答疑解惑的过程中,我也对问题进行了总结,大概可以归纳为 ...

  4. 【netty】Netty系列之Netty百万级推送服务设计要点

    1. 背景 1.1. 话题来源 最近很多从事移动互联网和物联网开发的同学给我发邮件或者微博私信我,咨询推送服务相关的问题.问题五花八门,在帮助大家答疑解惑的过程中,我也对问题进行了总结,大概可以归纳为 ...

  5. Netty系列之Netty百万级推送服务设计要点(转)

    1. 背景 1.1. 话题来源 最近很多从事移动互联网和物联网开发的同学给我发邮件或者微博私信我,咨询推送服务相关的问题.问题五花八门,在帮助大家答疑解惑的过程中,我也对问题进行了总结,大概可以归纳为 ...

  6. Netty学习总结(3)——Netty百万级推送服务

    1. 背景 1.1. 话题来源 最近很多从事移动互联网和物联网开发的同学给我发邮件或者微博私信我,咨询推送服务相关的问题.问题五花八门,在帮助大家答疑解惑的过程中,我也对问题进行了总结,大概可以归纳为 ...

  7. 基于netty-socketio的web推送服务

    实时消息的推送,PC端的推送技术可以使用socket建立一个长连接来实现.传统的web服务都是客户端发出请求,服务端给出响应.但是现在直观的要求是允许特定时间内在没有客户端发起请求的情况下服务端主动推 ...

  8. 移动互联网实战--Apple的APNS桩推送服务的实现(2)

    前记: 相信大家在搞IOS推送服务的开发时, 会直接使用javapns api来简单实现, 调试也直连Apple的APNS服务(产品/测试版)来实现. 很少有人会写个APNS的桩服务, 事实也是如此. ...

  9. iOS推送服务细节回顾

    iOS推送服务细节回顾 之前在做推送功能时候,就总结过一系列证书的制作,OC代码实现和服务器搭建等经验.又过了一段时间了,前前后后对推送服务做了多次的完善和优化,有iOS客户端的,还有本地服务器端的. ...

随机推荐

  1. iOS CFNetwork报错

    2016-11-16 10:05:35.082 天天送[46197:11758717] 46197: CFNetwork internal error (0xc01a:/BuildRoot/Libra ...

  2. 转载《Android Adapter简单总结》

    1.概念 Adapter是连接后端数据和前端显示的适配器接口,是数据和UI(View)之间一个重要的纽带.在常见的View(List View,Grid View)等地方都需要用到Adapter.如下 ...

  3. 初学JAVA 感想

    开始学习任何一门课(包括java),兴趣最重要.一直觉得自己在学计算机编程语言,学习了很多,但每门语言都停留在知识边缘地带,都没深入到它们的精华部分,对它们的精华部分知之甚少,于是趁学校开设这门课,并 ...

  4. EXTJS4.2中neptune主题的使用

    原文地址:http://blog.csdn.net/xieguojun2013/article/details/8880519 最近在在sencha.com官网了解到EXTJS的最新版本里增加了新的主 ...

  5. Linux下得到毫秒级时间--C语言实现(转-度娘818)

    Linux下得到毫秒级时间--C语言实现 原文链接: http://www.cnblogs.com/nwf5d/archive/2011/06/03/2071247.html #ifdef HAVE_ ...

  6. 如何配置网络使得宿主机能够访问VM数据库?

    https://www.zhihu.com/question/23955166 背景:公司内外网区分,不能同时上,局域网内得手动切换两个网络,分别访问外网或者内网,ip是动态获取的.现在本机上装有vm ...

  7. relative

    进行relative定位后的元素,不会影响原本的文本流. 下图左列的第二张图是进行了margin-top取负值,右列第二张图进行了relative定位     

  8. CC2540中的电压检测

    /** * Battery level conversion from ADC to a percentage: * * The maximum ADC value for the battery v ...

  9. go异常处理

    go的异常处理通过defer,panic,recover这3个流程来达到(defer是关键字,后2者是函数) (1)异常的捕获通常放在函数最末,也就是defer里面 (2)panci抛出异常 (3)r ...

  10. BarTender是怎么做出雪花状文字

    一些小伙伴在做标签时,发现有的人做的标签上的文字颜色不是纯色的,问我是怎么做的.这种雪花状文字要设置出来其实很简单,只要用到字体颜色填充工具就可以了.下面,小编就来给大家简单介绍一下BarTender ...