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. Lua table库整理(v5.1)

    这个库提供了表处理的通用函数. 所有函数都放在表 table. 无论何时,若一个操作需要取表的长度, 这张表必须是一个真序列. table.concat(list, [, sep, [, i , [, ...

  2. UE4 去除不正确的水面倒影以及不完整镜头轮廓

    最近在做的项目遇到了一点点问题,出现了如下效果 视角对着湖面移动会出现一个显示不完整的轮廓(比较长的蓝色矩形),详细一点就是下图这样,以及近处物体的倒影(从光照的照射角度来看是不应该出现的) 一开始就 ...

  3. CSS3的nth-child(n)选择器学习

    写法:tr:nth-child(2),表示非tr的子元素中的第二个元素,并非从0开始计数,跟编程语言中的数组有区别. 参考网址:http://www.w3schools.com/cssref/sel_ ...

  4. 拓展Yii Framework(易框架)

    1.拓展yii 此文针对Yii1.1.15而写,请注意甄别你的Yii Framework 版本. 拓展yii是开发期间常见的代码处理方式.例如,你写一个新的controller(业务控制器),你通过继 ...

  5. Mongodb优化

    本文将从各个层面讲述Mongodb的优化方法

  6. LeetCode() Symmetric Tree

    /** * Definition for a binary tree node. * struct TreeNode { * int val; * TreeNode *left; * TreeNode ...

  7. 关于vue.js中事件处理器的练习

    html: <!DOCTYPE html><html lang="en"><head> <meta charset="UTF-8 ...

  8. 关于js的keycode13

    一个form 里面只有一个input的时候  触发keydown 之类的事件  表单会在你的动作之外再次提交一次.并且 字段使用的是input的id  而不是name  可以在form上加一个onsu ...

  9. 编程:使用递归方式判断某个字串是否回文(Palindrome)

    Answer: import java.util.Scanner; public class Palindrome { private static int len;//全局变量整型数据 privat ...

  10. Android 中算法问题

    1:冒泡排序: 冒泡排序的思路: 相邻的两个数进行比较 (1):首先需要连个for 循环 (2):最外层for 循环控制最里面 for 循环的循环次数 (3):通过设置中间参数的方式进行交换 (4): ...