CS架构中服务器确认客户端是否在线的方法

fanzhouqi 2011-07-03 09:51:56
我现在用的方法是这样的:
用户表中有一个IsOnline和ActiveTime字段,用户登录后IsOnline属性就为true,然后客户端每隔3秒给服务器端发送一个心跳包,刷新ActiveTime字段为当前时间,服务器每隔30秒扫描一遍IsOnline属性为true的用户,发现最后收到的心跳包时间与当前时间之差大于10秒的(保守假设在通信线路上消耗的时间为2秒,那么正常情况下服务器是每5秒收到一个心跳包,10秒即连续收不到两个心跳包),那么,便将该用户的IsOnline属性置为false,表明该用户断线了。

这样的问题是:
假如有3W个在线用户,那平均每秒就有1W个包发到服务端,而且会执行1W条update语句,这个开销太疯狂了,而且还会随着用户的增加等比例上升。

大家做这种应用的时候是采用什么方法的呢?分享一下

PS:好奇QQ是采用什么样的方式才判断用户在线状态的。。
...全文
497 12 打赏 收藏 转发到动态 举报
AI 作业
写回复
用AI写文章
12 条回复
切换为时间正序
请发表友善的回复…
发表回复
--缪军-- 2011-07-03
  • 打赏
  • 举报
回复
楼主,既然是C/s分布式的,就应该有应用程序服务,而且可以是N个服务,
而不是client直接访问数据库,
心跳包更新的是应用程序服务的在线用户信息,而不是数据库,
如果用户太多,那么就不断地分割服务

C/S中的S不是特指数据库服务器
jsyhello 2011-07-03
  • 打赏
  • 举报
回复
建议先用内存保存一段时间 在一起update到数据库
lnmhfeng 2011-07-03
  • 打赏
  • 举报
回复
我觉得也不要一次心跳,就去Update一次数据库,在内存里查询要比较数据查询要好,只是你自己要定义一些规则来更新数据库的IsActive状态。

关于QQ,听别个人说像是基于长连接的,具体也没有研究过:(
fanzhouqi 2011-07-03
  • 打赏
  • 举报
回复
你的意思是在内存中维护一个在线用户的集合?这样如果条数多的话,我对这个集合进行检索和循环的速度貌似会很慢。
bdmh 2011-07-03
  • 打赏
  • 举报
回复
心跳包,和update语句有什么关系,难道你在不在线的标识还要写道数据库,这是你设计的缺陷
fanzhouqi 2011-07-03
  • 打赏
  • 举报
回复
[Quote=引用 6 楼 etudiant6666 的回复:]
每家的架构不同,判断方式也会不同,就你目前的架构,貌似可以采用数据库操作与内存队列结合的方式处理,即内存中的在线用户队列定时更新心跳接收信息,而只对收不到心跳(离线)的用户设置数据库离线标记,并将其剔除队列,而新用户登录完成后,对数据库设置在线操作,并将其加入到队列中,这样就达到了性能与功能的平衡。
[/Quote]
你的方法挺好的,给了我一个很好的思路。

也感谢其他各位的回复。

接下来的细节问题我会自己再考虑吧。
--缪军-- 2011-07-03
  • 打赏
  • 举报
回复
[Quote=引用 10 楼 fanzhouqi 的回复:]
[/Quote]
我也提到了,分割服务,
还有心跳包策略的设计和调整
fanzhouqi 2011-07-03
  • 打赏
  • 举报
回复
to #5
你误会了,我并没有让客户端直接连数据库,而是通过udp发包给服务器,服务器收到udp包后再更新数据库。

我现在考虑的就是如果在内存中维护一个在线用户集合的话,然后我每隔30秒遍历一次这个集合,查看哪些用户已超过10秒没有心跳包发过来了,将他剔除这个集合。
这样的话,比如这个集合有3W条记录,每30秒遍历一次,感觉就很吃性能。
而且并发性也存在问题,比如在foreach遍历的时候,有另外的线程登录进来,就要将新用户加进集合中,这样遍历操作又会抛异常。。。
thebesttome 2011-07-03
  • 打赏
  • 举报
回复

实现心跳包一个比较好的方法是在服务器当接收到包后跟新一次数据库说明用户在线,然后通过程序中维护一张自定义表来判断用户离线。当离线判定成功在写一次数据库说明用户离线。
具体实现可以全部在服务器。
客户端首先发一个心跳包给服务器。
服务器接收到包过后,在Update到数据库一次。说明用户在线。(比如置状态为0)
然后服务器启动线程。每3S接收一次心跳包。统计每个用户心跳包个数。同时服务器在接收到客户端发送来的包时候自己也开始没3S计数。比较用户离线就判断服务器计数和客户端计数的相差多少就行了。
这样就可以不用每一次去写数据库
  • 打赏
  • 举报
回复
[Quote=引用楼主 fanzhouqi 的回复:]
假如有3W个在线用户,那平均每秒就有1W个包发到服务端,而且会执行1W条update语句,这个开销太疯狂了,而且还会随着用户的增加等比例上升。
[/Quote]

1. 为什么要每隔3秒呢?为什么不是每隔15秒?

2. 你的设计怎么跟数据库update扯上关系了呢?
thebesttome 2011-07-03
  • 打赏
  • 举报
回复
一般判断客户端可以采用心跳包算法。在客户端发包到服务器。
心跳包自己定义,一般包括用户的信息。比如说用户的ID(唯一标示用户的)
然后在服务器中启动另外的线程接收客户端发过来的包。在统计数量。同时服务器也开始自己统计时间。
判断当多少时间内没收到包。判断用户离线。
具体技术:TCP编程。多线程编程。
窗户纸 2011-07-03
  • 打赏
  • 举报
回复
[Quote=引用楼主 fanzhouqi 的回复:]
我现在用的方法是这样的:
用户表中有一个IsOnline和ActiveTime字段,用户登录后IsOnline属性就为true,然后客户端每隔3秒给服务器端发送一个心跳包,刷新ActiveTime字段为当前时间,服务器每隔30秒扫描一遍IsOnline属性为true的用户,发现最后收到的心跳包时间与当前时间之差大于10秒的(保守假设在通信线路上消耗的时间为2秒,那么正常情况下服务器是每5秒收到一……
[/Quote]
每家的架构不同,判断方式也会不同,就你目前的架构,貌似可以采用数据库操作与内存队列结合的方式处理,即内存中的在线用户队列定时更新心跳接收信息,而只对收不到心跳(离线)的用户设置数据库离线标记,并将其剔除队列,而新用户登录完成后,对数据库设置在线操作,并将其加入到队列中,这样就达到了性能与功能的平衡。

111,098

社区成员

发帖
与我相关
我的任务
社区描述
.NET技术 C#
社区管理员
  • C#
  • AIGC Browser
  • by_封爱
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告

让您成为最强悍的C#开发者

试试用AI创作助手写篇文章吧