续一在这里: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那样的.
此时架构就变成了消息服务器下面隐藏着很多真正存放消息的服务器.
最后的架构如下: