ARTICLE DETAIL

资讯详情

深耕网站建设、视觉设计与SEO优化的一线实战洞察。

从0到1手搭直播高并发系统:架构、缓存与压测实战

从0到1手搭直播高并发系统:架构、缓存与压测实战 我到现在还记得第一次在JMeter里看到满屏红色报错时的反应——不是慌反而是兴奋。因为在那个节点之前我做过的后端功能几乎全是增删改查数据库最多5张表从来没有一个接口扛得住并发100以上。而这次我要逼自己去搭一套能支撑“很多人同时在线看、同时发弹幕”的直播高并发环境。这篇笔记就是记录我这个后端小白从 0 到 1 手搓直播环境的全过程架构选型、推流拉流链路、弹幕IM、Redis缓存设计、JMeter压测调优以及一路踩过来的坑。如果你也正在学后端、准备搞一个能写进简历的高并发项目或者单纯想从零搭一套直播Demo这篇应该能让你少走不少弯路。1. 一个CRUD选手为什么非要碰直播高并发1.1 直播高并发和普通业务系统差在哪儿我一开始以为直播系统就是“视频流 聊天室”后来一拆解才发现完全不是那么回事。普通业务系统的高并发核心是数据库和接口能不能扛住直播系统的高并发至少有三个完全不同的瓶颈要被同时处理。第一个是流媒体转发压力视频流不是普通请求它是一路长连接持续传输的二进制数据带宽和连接数会同时打高第二个是实时互动压力弹幕、礼物、点赞这类消息要求秒级甚至毫秒级触达不能用普通的HTTP轮询去硬扛第三个是热点数据压力一场直播里的热度榜、在线人数、评论流都是典型的读多写少、瞬间流量冲顶的场景。这三个问题叠加在一起对后端的要求从“能跑”直接跳到了“能并发、能低延迟、能抗热点”。这也是我选这个项目当练手目标的原因——它不是一个假想的并发模型而是每个瓶颈都能通过实际手段验证的完整闭环。1.2 先想清楚这套环境到底要服务谁动手之前我一直提醒自己一个问题别一上来就奔着“百万并发”去那是大厂CDN和边缘计算集群干的事一个后端小白不可能也不应该从那儿起步。我给自己的定义是搭建一套能承载千级并发观看、万级弹幕消息处理的学习级直播环境。这个量级听起来不大但已经足够把后端会遇到的核心问题全部逼出来——连接数管理、消息广播、缓存穿透、数据库连接池耗尽、进程OOM这些不会因为量级小而消失。先在这个规模下把原理吃透以后接触更大的架构才有底气。1.3 我给自己定的验收清单动手前我列了一个目标清单整个项目最终是否成功全部按这个清单验收[ ] 主播端能通过OBS推流观众端能通过网页低延迟观看[ ] 弹幕消息从发送到展示的延迟在1秒以内[ ] 在线人数、热度榜、礼物特效数据能实时准确地展示[ ] 用JMeter模拟并发场景时系统不宕机核心接口不报错[ ] 数据库、Redis、流媒体服务都做了基础的高可用和容灾手段后面每一步决策我都会拿这个清单来对照避免自己陷入“优化一个无关紧要的细节”里出不来。2. 直播架构选型技术栈怎么挑才不翻车2.1 流媒体服务器选型SRS、MediaMTX、Nginx-RTMP怎么选流媒体服务器是整个直播链路的心脏负责接收主播推上来的流再分发出去给所有观众。市面上常见的开源方案有SRS、MediaMTX和Nginx-RTMP模块我做了个简单对比方案协议支持上手难度性能适合场景SRSRTMP、HLS、HTTP-FLV、WebRTC、SRT中高标准直播、直播集群、学习首选MediaMTXRTSP、RTMP、HLS、WebRTC低中安防摄像头流转发、简单直播Nginx-RTMPRTMP、HLS低中小规模直播、个人实验综合对比后我选了SRS。原因有三点第一SRS对流媒体协议支持最全后面我想扩展WebRTC低延迟直播也不用换引擎第二它的配置项和真实生产环境接轨很多公司直接用SRS做源站第三它的日志和调试信息做得比较友好对新手排查问题非常关键。2.2 推流协议和拉流协议的取舍这里要给同样是小白的同学补个基础认知推流协议和拉流协议是两回事。推流端是主播侧的OBS或摄像头常用RTMP协议推上去拉流端是观众侧的网页播放器需要通过HTTP协议拉下来。实际项目中我用了RTMP推流 HTTP-FLV/HLS拉流的组合。拉流协议延迟兼容性适用场景HLS3-10秒极好浏览器原生支持点播、对延迟不敏感的直播HTTP-FLV1-3秒需配合flv.js直播互动、低延迟场景WebRTC毫秒级需服务端和浏览器同时支持连麦、实时互动我最终选择HTTP-FLV作为PC端主拉流协议HLS作为备用和移动端兜底。HTTP-FLV的延迟能控制在2秒左右配合flv.js播放器体验很接近真实直播产品。2.3 后端服务和前端的组合Spring Boot Vue因为我的主语言是Java后端服务用了Spring Boot前端管理后台用Vue 3。这套组合的好处是社区资料极其丰富踩坑时能搜到的解决方案最多。对于学习型项目一个成熟的轮子比一个冷门但“看起来更酷”的轮子重要得多。后端模块划分上我没有做成一个大包而是按职责拆成了几个独立服务liveshow-gateway统一入口负责鉴权和流量转发liveshow-stream对接SRS回调处理上下线通知liveshow-im处理弹幕、礼物等实时消息基于WebSocketliveshow-admin后台管理服务负责直播房间、用户、数据的CRUD虽然模块拆分了但初期我是全部打在同一个工程里跑的。拆分的意义更多是为了让自己养成“服务边界”的意识而不是一上来就被微服务架构累死。2.4 高并发中间件初选Redis、消息队列、负载均衡直播场景里Redis几乎承担了所有“需要极快读写”的工作在线人数统计、热度榜、用户Session、一键禁言等。消息队列我选了RabbitMQ用来做系统内部事件的通知和削峰。负载均衡用Nginx配合多个后端节点做反向代理。有人说Kafka才是大日志量场景的标配但对我这个量级和学习阶段来说RabbitMQ足够用而且Spring Boot对它的集成做得非常傻瓜化。我在项目中给它们的定位是Nginx入口层负载均衡同时处理静态资源请求Redis扛所有高频读写的热点数据RabbitMQ串联非实时的后台任务比如直播结束后的回放生成这个组合跑满我的验收目标没有问题以后真要往更大规模走再替换对应组件也不迟——架构演进本来就是一个持续替代的过程。3. 推流拉流链路搭建直播从推流到播放的完整通路3.1 部署SRS流媒体服务并完成基础配置我用Docker部署SRS这是目前最快的方式。一条命令就能拉起一个SRS实例docker run -d --name srs \ -p 1935:1935 \ -p 8080:8080 \ -p 1985:1985 \ -v /home/ubuntu/srs/conf:/usr/local/srs/conf \ registry.cn-hangzhou.aliyuncs.com/ossrs/srs:5.0但光跑起来没用我需要按自己的需求改配置。SRS的核心配置是srs.conf我精简后的关键配置如下listen 1935; max_connections 1000; daemon off; srs_log_tank console; http_api { enabled on; listen 1985; } http_server { enabled on; listen 8080; dir ./objs/nginx/html; } vhost __defaultVhost__ { hls { enabled on; hls_path ./objs/nginx/html; hls_fragment 2; hls_window 6; } http_remux { enabled on; mount [vhost]/[app]/[stream].flv; } }这里重点说下配置里的几个关键含义。max_connections 1000是SRS的最大连接数限制对学习环境来说已经容纳了足够多的观众连接hls_fragment 2表示每个HLS分片的时长是2秒hls_window 6则决定保留最近多少秒的分片——这两个参数决定了HLS延迟的下限数字越小延迟越低但对服务端切片压力越大。http_remux则开启HTTP-FLV协议的支持这是低延迟拉流的关键。3.2 OBS推流验证本地点播通了才算第一步环境起来以后第一件要做的事永远是用最简单的工具去验证链路是不是通的而不是急着写代码。我打开OBS进入设置里的“直播”页串流地址填rtmp://服务器IP:1935/live/串流密钥填一个自己定义的名字比如mylive。点开始推流后去SRS的控制台看是否出现了一条活跃的流或者直接用FFmpeg读取流信息验证ffprobe rtmp://服务器IP:1935/live/mylive如果这条命令能正常输出视频流和音频流的信息说明推流链路已经打通了。我最初犯过一个低级错误服务器安全组没开1935端口OBS推流一直超时排查了很久才意识到不是SRS的问题而是云服务器的端口策略问题。提示搭这类实验环境时务必先确认云防火墙、ECS安全组都放行了对应端口。1935RTMP、8080HTTP/FLV/HLS、1985API这几个端口缺一不可。3.3 HTTP-FLV与HLS拉流播放衔接前端播放器推流链路通了之后拉流端是所有步骤里最“直观”的一步。我用Vue写了一个简单的直播播放页核心代码如下script srchttps://cdn.jsdelivr.net/npm/flv.js/dist/flv.min.js/script video idvideoElement controls muted autoplay/video script if (flvjs.isSupported()) { var videoElement document.getElementById(videoElement); var flvPlayer flvjs.createPlayer({ type: flv, url: http://服务器IP:8080/live/mylive.flv, isLive: true, hasAudio: false }); flvPlayer.attachMediaElement(videoElement); flvPlayer.load(); flvPlayer.play(); } /script打开页面如果看到画面前2秒内出来说明HTTP-FLV链路正式跑通。HLS的验证更简单直接在浏览器地址栏访问http://服务器IP:8080/live/mylive.m3u8能返回一个m3u8格式的索引文件说明HLS切片也在正常生成。我实测下来同一局域网内HTTP-FLV的延迟在1-2秒左右HLS的延迟在4-6秒左右差距非常明显。前端播放器这里有个坑要提醒flv.js在视频流里如果包含有声音但播放器设置hasAudio: false会导致画面正常但声音卡顿反过来如果设置了hasAudio: true而实际流里又没音频轨会报错。最稳妥的做法是让SRS转码时统一输出或者在播放器里做音频轨检测但学习阶段建议直接统一推流端设置。3.4 源站与边缘节点学习阶段不需要一上来就是CDN做直播架构的时候很容易被“CDN分发”这个词带偏觉得没有CDN就不配叫直播系统。但CDN的本质是解决“地域分散的观众访问源站慢”的问题我学习阶段观众都在同一个小范围网络环境里直接访问源站也能有不错的效果。所以我做了个冷静的选择初期只搭一个SRS源站节点但是把SRS的API回调功能和后端服务打通。这样后面一旦需要扩展到边缘节点回调机制已经就绪不用推翻重来。SRS会在推流开始、推流结束时回调我的后端接口我在后端里通过这个回调维护直播间的上下线状态# SRS回调通知配置 on_publish http://127.0.0.1:8081/srs/callback/publish; on_unpublish http://127.0.0.1:8081/srs/callback/unpublish;后端只需要暴露这两个接口收到SRS的POST请求后更新数据库里对应房间的直播状态即可。这样一个简单的解耦就把流媒体服务和我自己的业务服务连成了一个完整的闭环。4. 高并发弹幕IM直播互动模块的设计4.1 为什么弹幕模块比视频流本身更容易压垮服务做完整条拉流链路后我开始着手弹幕系统。当时低估了它的难度以为WebSocket建立连接后消息丢给前端就行。结果一写才发现弹幕系统的高并发问题比视频流更隐蔽——视频流的分发被SRS接管了而弹幕系统的一切都要后端自己扛。想象一下一场1000人同时观看的直播观众平均每10秒发一条弹幕后端每秒就要处理100条上行消息但每条弹幕都要广播给房间内所有在线用户也就是每秒要下行推送1000 × 100 10万条消息。下行压力远大于上行这就是IM系统的典型特征——读扩散的代价会成倍放大。一开始我比较天真直接在Spring Boot里用ServerEndpoint写了个简单WebSocket用户连接后把Session对象放到内存Map里收到消息后遍历Map把消息发给所有人。单机测试没问题但节点一扩容就暴露了两个致命问题Session不共享和多节点消息不同步。4.2 WebSocket集群会话管理从单机到多节点的坑如果你用普通的ConcurrentHashMap存放WebSocket Session那你的服务一旦开了多个节点后半段用户连的可能就是另一个节点他根本收不到A节点广播的消息。我本能的反应是把Session往Redis里放做完才发现思路是错的。Session对象持有的是本地网络连接引用本质上不能跨进程传输。正确做法是维护一种节点-用户映射关系也就是让消息能找到该用户连接在哪个节点上再由那个节点做真正的推送。我最终的设计是这样的每个WebSocket节点启动时给自身生成一个唯一标识nodeId并注册到Redis用户连接时后端把userId - nodeId的映射写入Redis广播消息时先查询Redis里所有目标用户的nodeId然后通过节点间通信把消息投递到对应节点再由该节点推送早期我为了省事甚至没有引入消息队列而是直接用Redis Pub/Sub做了节点间通信。每个节点订阅一个固定的频道收到消息后检查自己的本地Session Map里有没有目标用户有才推。由于订阅频道是广播的所有节点都能收到同一条消息但只有持有目标Session的节点才真正推送逻辑非常简单。4.3 弹幕广播选型Redis Pub/Sub还是RabbitMQ做了第一版纯Redis Pub/Sub后又发现一个问题Pub/Sub模式是即发即弃的如果某个节点正在GC停顿或者网络抖动消息会直接丢失没有任何补偿机制。弹幕消息丢几条观众感知不强但礼物消息丢一条就是事故。最终我把方案改成了RabbitMQ的广播交换机 每个节点持久队列。Configuration public class RabbitConfig { Bean public FanoutExchange danmakuExchange() { return new FanoutExchange(exchange.danmaku, true, false); } Bean public Queue danmakuQueue() { return new Queue(queue.danmaku. nodeId, true, false, false); } Bean public Binding danmakuBinding() { return BindingBuilder.bind(danmakuQueue()).to(danmakuExchange()); } }每个节点创建队列时队列名都带自己的nodeId这样消息既不会被重复消费每个队列只对应一个节点也不会因为节点重启而丢失消息会持久化在队列里等待恢复。这套改造花了两天但带来的收益是决定性的——我可以在不丢消息的前提下随意上下线节点。4.4 弹幕消息协议设计一个JSON的进化史消息协议看着不起眼但设计得好不好直接影响扩展性。我的第一版消息长这样{user: 张三, content: 你好}上线后立刻发现不够用。用户需要标识头像、等级、是否房管消息还要区分是弹幕、礼物还是进场通知。于是改成这样{ type: DANMAKU, data: { userId: 10001, nickname: 张三, avatar: https://xxx/avatar.png, level: 8, content: 你好, timestamp: 1712876342000 } }所有消息统一包一层type和data后端按type分发前端按type渲染。后来加送礼特效和进场通知时只需要新增type值完全不用动WebSocket通道和广播逻辑。这是我在这个项目里学到的最值得的一个设计经验不一定要做企业级的大设计但一定要给未来的扩展留好后路。5. Redis缓存设计直播场景下的缓存三兄弟5.1 在线人数、热度榜、礼物特效缓存都怎么扛直播间的在线人数是典型的实时数据如果每次都查MySQL数据库很快就被读爆。我用Redis维护每个房间的在线人数# 用户进入直播间 SADD room:10001:online user_10001 EXPIRE room:10001:online 300 # 用户心跳续期 EXPIRE room:10001:online 300 # 获取直播间在线人数 SCARD room:10001:online用Redis的Set结构天然支持去重SCARD取人数是O(1)操作非常高效。通过心跳包5分钟续期用户断线后最多5分钟自动人数就会降下来不需要专门写清理逻辑。热度榜我用的是ZSet有序集合直播间收到的点赞、送礼都会累加分数# 点赞或送礼时累加热度值 ZINCRBY live:rank:20260314 10 live_room_10001 # 获取热度TOP10 ZREVRANGE live:rank:20260314 0 9 WITHSCORESZSet的原子自增在并发场景下不会出现加减错乱而且天然支持按分数排序实现一个榜单几乎不需要额外代码。这个方案后来也应用到了礼物贡献榜、主播周榜等场景一套代码多做复用。5.2 缓存穿透、击穿、雪崩一个直播场景全都遇上了学Redis缓存的时候穿透、击穿、雪崩是理论做直播系统以后我发现三个问题在真实场景里接踵而至。缓存穿透先出现。我给直播间详情接口加了Redis缓存但有些用户会恶意请求不存在的房间号导致请求每次都会打到数据库。解决思路很简单查不到数据的key也缓存一个空值并设置较短的过期时间比如60秒或者用布隆过滤器挡在前面。学习项目我用了空值缓存方案一行代码的事。缓存击穿发生在某个热点直播间突然涌进大量请求时。如果一个热Key正好到了过期时间一瞬间所有请求全部打到数据库能把MySQL直接拖垮。我的解决办法是对热点数据的缓存不设置过期时间而是由后台异步任务定期更新。这样既保证了数据新鲜度又彻底规避了过期瞬间的并发冲击只是实现成本略高。缓存雪崩是最危险的。我早期把所有直播间的数据缓存都设置了相同的过期时间导致一个整点时间点大面积的缓存集体失效数据库压力瞬时飙到历史最高。后来我给缓存时间加了随机值int expire baseExpire new Random().nextInt(300);这样过期时间分布在某个区间内不会再出现“整点集体暴毙”的情况。5.3 热Key问题大主播房间的缓存怎么顶住直播间热度不均某些头部直播间能占到全站80%的流量它的缓存Key就是传说中的“热Key”。单机Redis处理能力有限一个热Key的请求量就能打满单核CPU。我排查时发现直播间的热度排行每次都要ZREVRANGE取前十某个大主播的房间一个人就贡献了排行接口一半的QPS。解决方法是把这个Top10的榜单结果缓存成一个单独的Key而不是每次实时查ZSet// 排行榜缓存每10秒刷新一次 String rankKey live:rank:top10:cache; String cachedRank redisTemplate.opsForValue().get(rankKey); if (cachedRank null) { // 查ZSet计算Top10 SetZSetOperations.TypedTupleString top10 ...; redisTemplate.opsForValue().set(rankKey, JSON.toJSONString(top10), 10, TimeUnit.SECONDS); }从这里我还总结出一个经验凡是读多写少、且对数据新鲜度容忍度较高的场景都可以用定时刷新缓存的方式扛量这是应对热Key最直接的手段。提示Redis的单线程模型决定了它处理单个Key时存在性能上限。当发现单个Key的访问频率明显高于其他Key时不要急着换硬件先想能不能“缓存前再多套一层缓存”或者让这个Key的访问分散到多个节点上。6. 全链路压测JMeter打出来的瓶颈和排查过程6.1 压测方案设计并发数、场景、指标怎么定所有功能开发完成后进入最刺激也最有价值的环节——压测。我用JMeter模拟观众行为设计了三个压测场景场景模拟行为并发线程数持续时间场景一观众进入直播间、查询详情3005分钟场景二在线用户发弹幕2005分钟场景三综合场景进房发弹幕点赞50010分钟我特别关注三个指标接口错误率、响应时间TP95、系统资源使用率。错误率必须在0.1%以内TP95响应时间不能超过500毫秒CPU平均使用率不能长期超过80%。这些指标不是拍脑袋定的而是基于“观众端感知”倒推出来的。压测用的JMeter脚本重点配置了两个部分HTTP请求采样器用来打直播详情接口WebSocket Sampler插件用来模拟弹幕发送。WebSocket Sampler需要先建立连接再循环发送消息结束时关闭连接。6.2 第一轮压测数据库连接池被打爆第一轮压测几乎是秒败。JMeter线程数刚爬到200后端日志就开始刷连接池超时报错。排查链路是这样的我先看后端日志错误集中在数据库连接获取失败然后看监控面板MySQL的连接数瞬间飙到500多HikariCP默认最大连接数是20完全不够用再查慢查询日志发现最慢的是“查询直播间详情”的SQL——它联了房间表、主播表、标签表加上频繁的COUNT(*)统计每条SQL要20毫秒以上并发一起来连接就被占满了。这一轮的根本原因有两个层面第一是SQL确实太烂联表查询和统计查询完全没有拆分第二是连接池配置太小最大连接数只有20。我当时做的优化spring: datasource: hikari: maximum-pool-size: 100 minimum-idle: 20 connection-timeout: 30000但这只是治标。真正的治本是把高频查询改成走Redis缓存只有缓存未命中才查数据库数据库连接压力才能从根源上降下来。这个阶段的教训是先优化代码再提升配置顺序不能反。6.3 第二轮压测WebSocket服务OOM排查解决数据库问题后弹幕压测一开始WebSocket服务就出现OOM。这次排查过程比第一次更烧脑。我先用jstat查看JVM堆内存发现GC非常频繁但每次只能回收很少的空间接着用jmap导出堆转储用MAT分析大对象发现线上存在成千上万个Session对象。真相浮出水面——客户端断线后WebSocket的onClose回调没有及时触发导致Session一直留在内存Map里连接泄漏了。为什么onClose不触发我用netstat一查发现大量端口处于CLOSE_WAIT状态。这说明是客户端主动断开了连接但服务端没有正确关闭Socket。查了Spring WebSocket的源码后确认问题不在框架而在于我写的业务代码阻塞了会话销毁流程。某个消息处理器里发了个同步HTTP请求请求超时要等30秒这期间Session一直悬挂不释放。修复方法一是把阻塞操作异步化不占用WebSocket事件循环线程二是在onClose里强制清理本地Session Map并在Redis里删除节点映射三是设置空闲超时让心跳检测能及时回收僵尸连接。registry.addHandler(chatHandler, /ws/chat) .addInterceptors(new AuthHandshakeInterceptor()) .setAllowedOrigins(*) .withSockJS() .setHeartbeatTime(25_000);这个OOM问题整整花了我一个晚上排查但收获巨大。从那以后我养成了一个习惯每个网络连接相关的新代码都会用netstat看一遍连接状态分布只要CLOSE_WAIT多起来一定是有泄漏。6.4 第三轮压测Redis热Key导致的请求堆积第二轮修完后第三轮综合场景压测坚持得更久但Redis开始预警了。监控面板显示某个分片的CPU使用率冲到95%响应时间从正常的1毫秒涨到30毫秒后端服务的Redis操作大量排队。用redis-cli --hotkeys分析后锁定了凶手直播间在线实时人数排行榜的那个ZSet Key。我当时的榜单业务逻辑是每次有用户点赞就ZINCRBY每次有人进入直播间就重新计算整个榜单导致这个Key被高频写入。加上查询端每次也实时查全量榜单单Key压力被放大。我的修复方案是把热Key拆成多级队列点赞消息先写入RabbitMQ队列由消费者异步合并后再批量写入Redis把写频率降低了90%。查询端则直接用之前提到的定时刷新缓存每10秒算一次Top10从“每次实时聚合”改成“读预计算结果”。这里最核心的转变是不要太相信Redis的单机性能再快也扛不住无限次的无效读写先减少不必要的读写次数比提升集群规格更重要。6.5 压测结论这套环境最终扛住了什么三轮优化下来最终的压测结果让我挺满意的压测场景并发数错误率TP95响应时间系统状态直播详情查询5000%85msCPU 60%弹幕消息发送3000%45ms上行CPU 72%综合场景8000.05%150msCPU 80%虽然和真正的生产级直播系统还有不小差距但对我这个后端小白来说这套环境已经能稳定扛住近千级别的并发观看和互动达成了开头定下的验收目标。整个过程让我真正理解了一个道理压测不是用来证明系统有多强而是用来逼出系统在哪一层最弱然后把这个短板补上。7. 手搓这套环境后我的几个实在建议7.1 先跑通再优化别一上来就追求完美架构回头看这个项目我最后悔的时刻不是踩坑而是中间有一段时间总想着一口气把架构设计得非常完美消息中间件、分布式事务、数据分片、多级缓存恨不得全部上。结果一边写一边推翻进度几乎停滞。后来我换了个思路先把最简陋但完整的一条链路跑通——OBS推流、SRS转发、浏览器播放、最简单的WebSocket弹幕然后再基于实际出现的问题一层层加方案。这个从“能跑”到“跑得稳”的过程反而让我对每一项优化都理解得更深。如果你也是新手强烈建议走这条路先做完再做好。7.2 日志、监控和告警一定要从一开始就埋点压测期间最痛苦的事情之一是出了故障只能靠猜。应用里没打关键日志、连接池状态不知道、Redis慢查询没有记录导致排查问题只能靠翻代码一点点对。后面我补了一套轻量级的监控应用日志统一用Logback输出到文件按天滚动通过Spring Boot Actuator暴露/actuator/metrics接口采集JVM、线程池、连接池指标对关键业务指标在线人数、消息量做了定时统计写入日志和Redis有了这些基础数据后后面每次压测我都能用数据说话而不是凭第六感猜。这点越早做吃亏越少。7.3 给其他后端小白的建议这套项目怎么复现如果你也想手搓一套类似的直播环境我建议按这个顺序推进第一周搞定SRS部署和推拉流链路第二周把弹幕WebSocket做通第三周加Redis缓存和RabbitMQ广播第四周集中做JMeter压测和问题修复。中间遇到任何问题优先看官方文档和源码其次再搜社区方案大多数情况下你能搜到前人踩过的同款坑。项目和技术栈不是目的真正值钱的是你在处理这些故障的过程中建立的“排查直觉”——那种一看到错误日志就能自动联想起底层机制的能力。这种能力没办法靠刷题获得只能靠亲自动手搭一套真正的系统跑起来然后弄挂它再救活它。
返回列表