Ejabberd源码解析前奏--集群
一、如何工作
一个XMPP域是由一个或多个ejabberd节点伺服的. 这些节点可能运行在通过网络连接的不同机器上. 它们都必须有能力连接到所有其它节点的4369端口, 并且必须有相同的 magic cookie (见 Erlang/OTP 文档, 换句话说,在所有节点上,文件 ~ejabberd/.erlang.cookie 必须是相同的 ). 这是必须的,因为所有节点交换关于已连接的用户、s2s连接、已注册的服务等信息.每个 ejabberd 节点有如下四个模块:
1、Router
这个模块是每个节点的XMPP包的主router. 它基于它们的目标域来路由它们. 它使用一个全局路由表. 在这个路由表里搜索到包的目的地的域, 并且如果找到, 这个包就被路由到适当的进程. 如果没找到, 它被送到 s2s manager.
2、Local Router
这个模块路由那些目的域等于服务器的主机名之一的包. 如果目的JID有一个非空的 user 部分, 它路由到 session manager, 反之则它的处理依赖于它的内容.
3、Session Manager
这个模块路由包到本地用户. 它通过一个presence信息表查找一个包必须被发送给哪个用户资源. 然后该包要么路由到适当的 c2s 进程, 要么存储在离线存储 offline storage, 或弹回.
4、s2s Manager
这个模块路由包到其它 XMPP 服务器. 首先, 它检查是否已存在一个从该包的源域到目的域的s2s连接. 如果有, s2s manager 路由这个包到伺服这个连接的进程, 反之打开一个新的连接.
二、集群配置
假定你已经在一个机器named(第一个)上配置了 ejabberd , 并且你需要配置另外一个来做一个 ejabberd 集群. 那么按以下步骤做:
(1)从第一台机器拷贝 ~ejabberd/.erlang.cookie 文件到第二台机器.
(或者) 你也可以增加‘-setcookie content_of_.erlang.cookie’选项到以下所有‘erl’ 命令.
(2)在第二台机器上,在ejabberd工作目录中,以 ejabberd 守候进程用户运行以下命令:
erl -sname ejabberd \
-mnesia dir '"/var/lib/ejabberd/"' \
-mnesia extra_db_nodes "['ejabberd@first']" \
-s mnesia
这将启动 Mnesia 服务于和 ejabberd@first 相同的数据库. 你可以运行命令 ‘mnesia:info().’检查它. 你应该看到许多远程表和行,类似如下: 注意: 在你的系统里 Mnesia 目录可能是不同的. 要知道 ejabberd 期望按照缺省方式安装 Mnesia, 不带参数调用 ejabberdctl 然后它将显式一些帮助, 包括 Mnesia database spool 目录.
running db nodes = [ejabberd@first, ejabberd@second]
(3)现在在相同的‘erl’会话下运行以下命令:
mnesia:change_table_copy_type(schema, node(), disc_copies).
这将为该数据库建立本地磁盘存储. (或者) 在第二个节点通过Web管理修改scheme表的存储类型为‘RAM and disc copy’.
(4)现在你可以增加更多表的复制到这个节点 ,使用‘mnesia:add_table_copy’ 或 ‘mnesia:change_table_copy_type’如上 (只是把 ‘schema’ 替换成其他表名,并且 ‘disc_copies’可以被替换成‘ram_copies’ 或 ‘disc_only_copies’).
哪个表被复制,依赖于你的需要, 你可以从‘mnesia:info().’命令得到一些提示, 通过查看每个位于 ’first’的表的大小和缺省的存储类型.
复制一个表使得这个节点的这个表的查询更加快速. 另一方面, 写入将更慢. 而且当然如果复制之一的机器挂了, 其它复制将被使用.
看一下 Mnesia用户指南的 5.3 节(表 片段)将有所帮助. (或者) 同之前的条目, 但用于不同的表.
(5)运行‘init:stop().’ 或只是 ‘q().’ 来退出 Erlang shell. 这可能要花些时间,如果 Mnesia 还没有从first传输和处理完所有数据.
(6)现在在第二台机器上使用和第一台机器类似的配置运行 ejabberd: 你可能不需要重复‘acl’ 和 ‘access’ 选项,因为它们将从第一台机器获得; 并且 mod_irc 只应该在集群里的一台机器上激活.
你可以在其它机器上重复这些步骤来服务于这个域.
三、服务负载均衡
1、域负载均衡机制
ejabberd包含了一个机制来对插入一个ejabberd集群的组件进行负载均衡. 它意味着你可以在每一个ejabberd集群插入相同组件的一个或多个实例并且流量将自动分布.
缺省的分布式机制尝试递送到组件的一个本地实例. 如果有多个本地实例可用, 随机地选取一个实例. 如果没有本地实例可用, 随机选取一个远程组件实例.
如果你需要一个不同的行为, 你可以通过选项 domain_balancing 修改负载均衡行为. 这个选项的语法如下:
{domain_balancing, "component.example.com", BalancingCriteria}.
多个负载均衡标准可用:
(1)destination: 使用包的to属性的全JID.
(2)source: 使用包的from属性的全JID.
(3)bare_destination: 使用包的to属性的纯JID(没有资源).
(4)bare_source: 使用包的from属性的纯JID(没有资源).
如果对应标准的这个值是相同的, 则集群中相同的组件实例将被使用.
2、负载均衡水桶
当一个给定的组件有失败的风险的时候, 域均衡可能导致服务麻烦. 如果一个组件失败了,服务将无法正确工作,除非会话被重新均衡了.
在这种情况下, 最好限制这个问题再由失败组件处理的这些会话. 这就是 domain_balancing_component_number 选项所做的, 使负载均衡机制不动态化, 而是粘在固定数目的组件实例上.
语法是:
{domain_balancing_component_number, "component.example.com", Number}.