用户名唯一性验证 - 设计方法

时间:2012-06-23 05:43:03

标签: algorithm hash

这是一般设计问题 - 我想在用户输入值并标签输出时验证用户名字段的唯一性。我进行Ajax验证并从服务器获得响应。这都非常标准。现在,如果我有一个巨大的用户数据库怎么办?如何处理这种情况?我想知道在150万个用户名中是否存在用户名“foozbarz”?

  1. 数据库查询是不可能的[编辑] - 读取用户名数据库一次并填充缓存/哈希以便更快地查找(以澄清EmilVikström的观点)
  2. 在内存数据库中也不会有任何帮助
  3. 保留内存中的哈希(或缓存/内存缓存)以存储所有用户名 - 用户名可以轻松进行哈希处理,查找速度非常快。但是这有一些问题:  一个。哈希的大小 - 我们可以优化,以便我们可以减少哈希大小?  湾散列/缓存刷新频率(用户可能会在我们验证时​​添加)
  4. 根据某些条件对用户名表进行分片(例如:表username_1中的A-B等等) - 感谢piotrek 以获取此建议
  5. 或者,还有其他更好的方法吗?

5 个答案:

答案 0 :(得分:2)

为什么不简单地对数据进行分区?如果你有/计划拥有150M +用户,我认为你已经/将有预算。如果您刚刚开始(使用2k用户),请使用简单的数据库索引搜索方式。如果您有这么多用户观察性能问题而衡量这是因为您的数据库(而不是例如www服务器),那么您只需添加另一个数据库。在第一个上,您将拥有名称从a到m的用户,并在另一个上休息。您可以选择其他标准,如哈希,以使数据平衡。当您需要更多时,您将添加更多数据库。但如果你现在没有这么多用户,我建议你不要做任何过早的优化。有很多事情可能成为这一数据量的瓶颈

答案 1 :(得分:1)

你最有可能在存储所采用的名称时进行某种散列,显然,不散列意味着它是免费的。

您不应该做的是依靠该验证。如果名称是免费的,用户按下注册和用户检查之间可能会有很多时间。

公平地说,这里只有一个问题,你是否真的需要担心你是否会获得1.5亿用户。可伸缩性通常是一个问题,但除非这种情况发生在一夜之间,否则在发生这种情况之前,您可能会交换更好的解决方案。

其次,您担心这两个用户获得此名称是免费的,然后一个人接受它。首先,发生这种情况的可能性非常低。其次,我可以想到以一种方式“解决”这个问题的唯一方法,即用户永远不会点击确认并使用经过验证的名称并获得USERNAME TAKEN a)记住用户最后验证的内容,存储该内容,以及如果其他人同时注册该内容,请使用AJAX更改要采用的名称字段并通知用户。不要这样做。许多浪费的周期和实施太多的努力。 b)锁定用户名作为用户在短时间内验证一个用户名。这导致很多免费用户名在实际上没有时就会出现。你可能也不想要这个。

最简单的解决方案是在用户实际单击“确定”时简单地将哈希值放入表中,但在此之前,请检查名称是否再次存在。如果是这样,只需用USERNAME TAKEN发回用户。有人为别人争取名字的可能性非常非常小,我怀疑任何人都会对你的验证员(做了它的工作,这个名字在检查时是免费的)如何对用户“撒谎”大惊小怪

基本上,您唯一的问题是如何存储昵称。

答案 2 :(得分:1)

您的#1标准存在缺陷,因为这正是您拥有的数据库系统:存储和管理数据。如果你不打算阅读它,为什么你甚至有一个带有用户名的表呢?

首先要做的是通过添加索引来改进数据库系统,如果您的数据库系统支持索引,最好是HASH索引。你将很难在自己的表现附近写任何东西。

如果这还不够,则必须开始扩展数据库,例如通过构建集群数据库或将表分区为多个子表。

我认为公平的做法是在数据库前实现缓存,但对于单个名称。并非所有用户名都会发生冲突尝试,因此您可以缓存通常发生冲突的小子集。用于检查USER的碰撞状态的简单算法:

  1. 检查缓存中是否存在USER。如果是这样的话:
    1. 为缓存中的USER设置“上次检查”时间戳
    2. 你已经完成并且USER是一个碰撞
  2. 检查数据库中的USER。如果确实存在:
    1. 将USER添加到缓存
    2. 如果缓存已满(使用了所有X个插槽),请从缓存中删除最近最少使用的用户名(如果要最小化缓存修剪,则删除最近最少使用的用户名)。
    3. 你已经完成并且USER是一个碰撞
  3. 如果它与缓存或数据库不匹配,则表示已完成且USER不是冲突。
  4. 当然,您仍需要在数据库中使用UNIQUE约束来避免竞争条件。

答案 3 :(得分:0)

如果您要使用传统路由,则可以使用适当的索引来改进数据库查找。

你也可以尝试使用像ElasticSearch这样的东西,它对大型数据集进行非常低的延迟查找。

答案 4 :(得分:0)

如果您有150M +用户,则必须具备以下功能:

  1. 检查用户是否存在,如果找不到则发出信号
  2. 验证密码是否正确,如果密码不正确则发出信号
  3. 检索用户的数据
  4. 你将遇到这个问题,并且必须解决它。很可能与某个用户的查询相似。即使你非常依赖会话,你仍然会遇到“从150M +池中找到许多会话X”的问题,这在结构上与“从150M +池中找到许多用户X”相同。

    一旦你解决了更大的问题,你现在遇到的问题只是步骤#1。

    因此,我将查看可扩展的数据库解决方案(可能是NoSQL解决方案),并使用该解决方案实现“可用性检查”。

    您可能会以

    结尾
    retrieveUserData(user, password = None)
    

    如果用户和密码有效且正确,则返回用户信息。对于可用性检查,您将不发送密码,并且如果用户名可用,则会出现UserNotFound异常。