03 | 轮询与长连接:如何解决消息的实时到达问题?
03 | 轮询与长连接:如何解决消息的实时到达问题?
讲述:袁武林
时长11:29大小13.12M
短轮询场景
长轮询场景
服务端推送:真正的边缘触发
WebSocket
TCP 长连接衍生的 IM 协议
小结
赞 15
提建议
精选留言(70)
- 王棕生2019-09-02TCP 长连接的方式是怎么实现“当有消息需要发送给某个用户时,能够准确找到这个用户对应的网络连接”? 答: 首先用户有一个登陆的过程: (1)tcp客户端与服务端通过三次握手建立tcp连接;(2)基于该连接客户端发送登陆请求;(3)服务端对登陆请求进行解析和判断,如果合法,就将当前用户的uid和标识当前tcp连接的socket描述符(也就是fd)建立映射关系; (4)这个映射关系一般是保存在本地缓存或分布式缓存中。 然后,当服务端收到要发送给这个用户的消息时,先从缓存中根据uid查找fd,如果找到,就基于fd将消息推送出去。展开
作者回复: 👍
共 10 条评论82 - 菜菜菜菜菜鸟2019-09-02TCP不是可靠的吗,为什么还需要在应用层实现ack,不应该是消息发出对方就一定可以收到的吗
作者回复: 是个好问题。因为很多时候消息由tcp层交给应用层之后还可能出现丢失的情况,比如客户端落本地db失败了,类似这种。
共 6 条评论30 - 技术带头2019-09-08老师你好,我们也落地了一套im,服务端和本地都有存储,和用websoket。现在存在一个问题。群聊离线推送是将离线后产生的所有消息再用户上线的时候推送,还是客户端分页拉取
作者回复: 可以考虑推拉结合,离线消息太多如果全部都推的话性能和带宽上都不太友好,可以离线推送一页,后续的再由客户端来拉取。
18 - yic2019-09-08客户端发送心跳包,一般多久一次比较合适? 我看老师有回复国内不超过5分钟,微信用的是4分半。这个时间有什么依据吗?
作者回复: 以前有大厂测试过国内各家运营商的NAT超时情况,有的运营商在2/3G网络下NAT超时是5分钟。
共 2 条评论17 - 魏巍2019-09-03服务器端如果突然进程被kill掉,客户端如何及时得到通知并下线?
作者回复: 进程kill是会对socket执行close操作的哈,所以客户端是能感知到的。真要是通过拔网线的方式把服务端网络断开,这种情况客户端在发送数据时就会失败,然后短连后重连其他服务器就可以了。
共 2 条评论15 - 飞翔2019-09-02服务器维护一个hashmap key是 userid,value 是socket instance, 这样 用户A 发给用户B的信息里边含有用户B 的id, 用usedBid 到hashmap 里边查到 用户B的socket 就可以用socket 发送信息给用户B了,老师我还有一个问题 就是如果一台机器连接数有限, 如果需要多台机器,如果用户A的socker 和用户B的socket 不在一台机器上,这样怎么解决呀
作者回复: 一种做法是用户上线时维护一个全局的 uid->网关机 的映射,下发的时候就能做到精确定位;另一种方式是:下发时把所有消息下发给所有机器,每台机器如果发现当前用户连接在本机就下发,其他的就丢掉,这种会有一定的资源浪费。
共 12 条评论14 - 探索无止境2019-10-01老师你好,为什么说一台服务器可以最多可以支持1000万的连接请求,这个数值是怎么推算出来的?
作者回复: 不具备读写操作仅仅只是维护静态连接的话基本上就是个拼内存的活,调整tcp单连接的读写缓冲区大小到4k,优化下其他系统参数比如句柄限制啥的,建连速度稍微慢点,有个200g内存是没问题的。这里其实想说的是,不要光看单机能维护多少连接,每秒收发包数这些才是关键。
11 - 魏巍2019-09-03一个linux服务器可以接受多少tcp连接,如何量化这个数字?当业务层对持久化层操作响应慢时,为何客户端会频繁掉线?聊天数据的持久化与下发操作查库对数据库的读写压力如何缓解?实时聊天的数据库如果宕机,能否做自动切换数据库服务器的操作?
作者回复: 连接数一般不是问题哈,服务端单机几百万上千万都可以的,受限于分配给每个连接的buffer占用的内存。业务层持久化会慢会导致客户端掉线这个没看懂呀,能具体一点吗?第三个问题可以做db的读写分离,第四个问题应该是说db的自动切主吧,这个是可以的哈,很成熟的方案。
8 - sam2019-09-03轮询就是前段定时请求,这个比较了解。但长轮询第一次听说,实际开发也没用过,特别是服务器的“悬挂(hang)”怎么理解? 是HTTP协议的机制吗?
作者回复: 和http没关系哈,实现上比如接收到一个请求后,通过while循环判断,如果请求时间和当前时间的时间差没有到达超时阈值,就继续查询后端是否有新消息,直到超时或者查询到新消息。
共 2 条评论8 - 魏巍2019-09-03客户端发送心跳包,一般多久一次比较合适?
作者回复: 国内的话最好不要超过5分钟,微信应该是4分半。
共 3 条评论7 - 小可2019-09-02用户使用客户端与服务器建立连接时携带了userid与clientid,连接建立成功后,服务器端记录用户、客户端及连接之间的关系。一个可以用户使用多个客户端建立连接,一般是不同类型的客户端(网页、APP),后续有消息可根据此关系进行多端推送。
作者回复: 👍
共 2 条评论5 - 超威丶2019-09-02请问websocket为什么能实现实时通信
作者回复: websocket支持双向全双工的传输,所以可以做到服务端推送,让消息接收更加实时。
共 4 条评论5 - zombo2020-03-13老师请教一个区分,长连接是不是 "header: keep-alive" 的连接? 英文对应 persistent HTTP connection,但大家用得不多。而 webSocket 是HTML5才出来的,类似的机制,但各种浏览器支持得比较多。 因为机制和实现上,我好像看不出它们有太大的区别? 还是说 persistent HTTP 仍然是3次握手,websocket是一次?
作者回复: 最大的区别在于websocket是支持全双工的,也就是说是可以由服务端主动进行推送的,http 1.1 的keep alive只是能够多次http请求复用同一个tcp连接,但只能由客户端发起请求。
5 - 来自清真寺的圣诞树2019-10-14如果是websocket可以使用stomp协议解决?
作者回复: 有这么玩的,STOMP Over Websocket,可以基于STOMP的消息队列模式来实现消息推送。
4 - 冷笑的花猫2019-09-02请问老师,假设mqtt有两个缺点,不支持离线和群组功能,但可以修改源码增加这两类功能,而且mqtt已基本成熟,在mqtt之上开发不更方便和快捷吗?为啥要在tcp基础上自己开发呢?如果仅仅因为这些选择了了基于tcp自己开发,感觉说服力没那么强啊。 所以请老师能详细说下这些的优缺点吗?晚上搜索到的感觉不太靠谱,谢谢。
作者回复: 基于mqtt做二次开发是可以的呀,而且目前也有很多公司已经是这么做的了。只是说有开发能力的大厂更愿意自己来实现一套私有协议,主要是完全根据业务定制化,协议设计上会更高效一些。
5 - Shuai2019-09-02请问,XMPP是基于 XML 格式的协议,那像微信这种成熟的IM软件的私有通信协议是基于什么格式的呢?二进制吗?
作者回复: 据我了解微信是私有二进制协议。
4 - Geek_发现2019-09-02说一下我的猜想吧:不管是websocket全双工还是tcp有状态链接,都是应用了ack机制,用户访问服务器,ack会保存用户的信息,服务器收到ack后会开辟一块专有内存来保存所有的客户的ack信息;同理,服务器发送信息至客户,客户端也会保存服务器的ack信息。 总的来说,客户端和服务器应该都是采用异步方式来提升效率和客户体验,并且降低服务器连接压力
作者回复: 嗯,ack机制是确保消息被正确接收了,下节课会讲到哈
共 3 条评论4 - lecy_L2019-10-16老师你好,请问如果维护一个全局在线状态的情况下,精确定位通知的方案怎么做呢?
作者回复: 这个实现也比较简单,用户上线的时候把用户和连接的网关ip作为映射存在中央存储,然后消息推送时读取这个映射,查询待推送消息的接收人所在的网关机,再通过rpc方式把这条消息发给这台网关机就可以了。
4 - devil2019-09-24海量用户场景如QQ,微信,除了加机器以外,还有些什么方式可以处理海量的tcp连接吗?
作者回复: tcp连接的维护并不是一个耗资源的事情,只是占用一个句柄而已,没有消息传输时基本不怎么费资源,真正有压力的是连接上消息的下推。除了加机器,还可以通过优化系统参数等来提升单机的承载能力。
3 - 魔曦2019-09-03有新的消息是全部推送给客户端吗?那么瞬间服务器压力飙高?如何解决?每个服务器能维护多少长链接?如果数量有限那么微博抖音需要多大的集群支撑?
作者回复: 普通一对一场景消息扇出小,一般网关服务器没啥压力。大型直播间可能会有你刚才说的情况,这种情况可以通过扩容,限流,熔断来解决。单台服务器如果只是挂连接的话几百万上千万都没问题哈,但对于线上实际业务一般都不会真挂这么多,一般单机实际会控制在100w以内。
共 3 条评论3