OpenFire源码学习之二十三:关于消息的优化处理

消息处理

之前有说过,openfire的消息处理策略本人并不是很喜欢。先看下openfire上脱机消息策略。


个人认为消息关于会话的消息,用户的存储量应该无限大。服务器不应该被消息吃撑了。所谓聊天通讯,这一关很重要。

Openfire的消息是什么流程呢。

1、当用户登陆连接的时候。握手、认证、绑定资源、获取花名册、获取离线消息。

2、服务端会查找关系型数据库。经本人测试离线消息在数据库表中达到100万条以上的时候,查询速度非常慢,甚至会导致openfire奔溃。

.....

 

那么openfire在消息这块会有哪些不足之处呢。本人认为有一下几点:

1)用户登陆的时候需要验证用户的可效性。又一次需要查询数据库,而本人认为这一步没

   必要。可以删掉

2)用户每次登陆都需要重新获取自己的好友花名册。这样导致数据访问次数过多,服务端

push消息的量也增多。导致登陆流程很慢

3)用户发送的消息,没有回执。就是说A发送消息给B。而B又一致不回复。所以对于客

   户端A来讲压根不知道消息是否发送成。然而S(服务端)接收到A的消息转发给B的时

   候,B也不做回执。所以S也不知道消息到底是否成功到达。

4)用户的离线消息表访问峰值时,系统可能会奔溃。

 

针对上面的问题,下面一一做解答。

用户校验

问题1:比较简单。在DefaultLockOutProvider中有一个getDisabledStatus方法。该方法判断用户的可效行。禁用这个方法则可。

源码如下:

[java]  view plain  copy
  1. public LockOutFlag getDisabledStatus(String username) {  
  2.     if (username == null) {  
  3.         throw new UnsupportedOperationException("Null username not allowed!");  
  4.     }  
  5.     if (provider.shouldNotBeCached()) {  
  6.         return provider.getDisabledStatus(username);  
  7.     }  
  8.     LockOutFlag flag = lockOutCache.get(username);  
  9.     // If ID wan't found in cache, load it up and put it there.  
  10.     if (flag == null) {  
  11.         synchronized (username.intern()) {  
  12.             flag = lockOutCache.get(username);  
  13.             // If group wan't found in cache, load it up and put it there.  
  14.             if (flag == null) {  
  15.                 flag = provider.getDisabledStatus(username);  
  16.                 lockOutCache.put(username, flag);  
  17.             }  
  18.         }  
  19.     }  
  20.     return flag;  
  21. }  

用户数据同步

问题2:将用户花名册、group、MUC等相关信息预知Redis中。设置用户的数据版本标志。用户每次登陆后只需要跟服务端记录的用户版本进行匹配。版本一致的时候则不需要每次都要重新同步了。本人针对用户聊天室重新做了XMPP的拓展。

A.用户发送请求获取自己所拥有的房间:

[html]  view plain  copy
  1. <iq id="Ho4CO-2" type="get">  
  2.     <query xmlns="jabber:iq:room"></query>  
  3. </iq>  

B.服务端返回消息:

[html]  view plain  copy
  1. <iq type="result" id="GYIEb-8" to="1aaa@8ntmorv1ep4wgcy/Smack#1aaa1387704207688">  
  2.   <query xmlns="jabber:iq:room">  
  3.     <item>  
  4.       <room>  
  5.         <serviceid>1</serviceid>  
  6.         <name>eds</name>  
  7.         <roomid>16632</roomid>  
  8.         <naturalName>dd</naturalName>  
  9.         <description>dd</description>  
  10.         <subject>admin</subject>  
  11.         <affiliation>member</affiliation>  
  12.       </room>  
  13.       <room>  
  14.        .......  
  15.       </room>  
  16.     </item>  
  17.   </query>  
  18. </iq>   

C.用户获取房间内成员:

[html]  view plain  copy
  1. <iq id="hF4p7-9" to="srcs_room0@conference.8ntmorv1ep4wgcy" type="get">  
  2.      <query xmlns="http://jabber.org/protocol/muc#members"></query>  
  3. </iq>  

D.服务端返回消息

