mysql 物联网服务器_稍微记录一下最近弄物联网服务器的小心得

由于服务器与前端设备之间有交互,实时性要求也高,用UDP的话,设备发送的频率有点难以拿捏,快的话冗余数据多,慢的话下发控制指令不实时。所以最后选择了TCP。

服务器架构,主要分为两个部分,第一部分采用全异步TCP服务器(简称A),第二部分采用全异步HTTP服务器(简称B)。A负责接收底层设备的连接,并且整理打包原始数据。B负责接收A发过来的数据,进行各种业务逻辑处理。

A ----http包---->B

A

先从A开始说:

A有6个工作线程处理tcp的连接、接收、发送以及关闭,刚刚开始犯的一个错误是,在接收线程里面,进行了业务处理,所以导致线程阻塞,当连上来的设备有3k个的时候,已经开始变得很慢了。于是乎另外开了工作线程,用无锁队列建立了生产者-消费者模型(moodycamel)。这样处理过后,设备的连接速度变快了,APP通过B服务器下发指令的速度也加快了。

但是数据上报依然很缓慢,经过一番排查之后,发现原来是A服务器里面http客户端问题。当时用的是libcurl的esay接口。这个接口是阻塞的,所以工作线程每次只能发一个请求,此时生产大于消费,程序越运行内存越大,于是进行了异步http请求改造,使用了libcurl的multi接口,虽然也是阻塞的,但是一次性能够发送多个,从而加快了消费速度。

然而,运行当设备到达7k个的时候,上报数据速度又开始变慢了,看到网络波形,峰值很高,周期很长。当时猜测是某一处堵住了,在等资源释放,释放后又可以发送,所以才有这样的波形。

经过一凡排查,发现原来是端口号不够用。频繁地建立http短链接,导致16384个端口号都处于TIME_WAIT状态。TIME_WAIT需要2个ml,windows上是4分钟,调低到30s后,问题依然存在。所以此时代码逻辑的消费速度虽然与生产速度虽然匹配,但是受操作系统本身的机制影响。于是决定合并通道,在生产队列中取出来的数据,平均放在10个curl对象上(当时计算的1w个设备的生产速度而决定的),每次就产生10个TIME_WAIT。实际运行的时候发现这个算法也是不能行的,因为底层设备的数据发送速度不可预料,存在这样一种情况:某一段时间内,只会有生产个位数的数据包,每次都发起10次请求,很快也把TIME_WAIT用完了。

基于这样的情况,就对上面的算法进行的改造,限制最大发起http请求是50,每次数据包不足50的就放在一个http客户端发送,100以内的用两个http客户端……这样处理后,即防止了零散数据包耗损端口号,又保证了并发性。

此时,A服务器已经能够很好地运行了,估计能够单机支持10w个设备。

可是实际运行过程中,并没有像我预料的那样般顺畅,A服务器的运行内存越来越大,还以为是libcurl内存泄露。仔细排查一番后,发现,原来是B服务器响应慢!所以工作线程一直在等待,数据包越囤越大,内存就消耗了。

于是便进行了B服务器的排查。

首先,B服务器给A服务器通信的API,是串行执行的,接收到A的数据包后,按顺序一个数据包发起一个子请求,经过一系列的业务逻辑处理后,再轮到第二个包。这样就发挥不出B服务器的多核性能。于是乎也进行了异步请求的改造,将A发过来的数据包,比如50个数据,分成50个子请求,这样速度一下子就上来了。

事实上,它当时运行的情况也很符合我的心意,两个服务器之间的通信数据波形很平缓,很漂亮。

但在第二天,发生了始料未及的事情,redis崩溃了。这让我十分震惊,号称每秒1w并发的redis居然崩了。当时redis没有弄负载均衡,只是跑个单例。

接下来就有两种选择,第一是配置redis-cluster,进行负载均衡,增强并发性。但是代码里面多处用了redis的select接口,redis-cluster是不能使用select接口的,所以改动会非常大。

第二种就是找出导致redis崩溃的原因。

依照我的性能,果断选了第二种。

首先我是去看了下网络波形,发现存在网络抖动,抖动原因不明,现象就是某一时刻,设备发送过来的数据量降低,囤了一会儿只后全部扔了过来。这时候A->B的tcp数居然高达3w+,也就是直接来了一发3w并发的数据波。正常来说,应该也是能够处理的。但是又忽略了一个问题,B服务器与redis的连接数也只能是16384个,执行指令“netstat -an | grep "redis端口号" | grep "TIME_WAIT" | wc -l”,发现基本上都TIME_WAIT了。后面没有网络抖动的时候,A服务器正常发数据,但由于需要等待4分钟,所以数据量屯太大,B服务器内存不足,系统把redis杀掉了。同样的情况,在mysql下面也会发生,只是mysql暂时没有崩,并不保证它没问题。

对于TIME_WAIT的方法,那肯定也参考之前的方式,合并通道。将A发来的数据包,每20个一组,循环处理,而不是发起20个子请求,这样redis的连接数就直接缩小了20倍了。

至此,服务器已经安稳地运行了一天了,网络波形一直很平稳,终于完成了整个物联网框架的雏形了,接下来继续观察7天,应该还有别的漏洞需要修补,再接再厉哈。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值