当前位置:首页 > 问答 > 正文

用Redis怎么快速搞定网站PV统计,性能又杠杠的那种

想用Redis快速搞定网站PV统计,而且要求性能贼高,这事儿Redis确实是不二之选,它的所有数据都在内存里,读写速度是微秒级别的,比去硬盘里翻数据的传统数据库快了几个数量级,下面我就说几种最常用、最有效的法子。

核心思路:利用Redis的高性能数据结构

别把Redis当成一个简单的键值对仓库,它提供的几种数据结构才是解决统计问题的法宝,针对PV统计,我们主要用以下两种:

  1. 字符串(String)和 INCR 命令
  2. 哈希(Hash)

简单粗暴的全局PV统计

如果你的需求只是想知道整个网站被访问了多少次,那这个方法是速度最快的,没有之一。

  • 怎么做: 在Redis里设置一个键,比如叫 global_page_views,每次有用户访问网站,就在后端代码里执行一条 Redis 命令:INCR global_page_views

  • 为啥快? INCR 这个命令是原子性的,原子性的意思就是说,就算同一时刻有成千上万个用户同时触发这个操作,Redis也会排着队一个一个地给这个值加1,绝对不会出现漏加或者重复加的情况,这就像只有一个售票窗口,大家必须排队买票,票号是绝对不会乱的,这个操作简单到极致,所以速度也快到了极致。

  • 优点:

    • 极其简单,一行命令搞定。
    • 性能最高,几乎不会成为系统瓶颈。
  • 缺点:

    太简单了,只能统计一个总的数字,没法按天、按页面细分。


按天统计PV(推荐)

这是最实用的方法,既能看每天的访问量,又能看总的访问量,而且性能依然非常棒。

  • 怎么做: 我们不再用一个固定的键,而是设计一个会变的键名,把日期信息放进去,比如键名可以设计成 page_views:2024-06-07,这样,每天的访问数据都存在一个独立的键里。 每次访问时,后端代码获取当前日期,动态拼出键名,然后执行 INCR page_views:2024-06-07

  • 进阶用法: 如果想顺便把总PV也统计了,可以结合方法一,同时执行两条命令: INCR page_views:2024-06-07 INCR global_page_views 虽然执行了两条命令,但因为Redis是单线程的,这两个操作依然是先后顺序执行,保证了数据的准确性。

    用Redis怎么快速搞定网站PV统计,性能又杠杠的那种

  • 优点:

    • 可以按天查看数据,非常实用。
    • 通过查询多个日期的键并把值加起来,就能轻松计算周、月、年的PV。
    • 性能依然很高。
  • 需要注意的小问题: 如果网站日PV量巨大,比如上亿,那么每天都会生成一个新的键,这些键默认会一直留在内存里,为了节省空间,可以设置过期时间,比如每个日期的键在35天后自动删除(EXPIRE key 3024000),这样既保留了最近一个月的数据,又能自动清理旧数据。


更精细化的统计(比如按页面+按天)

有时候我们不光想知道全站的情况,还想知道某个特定页面(比如一篇爆款文章)每天的访问量。

  • 怎么做: 这时可以用Redis的哈希(Hash)结构,我们可以设计一个哈希,它的键名是日期,daily_stats:2024-06-07,在这个哈希里面,我们用页面的URL作为字段(field),用访问次数作为值(value)。 用户访问了 /article/123 这个页面,我们就执行命令: HINCRBY daily_stats:2024-06-07 /article/123 1 这个命令的意思是,在 2024-06-07 这个哈希里,给 /article/123 这个字段的值增加1。

  • 为啥用哈希?

    • 非常节省内存:如果按方法二,为每个页面每天创建一个键(如 pv:2024-06-07:/article/123),当页面很多时,会产生海量的键,管理起来麻烦,也会消耗更多内存,而哈希结构把同一天的所有页面数据都打包在了一个键里,键的数量大大减少,更紧凑。
    • 查询方便:可以很方便地获取某一天所有页面的访问情况(HGETALL daily_stats:2024-06-07),或者只获取某个特定页面的访问量(HGET daily_stats:2024-06-07 /article/123)。
  • 优点:

    用Redis怎么快速搞定网站PV统计,性能又杠杠的那种

    • 统计维度更精细,可以分析单个页面的流量。
    • 数据结构更优,比用大量字符串键更节省资源。
  • 缺点:

    当某一天的热门页面极多时,这个哈希可能会变得很大,不过对于绝大多数网站来说,这都不是问题。


性能保障的关键技巧

光有方法还不够,要想“性能杠杠的”,还得注意以下几点:

  1. 使用管道(Pipeline):如果在一个请求处理逻辑中,需要执行多条Redis命令(比如同时更新总PV和日PV),应该使用管道技术,管道能将多个命令打包,一次性地发送给Redis,并一次性读回所有响应,这极大地减少了网络往返的时间开销,是提升性能的大杀器。

  2. 定时持久化,而不是实时持久化:Redis的数据在内存里,如果服务器断电,数据会丢失,但对于PV统计这种允许少量丢失的数据(少统计几次PV天塌不下来),我们完全可以配置Redis以较低频率(比如每分钟)将数据快照保存到硬盘一次(RDB持久化),这样就在性能和数据安全性之间取得了很好的平衡,千万不要每增加一次PV就写一次硬盘,那样速度就慢下来了。

  3. 异步写入:在Web应用的后端代码中,执行Redis增加PV的操作,不应该阻塞主要的页面渲染逻辑,最好的做法是把这个操作扔到一个消息队列里,或者用一个异步任务去执行,让用户先看到页面,统计的事情后台慢慢处理,这样用户就完全感觉不到统计带来的延迟。

  • 只要总数:用 INCR 一个键,最快。
  • 要按天看:用 INCR 和动态日期键名,最实用。
  • 要按天且按页面看:用哈希(Hash)结构,最精细。

管道、异步、合理设置持久化 这三点,你的PV统计系统性能想不快都难,Redis干这个,绝对是专业对口。