【问题标题】:How to store unique visits in Redis如何在 Redis 中存储唯一访问
【发布时间】:2020-09-22 18:21:35
【问题描述】:

我想知道有多少人访问了每个博客页面。为此,我在博客表 (MS SQL DB) 中有一个列来保持总访问次数。但我也希望这些访问尽可能独特。 所以我在Redis缓存中保留了用户的唯一Id和博客Id,每次用户访问一个页面,我都会检查她之前是否访问过这个页面,如果没有,我会增加总访问次数。

我的问题是,存储此类数据的最佳方式是什么? 目前,我创建了一个类似“project-visit-{blogId}-{userId}”的密钥并使用 StringSetAsync 和 StringGetAsync。但是不知道这个方法是否有效。

有什么想法吗?

【问题讨论】:

  • 您考虑过使用 cookie 吗?您可能可以使用它来引用缓存中的数据。
  • 不,用户可能会清除她的缓存并访问一个页面一百次。

标签: redis stackexchange.redis


【解决方案1】:

如果您可以牺牲一些精度,HyperLogLog (HLL) 概率数据结构是计算唯一访问次数的绝佳解决方案,因为:

  • 它只使用 12K 内存,而且这些内存是固定的 - 它们不会随着唯一访问次数的增加而增长
  • 您无需存储用户数据,让您的服务更加注重隐私

HyperLogLog 算法确实很聪明,但是你不需要了解它的内部工作原理就可以使用它,几年前 Redis 将它添加为一种数据结构。因此,作为用户,您只需要知道使用 HyperLogLogs,您可以在 12K 的固定内存空间中统计唯一元素(访问),误差幅度为 0.81%

假设您想记录每天的唯一访问次数;您必须每天拥有一个 HyperLogLog,命名为 cnt:page-name:20200917,并且每次用户访问页面时,您都会将它们添加到 HLL:

> PFADD cnt:page-name:20200917 {userID}

如果您多次添加同一个用户,他们仍然只会被计算一次。 要获得您运行的计数:

> PFCOUNT cnt:page-name:20200917

您可以通过为不同的时间间隔设置不同的 HLL 来更改唯一用户的粒度,例如 2020 年 9 月的 cnt:page-name:202009

这个快速解释器很好地说明了它:https://www.youtube.com/watch?v=UAL2dxl1fsE

这篇博文也可能有帮助:https://redislabs.com/redis-best-practices/counting/hyperloglog/

如果您对内部实现感到好奇,Antirez 的发布帖子非常适合阅读:http://antirez.com/news/75

注意:请注意,使用此解决方案您会丢失访问该页面的用户信息,您只有计数

【讨论】:

  • 它有内存限制吗?我可以为一个页面创建一个日志来记录该页面的所有访问量,无论时间如何?
  • 饱和 HLL 的元素数量是有限的,但它非常高,远高于地球上的人类数量,所以你应该没问题。 :) 是的,如果您不需要任何粒度,您可以为页面使用单个 HLL,它会显示自创建以来的唯一访问次数(HLL)。
【解决方案2】:

您的解决方案不是原子的,除非您将 get 和 set 操作包装在事务或 Lua 脚本中。

更好的解决方案是将project-visit-{blogId}-{userId} 保存到Redis 集中。当您访问时,请致电SADD 将项目添加到集合中。仅当用户之前没有访问过此页面时,Redis 才会将新项目添加到集合中。如果要获取总数,只需调用SCARD 即可获取集合的大小。

【讨论】:

    【解决方案3】:

    无论后端技术(编程语言等)如何,您都可以使用 Redis 流。它是 Redis 5 中的一项非常新的功能,允许您为在 Redis 中创建的主题(流)定义发布者和订阅者。然后,在每次用户访问中,您向该流提交一条新记录(当然,异步)。您可以在该记录中保存您想要的任何信息(用户 ip、id 等)。

    为每次唯一访问定义一个键根本不是一个好主意,因为:

    • Redis GC 的日子不好过
    • 性能(比较用例)无法与 Stream 相比,尤其是当您将该 redis 实例用于其他目的时
    • 不断收集这些独特的访问并对其进行处理效率不高。您必须始终扫描所有键

    结论: 如果您想使用 Redis,请使用 Redis Stream。如果可以更改 Redis,请务必使用 Kafka(或类似技术)。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2017-02-23
      • 1970-01-01
      • 2021-08-26
      • 2012-10-08
      • 1970-01-01
      • 2017-12-28
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多