那谁的技术博客

感兴趣领域:高性能服务器编程,存储,算法,Linux内核
随笔 - 210, 文章 - 0, 评论 - 1183, 引用 - 0
数据加载中……

自己设想的一个IM服务器的架构

续一在这里:http://www.cppblog.com/converse/archive/2009/01/14/71993.html

可能不太成熟,欢迎讨论.

客户端需要的功能: 登录, 获取信息(如自己的资料, 好友的在线状态,好友资料如签名, 图片, 其它资料等), 客户之间发送消息
       
服务器端:          
        有以下几种服务器:
       
        登录服务器:   
        负责管理客户端登入/登出,验证登录客户端的合法性等,与客户端发送心跳包维持连接的状态,在客户端登录之后, 告知消息服务器该用户上线, 消息服务器查询是否有该用户的离线消息将消息发送给用户.
        同时, 登录服务器是仅有的C2S服务器, 也就是说所有要发送给客户端的消息都需要经过登录服务器发送, 而给客户端发送的消息都是采用udp形式发送(包括心跳包), udp容易丢失, 因此需要在发送之后对端有回应, 否则就要再试发送.

        登录服务器和下面的资料服务器,消息服务器以及其它的内部服务器之间采用TCP长连接保持连接.
       
        资料服务器:   
        负责管理客户资料, 如图片,个人说明,好友分组, 好友等等, 这些都需要cache, 如果在cache中查询不到才去数据库中查询.
        客户端登录之后首先往好友服务器查询自己的资料(图片,个人说明,好友在线状态等), 其中查询好友在线状态需要和登录服务器进行交互.资料服务器只是一个最外部对外面开放的服务器, 底下下设各种与好友资料相关的服务器, 如图片服务器, 个人资料服务器, 好友在线状态服务器等.
                   
        消息服务器:   
        负责存取离线消息.
       
        对外暴露的只有登录服务器而已, 而资料服务器和消息服务器隐藏在登录服务器之后.
       
        大致如图:
       
        客户端1 ....  客户端n
          \      |       /         ----> udp发送消息
             登录服务器
            /         \            ----->tcp长连接
        资料服务器      消息服务器
        /        \                 ------>tcp长连接
图片服务器   个人资料服务器       
                   
几个可能的性能问题:
1) 当用户量上来的时候服务器如何扩容?考虑采用不同的IP地址绑定同一个域名的形式, 也就是说登录服务器单独一个域名, 但是扩容之后的不同登录服务器都绑定在这个域名上, 由客户端的DNS域名解析自己决定与哪个登录服务器进行通信.
  
2) 服务器之间采用tcp长连接, 如果其中一个服务器宕机, 如何处理?需要有好的服务器平滑切换备份机器的技术, 以及好的监控服务器机制.

3) 如何高效存取离线消息?
   考虑如下一个方案:有0x00-0xff个目录, 每个目录有0x00-0xff个文件, 在类似bdb这样的数据库中存放一条记录, key是用户id, value是"目录:文件", 查询发送给某个用户的离线消息时首先到这个数据库中得到相应的目录和文件, 再取出所有给该用户的消息(消息在这个文件中有自己的一套格式).当用户量上来的时候, 需要增加前面说的目录和文件数量.
  
4) 如何保存用户的在线状态?也就是说,如何迅速做到知道哪些用户是否在线?这个是不能用cache实现的, 因为cache存放的应该是那些访问频繁同时不关注服务器停止之后是否会丢失的数据, 如果用数据库来保存, 那么数据的增删很频繁.


================= 分割线 ======================================
补充:
1)关于在线状态服务器:单独拿出一个服务器做这个保存在线状态的服务器, 在内存中保存用户的在线状态,这台服务器与登录服务器相连, 有用户登录时发包加一条数据,登出时也发包删除一条数据, 由于直接放在内存中, 有以下的优缺点:优点是速度快, 而且由于是一台单独的服务器做这个功能, 即使是千万级别的用户同时在线按照现在服务器的硬件配置也足以保存;缺点是假如这个服务器挂了, 数据会丢失, 但是考虑到前面的登录服务器会每隔几秒给客户端发送一个心跳包查询在线状态,因此即使有误差也可以控制在很短的时间里面.
因此, 现在的架构变成了登录服务器下面还隐藏着一个保存用户在线状态的服务器.

