news 2026/10/15 9:28:53

单机10万WebSocket长连接实战:SpringBoot+Netty调优全解析

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
单机10万WebSocket长连接实战:SpringBoot+Netty调优全解析

做实时推送、IM、行情订阅、设备在线管理的同学,迟早会撞上一个硬骨头:一台机器上的WebSocket长连接,到底能扛多少?我之前接过一个需求,目标很明确——单机10万在线长连接,而且是用SpringBoot这套生态来做。第一次听到这个数字的人,多少会有点慌:SpringBoot默认那套内嵌Tomcat的WebSocket,真的撑得住吗?

先给结论:能撑住,但前提是你别把它当成普通HTTP接口来设计。10万长连接这件事,本质上是“内存 + 线程 + 内核参数 + 连接管理 + 监控压测”的组合工程,SpringBoot只是壳,技术选型和调优才是核心。这篇文章我会按自己做方案时的思路,从算账开始,讲到选型、调参、实现、压测和排障,把聚合多路消息、维持海量长连接的完整链路捋一遍。适合正在做实时消息服务,或者刚接手WebSocket高并发场景的开发者参考。

1. 先算一笔账:10万连接的内存与线程账本

1.1 内存账本:一个连接到底吃掉多少资源

很多同学一听说“单机10万连接”,第一反应是“加内存”。但如果你不知道内存花在哪里,加多少都是瞎猜。我习惯先做一笔账。

一个WebSocket连接,从进程角度看有三块内存开销:

  1. 应用层会话对象:无论是Spring的WebSocketSession还是Netty的Channel,本质是个对象,里面有状态、属性、关联的附件。单个对象不算大,几十到几百字节。
  2. 缓冲内存:这是大头。TCP读写要有缓冲,WebSocket帧解析要有缓冲,发送队列还要等数据写出去。Netty默认每个Channel在写入时会分配字节缓冲,如果一次消息8KB,一万条在途消息就是80MB,10万条就是800MB。Tomcat的WebSocket实现也有文本/二进制缓冲,默认约8KB一个。
  3. 内核里的socket内存:每个TCP socket在内核里还有收发队列。虽然空闲连接占用的内核内存不多,但积少成多,10万连接加起来也是GB级别。

所以“10万在线连接”如果只是挂着不发消息,和“每秒处理10万消息”是完全不同的两码事。前者的内存开销大约在JVM堆内1.5~2GB、堆外加内核2~3GB的规模;后者则需要按消息吞吐量单独评估。这也是为什么我一上来就强调:先把需求说清楚,是“挂得住”,还是“跑得动”。

1.2 线程模型才是真正的分水岭

内存决定你买多大的机器,线程模型决定你这条连接能不能稳定地维持住。

最早的BIO模式,一个连接占一个线程。假设一个线程栈默认1MB,10万连接意味着10万线程、约100GB的栈内存,这还不算线程切换的CPU开销,直接出局。NIO模型把连接和线程解耦了,这是10万连接能成立的第一个前提。

Tomcat从8.0开始默认使用NIO,连接由Poller事件线程维护,实际的读写操作分发给worker线程池执行。SpringBoot内嵌Tomcat默认的server.tomcat.threads.max是200,也就是说10万个空闲连接挂在那里是没问题的,但如果同一时刻有大量连接在收发消息,200个worker线程就可能排队,消息延迟会被拉高。

Netty的模型更进一步:每个Channel固定绑定到一个EventLoop线程,数据读写都在同一个线程上串行执行,避免了线程池排队和锁竞争。同样是8核CPU,Netty的worker线程数默认是16个,但性能反而会比“200个通用线程池”好,因为它把长连接上的消息处理收敛到了固定线程内。选型的分歧,从这一步就开始了。

2. 技术选型:SpringBoot是壳,传输层才是灵魂

2.1 基于Spring WebSocket + 内嵌Tomcat的可行路径

如果你的项目里已经全是Spring生态,用spring-boot-starter-websocket最顺手。@ServerEndpoint("/ws")注解一标,TextWebSocketHandler一写,就能跑起来。加上Spring Security、拦截器、参数校验,开发体验非常顺。

但要用它扛10万连接,有几个关键点必须改:

  • 线程池放大到合理范围。默认200个worker线程对10万连接来说偏小,我一般调到400~600,但绝不调到几千。线程不是越多越好,超过CPU核数太多,上下文切换反而会拖垮吞吐。
  • WebSocket会话缓冲要显式控制。通过setTextMessageBufferSize和setBinaryMessageBufferSize设置,不要放任默认值在大量连接下累积。
  • 最好加一层连接管理器来统一保存会话,而不是散落在各个Handler里。

