SkeyeVSS开发心得-SSE架构与注意事项

张开发
2026/4/10 4:30:06 15 分钟阅读

分享文章

SkeyeVSS开发心得-SSE架构与注意事项
本文是 VSS-SSE架构设计 的配套的开发笔记在「独立端口、/events、messageChan→Flush」模型之上补充联调、部署、扩展开仓时容易忽略的点。项目源码地址https://github.com/openskeye/go-vss1. 明确三个要点推送只认messageChan业务 Logic 不要把 SSE 的http.ResponseWriter往下传并自行Write统一messageChan - SSEResponse{...}由server/sse.go的handler做toRespFlush否则帧格式、结束语义、关闭顺序会分裂。for range messageChan退出后必然会close(messageChan)DelayClose时延迟 2s。Logic禁止在向 channel 已关闭后仍发送否则会panic长协程必须在ctx.Done()后停止写 channel。高频/洪峰要考虑背压messageChan有界满则发送方阻塞——SIP 日志类场景要与上游限流、丢包策略见 §5。2. 与 [VSS-SSE架构设计]的「实现更新」messageChan容量文档中已说明「缓冲10」实现以配置为准var buf l.svcCtx.Config.SSE.MessageChanBuffer if buf 0 { buf 256 } var ( messageChan make(chan *types.SSEResponse, buf)配置项SSE.MessageChanBuffercore/tps/conf/config.go0或未配则服务端用256。开发心得变更环境时别假设固定 10压测/日志洪峰前应调大或做业务侧节流。3. HTTP 层帧格式、Flusher、代理3.1data: {data: ...}嵌套toResp成功帧为data: {data: JSON}\n\n不是业务 JSON。前端用EventSource时event.data是一段字符串需JSON.parse后再读.data否则联调会误以为服务端乱码。3.2http.Flusher强转写出路径使用w.(http.Flusher).Flush()。若反向代理或中间件把ResponseWriter包了一层且未实现Flusher会panic。部署心得网关/自管 middleware需透传 FlusherNginx 等对 SSE 常见配置为proxy_buffering off、合适的proxy_read_timeout。3.3 结束语义Errevent: enderror字段 → handler跳出循环。Doneevent: enddata: {}。DelayClose: truedefer里2s 后再close(messageChan)给尾包/对端处理留时间Logic 若在Done后仍异步写 channel仍有竞态风险应Done即停写。3.4 CORS响应头Access-Control-Allow-Origin: *。若浏览器要带 Cookie 鉴权常与*冲突——当前 handler 未做认证见 2.3 中的第七节公网应靠网关认证 / 内网隔离。4. 路由与并发模型sseHandlervssip_logsfunc sseHandler[Logic any, Req types.SSERequestType](...) { // ... schema validator失败则直写 messageChan ... go handler.DO(req) }带 Query 的类型go handler.DO(req)解析/校验在当前 goroutine业务在子 goroutine。sip_logs同步VSipLogs.New(...).DO()DO内部再如何起 goroutine 由其实现决定2.3 已述。心得新增type时要想清楚——是否需要在DO前再阻塞做资源抢占例如 sip_logs 的全局单活不要照抄sseHandler或 sip_logs而不读实现。4.1 默认分支switch的default对未识别type以及type为空统一返回type 不能为空类错误。联调缺参和拼错 type表现接近应用枚举文档或常量避免手写字符串这里我做的简易实现需要根据业务做出调整。5. 背压、阻塞与 SIP 日志类场景messageChan满→ Logic 里messageChan -阻塞若发生在持有锁或与 SIP 广播同线程路上可能间接拖慢其它模块。** sip_logs等若已实现限流/非阻塞发送**更新后应以实际sip_logs.go为准做容量估算未做限流时应降低广播频率或加大MessageChanBuffer。心得把SSE.MessageChanBuffer当成与SipLogMaxPerSecond若配置同级看待一起调。6. 生命周期与contextctx来自context.WithCancel(r.Context())客户端断开时ctx取消。handler侧for range messageChan并不select ctx.Done()见 2.3 第九节客户端断开后若 Logic仍持续messageChan -channel 可能迟迟不被消费直至 Logic 停止若 Logic 已停而 channel 里还有数据行为依赖剩余事务。心得每个Logic 应明确select { case -ctx.Done(): return; case ... }停止生产结束前视情况发Done或Err。7. 扩展新type的检查清单routers.go增加caseGetType()与 querytype常量一致。有 Querystruct带form/validatetag与前端一致。New(ctx, svcCtx, messageChan)保存ctx禁止在 goroutine 里无取消地死循环。预估 QPS是否会塞满messageChan是否要做聚批/采样。结束路径必须在错误/完成时让handler能走出for rangeErr/Done/空串跳出规则见toResp。若对公网网关鉴权、限流、与 SSE超时评审根据需求调整。8. 与其它通道对比选型能力SSE/eventsGin/apiWS端口SSE.PortHttp.PortWS.Port方向服务端推送为主请求-响应双向鉴权handler 未内置视业务子协议 Token帧文本 SSE固定toResp包装JSON body自定不要用 SSE 传大文件二进制大流量用下载接口 file_download进度或独立存储链。9. 相关文档与源码说明路径架构总览2.3 VSS-SSE架构设计服务实现core/app/sev/vss/internal/server/sse.go路由core/app/sev/vss/internal/handler/sse/routers.go业务 Logiccore/app/sev/vss/internal/logic/sse/*.goServiceContext开发心得-ServiceContext设计与使用

更多文章