2) 离线消息服务器:扩容的时候可以考虑把这部分的服务器做成分布式的, 也就是说, 暴露在最外面的是一台服务器, 当查询某个用户消息的请求到来时, 再根据hash等方式计算出真正所在的服务器, 而这一部分服务器是分布式的, 类似于memcached那样的.
此时架构就变成了消息服务器下面隐藏着很多真正存放消息的服务器.

最后的架构如下:



posted on 2009-01-13 15:57 那谁 阅读(9174) 评论(11)  编辑 收藏 引用 所属分类: 服务器设计

评论

# re: 自己设想的一个IM服务器的架构  回复  更多评论   

用户的在线状态,简单一点,直接保存在内存中,复杂一点,保存在共享内存中
2009-01-13 17:42 | eXile

# re: 自己设想的一个IM服务器的架构  回复  更多评论   

@eXile
是的,我刚也想到了,马上补上.
2009-01-13 19:41 |

# re: 自己设想的一个IM服务器的架构  回复  更多评论   

可以参考一下JABBERD 我觉得那个设计得挺好。
可以用UML画图看看你的架构:)
2009-01-13 19:57 | 淋雨的感觉

# re: 自己设想的一个IM服务器的架构  回复  更多评论   

不错!

我也曾经做了一个 p2p的 IM。。

但是你的架构的负载量不行!
2009-01-13 20:52 | expter

# re: 自己设想的一个IM服务器的架构  回复  更多评论   

@expter
还请问问哪些地方需要改善的?能否详说.

2009-01-13 22:27 |

# re: 自己设想的一个IM服务器的架构  回复  更多评论   

1,服务器分层不太清晰,登陆服做的事情过多,考虑可以分层实现
2,消息跨服需中转,如果服务器很多的话,那么服务器组的管理也是一个问题
2009-01-14 09:40 | zuhd

# re: 自己设想的一个IM服务器的架构  回复  更多评论   

同上,登录服务器作的事情过多,如果一台登录服务器挂掉了,是否意味着所有登录到这台服务器的用户全部下线?发生此情况后,在线状态服务器如何获知哪些用户下线了?在线状态更新等待超时,还是等待来自登录服务器的心跳信号超时?同样有问题消息服务器的设计上,你把消息服务器隐藏在登录服务器之后,如果处理多人IM,将会是将1条IM变成n条IM通信在登录服务器和消息服务器之间通信,浪费资源。
2009-01-14 12:27 | www.helpsoff.com.cn

# re: 自己设想的一个IM服务器的架构  回复  更多评论   

楼上几位,我已经按照你们的意见做了修改,请看续一:
http://www.cppblog.com/converse/archive/2009/01/14/71993.html
2009-01-14 13:49 | 那谁

# re: 自己设想的一个IM服务器的架构  回复  更多评论   

顶 楼主 学到了很多东西
2011-07-04 08:23 | 不却

# re: 自己设想的一个IM服务器的架构  回复  更多评论   

想法很淫@#¥荡,但是等你真正去做的时候会发现很多问题,首先看你第一点就是说的有问题了,
“1) 当用户量上来的时候服务器如何扩容?考虑采用不同的IP地址绑定同一个域名的形式, 也就是说登录服务器单独一个域名, 但是扩容之后的不同登录服务器都绑定在这个域名上, ”
------------------------------------------------------
一台主机可以绑定多个域名,但是一个域名只能绑定一台主机。
“由客户端的DNS域名解析自己决定与哪个登录服务器进行通信.”,这句也是有问题的,所有客户端解析这个域名得到的结果必定是一样的。
2011-08-21 02:02 | 小覃

# re: 自己设想的一个IM服务器的架构  回复  更多评论   

不能单靠软件来实现,还有有设备的支持,设备根据服务器的负载自动选择服务器,比如并发送突然过大,这时要靠网络设备来负载均衡。 使用分布式文件系统、P2P、服务器存储优化等技术,用户文件互传远程管理等操作可以直接使用P2P实现。
2011-08-21 02:21 | 小覃

只有注册用户登录后才能发表评论。
网站导航: 博客园   IT新闻   BlogJava   知识库   博问   管理