直播间实时在线人数方案

在路演项目的上线阶段,遇到了直播间实时在线人数的挑战。首先考虑使用阿里在线人数接口,但由于5min延迟问题,该方案被排除。最终选择了通过WebSocket实现实时更新,在用户加入或离开时向所有用户广播当前在线人数。另外,还提及了一种心跳机制的方案,利用Redis维护在线状态,但因未申请Redis资源未实际验证。欢迎分享更多解决方案。

最近路演项目已经到了上线阶段,现在来梳理下路演开发中所遇到的问题。

  1. 首先是直播间实时在线人数问题

  1. 当时的考虑是用阿里的在线人数接口,然后通过解析阿里的数据获得当前房间里的在线人数。由于阿里的数据有5min的延迟,导致用户刚进入直播间,头像已经显示了,但是阿里给返回的人数为0,故将此方案排除。

  1. 最后确定的方案是通过websocket去实现实时在线人数,代码如下:

@Component
@Slf4j
@ServerEndpoint(value = "/websocket/{channelId}")
public class WebsocketService {
    
    //记录当前连接,每个客户端都有对应的session,服务器端通过它向客户端发送消息
    private Session session;
    private String channelId;
    //concurrent包的线程安全Set,用来存放每个客户端对应的MyWebSocket对象。
    private static final Map<Session,String> map = new ConcurrentHashMap<>();
    
    /**
     * @description  有新的链接建立成功时调用该方法
     * @param session
     * @return void
     **/
    @OnOpen
    public void open(Session session, @PathParam(value="channelId")String channelId) throws IOException {
        List<String> list = new ArrayList<>();
        this.session = session;
        map.put(session,channelId);
        for (String str : map.values()){
            if(channelId.equals(str)){
                list.add(channelId);
            }
        }
        sendMessage(channelId,list.size());
        log.info("当前在线用户:" + map.size());
    }


    @OnClose
    public void onClose(Session session) throws IOException {
        this.session = session;
        String channelId = map.get(session);
        int count = subOnlineNum(session);

        sendMessage(channelId,count);
        log.info("当前在线用户:" + count);
    }

    public void sendMessage(String channelId,int count) throws IOException {

        List<Session> sessions = new ArrayList<>();
        for(Session key: map.keySet()){
            if(map.get(key).equals(channelId)){
                sessions.add(key);
            }
        }
        for (Session session : sessions){
            session.getBasicRemote().sendText(String.valueOf(count));
        }
    }

    /**
     * @description  在线数减1
     * @param
     * @return void
     **/
    public static synchronized int  subOnlineNum(Session session){
        String channelId = map.get(session);
        List<String> list = new ArrayList<>();

        for (String str : map.values()){
            if(channelId.equals(str)){
                list.add(channelId);
            }
        }
        map.remove(session);
        return list.size()-1;
    }

当不同的房间号有链接进来,就向当前所在房间的所有用户发送当前的在线人数,已解决实时在线人数问题。

  1. 还有一种方案是咨询做过直播的前辈,他给的方案使用心跳机制去解决实时在线人数,因为当时项目没有申请redis资源,所以这种方案没没经过验算,故只提供个思路。

  • 创建完直播间,直接写一个redis 的key .用set 去维护,每个直播间单独一个key

  • 如果直播间 关播 直接把key 清了就结束了,但是web 端维不了退房的操作。这里可能需要把key 设计成 hash。

  • 里面放心跳时间。 k:uid v:heartTime,服务器邀请定时把没有心跳的用户清出去。

