前言
HTTP协议是一种无状态的、基于TCP的请求/响应模式的协议,请求只能由客户端发起、服务端进行响应。在大多数场景,这种请求/响应的Pull模式已经可以满足需求。但在某些情形,例如消息推送、通知等应用场景,需要实时将数据同步到客户端,这就要求服务端支持主动Push数据。
短连接与长连接,短轮询与长轮询
短连接:每次Http请求都会建立Tcp连接,管理容易 长连接:只需要建立一次Tcp连接,以后Http请求重复使用同一个Tcp连接 长、短连接是客户端与服务端建立和保持TCP连接的机制;而长、短轮询是指客户端请求服务端,服务端给予应答的方式。 短轮询:重复发送Http请求,查询目标事件是否完成,优点:编写简单,缺点:浪费带宽和服务器资源 长轮询:在服务端hold住Http请求(死循环或者sleep等等方式),等到目标时间发生(保持这个请求等待数据到来或者恰当的超时),返回Http响应。优点:在无消息的情况下不会频繁的请求,缺点:编写复杂
WebSocket和HTTP长连接区别
HTTP1.1通过使用Connection:keep-alive进行长连接,HTTP 1.1默认进行持久连接。在一次 TCP 连接中可以完成多个 HTTP 请求,但是对每个请求仍然要单独发 header,Keep-Alive不会永久保持连接,它有一个保持时间,可以在不同的服务器软件(如Apache)中设定这个时间。 websocket的长连接,是一个真的全双工,第一次tcp链路建立之后,后续数据可以双方都进行发送,不需要发送请求头,并且这个连接会持续存在直到客户端或者服务器端的某一方主动关闭连接,与HTTP长连接不同,WebSocket可以更灵活的控制连接关闭的时机,而不是HTTP协议的Keep-Alive一到,服务端立马就关闭(这样很不人性化)。 通常建立一个WebSocket连接,客户端浏览器首先要向服务器发起一个HTTP请求,这个请求和通常的HTTP请求不同,包含了一些附加头信息,其中附加头信息“Upgrade: WebSocket”表明这是一个申请协议升级的HTTP请求。服务器端解析这些附加的头信息,然后生成应答信息返回给客户端,客户端和服务器端的WebSocket连接就建立起来了,双方可以通过这个连接通道自由地传递信息,并且这个连接会持续存在直到客户端或者服务器端的某一方主动关闭连接。
技术选型及架构
服务端推送技术历史悠久,经历了短轮询、长轮询的发展,一定程度上能够解决问题,但也存在着不足,例如时效性、资源浪费等。WebSocket规范基本结束了这一局面,成为目前服务端推送技术的主流方案。在众多的WebSocket实现中(八种 WebSocket 框架的性能比较),基于Netty实现WebSocket长连接网关应该也是目前比较主流的实践方式。
WebSocket不同于HTTP,是有状态的,因此无法直接以集群的方式实现负载均衡,连接建立之后会与服务端某实例节点保持会话。因此在进行下行推送的时候,往往需要找到uid对应的长连接,总体两种方案: (1)通过注册中心例如zk来维护全局的会话映射关系,即外部存储,维护uid和长连接所在主机ip的关系,流量路由到对应ip主机上,获取连接进行推送
对于注册中心方式,映射关系直接存储比较清晰,尤其是大集群的场景更合适。缺点是实现复杂度会提升,强依赖注册中心,需要有运维保障。
(2)使用事件广播的形式,送消息时发布消息,所有长连接服务节点都会收到,uid长连接在自己内存队列中的进行消费,即消息推送
对于事件广播(广播可以基于mq,redis,zk等,也是各有利弊),优点是实现比较轻量,缺点就是当节点较多时,所有节点都被广播,资源是浪费的,并且集群规模大的情况,会出现性能瓶颈。
方案 | 优点 | 缺点 |
---|
注册中心 | 映射关系直接存储比较清晰,尤其是大集群的场景更合适 | 实现复杂度会提升,强依赖注册中心,需要有运维保障 | 事件广播 | 广播可以基于mq,redis,zk等,也是各有利弊,实现比较轻量 | 当节点较多时,所有节点都被广播,资源是浪费的,并且集群规模大的情况,会出现性能瓶颈 |
一个简单的基于netty的IM系统实现可以参考之前的文章如何用Netty写一个IM聊天系统
|