百万级WebSocket实时推送架构:Redis Cluster会话状态管理实践
先说结论这个项目做完之后我最大的感受就是——WebSocket本身不复杂复杂的是把“连接”和“状态”这两件事放进分布式架构里还要在百万级连接的压力下不翻车。省钱返利小助手这类业务看着是一个聊天/客服工具本质上是一套强实时、高读写的交互系统。用户要实时看到返利到账、优惠券提醒、比价结果推送这些场景天然需要服务端主动推送轮询根本扛不住那个频次和延迟。而要把WebSocket连接和用户会话状态在多个节点之间协调好Redis Cluster是目前工程上最稳、性价比最高的选择。这篇文章我按实践顺序来拆先聊需求背后的技术账再讲会话状态的整体设计然后给Java侧的实现细节和Redis Cluster的容量预算最后把上线前后踩过的坑全部摊开。适合正在做IM、客服、实时通知、在线协作这类项目的开发者参考。1. 需求背后的技术账为什么省钱返利场景非用这套架构不可1.1 所谓实时交互在这个项目里到底指什么省钱返利小助手不是一个单纯的比价工具它的核心交互链路是用户复制商品链接过来后台解析、查券、显示返利用户下单后系统跟踪订单状态、结算返利返利到账那一刻推送给用户。这里面真正对延迟敏感的不是“查券”本身用户能等3秒而是“返利到账通知”和“限时优惠券变动通知”。这类消息的特点是短、频、快而且不可能靠客户端轮询解决。轮询的代价是按秒级拉一次接口100万用户在线时就算错峰每秒也有几十万次HTTP请求打到后端光连接开销就把资源吃掉了。WebSocket在这里解决的是“服务端主动找用户说话”的问题。一次握手之后服务端可以在任意时刻把消息塞给客户端双向通信头部开销比HTTP握手小几个数量级。同一台8核16G的机器撑住几万条HTTP长轮询都费劲但同样配置撑住十几万条WebSocket连接是可能的。所以这个项目从一开始就定了基调实时消息通道用WebSocket会话状态和跨节点协调交给Redis Cluster。1.2 WebSocket与Redis Cluster各自解决什么问题我拆解一下这两个组件各自的职责边界很多团队一开始会把它们混着用导致后面被坑。WebSocket端解决的是“连接管理”谁的连接打到哪台机器、连接活着还是死了、心跳由谁负责、断线之后怎么续上。这本质上是连接层的问题。连接是会移动的比如用户断网重连负载均衡可能把新连接分配到了另一台后端节点这个时候旧的连接状态就不能再留在本机内存里了。Redis Cluster解决的是“状态同步”用户ID和sessionId怎么映射、连接落在哪台节点、用户当前订阅了哪些优惠券topic、消息要转给哪个节点去推。这本质上是状态层的问题。Redis选Cluster模式而不是单机或主从原因是连接与状态的映射关系在百万用户量级下必须做水平扩展单机内存和单点风险都撑不住。提示这个架构里Redis存的不是聊天记录本身而是“会话状态”。聊天记录、返利订单详情这类数据应该进消息队列和数据库别混在会话状态的存储里否则Redis内存和过期策略会被拖垮。2. 会话状态管理的整体设计从连接到状态保持2.1 连接生命周期与心跳机制我在这个项目里把一条WebSocket连接的生命周期拆成五个阶段握手鉴权、注册状态、心跳保活、消息收发、断开清理。每个阶段都对应Redis里的若干次读写。握手阶段客户端通过HTTP Upgrade发起请求WebSocket底层框架我用的Spring WebSocket底层是Tomcat的WebSocket实现会先走一遍拦截器在这里做token鉴权。鉴权通过之后onOpen回调里拿到用户身份这时候第一步不是给客户端回“连接成功”而是去Redis写入会话映射。心跳是最容易被忽略的坑。TCP层有keepalive但默认间隔太长而且经过负载均衡和宿主机网络栈之后不可靠。应用层心跳必须自己做。我的方案是客户端每30秒发一个ping帧服务端收到后回pong帧服务端同时用空闲检测如果60秒没收到任何客户端消息主动断开这条连接并清理Redis状态。这里有一个关键细节心跳消息本身不要触发业务逻辑但必须刷新Redis里的活跃时间戳否则会出现“连接活着但状态被过期清理”的灵异事件。断开清理阶段onClose和onError都要走同一套清理逻辑不要各写一遍。我踩过一次因为只处理了onClose、没处理onError导致Redis里残留了几万条僵尸会话记录的坑。2.2 会话状态在Redis Cluster里的存储模型状态存储设计我前后改了三版最终定型为三层映射全部放在Redis Cluster里第一层是用户ID到会话信息的映射。Key设计为session:{userId}Hash结构字段包括sessionId、nodeId、loginTime、lastActiveTime。为什么用Hash而不是直接存JSON字符串因为我想在不读取整个对象的情况下单独更新lastActiveTimeHash可以做到单字段更新省流量省CPU。第二层是会话ID到节点ID的映射。Key设计为route:{sessionId}Value是后端节点的唯一标识比如node-1。这一层的意义在于消息分发时能快速找到连接落在哪台机器。如果不存这一层每次推送消息都要全节点广播100万连接在线时广播风暴直接能打垮网络。第三层是在线用户集合。Key设计为online:users用Set存储所有在线userId用于后台统计在线人数、定向运营筛选。这层数据允许一定的延迟所以不用每次心跳都更新连接建立时写入、断开时移除就行。TTL策略方面session:{userId}设置为10分钟过期每次心跳刷新。route:{sessionId}不设TTL由断开事件显式删除。为什么不给route也设TTL因为只要连接在session一定在但route如果提前过期消息分发就找不到节点了而且显式删除的路径很明确没有漏删的理由。在线集合同样不设TTL靠断开事件维护。2.3 路由策略连接与状态怎么对上这里有个很多人会困惑的问题WebSocket连接长在后端节点A上订单服务在节点B上要推送消息它怎么知道去哪找这条连接答案就是查Redis。完整的消息推送链路是这样的业务服务收到“返利到账”事件拿到userId。查询session:{userId}拿到sessionId和nodeId。如果nodeId是本机直接从本地连接管理器一个ConcurrentHashMapkey是sessionIdvalue是WebSocketSession拿出连接推送。如果nodeId是其他节点把消息丢给目标节点的推送接口我用的是内部HTTP回调也可以用Redis Pub/Sub做广播但广播要小心流量放大。目标节点收到消息后根据sessionId查本地连接管理器推送成功返回ACK。这五步里面第2步是Redis读取第4步是节点间通信其他都是本地操作。整个链路最耗时的其实是第4步但内部网络的延迟通常在1ms以内可以忽略。注意本地连接管理器必须是内存态不能每次推送都从Redis拿WebSocketSession对象因为WebSocketSession是JVM对象没法序列化到Redis里再还原成可用的连接。Redis里只存路由信息真正的连接永远在后端节点的内存里。3. 核心实操Java侧的具体实现细节3.1 WebSocket端点与鉴权接入我用的方案是Spring WebSocket Spring Boot端点类用ServerEndpoint注解那一套但要注意容器的选择。Tomcat自带的WebSocket实现在连接数上来之后线程模型是“每个连接一个线程”5000个并发连接就开始明显吃力。我的做法是后端接入Netty直接用Spring WebSocket确实省事但Netty的线程模型撑10万连接根本不慌。这里不展开Netty的线程模型原理只强调一点100万级连接的规模IO线程和业务线程必须分离而Netty天然就是这套模型。端点的鉴权放在握手拦截器里。客户端在Sec-WebSocket-Protocol头或者query参数里携带token拦截器校验通过后才允许握手。校验token时顺带把userId解析出来存入WebSocketSession的attributes里后续onOpen直接用不用再查一次数据库。public class AuthHandshakeInterceptor implements HandshakeInterceptor { private final SessionService sessionService; Override public boolean beforeHandshake(ServerHttpRequest request, ServerHttpResponse response, WebSocketHandler wsHandler, MapString, Object attributes) { String token parseToken(request); UserSession user sessionService.validateToken(token); if (user null) { response.setStatusCode(HttpStatus.UNAUTHORIZED); return false; } attributes.put(userId, user.getUserId()); attributes.put(sessionId, generateSessionId()); return true; } }这里有两个细节容易踩坑。第一握手阶段的鉴权失败不能让客户端看到详细的失败原因否则就是给攻击者送情报统一返回401 UNAUTHORIZED即可。第二attributes里的参数在onOpen里可以直接通过session.getAttributes()取到这是握手阶段往后传递数据最干净的方式。3.2 状态写入Redis的关键代码与序列化选择会话状态写入Redis我有几条硬性规则序列化统一用JSON不用Java原生序列化。Java原生序列化出来的二进制读出来就是一堆\xAC\xED\x00\x05开头的垃圾排查问题的时候在Redis里没法直观看到内容。JSON的好处是能直接redis-cli查看线上问题定位快好几倍。连接建立后必须先写Redis再回客户端。顺序不能反。如果先回客户端“连接成功”然后才写Redis这中间有几十毫秒的空窗期用户发来第一条消息时服务端按userId查不到会话就会误判为未注册。OnOpen public void onOpen(Session session) { String userId (String) session.getUserProperties().get(userId); String sessionId (String) session.getUserProperties().get(sessionId); String nodeId NodeRegistry.getCurrentNodeId(); // 第一层用户 - 会话 String sessionKey session: userId; MapString, String sessionMeta new HashMap(); sessionMeta.put(sessionId, sessionId); sessionMeta.put(nodeId, nodeId); sessionMeta.put(loginTime, String.valueOf(System.currentTimeMillis())); sessionMeta.put(lastActiveTime, String.valueOf(System.currentTimeMillis())); redisTemplate.opsForHash().putAll(sessionKey, sessionMeta); redisTemplate.expire(sessionKey, 10, TimeUnit.MINUTES); // 第二层会话 - 节点 redisTemplate.opsForValue().set(route: sessionId, nodeId); // 第三层在线用户集合 redisTemplate.opsForSet().add(online:users, userId); // 最后才往本地连接管理器注册 LocalConnectionManager.add(sessionId, session); }序列化我重点说一个陷阱用GenericJackson2JsonRedisTemplate还是StringRedisTemplate我推荐StringRedisTemplate加手动序列化也就是写一段工具类把对象转成JSON字符串原因有三第一GenericJackson2JsonRedisTemplate会在序列化结果里额外写入class字段用来反序列化时还原真实类型但Redis里存的这些元数据占了大量空间。100万用户的会话状态每个多存20字节的class信息就是20MB的额外内存而且不直观。第二手动序列化可以严格控制在同一个DTO类里增减字段反序列化时用ObjectMapper的FAIL_ON_UNKNOWN_PROPERTIESfalse未来加字段不会把老数据卡死。第三GenericJackson2JsonRedisTemplate偶发的类型转换异常在线上排查起来很痛苦不如自己控制。3.3 百万级连接下的Broker分发与消息推送设计消息推送的分发策略是这个架构的命门。在100万连接量级下“全覆盖广播”是一种极其昂贵的操作一定要尽量避免。我按消息的受众范围分了三种推送模式定向推送userId明确比如返利到账只推给某个用户。走前面说的查Redis路由链路。组播推送比如“全部收藏了某商品券的用户”。这些用户在Redis里维护一个group:item:{itemId}的Set推送时遍历Set里的userId各自走定向推送。注意这里不要用Redis的Pub/Sub做组播因为Pub/Sub的消息是即发即弃消费者不在线消息就丢了而业务消息不能丢。正确做法是把消息丢进消息队列然后消费端逐条走定向推送。我在这个项目里过了一遍消息队列真正有延迟要求、又需要可靠投递的推送都用它。场景广播比如“全平台限时秒杀即将开始”这类消息看起来要广播但真正的受众是当前在线的、对秒杀感兴趣的活跃用户。让后端每个节点本地维护一个“在线订阅表”广播消息只在节点间传一次每个节点往自己本地的在线连接推送。public void pushToUser(String userId, PushMessage message) { String sessionKey session: userId; MapObject, Object sessionMeta redisTemplate.opsForHash().entries(sessionKey); if (sessionMeta null || sessionMeta.isEmpty()) { // 离线消息转入离线队列等用户下次上线再补推 offlineMessageService.save(userId, message); return; } String nodeId (String) sessionMeta.get(nodeId); String sessionId (String) sessionMeta.get(sessionId); if (NodeRegistry.getCurrentNodeId().equals(nodeId)) { LocalConnectionManager.send(sessionId, message); } else { NodePushClient.send(nodeId, sessionId, message); } }这里有一个性能隐患每次pushToUser都读一次Redis Hash的entries这个方法调用很频繁时Redis的读放大就很明显。我在本地加了一个两级缓存第一级是userId到nodeId的映射缓存在本地内存里30秒过期第二级才是穿透到Redis查询。如果消息投递失败比如目标节点返回连接不存在再清掉本地缓存重新查一遍Redis定位到最新节点。4. Redis Cluster的容量与性能预算4.1 容量估算会话数据到底占多少内存做容量预算的前提是把数据模型量化。我按100万在线用户来算会话基础数据session:{userId}一个Hash存4个字段Key本身约20字节Hash的field和value加起来大约200字节加上Redis Hash自身的编码开销算300字节一个用户。路由数据route:{sessionId}Key约20字节Value是节点ID约12字节加上Redis DictEntry和SDS的开销算80字节。在线集合online:users100万个userId放进一个Set每个元素加上集合开销大约40字节这就是40MB。账号体系、离线消息这些先不算光会话状态就是100万乘以380字节约362MB。这只是数据部分还没算Redis的复制buffer、持久化RDB/AOF的额外消耗。所以在Cluster模式下3主3从的架构每个主节点分片大约1/3的数据也就是120MB左右的数据量留2倍内存给持久化和复制每个节点的内存规划做到2GB以上。这里有个容易犯的错误按单机Redis的容量思维去配Cluster结果每台只给512MB上线三个月内存被打满。Redis做状态存储和做缓存不一样缓存数据没了可以从数据库回源但会话状态没了用户就直接断线重连流量的尖峰和内存的持续增长需要预留足够的buffer。4.2 热点问题与key设计规范Redis Cluster有个特性数据按hash slot分布默认16384个槽位每个key通过CRC16算法映射到槽位。多key操作比如MGET、事务要求所有key在同一个槽位所以用{userId}这种hash tag可以把相关key固定到同一槽位。但这里有个权衡如果在线用户集合、session、route都用同一个hash tag那把大量数据打进同一个槽位分片就失去了意义。我的经验是session:{userId}和route:{sessionId}不需要在同一槽位因为它们不会在一个多key操作里同时访问。真正需要hash tag的是同一个用户的多个状态比如session:{userId}和notify:queue:{userId}这两个key经常一起操作。还有一个热点问题要特别注意在线用户集合online:users是一个超大的Set即便只做SADD/SREM操作在百万成员量级下单个集合的读写也会成为Redis所在节点的CPU热点。我的处理方式是把在线集合按userId的哈希值分片拆成online:users:0到online:users:15共16个Set统计在线人数时把16个SCARD加起来。这样任何一个节点的负载都降下来了。4.3 集群扩缩容对WebSocket的影响Redis Cluster的在线迁移会对会话状态管理产生冲击这个在架构设计阶段就要考虑到。扩容时新增一个分片会从已有节点迁移部分槽位过去迁移期间slot对应的key可能被阻塞几百毫秒到几秒。对WebSocket的影响是心跳刷新或者状态查询可能超时导致连接被误判为失效。我采用的规避方案是Redis客户端访问开启重试和超时熔断。心跳刷新Redis失败时不立即断开连接而是允许连续失败3次再断开。因为Redis迁移导致的失败是短时间的客户端等一会就恢复但连接一断就是大规模重连风暴代价完全不是一个量级。另外要提前给Redis Cluster的客户端配置正确的拓扑刷新机制。现在用的客户端框架都支持Cluster拓扑自动刷新但很多人默认配置没调槽位迁移后客户端还在往旧节点发请求导致一堆MOVED重定向错误。我在上线前专门测过一轮扩缩容过程中消息推送的失败率在5秒内恢复到0才算合格。5. 上线前后踩过的那些坑5.1 连接风暴把Redis打挂的一次事故上线第一个月就出过一次事故。某个渠道做了返利翻倍活动大量用户同时打开小程序一瞬间新WebSocket连接数翻了十倍。每一条新连接都要写三次Redissession、route、online集合再加上握手前的token校验也要查RedisRedis Cluster的主节点CPU瞬间打满所有请求的延迟从1ms飙升到200ms然后客户端因为超时重连又带来新一波连接雪崩就这样发生了。事后复盘加了三个保护措施连接建立入口加全局限流每秒放行新连接数不超过5000条多余连接在负载均衡层直接返回“稍后再试”。用户端有重试逻辑短暂的拒绝并不会影响体验。握手时的token校验不走Redis改成JWT本地验签。原因是连接建立时的Redis写入已经不少了校验这种读操作能省则省。JWT验签不依赖Redis本地几微秒完成。Redis写入改为异步批量。连接建立时的三次写操作合并成一个pipeline提交减少RTT。这个改动让Redis的QPS降了差不多60%效果立竿见影。5.2 心跳间隔不合理导致的误判最开始心跳策略是客户端每30秒发一次服务端空闲检测90秒断开。看起来挺合理结果测试环境出现了一批连接被无故断开的情况。一查发现是客户端App在后台被系统挂起心跳定时器不执行服务端90秒没收消息就断了用户把App切回前台WebSocket还没重连成功消息就丢了。后来改成客户端每30秒发一次心跳服务端空闲检测放宽到180秒。同时客户端在App从后台切回前台时主动检测WebSocket状态如果断了立即重连并在重连成功后拉取一次离线消息。这个改动之后连接被误断的案例基本绝迹。5.3 序列化版本兼容的隐形炸弹有一次发布版本往session:{userId}的Hash里加了一个clientVersion字段。以为很安全结果发布后不久大批用户的会话状态变成了空所有在线用户被迫重连了一遍。排查发现线上有一批老的客户端节点还在用旧代码它们读到新的session数据结构时反序列化用了严格模式遇到未知字段直接抛异常异常处理又写成了“删除整个key”结果session被一遍遍清空。教训有三条第一反序列化必须开启FAIL_ON_UNKNOWN_PROPERTIESfalse永远不允许因为多了一个字段而反序列化失败。第二清理逻辑必须做到字段级不要因为一次序列化异常就直接删除整个key。异常的时候应该保留原始数据并告警让值班的人决定要不要清。第三所有状态结构的变更先改服务端代码灰度发布验证稳定后再让老节点滚动升级不要一次性全量上线。6. 常见问题排查速查表为了减少大家上线后的排查成本我把这个项目里遇到过的典型问题整理成一张表每一条都是实际踩过的现象可能原因排查命令 / 方法解决方案用户收到重复推送消息队列重复投递消费者幂等没做查推送日志里同一条消息的msgId是否相同推送前用Redis SETNX做去重过期时间60秒部分用户连接秒断心跳超时阈值太小或客户端被系统挂起redis-cli --bigkeys查session是否在频繁过期放宽服务端空闲检测时间客户端补重连主动检测Redis CPU飙高大批连接建立触发3次写放大或在线集合热点redis-cli --hotkeys查热点keypipeline合并写入在线集合拆片消息推送延迟超过1秒节点间HTTP回调超时或本地缓存过期后穿透查Redis抓一下pushToUser的耗时分布内部HTTP连接池调大缓存过期时间加长Redis内存增长异常session和route没有正确清理僵尸数据堆积redis-cli --bigkeys统计key数量用脚本巡检过期session补一个定时清理任务集群扩缩容后大量MOVED错误客户端拓扑未刷新查询客户端日志的MOVED重定向次数开启客户端自动刷新拓扑提前做扩容演练排查时有个通用的思考顺序先确认是不是Redis集群的问题看慢日志、命中率、内存再确认是不是连接管理的问题看本机连接数、断开率最后才怀疑业务代码。大部分“灵异事件”最后都能归到这三类里面。7. 这套架构的边界与后续演进思路这套WebSocket Redis Cluster的方案覆盖的是百万级在线、每天推送量千万级以下、会话状态不超过几百GB的场景。如果业务继续往上涨有两个方向需要考虑演进。一个是把状态层从Redis Cluster迁到支持水平扩展的分布式内存网格让会话数据更靠近计算节点减少一次Redis访问带来的开销。但引入这类组件的运维成本明显上升不是所有项目都值得。另一个是把消息推送从“推给节点再让节点找连接”演进成“连接自己订阅主题”的模式。也就是每个WebSocket连接在建立时声明自己关心哪几类消息后端不做userId级别的路由查询而是根据主题把消息送到所有订阅了该主题的连接所在节点。这个模式更省Redis访问但要求业务方提前规划好主题分类不适合临时起意的定向推送。以我目前的判断省钱返利小助手现有的业务体量这套架构再跑两三年是够用的。它的核心价值不仅是扛住了百万用户的实时交互更重要的是把“连接”和“状态”两层关注点分开了今后如果节点不够加机器就行如果状态不够扩Redis分片就行。两边独立扩互不牵连这比一开始就上一套重型的消息中间件方案要务实得多。最后再提一个容易被忽视的细节所有Redis的key命令用对了大量耗时其实出在客户端的连接池配置和序列化选择上这些基础组件在压测阶段花一小时调好线上能少熬三个通宵。

相关新闻

Python接口自动化测试中的Token状态管理与复用实战

Python接口自动化测试中的Token状态管理与复用实战

简介:本资源是一份面向接口自动化测试初学者与功能测试转岗人员的实战型技术文档,聚焦解决Token鉴权场景下的核心难点——如何稳定获取并复用token完成后续接口链路调用。内容基于真实停车场管理平台API(ecapi.parkingwang.com)展…

2026/10/15 22:34:58 阅读更多 →
AI视频生成门槛再降?Q4预览版实测:从能生成到能叙事

AI视频生成门槛再降?Q4预览版实测:从能生成到能叙事

AI视频生成这个赛道的迭代速度,快得有点让人喘不过气。前几天我还在跟朋友讨论某个开源模型的运镜效果,结果转头就看到某国产视觉大模型团队放出了第四代模型的预览版。名字里带个Q4,听起来像季度版本,但实际体验下来,…

2026/10/15 22:34:58 阅读更多 →
流水作业调度不求人:从状态压缩DP到Johnson规则的完整实践指南

流水作业调度不求人:从状态压缩DP到Johnson规则的完整实践指南

流水作业调度,这个名字听起来像是车间主任才会头疼的事情,但做生产计划、供应链管理,或者研究算法的人都绕不开它。很多教材把它放在“动态规划”章节,导致不少初学者以为流水作业调度只能拿DP硬啃,其实这个问题的核心…

2026/10/15 22:34:58 阅读更多 →

最新新闻

Python函数全解析:从基础语法到工程实践

Python函数全解析:从基础语法到工程实践

函数是每个 Python 开发者都绕不开的核心话题,无论你写的是几十行的脚本,还是几千文件的大型系统,本质上都是在定义函数、调用函数、组织函数。很多人学完基础语法后写代码总感觉“差点意思”,代码又长又乱,改一个逻辑…

2026/10/15 23:20:40 阅读更多 →
PyTorch深度学习实战:动态图、张量与自动求导核心机制解析

PyTorch深度学习实战:动态图、张量与自动求导核心机制解析

1. 为什么“PyTorch”这三个字值得单独拿出来聊 如果你在深度学习圈子里待过一阵子,大概率会发现一个现象:大家聊模型结构、聊训练技巧、聊部署方案的时候,绕来绕去最后总会落到一个东西上—— PyTorch 。它不是一个具体的项目名&#xff0…

2026/10/15 23:20:40 阅读更多 →
本地SSL不是一张证书的事:宝塔面板商城HTTPS配置全解析

本地SSL不是一张证书的事:宝塔面板商城HTTPS配置全解析

在本地环境跑商城系统,很多人都是到了登录页才开始和 HTTPS 较劲的。我上一次用宝塔面板部署萤火商城,本地访问一切正常,唯独开了 SSL 之后就冒出各种怪问题:要么证书装了页面直接打不开,要么首页能开但一动就跳回 htt…

2026/10/15 23:20:40 阅读更多 →
用Web Audio实现网页消息提醒音:前端提示音库架构与避坑指南

用Web Audio实现网页消息提醒音:前端提示音库架构与避坑指南

简介:网页消息提醒音js是一份面向Web前端开发者的轻量级交互资源,解决网页应用中新消息或事件到来时的提示音播放需求,适合在实时通讯、社交网络、在线协作等场景中提升用户感知效率。资源共3个文件,压缩包仅181KB,包含…

2026/10/15 23:20:40 阅读更多 →
UE4塔防游戏C++核心实现:对象池、路径AI与数据驱动波次管理解析

UE4塔防游戏C++核心实现:对象池、路径AI与数据驱动波次管理解析

简介:这款基于UE4.22引擎开发的3D塔防游戏工程,是作者的个人学习项目,面向想从零接触虚幻引擎与C游戏开发的学习者。玩法是在地图周围的岩石区域布置炮塔,抵御连续11波士兵进攻;每波敌人数量与生命值都会逐步提升&…

2026/10/15 23:20:40 阅读更多 →
NAT与动态路由深度联动:智能制造网络的自适应通信架构

NAT与动态路由深度联动:智能制造网络的自适应通信架构

1. 项目概述:这不是教科书里的概念堆砌,而是真实网络边界上每天都在发生的“交通调度”你有没有遇到过这样的场景:某实验室新部署了一套工业视觉检测系统,后端服务器在内网192.168.100.0/24网段,前端质检终端却分散在车…

2026/10/15 23:19:39 阅读更多 →

日新闻

Docker Compose 容器化部署 ChirpStack LoRaWAN 网络服务器实战

Docker Compose 容器化部署 ChirpStack LoRaWAN 网络服务器实战

1. 为什么选择容器化方式部署 LoRa 网络服务LoRa 物联网项目落地时,网络服务器是整个链路的核心枢纽。它负责接收网关上报的数据包、完成去重与解密、再把有效载荷分发给上层应用。早期大家习惯把网络服务器直接装在物理机上,依赖一堆系统库和特定版本的…

2026/10/15 0:00:46 阅读更多 →
共享LLM服务下的跨模型自动扩缩容:Kubernetes实战与避坑指南

共享LLM服务下的跨模型自动扩缩容:Kubernetes实战与避坑指南

1. 共享推理服务里,扩缩容到底难在哪做过大模型推理服务部署的人,大概都经历过这样的场景:一个团队共用一套推理集群,A 业务跑的是 7B 的小模型,B 业务跑的是 72B 的大模型,C 业务白天流量高、晚上几乎归零…

2026/10/15 0:00:46 阅读更多 →
Systemd 启动阶段根文件系统只读之谜:fstab 与 remount-fs 服务深度解析

Systemd 启动阶段根文件系统只读之谜:fstab 与 remount-fs 服务深度解析

1. 引子:一次内核恐慌引发的追查先从一个真实场景说起。某次我给一台老旧的嵌入式设备折腾系统裁减,为了把启动时间压进两秒以内,我手贱地把一串自认为“没用”的 systemd 服务给 disable 了,其中就包括systemd-remount-fs.servic…

2026/10/15 0:00:46 阅读更多 →

周新闻

流感时间序列预测实战:ARIMA/LSTM全流程拆解与避坑指南

流感时间序列预测实战:ARIMA/LSTM全流程拆解与避坑指南

简介:基于 ARIMA、LSTM、Transformer 等模型的流感时间序列预测 Python 源码,面向计算机相关专业课程设计与期末大作业学生,以及项目实战学习者。内容覆盖预处理、平稳性检验、定阶、残差分析、多模型对比预测的完整时序建模流程,…

2026/10/15 16:18:54 阅读更多 →
影刀RPA新手教程:键盘模拟输入实战——输入文本与模拟按键的区别

影刀RPA新手教程:键盘模拟输入实战——输入文本与模拟按键的区别

影刀RPA新手教程:键盘模拟输入实战——输入文本与模拟按键的区别 做影刀RPA自动化,十个新手有八个栽在"往输入框里填东西"这件事上:要么填不进去,要么填了一半,要么直接把原来内容追加在后面。这背后的根因&…

2026/10/15 19:41:51 阅读更多 →
影刀RPA新手教程:阅文起点小说数据采集实战——书籍信息与章节内容

影刀RPA新手教程:阅文起点小说数据采集实战——书籍信息与章节内容

影刀RPA新手教程:阅文起点小说数据采集实战——书籍信息与章节内容 1. 认识影刀:什么场景该用RPA采小说数据 起点中文网的页面结构相对稳定——分类榜单、书籍详情、章节内容三块独立页面,跳转链路清晰。这种场景非常适合影刀自动化&#x…

2026/10/15 13:48:15 阅读更多 →

月新闻

我发现了一个新思路:用 Remotion + Claude Code 像写代码一样自动化生成短视频

我发现了一个新思路:用 Remotion + Claude Code 像写代码一样自动化生成短视频

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/15 0:14:36 阅读更多 →
Windows下 Codex 中 Chrome 和 Computer Use 插件不可用问题排查及解决参考方式:TaoToken 统一 Key 配置与验证

Windows下 Codex 中 Chrome 和 Computer Use 插件不可用问题排查及解决参考方式:TaoToken 统一 Key 配置与验证

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/14 22:45:47 阅读更多 →
黑夜航拍船只数据集训练YOLOV5模型全流程解析

黑夜航拍船只数据集训练YOLOV5模型全流程解析

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/15 9:49:14 阅读更多 →