请教一个服务器数据接收延迟问题
基本场景:
服务器上部署了一个 Java 后端程序,作为数据的接入节点,有数个客户端通过 Socket 的方式连接到这个节点上,每个客户端会实时将数据传输到节点上,节点收到数据后做基本的结构化后将数据写入 Redis 队列,有定时任务会去读取 Redis 队列的数据,将数据批量写入到 MongoDB 。
各个客户端上是安装的 5G 流量卡。
业务场景是通过点阵笔设备提取学生的实时书写笔迹,每个客户端平均会连接 40 支笔,每支笔在完整书写一页的情况下传输的数据量在 27000 条左右,根据不同的试卷和学生进行分表。
基本环境:
当前数据服务器节点:12 核(vCPU) 24 GiB ,公网带宽 5M 。
数据库:Mongodb V8.0.6 ,部署在另外的服务器上,各节点相互之间通过内网连接。
问题描述:
偶尔发生,从日志观察有明显延迟情况,传输的数据中有记录数据的产生时间,这边收到数据做结构化的时候也会设置一个写入时间,两者相差有时候能达到 1 小时以上。
在客户端断开的情况下,数据节点还是会不停的输出收到数据。
从 Redis 的队列观察来看,数据的写入并不慢,数据基本上刚进入 Redis 就会被读取并写入库,不存在数据的积压情况。
从服务器 top 命令来看,这个数据采集的 Java 服务的 CPU 占用经常在 50-60 之间,还有另外一个做成绩识别的服务会占用到 40-140 之间。
load average: 1.33, 1.39, 1.56
Tasks: 213 total, 1 running, 212 sleeping, 0 stopped, 0 zombie
%Cpu(s): 7.6 us, 0.9 sy, 0.0 ni, 90.9 id, 0.0 wa, 0.0 hi, 0.6 si, 0.0 st
MiB Mem : 22870.4 total, 3022.4 free, 8054.5 used, 11793.5 buff/cache
MiB Swap: 0.0 total, 0.0 free, 0.0 used. 14421.1 avail Mem
核心诉求是课堂中的笔迹数据能够实时提取,
请各位大佬帮小弟分析下问题在哪里,个人业务开发做的比较多,这方面的知识相对浅薄。
- 设备之间本身有时间差,有些设备时间不准?
- 网络阻塞,5G 流量卡是卡,但是网速可能很慢?
加日志,观察,加服务器,观察
现在观察到的情况是客户端已经断电了,但是服务器这边日志持续几十分钟还在不停的输出收到数据,从这个现象看应该不可能是网络问题,应该是客户端断电前发送的数据堆积在接收缓冲区,服务器因资源不足( CPU 阻塞、I/O 延迟)缓慢处理,导致日志持续输出。
一条数据大小大概是多少呢?
这个我没有算过但并不大,一条记录解析出来几个简单字段,主要是包含笔迹点位坐标数据
load average: 1.33, 1.39, 1.56
Tasks: 213 total, 1 running, 212 sleeping, 0 stopped, 0 zombie
%Cpu(s): 7.6 us, 0.9 sy, 0.0 ni, 90.9 id, 0.0 wa, 0.0 hi, 0.6 si, 0.0 st
MiB Mem : 22870.4 total, 3022.4 free, 8054.5 used, 11793.5 buff/cache
MiB Swap: 0.0 total, 0.0 free, 0.0 used. 14421.1 avail Mem
这个信息无法说明什么。有高负载时候的 top 信息吗?内存占用过高?没看明白,到底是写入 redis 这一步有延迟,还是从 redis 读出来写到 mongodb 这一步有延迟?
推荐思路分析:
- 带宽是否存在数据积压
- 服务器多线程处理能力
定时任务同步事件间隔(可试试事件驱动机制,避免轮询机制)
可以考虑计算一下数据量,有可能是网络阻塞。大致估算了下,按每页 30 行,每行 20 秒,每条数据 500B ,10 个客户端计算,每秒的数据量是 9MB ,是 5M 带宽理论承载量的 14 倍(如果算错了就当我没说=_=)
大概率是数据堆积了,处理不过来
根据描述个人倾向是 Java 后端程序的问题,不知道接收传输和之后基本结构化要做哪些操作,可能是其中的算法需要优化。
没有太好的思路,说几个我怀疑的点:
设备自身的时间同步是怎么做的?
在客户端断开的情况下,数据节点还是会不停的输出收到数据。
如何确认“客户端断开”,是关闭了客户端?还是说不存在相关的 TCP 连接?公网带宽 5M
带宽占用看了吗?
具体的服务器压力建议看 /proc/pressure/*
5Mbps 的公网带宽感觉有点小了,开 iftop 看下?
是直接关闭了客户端,电源都断了。从阿里云的服务器监控来看带宽没有到上限。从观察到的情况看是数据堆积,但看服务器的 CPU 利用率又没有完全的高负载,redis 队列的数据消费也很快,就挺迷惑的。目前已经安装了 atop ,等下次出现这个情况的时候看看监控的报告情况。
刚刚按照大佬说的看了下/proc/pressure 下的记录。
(base) root@iZ2zeczbp1cst7ksmb2r6tZ:/proc/pressure# cat /proc/pressure/cpu
some avg10=0.00 avg60=0.01 avg300=0.00 total=634955287
full avg10=0.00 avg60=0.00 avg300=0.00 total=0
(base) root@iZ2zeczbp1cst7ksmb2r6tZ:/proc/pressure# cat /proc/pressure/io
some avg10=0.00 avg60=0.00 avg300=0.00 total=52434985
full avg10=0.00 avg60=0.00 avg300=0.00 total=51014230
(base) root@iZ2zeczbp1cst7ksmb2r6tZ:/proc/pressure# cat /proc/pressure/memory
some avg10=0.00 avg60=0.00 avg300=0.00 total=0
full avg10=0.00 avg60=0.00 avg300=0.00 total=0
"两者相差有时候能达到 1 小时以上"
逻辑再慢也漫不到这个地步,可能是管道堵塞。
上个月让 ai 写个 python websocket client 。
服务器发送过来,过了一分钟才收到消息。(应该 100ms 才对)
心跳接收和消息接收我用的同个,由于心跳会 sleep(5),导致堵塞了消息接收。
让 ai 找问题,一本正经的扯淡。
最后跟他说可能是堵塞 他就改好了。
"持续几十分钟还在不停的输出...'
难道也在 onMessage 里 sleep 了?
一般来说,越是难定位的问题,原因越是简单的离谱。
这里就在认为上面都是完全对的情况下,给点个人思路:
客户端连接都断开了,服务端这边有断开吗?
服务端连接断开和连接接收数据的时候可以加日志打印。可能是连接断开但是连接里的数据没有接收干净,或者看下服务端连接关联的对象什么时候销毁。
主要思路就是通过定界不断缩小范围。
笔迹点位坐标数据. 估计数据挺大的
数据服务器节点处理慢了, 结构化处理有性能问题吗?
你是怎么编写的 socket, 用 jdk 原生的吗?
是不是用的 BIO
百度搜了一遍,tomcat 有类似的漏洞,但是我的版本已经修复。 实测直接访问 tomcat 地址 xxx.jsp/报 404 , 访问 nginx 地址 xxx.jsp/弹出…
我在Proxmox 8上跑了两个虚拟机打游戏,GPU 直通也正常: Windows 11 虚拟机 Bazzite (基于 Fedora/SteamOS )虚拟机 有不少游戏…
uTools 在 7.0 版本中限制非会员插件应用安装位置将限制不超过 10 个,称是迫于日消耗 CDN 流量近 1T ,为控制成本做出取舍。各位怎么看 能怎么看,无非是之…