Tomcat方案的优点是省事,缺点是一旦出现不明问题,你只能追进Tomcat连接器实现的细节。如果需求就是“挂着10万连接、偶尔发个通知”,它完全够用;但如果你的场景是消息密集型,我建议直接看下面这个方案。

2.2 用Netty接管传输层的高性能方案

SpringBoot做应用壳,Netty做WebSocket传输层,是我见过的大多数生产级实时服务的做法。Netty流水线大概长这样:

EventLoopGroup bossGroup = new NioEventLoopGroup(1); EventLoopGroup workerGroup = new NioEventLoopGroup(); ServerBootstrap b = new ServerBootstrap(); b.group(bossGroup, workerGroup) .channel(NioServerSocketChannel.class) .option(ChannelOption.SO_BACKLOG, 1024) .childOption(ChannelOption.TCP_NODELAY, true) .childOption(ChannelOption.SO_KEEPALIVE, true) .childOption(ChannelOption.ALLOCATOR, PooledByteBufAllocator.DEFAULT) .childOption(ChannelOption.WRITE_BUFFER_WATER_MARK, new WriteBufferWaterMark(32 * 1024, 64 * 1024)) .childHandler(new ChannelInitializer<SocketChannel>() { @Override protected void initChannel(SocketChannel ch) { ChannelPipeline p = ch.pipeline(); p.addLast(new HttpServerCodec()); p.addLast(new HttpObjectAggregator(64 * 1024)); p.addLast(new WebSocketServerProtocolHandler("/ws")); p.addLast(new BizHandler()); } });

这四行配置,每一行都是在为10万连接服务:

  • PooledByteBufAllocator.DEFAULT:复用小块缓冲,避免每个消息都产生堆外内存分配,能显著减少GC压力和系统内存碎片。
  • WRITE_BUFFER_WATER_MARK(32KB, 64KB):低水位32KB,高水位64KB。当某条连接的待写数据超过64KB时,channel.isWritable()返回false。这是背压的第一道防线,防止一条网络慢的客户端拖垮整个服务。
  • SO_BACKLOG=1024:握手突发时的accept队列容量,后面还要配合内核somaxconn使用。
  • TCP_NODELAY=true:关闭Nagle算法,减少小消息的延迟毛刺。

2.3 “聚合”在实战里的两种形态

回到标题里的“聚合websocket”,我实际做项目时遇到过两种理解。一种是“把多路消息源聚合到一条WebSocket连接上推给客户端”,另一种是“多个业务服务共享一个WebSocket接入入口”。不管哪种,设计上都有几个共性:

  • 订阅关系管理:客户端用一个连接订阅多个主题,服务端维护userId -> Set<topic>的映射,广播时按主题反查连接。
  • 消息路由:上游消息从MQ或内部事件总线进来后,要能快速定位到目标连接集合,而不是全量遍历10万连接。
  • 单连接多协议:JSON文本帧、二进制帧、心跳帧都要能区分,客户端侧用一条连接承载所有业务。

这些逻辑放在业务Handler里实现,传输层只负责把帧交给业务层。传输层和业务层的边界清晰,后面加功能才不会动到连接管理的内核代码。

3. 系统级调优:内核参数与JVM配置一个都别省

3.1 Linux内核参数与关键语义

代码写得再好,内核不给力也没用。10万连接对Linux系统参数的要求是硬性的。下面这组配置是我部署脚本里的常客,放在/etc/sysctl.d/websocket.conf里,执行sysctl --system生效:

fs.file-max = 500000 net.core.somaxconn = 4096 net.ipv4.tcp_max_syn_backlog = 8192 net.ipv4.ip_local_port_range = 1024 65535 net.ipv4.tcp_fin_timeout = 30 net.ipv4.tcp_tw_reuse = 1 net.ipv4.tcp_keepalive_time = 300 net.ipv4.tcp_keepalive_intvl = 30 net.ipv4.tcp_keepalive_probes = 3 net.core.netdev_max_backlog = 10000 net.ipv4.tcp_rmem = 4096 87380 4194304 net.ipv4.tcp_wmem = 4096 16384 4194304

