存储大量会话的最有效数据结构是什么?



对于每个客户端,服务器为该特定客户端创建一个会话。会议的到期时间为1天。因此,这将最终以多达十亿的会议。

假设我使用哈希地图,然后在客户端与服务器通信时查找会很快。但是,我需要删除那些过期的会议,例如每小时一次。在擦除过程中,由于数量巨大,可能需要一些时间,这将导致服务器无法处理客户端的通信。

那么,有什么高性能解决方案吗?即,我不想锁定擦除过期的地图。

使用数据结构可能太简单了,如果您的会话数量很高,则需要稍有不同的方法。

查看将会话数据存储在Redis或其他键值存储中。对于高负载的服务器,这将更加正常。Redis和其他大多数人都会持续存在,如果您需要在后台清理问题,则不会锁定问题。

我认为地图实际上不是最好的收藏。考虑到您所说的话,我会选择一套(如果您不需要订单,则无序)。由于您永远不会有与相同的会话的两次,它们都会有所不同,而且您真的不需要地图提供的关联,否则我不正确理解您的问题。

简单解决方案:使用哈希表。当您搜索一个存储桶以寻找条目时,请删除您遇到的任何过期的会话。这几乎是免费的,因为无论如何您都在搜索链条。它不能保证会话会在有效期后立即删除,但是很可能在不久之后将搜索包含过期会话的链。

您应该将标准列表为固定数量的存储桶,代表您期望成为服务器的容量。这避免了重新进行的需要,这意味着每个铲斗链都可以独立锁定。但是,您不需要每个链条的锁;您可以将同一锁用于几个(甚至许多)链。选择许多锁足以使您的预期锁定争议在峰值请求压力下会很低;您可以根据所拥有的同时活动处理程序的数量来计算一个好数。如果链条居住在内存,链条搜索将花费很少的时间,因此在上下文切换之前,它几乎总是完成。因此,"同时活跃"是指它们实际上被映射到CPU并运行,而不仅仅是映射到内核过程。因此,即使是一小部分锁,您也应该能够将桶链的争论降低到非常低的水平。

处理此操作的一种方法是创建哈希地图以保存会话,以及一个MRU(最近使用的)列表。MRU列表被实现为双关联列表。每当用户访问网站时,他的会话都会回到MRU列表的顶部。另外,每当创建会话时,系统都会检查MRU列表中的最后一项,以查看最旧的会话是否已过期,以便您可以删除它。

或者,您可以在列表末尾删除所有过期的会话。

此外,如果尚未删除查找代码,则需要将查找代码删除。

所以,当您收到请求时,事件的顺序看起来像这样:

session = get session info from user token
if no session
    create session
    add to front of MRU list
else if session has expired
    delete from mru list
    remove from hash map
else // session has not expired
    move session to front of MRU list
end
// delete expired sessions
p = last item in MRU list
while p has expired
    prev = p->prev
    remove from MRU list
    delete from hash map
    p = prev
end

如果您担心清理过期的会话会锁定您的哈希地图太长,请限制您一次删除的过期会话数量。如果将其设置为仅清理两个过期的会话,则在添加新会话时,您将最大程度地减少数据结构的锁定时间,而过期的会话不会持续太长。

最新更新