首页
学习
活动
专区
工具
TVP
发布
精选内容/技术社群/优惠产品,尽在小程序
立即前往

JAVA服务器推送功能设计,消息方法总结

结合实际的场景来把netty这个框架运行起来,一起去梳理这个过程,里面用到了nio和Reactor,nio实现了对应的API,但是它没有对多线程进行结合,大牛才设计出来reactor这个模式,来实现高性能的nio的编程,经过梳理才到了netty,reactor一定要搞懂。推送系统先别管是什么推送系统,先理解成一个客户端和服务端的一个程序,也先别管具体的业务场景,功能的属性比较弱,推送系统本身就是比较简单一个推送系统,里面也没有增删查改复杂。默认大家都理解长连接和短连接,网络请求的基本概念。

(一)设计和思路

介绍

客户端可能通过自定义的协议,或者是app应用,需要跟推送服务器建立一个连接,推和拉的区别是推是服务器主动像客户端发起请求,往往这个技术很难实现的,主动推数据需要建立一条网络通道,服务器才可以完成推送,不说它也不知道是哪个客户端,一定是客户端主动和推送服务器建立了连接socket,一般的情况是通过拉的模式来完成推送,涉及到一些socket的技术点。归根到底就是数据交互,TCP连接的方式,客户端和服务端时间的交互。一个客户端跟推送服务器连接,10个,100个,1000个,百万个连接怎么办?不管程序如何优化始终是需要有上限的。有上限肯定是多台,推送系统是多台。网络请求如何形成集群呢?

推送API对外开放的,个推,极光,飞鸽,移动互联网应用开发,对外提供一套API,统一的。用户注册发短信,与农户注册发通知,订单中心,聊天系统。业务系统都是统一的。

消息不可能直接达到推送系统,中间需要存在一个消息队列,消息队列进行存储,用到一个中间件(消息中间件或者数据库)

推送系统和消息队列产生信息的交互,在将对应的消息推送给指定的client。如果是个网络连接就意味着,当前这个用户只会给一个系统建立连接,目前推送系统只有5台。推送系统是集群的。

所以clients要跟推送系统中间添加一个负载均衡,这种中心化的nginx不是需要考虑的,正常的系统是中间添加一个push-server-dispatch 对用户接口(分派接口的),根据请求返回消息推送服务器的地址。

客户端和推送系统之前的push-server-dispatch

push-server-dispatch 就类似网络的DNS的服务器,咱们平常登录网页的时候填写的是域名,通过DNS告诉我们域名所在的IP,直接访问对应的IP地址。

推送服务注册更新在push-server-dispatch

userId发送请求给push-server-dispatch

推送系统返回一个服务地址

client 跟推送服务建立连接(中间不会存在nginx来进行通信的,如果中间添加了负载均衡,还需要在通过负载均衡确定某一个推送服务,量大的话都无法使用,只能进行1VS1的)肯定有老铁说zookeeper,这里先不说zookeeper的事情。

简单的数据包的扭转

SocketServer

SocketClient

连接的方式

1.短连接

请求、响应之后,关闭已经建立的TCP连接,下次请求再建立一个连接(浏览器)。里面有keeplive保持连接的特性。

2.长连接

请求、响应之后,不关闭TCP连接,多次请求,复用同一个连接。存在一个问题,数据链都是在一个通道里面,你的也好,我的也好,都在一个通道,请求过来响应过去,不管请求和响应都是数据包在流转,数据包流转。

为了避免频繁创建连接/释放连接带来的性能损耗,以及消息获取的实时性,采用长连接的形式。

交互中存在的问题

发送一条消息(12345),在发送一条消息(66666),犹豫网络卡顿了,或者是发送卡顿了,或者一些不明原因,接收到的消息是123 66666 45 ,服务端接收到的消息是1条,而不是发送了2次的2条消息,发送2条消息,理论上是2条数据,但是在实际的传输过程中,变成了1条数据。

发送流程

当发送方发送数据的时候,操作系统底层,并不是直接通过网线就直接出去了,操作系统有个发送的缓冲区,接收方有个也有个缓冲区,接收方从缓存中读取数据。这里面就会涉及到一个粘包和拆包的问题。

1.粘包《发送方》

操作系统接收到发送缓冲区,可能会判断目前的数据太小了,等一下发,等第二个进入缓冲区的时候的才完成下一步的发送,这里面有个算法的【Nagle】,算法就是为了做这一件事,就是为了提高网络效率,而去做的事情,举个例子:一个人去坐车可能车不开,非要达到多少人了车才开。这是为了提高网络的性能。这就是沾在一起的情况。

2.拆包《发送方》

一下发送了,5,6条数据过来,数据量太大了,太多了一下发不完,发不了。5条数据拿出来一半来发,把这一半发过去,剩下一半,每个链接有自己专属的缓冲区,不会存在冲突。

3.粘包《接收方》

接收到进入接收缓冲区,没有立刻处理accapt了,马上下个也来了,缓存冲里面的数据有堆积,读的时候发现缓冲区里面的数据怎么这么多了。一个一个读,发现好几个沾在一起。

4.拆包《接收方》

最后读数据发现读出来了很多空的。因为数据被拆了。

上边这块就是网络编程肯定会出现这种情况,怎么样解决呢。消息发送是有协议的,比如Http协议,可以通过协议本身发现数据是否完整,比方说,数据被拆分了,被沾在一起了,这些都是可以通过数据的内容发现出来的。每次都判断接收到的是否满足数组的长度,

(二)netty如何解决上边的粘包拆包的问题

示例展示

XNettyServer

XHandller

XDecoder

流程梳理

netty读取数据触发,2个请求数据被合并了

数据解析(编解码),数据规范,http或者自己写的都是可以解析出来,解析过将合并变成一个一个的请求。请求拆分,根据协议,编解码都是自己来写的。decode将输入的数据进行处理,在输出到后面的环节。存在一个等待的过程长度不够,先保存下来。够了再处理。

交给Xhandler来进行处理。

自研过于复杂,采用合适的开源协议(XMPP/MQTT/WebSocket)

PS:下节一起完成下代码编写,websocket完成的推送代码实现。

  • 发表于:
  • 原文链接https://kuaibao.qq.com/s/20201221A0EACP00?refer=cp_1026
  • 腾讯「腾讯云开发者社区」是腾讯内容开放平台帐号(企鹅号)传播渠道之一,根据《腾讯内容开放平台服务协议》转载发布内容。
  • 如有侵权,请联系 cloudcommunity@tencent.com 删除。

扫码

添加站长 进交流群

领取专属 10元无门槛券

私享最新 技术干货

扫码加入开发者社群
领券
http://www.vxiaotou.com