每个参数背后都有故事:

  • fs.file-max:整个系统能打开的文件描述符上限。10万连接默认就是10万fd,加上线程、日志文件、临时文件,建议直接开到50万。
  • somaxconn和tcp_max_syn_backlog:WebSocket握手本质是HTTP Upgrade,握手期间连接先进入accept队列。压测时几万连接同时建立,这两个队列太小会直接握手失败,你会看到大量Connection reset。
  • tcp_keepalive_time=300:默认TCP keepalive是2小时,太久了。客户端拔网线、断电这种非正常断开,不靠TCP keepalive和应用层心跳,僵尸连接会一直占用资源。调到300秒并配合30秒间隔探测,能在几分钟内把死连接清理掉。
  • tcp_tw_reuse=1:这个主要影响客户端主动断开后重建连接的情况。TIME_WAIT状态过多会耗尽端口,虽然对服务端承受入站连接影响不大,但压测时你的压测机端口耗尽,往往靠它续命。

还有一类容易漏的:nf_conntrack。如果你的服务器开了iptables/nftables,每个TCP连接都会被conntrack记录。默认表大小经常只有几万,10万连接直接打爆。解决方式是调大net.netfilter.nf_conntrack_max=500000,如果确定不需要状态防火墙,尽量精简规则,把不必要的连接跟踪关掉,能省出大量内核内存。

3.2 文件描述符限制:limits.conf与systemd的坑

内核提了fs.file-max,进程级的nofile限制也必须同步改。改/etc/security/limits.conf:

* soft nofile 200000 * hard nofile 200000

这里有个大坑:如果你是systemd托管服务(很多线上SpringBoot服务用systemd),limits.conf是不生效的,必须在service文件里加LimitNOFILE=200000,然后daemon-reload。我排查过不少“明明改了ulimit,连接数还是上不去”的案例,最后都栽在systemd这层。

3.3 JVM参数与堆外内存排查

一个支持10万连接的SpringBoot应用,JVM建议这么调:

-Xms8g -Xmx8g -XX:+UseG1GC -XX:MaxGCPauseMillis=100 -Xss512k -XX:MetaspaceSize=256m -XX:MaxMetaspaceSize=512m -XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=/data/dump

解释几个关键点:

  • -Xms等于-Xmx:避免运行时扩容触发Full GC。大堆场景下堆大小抖动是性能杀手。
  • UseG1GC:8G以上的堆,G1的停顿预测比CMS更稳,适合对P99延迟敏感的消息服务。
  • Xss512k:如果业务线程较多,512K的栈能省一半内存。但要小心递归深的代码,比如某些JSON序列化器,栈溢出后很难排查。
  • HeapDumpOnOutOfMemoryError:10万连接的OOM事故,没有堆转储文件,事后分析就是大海捞针。

如果你用了Netty,还要留意堆外内存。Netty默认用DirectBuffer,MaxDirectMemorySize默认等于最大堆大小,听起来很充裕,但堆外内存的分配并不总会按预期规律增长。排查堆外内存时,可以用-XX:NativeMemoryTracking=summary启动,然后执行jcmd <pid> VM.native_memory summary,一眼就能看出DirectBuffer、CodeCache这些区域分别占了多少。

4. 连接管理:10万会话的存储、心跳与消息派发

4.1 连接注册表:别用遍历的思路管理10万连接

10万个连接,最忌讳的就是每次推送都遍历一遍。我的做法是在内存里维护一张连接注册表,让“根据用户或主题找连接”变成一次哈希查找。

Netty版本的注册表实现,核心就一个ConcurrentHashMap:

@Component public class ConnectionManager { private final ConcurrentMap<String, Channel> channels = new ConcurrentHashMap<>(); public void add(String userId, Channel channel) { channels.put(userId, channel); channel.closeFuture().addListener(f -> channels.remove(userId, channel)); } public Channel get(String userId) { return channels.get(userId); } public int onlineCount() { return channels.size(); } }

这里最容易被忽略的是closeFuture().addListener这一行。不加这个监听器,连接关闭后注册表里还残留着引用,久而久之就变成“幽灵会话”,在线人数统计失真,消息发到已关闭的连接上还会产生莫名异常。把remove操作挂在closeFuture上,比自己写finally块、靠异常来清理要可靠得多。

广播场景下,如果按主题分组推送,可以再加一层ConcurrentHashMap<String, ChannelGroup>,主题映射到一组连接,命中主题后直接对这个group发消息。10万连接全量遍历一次,光是遍历和判断就可能耗时几十毫秒;而分组命中基本是微秒级。

