您的位置:首页 > 数据库 > Redis

基于Redis有序集合的终端在线推送解决方案

2015-11-28 00:13 555 查看

问题背景

在我们的系统中,系统管理员关注所有终端的在线状态。因此,管理系统需要列出每个终端当前是否在线,最后心跳(在线)时间,以及当前系统中所有在线、离线终端数量。

这是一个常见的需求。常见的方案是,终端定时给服务端发送心跳信息(例如每隔1分钟发一次心跳信息),服务端在数据库中维护一张终端在线状态表(t_client_status),该表包含终端(mid)、最后心跳时间(last_time)等信息。当管理员需要查看终端在线状态时,后台进程查询t_client_status表给出结果。

在终端数量较少(低于10K)时,以上提到的方案是可以满足功能需求和性能需求的。然而,当终端数量较大时,由于服务端需要频繁刷新t_client_status的last_time字段,产生大量的磁盘IO操作,导致系统性能下降,影响系统的并发数,甚至可能导致数据库崩溃。

因此,我们需要考虑更加有效的方案处理终端在线状态。

解决思路

传统的解决方案中,导致磁盘IO过多的原因,在于采用了全量更新的方式。对于每次终端上报的心跳信息,都去刷新数据库。因此,我们希望能增量地去完成刷新。我们的解决方案中,主要考虑如何完成增量刷新。

最后,我们发现,Redis的有序集合可以实现增量刷新的效果。

有序集合时Redis提供的一种集合类型的数据结构。和普通集合不同的是,有序集合中不仅保存元素,同时还保存元素的分数,并按照从顺序排列。有序集合可以用在积分榜等场景中。

Redis的有序集合提供了如下命令:

zadd

zcount

zrangebyscore

zmembers



实现细节

1.添加心跳信息

zadd("heartbeats", nowtime+heartbeat_interval, mid)


2.查询在线总量

zcount("heartbeats", nowtime, "+inf")


3.增量刷新在线状态

//1. get offline clients
offline_list = zrangebyscore("heartbeats", "-inf", nowtime)

//2. get online clients
ret = zadd("heartbeats", nowtime+heartbeat_interval, mid)
if ret == 1 then
online_list += mid

//3. update offline_list && online_list to db
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: