投票排名系统(3)——投票流程与持久化

Posted by Beyonderwei on 2021-08-07
Words 1.5k and Reading Time 5 Minutes
Viewed Times

一、投票流程

       之所以我们通过Redis的Sorted Set来保存选手的信息,一方面是因为可以快速的对选手进行排名,还有一点便是为了用于投票功能的实现。
       通常投票(主播排名中就相当于送礼物)是一个被操作非常非常频繁的请求,想象一下你在看直播时,尤其是大主播,他们的礼物栏通常都是基本不间断的,更何况我们的应用要应对的还不只是一个主播,而是成千上万个,因此如果直接操作数据库基本是不可能的。
      所以投票的过程实际上就是增加Sorted Set 中某个id的分数,从而实现投票的流程。
在这里插入图片描述
对应的Redis命令就是:rdb.zincrby("vote"), 1, id)
注意: 实际中可能增加的数值并不是1,而是根据礼物的金额而定。

二、数据的持久化

       虽然说Redis带有数据的持久化功能,但是通常还只是用来做缓存的,因此票数信息最终还是要落盘写到数据库Mongo或者MySQL中,而不是一直在内存中。
       通过上面的分析我们知道投票是一个很频繁的操作,不可能每一次投票都操作数据组,因此你可能会想到如下的方案:

1. 定时持久化

       这是非常容易想到的一个方案,既然不能每次都操作数据库,但是我间隔一定时间同步一次(比如5秒、1分钟等),既保证了投票功能的正常运行,又能将票数信息持久化到数据库。过程很简单,如下:
在这里插入图片描述
看似很美好,但是这并不是一个好的方案,主要存在以下问题:

  • 每次同步的数据量非常大,
  • 大量数据信息需要被同步就导致从Redis查询时需要获取整个ZSet,主播很多时也可能会是一个大key了,会导致操作耗时,存在阻塞风险,同时可能对服务器的带宽
  • 向数据库中写数据时,相当于一次更新了整张表的票数信息数据,同样也非常耗时,给数据库带来压力

2. 定时持久化改变的数据

       既然第一个方案会出现一次性持久化大量数据,并且这里面可能很多主播的票数信息是没有改变的,那么何不通过一种方法,记录下哪些主播的票数变化了,然后只持久化变化了的这些主播的票数,这样可以大大减少每次持久化需要更新的数据,同时通过减小持久化的时间间隔,这样每次做数据持久化时,更新的数据就更少,就避免了方案1中的问题。

  • 记录票数变化的主播:
    上述方案的主要点在于如何记录票数变化的主播,实际很简单,只需要在投票接口将票数变化了的主播记录到Hash中,key就是主播的id,值可以记录主播的票数变化(增加了多少票):
    在这里插入图片描述

       这样当每次定时任务执行时,只需要从Hash中获取票数变化了的主播的ID,然后只更新这些主播的票数信息,那么就可以将每次的更新数量降低,避免方案1中的问题。

  • 更新数据:
    在这里插入图片描述

    3. 定时 & 定变化量阈值更新数据

           由于定时操作可能在更新时,某些主播的票数已经变化非常多了,因此需要对票数的变化量设置一个阈值,当变化量达到一定程度的时候,也进行一次更新。(有没有感觉很熟悉,其实就是Redis数据持久化时的AOF方案呀),只不过我们是只把Redis用于缓存,确实大部分场景Redis更适合做缓存而不是数据库。
  • 定变化量阈值更新数据:
    除了方案二中添加定时任务以外,设定一个阈值,用于在每次变化量大于阈值时,更新用户的票数到数据库,流程如下:
    在这里插入图片描述

4. 问题讨论

  • 问题讨论(1): 定时更新的时间选择,大一点好还是小一点好?
    答案(1): 肯定不是,因为越大意味着持久化时的数据量就越大,导致操作耗时,越小可以减小一次持久化的数据量,但是太小又会导致每次只持久化很少的数据,因此需要根据投票量综合考虑,同时也要考虑对最大数据丢失的容忍程度,因为缓存是可能挂掉的。
  • 问题讨论(2): 为什么拿Hash存储票数变化:
    答案(2): 因为只需要记录票数变化的主播ID和变化量,且不需要排名,因此不使用ZSet或是Set,如果不记录票数变化量,也可以使用Set。
  • 问题讨论(3): Hash的过期时间:
    答案(3): 肯定要大于持久化数据的时间间隔,当然为了保险起见可以设置3倍的数据持久化的定时时间。

三、总结

  • 本节我们主要讲了投票的实现流程和数据的持久化方案,其中数据的持久化方案中我们从简单的最容易想到的方案出发,不断分析问题、不断优化,得到了一个算是比较好的实现方式。

  • 实际上在此基础上我们还有一些值得讨论和优化的地方,这部分内容在下一节介绍,


本文为作者原创文章,未经作者允许不得转载。

...

...

00:00
00:00