[html]  view plain  copy
  1. <iq type="result" id="S4Q6V-8" from="srcs_room0@conference.8ntmorv1ep4wgcy" to="user1@8ntmorv1ep4wgcy/Smack#user11387159214678">  
  2.   <query xmlns="http://jabber.org/protocol/muc#members">  
  3.     <item affiliation="owner">  
  4.       <user jid="56@8ntmorv1ep4wgcy"/>  
  5.       <user jid="58@8ntmorv1ep4wgcy"/>  
  6.       <user jid="admin@8ntmorv1ep4wgcy"/>  
  7.     </item>  
  8.     <item affiliation="admin">  
  9.       <user jid="user1@8ntmorv1ep4wgcy"/>  
  10.       <user jid="user62@8ntmorv1ep4wgcy"/>  
  11.       <user jid="user63@8ntmorv1ep4wgcy"/>  
  12.     </item>  
  13.     <item affiliation="members">  
  14.       <user jid="user32@8ntmorv1ep4wgcy"/>  
  15.       .......  
  16.     </item>  
  17.   </query>  
  18. </iq>  

下面代码主要描述服务端对用户聊天室请求的处理

[java]  view plain  copy
  1. public class IQMucMembersHandler extends IQHandler {  
  2.   
  3.     private IQHandlerInfo info;  
  4.     private XMPPServer localServer;  
  5.       
  6.     public IQMucMembersHandler() {  
  7.         super("XMPP MucMembers Handler");  
  8.         info = new IQHandlerInfo("query""http://jabber.org/protocol/muc#members");  
  9.     }  
  10.   
  11.     @Override  
  12.     public IQ handleIQ(IQ packet)  {  
  13.         IQ reply = IQ.createResultIQ(packet);  
  14.         reply.setType(IQ.Type.result);  
  15.         reply.setID(packet.getID());  
  16.         reply.setTo(packet.getFrom());  
  17.         reply.setFrom(packet.getTo());  
  18.           
  19.         if (IQ.Type.get.equals(packet.getType())) {  
  20.             JID roomJID = packet.getTo();  
  21.             MUCRoom room = localServer.getMultiUserChatManager().  
  22.                             getMultiUserChatService(roomJID).getChatRoom(packet.getTo().getNode());  
  23.             Element item = reply.setChildElement("query","http://jabber.org/protocol/muc#members");  
  24.             if (room != null) {  
  25.                 Element owner = item.addElement("item");  
  26.                 owner.addAttribute("affiliation""owner");  
  27.                 Collection<JID> owners  = room.getOwners();  
  28.                 if (!owners.isEmpty()) {  
  29.                     for (JID userJID : owners) {  
  30.                         if ("admin".equals(userJID.getNode())){  
  31.                             continue;  
  32.                         }  
  33.                         Element jid = owner.addElement("user");  
  34.                         jid.addAttribute("jid", userJID.toBareJID());  
  35.                     }  
  36.                 }  
  37.                   
  38.                 Element admin = item.addElement("item");  
  39.                 admin.addAttribute("affiliation""admin");  
  40.                 Collection<JID> admins  = room.getAdmins();  
  41.                 if (!admins.isEmpty() ) {  
  42.                     for (JID userJID : admins) {  
  43.                         Element jid = admin.addElement("user");  
  44.                         jid.addAttribute("jid", userJID.toBareJID());  
  45.                     }  
  46.                 }  
  47.                   
  48.                 Element member = item.addElement("item");  
  49.                 member.addAttribute("affiliation""members");  
  50.                 Collection<JID> members  = room.getMembers();  
  51.                 if (!members.isEmpty()) {  
  52.                     for (JID userJID : members) {  
  53.                         Element jid = member.addElement("user");  
  54.                         jid.addAttribute("jid", userJID.toBareJID());  
  55.                     }  
  56.                 }  
  57.             }  
  58.               
  59.         }  
  60.         return reply;  
  61.     }  
  62.   
  63.     @Override  
  64.     public void initialize(XMPPServer server) {  
  65.         super.initialize(server);  
  66.         localServer = server;  
  67.      }  
  68.   
  69.     @Override  
  70.     public IQHandlerInfo getInfo() {  
  71.         return info;  
  72.     }  
  73. }  
这里回答了提出来的2点问题。第3、4个问下会在下面章节中回答
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值