用netty开发了一个iot网关的解析服务
作用就是
网关与服务开启TCP长连接,自定义协议收发消息。
上头挺狠的要接32个网关,每个网关接255个设备,一共8160台子设备,但实际只需要开32个长连接
就是数据量太多,环境温度的精度是0.1,在这里就算每秒8000条状态数据上报到服务器
项目架构是springboot2.1.5 + Netty4.1.36
测试用的pc机win10 8核i7,jvm参数-Xmx512M -Xms2048
单体应用,上头明确要求必须单体,并且安装在PC机上(win7 win10)
boss线程一个,worker线程32个
业务很简单,就是按照自定义协议解码后,用fastjson把状态数据(json)提取出来,拼成字符串,用spring-data-redis作为客户端存入redis中,数据结构是HASH,key设计如下
网关号:设备号
- 温度 = 值
- 湿度 = 值
自己写了个网关模拟器,模拟32个长连接并每3秒每个连接发送255条状态,一共8160。
发现redis虽然也是每3秒刷新了,但有延迟,估计6s左右,打印了日志,channelRead()
方法执行时间平均9ms
这里很奇怪,lettuce开启了8个线程,只有lettuce-EventLoopGroup
线程一直是running状态,其余的8个几乎都是await,只有个别一两个偶尔running一下,大概一两分钟running一次
之后发现自己这个逻辑是在io线程中操作的,业务逻辑应该放到业务线程池中,根据官方建议的就用EventExecutorGroup来处理Handler
static final EventExecutorGroup group = new DefaultEventExecutorGroup(16);
...
ChannelPipeline pipeline = ch.pipeline();
pipeline.addLast("decoder", new MyProtocolDecoder());
pipeline.addLast("encoder", new MyProtocolEncoder());
pipeline.addLast(group, "handler", new MyBusinessLogicHandler());
开始测试发现内存开始增长,每次gc都不完全,三分钟左右CPU达到100%
然后服务卡死,jvisualvm也获取不到实时信息了
dump内存下来用mat分析了一下,阻塞队列过大,猜是线程开始堆积导致OOM,jvm开始GC然后CPU就飙起来了,飙起来就下不去了
这种时候该咋整啊,把内存扩到4g也只是活的时间长了点,并没有解决问题
况且有的客户还非要用笔记本的,内存可能就4g,哭了