4.2 心跳机制:把假死连接踢出去

长连接最怕“假死”。客户端网络断开但服务端没收到FIN,连接就僵在那,占着fd、占着内存。解决手段是心跳。

WebSocket协议自带Ping/Pong帧,优先用这个,因为它是协议层面的消息,不污染业务数据。Netty里加心跳只需要一个IdleStateHandler:

p.addLast(new IdleStateHandler(60, 30, 0));

第一个参数是读空闲60秒,第二个是写空闲30秒。也就是说,服务端每30秒主动发一次Ping,如果客户端60秒内没回来任何数据,包括Pong,就触发IdleStateEvent。

但是注意,读空闲一到就关连接太激进了。网络抖动、客户端GC停顿、用户把App切到后台,都可能让一次Pong晚到。我习惯的做法是:连续2次读空闲才关连接,并且给客户端一个重连缓冲期。判断逻辑写在userEventTriggered里,用计数器累积空闲次数,达到阈值再执行close。

4.3 消息派发与背压保护

消息发不出去、积压在内存里,是高并发WebSocket服务最常见的OOM来源。一条连到弱网客户端的连接,服务端拼命往它写数据,写不出去就积在发送缓冲区里,一条连接积攒几十MB,10条慢连接就能把堆外的DirectBuffer吃干净。

Netty的WRITE_BUFFER_WATER_MARK就是对付这个的。发送数据前检查channel.isWritable(),如果返回false,说明这个连接已经积压到高水位64KB以上,这时候要直接跳过这条连接,或者把它标记为“慢连接”,进入单独的重试/关闭流程。

另一个实用技巧是:广播时不要对每条连接都writeAndFlush,这样会频繁触发flush。对于低频通知,直接遍历注册表推送没问题;对于高频行情类广播,应该把消息序列化一次,然后对连接组批量写,并且只对isWritable()的连接写。这样既能减少序列化开销,又能避免一条慢连接拖垮所有快连接。

Spring的WebSocket方案也有类似的限制手段。STOMP消息代理上有server.sendBufferSizeLimit之类的参数可以约束单个session的发送缓冲,防止内存被某个慢客户端吃光。无论用哪套,核心思路一致:允许丢慢连接,不允许被慢连接拖死。

5. 全链路压测与监控:用数据验证10万连接

5.1 压测方案与工具选择:先解决客户端端口瓶颈

代码写完了,调优做完了,下一步是验证。这里我踩过最大的坑不是服务端,而是压测客户端。

先说工具:JMeter带WebSocket Sampler插件,适合冒烟测试和功能验证,但单机压10万并发不现实,跑分布式又太重。自研Go压测脚本是最实用的,每个goroutine可以管理一批连接,100个goroutine、每个goroutine负责1000条连接,就能模拟10万在线,Go的并发模型非常适合这种场景。

但压测客户端有个物理限制:一个客户端源IP到同一个服务端IP和端口,最多只能建立大约28K个连接,由ip_local_port_range限制,默认是32768到60999。想从一台机器压出10万连接,必须给网卡绑定多个辅助IP,或者用多台压测机。很多人压测时连接数卡在2万多,以为服务端不行,其实是客户端端口用完了。

压测时要重点盯几个指标:

  • 连接建立速率:10万连接是30分钟慢慢爬上去,还是5分钟内瞬间打满,对服务端完全是两种压力。瞬间打满时,SYN队列、accept队列、线程池、GC都要经受考验。
  • 最大在线连接数:这是硬指标,压在10万以上并稳定10分钟,才算验证通过。
  • P99消息延迟:在线连接数只是“挂着”,还要验证消息能发得出去。压测脚本里留一部分连接持续收发消息,看服务端的P99延迟是否劣化。
  • RSS内存曲线:观察进程内存是否随连接数线性增长,以及停止建连后是否会回落。

我实测过一组典型配置:8核16G的云主机,按前面的内核参数和JVM参数,Netty传输层方案,压到10万在线连接是稳的,进程RSS大约占7~9GB,其中堆内存5GB左右,剩余的堆外和内核吃掉。具体数字会因消息量和负载模式浮动,但这个量级可以作为方案评估的参考。

5.2 关键指标与监控体系

连接数上到10万之后,别再依赖netstat,那玩意在10万连接下能卡到你怀疑人生。请用ss:

ss -s ss -tan state established sport = :8080 | wc -l

