搭建基于Windows的水表行业高可用Socket通信服务框架
来源:双佳水务集团有限公司 | 作者:双佳水务集团有限公司 | 发布时间: 2022-10-26 | 756 次浏览 | 分享到:



 Socket服务器主要用于提供高效、稳定的数据处理、消息转发等服务,它直接决定了前台应用程序的性能。

       Socket通信从技术上分为客户端和服务端,目前客户端主要为无线远传集中器、有线远传集中器、单个物联网终端水表,实际上客户端在单微机上都只有一个Tcp客户端在连接。服务端Tcp连接包含长连接和短连接共存,随着用户量以及设备量的增加,一个高可用的Socket服务端技术的实现是非常重要的。

       直入主题,介绍我们的Socket通信服务框架,从架构上分为:网络层、业务层、数据层,其中在网络层增加了消息队列,在业务层加入业务抽象类处理不同的业务类型,在数据层引入SQL消息队列以及缓存数据库。具体如图:

(一)网络层

       网络层主要实现Socket连接的创建、消息接收、消息发送、关闭连接功能。作为Socket通信服务端,网络层的性能非常重要,所以我们在设计网络层的时候,着重的突破以下几方面:最大连接数、最大并发数、消息处理秒级别。主要通过如下几种技术和技巧解决:

1)使用基于IOCP模型的SAEA方式

       在Windows环境下利用Windows内核来进行I/O的调度,是用于Socket通信模式中性能最好的网络通信模型。Windows I/O Completion Ports完成端口技术的提出解决了“one-thread-per-client”即一个客户端连接就启动一个新的线程和客户端进行通信导致CPU在线程之间进行上下文切换所带来了负担的缺点,它充分利用内核对象的调度,仅仅只需要少量的几个线程来处理和客户端的所有通信,消除了无畏的上下文切换,从而最大限度的提升了网络通信的性能。

而在.NET环境下使用SAEA(SocketAsyncEventArgs)方式,重点在于池化,主要目的是避免在异步套接字I/O量非常大的情况下发生重复的对象分配和同步,提升性能和减少GC回收压力。

2)使用双工通信

       双工通信是提升Socket服务通信效率的一种有效技术方法。我们采用启动一个TcpSend线程调度器,在SAEA异步接收消息进行业务处理后,如果需要进行发送消息到客户端,采用向发送消息队列中Push一条消息,包含SAEA连接对象,通过TcpSend调度器轮询进行消息发送,以实现全双工通信。

3)消息队列及调度任务

       网络层消息队列主要为接收消息队列以及发送消息队列,主要目的在于提高Socket服务器的吞吐量。我们定义一个接收消息队列RecQueue和一个发送消息队列SendQueue,然后启动多个调度任务,不断的从消息队列中拿取消息,接收消息队列调度任务将消息拿取抛至业务层进行业务逻辑处理,发送消息队列调度任务拿取消息调用网络层发送消息接口,向指定客户端发送消息。

4)心跳扫描

       心跳分两种,一种为长连接客户端模式时由客户端定时发送心跳过来,服务端接收心跳消息,一旦超时没有心跳消息则判断客户端断开,服务端主动关闭该连接。另一种为服务端启动的定时心跳扫描,定时扫描每条连接,不论长连接还是短连接如果超过超时时间没有I/O响应,则关闭它,杜绝了挂掉的客户端成为落地生根的钉子户,占用系统资源。

5)粘包处理

       针对短连接不存在粘包情况,因为每次接收消息都要经过握手连接,接收消息,关闭连接。但是针对长连接,服务端在接收消息包时,就可能出现两条或多条消息一起接收了,而出现粘包情况。在这里我们采取了封装报文头和报文尾,并且加入报文长度位进行处理,来解决粘包的问题。

(二)业务层

       业务层接收到网络层调度任务抛过来的消息后,解决消息包,根据获取到的消息类型TYPE,通过抽象类转到相对对象的业务处理流程进行处理。

       业务处理流程通过单机或集群进行业务处理后,生成数据缓存实体,存入到Redis缓存数据库,以供Redis调度任务进行数据处理。

       同时业务层有发送消息时,根据具体的业务应用,封装不同功能的消息包,调用网络层消息发送接口,往网络层消息发送队列插入消息,以供网络层发送消息队列调度任务进行发送处理。

(三)数据层

       数据层的设计是整个Socket通信服务架构的关键。举个例子说明:假设我们的Socket服务器每秒均值处理2000条消息,每处理一条消息都会将数据作为历史记录存储到数据库,同时还要关联其他相关业务数据和表。那么数据层要想跟上网络层的处理性能,其执行SQL语句的效率也就必须达到每秒2000*n次,通常情况下我们的SQL语句的执行效率要达到那么高是很困难的。所以在整个Socket通信服务端,数据库的执行效率是瓶颈!

       那么如何提高数据库的执行效率,让数据层的处理速度和网络层的处理速度达到一个平衡?我们的设计是分两步走:首先采用高效内存数据库Redis+异步数据存储处理方式,确保通过高效的内存数据库R