TCP 长连接的方式是怎么实现“当有消息需要发送给某个用户时,能够准确找到这个用户对应的网络连接”?
首先用户有一个登陆的过程:
(1) tcp客户端与服务端通过三次握手建立tcp连接;
(2) 基于该连接客户端发送登陆请求;
(3) 服务端对登陆请求进行解析和判断,如果合法,就将当前用户的uid和标识当前tcp连接的socket描述符(也就是fd)建立映射关系;
(4) 这个映射关系一般是保存在本地缓存或分布式缓存中。
然后,当服务端收到要发送给这个用户的消息时,先从缓存中根据uid查找fd,如果找到,就基于fd将消息推送出去。
服务器端如果突然进程被kill掉,客户端如何及时得到通知并下线?
进程kill是会对socket执行close操作的,所以客户端是能感知到的。
真要是通过拔网线的方式把服务端网络断开,这种情况客户端在发送数据时就会失败,然后短连后重连其他服务器就可以了。
客户端发送心跳包,一般多久一次比较合适?
国内的话最好不要超过5分钟,微信应该是4分半。
客户端发送心跳包,一般多久一次比较合适? 我看有人回复国内不超过5分钟,微信用的是4分半。这个时间有什么依据吗?
以前有大厂测试过国内各家运营商的NAT超时情况,有的运营商在2/3G网络下NAT超时是5分钟。
websocket为什么能实现实时通信?
websocket支持双向全双工的传输,所以可以做到服务端推送,让消息接收更加实时。
长连接是不是 "header: keep-alive" 的连接?
英文对应 persistent HTTP connection,但大家用得不多。而 webSocket 是HTML5才出来的,类似的机制,但各种浏览器支持得比较多。
因为机制和实现上,我好像看不出它们有太大的区别? 还是说 persistent HTTP 仍然是3次握手,websocket是一次?
最大的区别在于websocket是支持全双工的,也就是说是可以由服务端主动进行推送的,http 1.1 的keep alive只是能够多次http请求复用同一个tcp连接,但只能由客户端发起请求。
如果维护一个全局在线状态的情况下,精确定位通知的方案怎么做呢?
这个实现也比较简单,用户上线的时候把用户和连接的网关ip作为映射存在中央存储,然后消息推送时读取这个映射,查询待推送消息的接收人所在的网关机,再通过rpc方式把这条消息发给这台网关机就可以了。
海量用户场景如QQ,微信,除了加机器以外,还有些什么方式可以处理海量的tcp连接吗?
tcp连接的维护并不是一个耗资源的事情,只是占用一个句柄而已,没有消息传输时基本不怎么费资源,真正有压力的是连接上消息的下推。除了加机器,还可以通过优化系统参数等来提升单机的承载能力。
有新的消息是全部推送给客户端吗?那么瞬间服务器压力飙高,如何解决?
每个服务器能维护多少长链接,如果数量有限那么微博抖音需要多大的集群支撑?
普通一对一场景消息扇出小,一般网关服务器没啥压力。
大型直播间可能会有你刚才说的情况,这种情况可以通过扩容,限流,熔断来解决。
单台服务器如果只是挂连接的话几百万上千万都没问题,但对于线上实际业务一般都不会真挂这么多,一般单机实际会控制在100w以内。
多终端场景下,用户维度上的应该是一个socket列表。
网关接入层是否是有状态的?
在进行推送时候需要定位到某台机器?多终端要定位多台机器?
可以是无状态的,一种做法是用户上线时维护一个全局的 uid->网关机 的映射,下发的时候就能做到精确定位;
另一种方式是:下发时把所有消息下发给所有机器,每台机器如果发现当前用户连接在本机就下发,其他的就丢掉,这种会有一定的资源浪费。
为什么web端不能像客户端一样,用tcp呢?
也是可以的,考虑到web端很多浏览器都原生支持websocket协议,实现上更简单,而且web端对于流量相对没有那么敏感,所以web端更多的可以考虑websocket。
抛开使用通讯协议本身,现在面临的一个挑战是Android程序保活。
现在国内Android手机的系统都是各大厂商自己定制修改的。
为了保证使用电量,杀程序,杀后台服务情况严重,包括一些第三方的推送也会被杀死。
这样消息的及时推送就是一个很大的问题。请问有什么好的应对策略么?
这种目前也没有太好的办法:一个是加入“保活联盟”类似的组织通过app间的互相拉起来提升;
另外就是通过多个第三方系统推送sdk来提升系统push的到达率。
如果产品只有Web端,TCP 长连接和WebSocket相比,还有别的优势么?
那还是websocket更好一些,很多浏览器默认就支持了。
1、客户端和服务端只需要完成一次握手,就可以创建持久的长连接,并进行随时的双向数据传输;如果是这样的话,那是不是意味着需要服务器资源去存储这个长连接,那当客户端很多的情况下,服务器资源会不会被大量消耗?
2、在一些不是html的场景下,如微服务中消息推送,是不是还是只能通过消息队列等方式发送消息?
- 映射关系需要服务端存储,有一定的资源开销。
- 和html没关系,微服务里面的rpc调用也是可以通过tcp长连实现,不一定需要队列。
在《网页端收消息,究竟是推还是拉?》文章中却是讲,网页端的消息发送是用长轮询机制,而不是长连接。貌似长轮询并不会造成后端资源轮询的压力?
长轮询实际上也并不是一直hang在服务端,而是会有一个timeout超时,因此当没有消息时浏览器还是会每隔一段时间重新发起一次轮询请求,实际上这个时候是会去查询资源是否有新消息的,当没有新消息的时候这些轮询请求都是无效的。
长连接的方式避免了这种无效请求,真正实现了“有消息时服务端主动推送”。
在websocket基本普及的今天,应该是web端更多应该采取的策略。
客户端发送心跳需要服务端响应吗?
一般是需要的,如果客户端发送的心跳包没有收到服务端的回应,可能是中间网络出现了问题或者连接的服务器出现故障,这种情况客户端可以断线重连。
grpc stream 适用于 客户端-服务端 吗?
grpc更多建议用在后端服务器间的调用上,客户端和网关机之间不推荐,对客户端的实现要求也比较高。
维护用户tcp链接到tcp-gateway的IP的映射,是在tcp-gateway上实现还是单独做一个服务来维护呢?
如果是用户和接入的ip的映射那肯定是单独的中央存储或者服务来维护了。当然,可以不去记录这个映射,让每台网关机自己维护自己的,所有消息发给所有网关机去认领也是可以的。
因为WebSocke是全双工的push方案,如果某些场景只需要服务端推送到客户端,而不需要客户端通过长链接和服务端打交道,换一种单工的socket方案是不是值得呢?
你说的这种的没怎么见过,具体是什么场景呢?即使只需要服务端推送到客户端,客户端也需要能找到服务端连接上才可以呀,所以客户端是需要通过长连和服务端通信的,至少是建立告知自己的身份这些吧,而且基于tcp的实现都是全双工的。
为什么不选用UDP呢?
- 用户基于UDP登录注册到服务侧以后,服务侧也可以根据用户IP+Port找到用户。
- 即使基于TCP,也需要有应用层可靠性机制,来保证可靠投递;那基于UDP也可以通过应用层保证可靠性。
- TCP还容易拥塞,产生较大时延。
udp也是可以的呀,早期QQ的通信协议就是采用的udp。
只不过针对udp协议,由于不能保证连接层的可靠性,所以需要应用层来保证。
对于早期互联网场景,网络状况大都不好,网络经常容易断开,tcp的三次握手和四次挥手的开销会比较大,另外TCP有拥塞控制,会导致弱网情况下传输消息不高,这应该也是QQ早期采用udp的原因。
但是随着网络状况的改善,而且udp在网络穿透能力上相比tcp还是会差一些,现在大部分IM(包括QQ)实际上都是采用tcp为主的传输协议了。
请教个问题,qq、微信这种同时在线人数好几亿,这么多连接,应该有服务集群来支撑。是怎么做到连接的负载均衡?
怎么做到某个用户端连接哪个IM的接入服务端的,如何定位要链接的服务器的?
在线连接数不是问题呀,很多用户只是连接在,没有消息收发的。集群化部署需要让用户能随机连接到任意的接入服务器,也就是接入服务器需要无状态。
一般不要让某一个用户定点连某一台服务器,这种的扩展性和可靠性都比较低。
长连续缺点说虽然减少了Qps,但是并没有减小服务器读盘动作,想问一个问题,我觉得webSocket在替代客户端和服器轮询请求是有优势的,但好像他也没缓解服务器读盘。这一块服务端内怎么处理的呢?
轮询的话服务端需要不停去查询存储有没有新消息,不管实际有没有新消息。长连接的话可以做到服务端推送,真正有新消息时只需要推送一次就可以了,不需要一直轮询。
断网后,我们可以在浏览器断网后,触发offline之前,在做一些什么行动去链接么?
断网重连一般需要先建连并提供本地存储的最新的消息信息,然后服务端根据这些信息去取离线消息,然后再推送给客户端。
客户端接收到服务器的数据后 如何确定消息的类型?
消息类型和消息内容是一起在数据包里推送到客户端的,解析出来就好了。
如果APP不在线,需要通过第三方系统推送,但是现在Android系统厂商很多,是不是需要APP服务商封装一个统一的API去自适配多个厂商的系统推送?
这种的有很多第三方推送服务了,比如:腾讯的信鸽,极光等等。
Linux 服务器的socket文件描述符,一般都是有数量限制的,当一个用户保持一个 tcp 连接,就会占用一个文件描述符,这样当socket文件描述符耗尽的时候,在有新的连接进来,就会堵塞等待了? 这个地方逻辑是怎么处理的呢?
文件描述符一般情况下不是问题,单台机器句柄数开到1000w都没问题。
真要是耗尽了就连不上了来了,可以通过客户端的重连机制来尝试其他机器。
rpc框架里用的socket去做的,是您说的tcp长连接的方式吗?
本质上是一样的,rpc的实现上大多是基于tcp的长连接来提升调用效率。
一般链接量大了,不用内存缓存连接映射信息,而是放在redis集群中,key是mid,valie是server:channel。
就可以在集群中,找到对应server的连接了。
嗯,是一种方式,不过还需要考虑维护这个全局在线状态时的开销和一致性问题。
websocket长连接,服务端推消息给客户端,怎么样确保消息到达了?就是有回调函数吗?
消息的可靠性可以通过应用层实现的类似tcp的ack机制来让消息接收方收到后”确认“给IM服务器。
客户端与服务端通过三次握手建立连接后,服务端会保存唯一的socket连接,socket包含了客户端的ip和port,服务端需要保存连接用户的ID和socket的映射关系(<userId,socket>)。这样当服务端需要给某个用户发送消息时,通过映射关系就可以获取到socket,通过socket发送数据给客户端。
连接层的信息映射保存时不需要关心客户端的ip和port哈,一般可以保存为socket对象或者channel对象就可以。
http基础上实现能控制timeout的长轮询,这个怎么做的啊?
简单实现的话:ajax发起一个请求,超时比如设置为60s,后端servlet接收到之后,while循环判断当前时刻和请求时刻是否到达超时时间,没有的话调用后端service获取数据,如果没有获取到就sleep 1s,继续while循环。
1.及时率的统计方案是什么样的呢?业界各个的及时率大概是什么样的标准?
2.从移动客户端的角度如果想优化及时率的话,有什么切入点可以分享么?
一般只需要衡量服务端内部消息流转的延时就可以,标准这一块貌似没听到过有公开的。
服务端内部耗时优化就不说了,到公网传输的耗时可以考虑:
- 多线接入,选择最优路径。
- 优化传输的包大小,比如协议精简,压缩等。
网友评论