应用层监控,建议把连接数直接暴露成指标。Netty模式下可以在ConnectionManager里维护一个AtomicInteger,通过Micrometer注册成Gauge,接上Prometheus和Grafana。我常用的指标列表:

  • 在线连接数:online_connections
  • 握手成功速率:ws_handshake_total
  • 心跳超时次数:ws_idle_timeout_total
  • 消息发送失败次数:ws_send_failure_total
  • 积压超水线连接数:ws_slow_connection_count

JVM层面,jstat -gcutil <pid> 5000看GC频率,jcmd <pid> GC.heap_info看分区占用。压测期间最好开着GC日志,事后复盘才能定位毛刺来源。

5.3 连接数上不去的三个第一嫌疑

  • 第一嫌疑是fd限制。先看进程实际限制:cat /proc/<pid>/limits,如果nofile只有1024,你怎么压都上不去。
  • 第二嫌疑是nf_conntrack表满了。dmesg | tail会有明确报错,或者conntrack -S看insert_failed计数。
  • 第三嫌疑是压测机端口耗尽。检查压测端的ss -tan,如果大量连接处在TIME_WAIT,说明源端口复用有问题,tcp_tw_reuse没生效或没写对。

6. 常见问题与排障实录

6.1 连接稳定后突然大规模掉线

这种问题十有八九出在网络中间设备上。长连接经过负载均衡或NAT网关时,网关通常有会话空闲超时,比如120秒或300秒,超时后网关直接丢弃映射,客户端再发数据,要么RST,要么黑洞。

解决思路是让心跳保活跑在网关超时时间的一半以内。如果网关超时无法调整,就把应用层心跳间隔从60秒改成30秒,或者把TCP keepalive探测时间调到和网关匹配。另一个排查手段是抓包:看服务端收到的RST是来自客户端IP还是中间设备IP,来源不同,处理思路完全不同。

6.2 内存RSS比堆大很多怎么查

如果你发现进程RSS明显大于-Xmx,先别慌,逐一核对这几块:

  • Netty的DirectBuffer:jcmd <pid> VM.native_memory summary看DirectBuffer区域。
  • 内核TCP接收/发送队列:ss -m能看每个socket的buffer占用,找找有没有单连接积压几十MB的情况。
  • JIT CodeCache:默认上限240MB,正常不会爆,但如果用了大量动态代理或反射,CodeCache增长会很快。
  • 线程栈:ps -eLf | grep <pid> | wc -l数一下线程数,乘以栈大小就是大致的线程内存。

排查方向明确之后,对应的手段分别是:控制写水线、调整内核tcp_rmem/tcp_wmem、精简代理反射、降线程数。不要一上来就加-Xmx,那只是掩盖症状。

6.3 GC停顿导致消息延迟尖刺

10万连接场景下,G1GC的停顿若控制不好,消息延迟毛刺会很明显。我遇到过的情况是:新生代容量设置太小,对象分配速率一高,Young GC频繁触发,每次停顿几十毫秒,消息P99直接飙到1秒以上。

调整思路是:

  • 用-XX:G1NewSizePercent=10和-XX:G1MaxNewSizePercent=40给新生代留出足够空间,减少YGC频率。
  • 减少临时对象分配。比如消息序列化结果复用ThreadLocal缓冲,避免每发一条消息都new一个字节数组。
  • 如果毛刺还是压不住,检查是否存在直接内存泄漏导致的Full GC。堆转储文件里如果字节数组实例数量异常庞大,那基本可以判定是某个业务Handler忘记释放或缓存失控。

6.4 Spring方案2万连接就出问题,要不要换Netty?

我经常被问到这个问题。先说结论:先排查你自己的代码,再怪框架。Spring内嵌Tomcat跑2万连接就崩,大概率是下面某个环节出了问题:

  • worker线程池被打满:如果Handler里有阻塞操作,比如同步调数据库、加锁,就算只有2万连接,200个worker也很快耗尽。解决办法是把阻塞操作丢到独立业务线程池,让WebSocket线程只做转发。
  • 会话没有清理:确认有没有维护连接注册表,连接关闭后有没有及时remove。
  • 消息缓冲失控:确认有没有对session的发送缓冲做限制。

如果这些都没问题,消息吞吐还是上不去,再考虑换Netty。但如果你的场景真到了“10万连接+持续高吞吐”这个级别,直接选Netty方案,省得到时候迁移。