  • hash 里面用户在,切心跳正常 说明还在看直播,如果定时任务清理的话 ,只需要判断,用户在hash 里面就行

如果还有其它方案的话,可以留言大家进行沟通。

<think>好的,用户的问题是关于如何使用SQL查询直播间历史最高在线人数或峰值在线人数。我需要先理解这个问题,然后逐步构建解决方案。 首先,用户的需求是找到某个直播间在历史中的最大在线人数。这通常涉及到记录用户直播间的进入和离开时间的数据。常见的数据表结构可能包含用户ID、直播间ID、进入时间和离开时间等字段。 接下来,我需要考虑如何从这些时间数据中计算出每个时间点的在线人数。一个常用的方法是使用时间轴上的每个进入和离开事件,将进入记为+1,离开记为-1,然后按时间顺序累加这些值,得到每个时刻的在线人数。不过,在SQL中直接处理时间点可能比较复杂,特别是当数据量大的时候。 另一个思路是将进入时间和离开时间分别处理。比如,生成两个事件:用户进入时增加在线人数,离开时减少。然后按时间排序这些事件,逐步累加计算当前在线人数。这种方法可以通过联合查询将进入和离开事件合并,然后使用窗口函数进行累加。 例如,可以创建一个临时表,将进入和离开时间作为两个事件,进入事件类型为+1,离开为-1。然后按时间排序,计算累计和,这样每个时间点的累计值就是当时的在线人数。最大值即为峰值。 需要注意的是,离开时间可能需要处理NULL值,比如用户还在线时离开时间为空。这时候可能需要用当前时间作为默认值,或者根据业务逻辑处理。比如,如果用户还在直播间,离开时间可能未被记录,此时可能需要使用当前时间或直播结束时间作为替代。 另外,如果数据是按会话存储的,每个会话有开始和结束时间,那么可以使用时间范围的重叠来计算同时在线的人数。但这种方法在SQL中处理起来可能比较困难,尤其是计算每个时间点的在线人数。因此,事件展开的方法可能更可行。 还需要考虑性能问题,特别是当数据量很大时,使用窗口函数可能会导致性能下降。这时候可能需要优化查询,比如添加索引,或者分批次处理数据。 总结步骤: 1. 确定数据表结构,确保包含用户进入和离开的时间。 2. 生成进入和离开事件,标记为+1和-1。 3. 合并事件并按时间排序。 4. 计算累计和,得到每个时间点的在线人数。 5. 找出最大值作为峰值。 可能还需要考虑时间排序时的冲突,比如同一时间点既有进入也有离开,这时候需要确定事件处理的顺序,比如先处理进入事件再处理离开事件,以确保准确性。 最后,编写SQL查询时,使用通用语法,并考虑不同数据库系统的兼容性,比如使用CTE(公共表表达式)或者窗口函数。</think>要使用SQL查询直播间的历史最高在线人数,需要分析用户进入和离开时间数据。假设存在用户观看记录表`live_sessions`,包含字段`user_id`, `live_id`, `enter_time`, `leave_time`,可通过以下步骤实现: ### 步骤说明 1. **数据准备** 将用户进入和离开行为转化为两类事件: - **进入事件**:`enter_time`时人数+1 - **离开事件**:`leave_time`时人数-1 注意:若用户尚未离开,`leave_time`需替换为当前时间或直播结束时间[^1] 2. **事件合并计算** 通过联合查询生成事件序列,并按时间排序: ```sql WITH events AS ( SELECT live_id, enter_time AS event_time, 1 AS change FROM live_sessions UNION ALL SELECT live_id, leave_time AS event_time, -1 AS change FROM live_sessions WHERE leave_time IS NOT NULL ) ``` 3. **累计在线人数** 使用窗口函数计算实时在线人数: ```sql SELECT live_id, event_time, SUM(change) OVER (PARTITION BY live_id ORDER BY event_time) AS current_users FROM events ``` 4. **提取峰值** 最终查询取最大值: ```sql SELECT live_id, MAX(current_users) AS max_online_users FROM ( -- 上述累计计算子查询 ) AS tmp GROUP BY live_id ``` ### 完整示例 ```sql WITH events AS ( SELECT live_id, enter_time AS event_time, 1 AS change FROM live_sessions UNION ALL SELECT live_id, leave_time, -1 FROM live_sessions WHERE leave_time IS NOT NULL ), online_counts AS ( SELECT live_id, event_time, SUM(change) OVER (PARTITION BY live_id ORDER BY event_time) AS concurrent_users FROM events ) SELECT live_id, MAX(concurrent_users) AS peak_online_users FROM online_counts GROUP BY live_id; ```
评论 1
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值