perf: 优化后端性能与直播延迟,包含数据库WAL模式、流媒体写缓冲、转码 Preset 优化、聊天锁和指标采集优化,以及前端自动追帧功能

This commit is contained in:
2026-06-15 15:08:07 +08:00
parent 261b1ab169
commit e0a6923984
5 changed files with 150 additions and 24 deletions

View File

@@ -1,6 +1,7 @@
package stream
import (
"bufio"
"context"
"crypto/rand"
"encoding/hex"
@@ -15,6 +16,7 @@ import (
"time"
"github.com/gin-gonic/gin"
"github.com/nareix/joy4/av"
"github.com/nareix/joy4/av/avutil"
"github.com/nareix/joy4/av/pubsub"
"github.com/nareix/joy4/format"
@@ -82,6 +84,23 @@ func (w writeFlusher) Flush() error {
return nil
}
type bufferedWriteFlusher struct {
bufw *bufio.Writer
httpFlusher http.Flusher
}
func (w *bufferedWriteFlusher) Write(p []byte) (n int, err error) {
return w.bufw.Write(p)
}
func (w *bufferedWriteFlusher) Flush() error {
if err := w.bufw.Flush(); err != nil {
return err
}
w.httpFlusher.Flush()
return nil
}
// NewRTMPServer creates and initializes a new media server
func NewRTMPServer() *RTMPServer {
s := &RTMPServer{
@@ -235,13 +254,47 @@ func (s *RTMPServer) HandleHTTPFLV(c *gin.Context) {
c.Status(http.StatusOK)
flusher.Flush()
muxer := flv.NewMuxerWriteFlusher(writeFlusher{
// Coalesce the 3 internal write calls of WriteTag using a 4KB bufio.Writer
bufWriter := bufio.NewWriterSize(c.Writer, 4096)
bwf := &bufferedWriteFlusher{
bufw: bufWriter,
httpFlusher: flusher,
Writer: c.Writer,
})
}
muxer := flv.NewMuxerWriteFlusher(bwf)
cursor := q.Latest()
if err := avutil.CopyFile(muxer, cursor); err != nil && err != io.EOF {
// Write header first
streams, err := cursor.Streams()
if err != nil {
monitor.Errorf("HTTP-FLV failed to get cursor streams: %v", err)
return
}
if err = muxer.WriteHeader(streams); err != nil {
monitor.Errorf("HTTP-FLV failed to write header: %v", err)
return
}
if err = bwf.Flush(); err != nil {
return
}
// Read and write packet loop with per-packet flushing for low latency
for {
var pkt av.Packet
pkt, err = cursor.ReadPacket()
if err != nil {
break
}
if err = muxer.WritePacket(pkt); err != nil {
break
}
// Flush immediately so the frame is sent to the client (grouped write syscall)
if err = bwf.Flush(); err != nil {
break
}
}
if err != nil && err != io.EOF {
errStr := err.Error()
if strings.Contains(errStr, "broken pipe") || strings.Contains(errStr, "connection reset by peer") {
monitor.Infof("HTTP-FLV viewer disconnected: %s", streamPath)
@@ -299,10 +352,11 @@ func (s *RTMPServer) startVariantTranscoders(roomID string) {
"ffmpeg",
"-nostdin",
"-loglevel", "error",
"-fflags", "nobuffer",
"-i", inputURL,
"-vf", "scale="+profile.scale+":force_original_aspect_ratio=decrease",
"-c:v", "libx264",
"-preset", "veryfast",
"-preset", "ultrafast",
"-tune", "zerolatency",
"-g", "48",
"-keyint_min", "48",