6.5 常见问题速查表

现象可能原因检查手段解决方案
连接数卡在2万左右压测机端口耗尽压测端ss -tan看TIME_WAIT绑定多个源IP / 开启tcp_tw_reuse
连到3~5万就失败fd限制或nf_conntrack满cat /proc/<pid>/limits、dmesg调nofile / 扩conntrack
连接稳定后不定时掉线中间设备空闲超时抓包看RST来源缩短心跳间隔
内存RSS远大于堆DirectBuffer/线程栈/内核缓冲jcmd VM.native_memory控制写水线 / 调线程数
GC停顿导致延迟尖刺新生代太小/临时对象多GC日志看YGC频率调G1新生代比例 / 复用缓冲
Spring方案2万连接就崩线程池被阻塞操作打满线程dump看worker状态业务线程池隔离

按这个路径走下来,10万长连接绝对不是玄学。我个人在实际项目里的体感是:最难的不是某一项技术,而是把内存、线程、内核、连接管理、监控压测这五件事串成一个整体。每次调整一个参数,都要用压测数据去验证,不要靠感觉调。

最后再分享一个小技巧:上线前一定要做“连接闪断恢复”演练——瞬间断开2万条连接,再让客户端集体重连,看服务端能不能在1分钟内恢复稳定。这个环节能暴露出连接注册表清理、心跳阈值、SYN队列这些最隐蔽的问题。等你把这一轮也跑顺了,单机10万连接这个目标,基本就算是真正拿下了。

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/10/15 9:28:49

MATLAB实现高斯光束整形迭代算法详解

1. 高斯光束整形的基本概念光学系统设计中&#xff0c;光束整形是一个永恒的话题。高斯光束作为激光器最常见的输出模式&#xff0c;其强度分布遵循高斯函数&#xff0c;在中心区域强度最高&#xff0c;向边缘呈指数衰减。这种特性虽然在某些应用中很有优势&#xff0c;但在需要…

作者头像 李华
网站建设 2026/10/15 9:28:49

UTC时间戳转换与多语言时区处理实践

1. 时间格式转换的核心需求解析在数据处理和系统开发中&#xff0c;时间格式转换是最基础却最容易出错的环节之一。最近在处理一批物联网设备上报的日志数据时&#xff0c;遇到了一个典型场景&#xff1a;原始数据中的时间戳采用UTC秒级精度&#xff08;如1625097600&#xff0…

作者头像 李华
网站建设 2026/10/15 9:28:41

从ROS 1到ROS 2:机器人系统软件架构演进与工程实践

2018年我调试一台移动底盘的时候&#xff0c;还在用串口转WiFi模块拉日志&#xff0c;每个节点的输出都要手工加时间戳比对。到了2022年&#xff0c;同样一台底盘&#xff0c;我在电脑上打开网页就能看到整棵话题树的实时波形&#xff0c;节点的崩溃快照自动上报到远端服务器。…

作者头像 李华
网站建设 2026/10/15 9:28:39

SpringBoot+Netty打造聚合WebSocket:单机10万长连接实战

做物联网、IM、实时消息推送这一类项目&#xff0c;最绕不开的就是WebSocket长连接规模问题。很多人用SpringBoot默认的spring-boot-starter-websocket把业务写完&#xff0c;本地测几百连接都很正常&#xff0c;设备量一上来&#xff0c;连接数到两三千就开始频繁掉线&#xf…

作者头像 李华
网站建设 2026/10/15 9:28:24

MC9S12XS128指令集查询指南:编码、寻址与周期数解析

简介&#xff1a;MC9S12XS128 是飞思卡尔&#xff08;现 NXP&#xff09;面向智能车等场景常用的微控制器&#xff0c;其指令集速查文档正是为汇编开发者和嵌入式爱好者整理的精简工具。文档以 docx 格式呈现&#xff0c;共 1 个文件&#xff0c;压缩包仅 30KB&#xff0c;轻量…

作者头像 李华
网站建设 2026/10/15 9:28:02

从本地脚本到生产环境:部署架构选型与避坑指南

坦白说&#xff0c;看到“部署”这个词&#xff0c;我真觉得是每个写代码的人都绕不过去的结。你问十个工程师&#xff0c;十个能给出十种答案&#xff1a;有人觉得把脚本扔到服务器上定时跑就是部署&#xff0c;有人觉得docker compose up -d才算正经&#xff0c;还有人会跟你…

作者头像 李华