社区列表根据关注人数排序(排行榜)的实现思路整理


title: 社区列表根据关注人数排序(排行榜)的实现思路整理
date: 2018-09-08
tags: [工作笔记]


场景说明

客户端有一个社区列表的展示界面,该列表的排序方式是按照关注人数进行反向排序(从大到小),类似:

社区id 社区名称 社区关注人数
1 AAA 4
3 CCC 3
2 BBB 2
4 DDD 1

但是社区的 关注人数是动态变化的 ,当社区数量较多时也要考虑分页的情况,那么该列表的排序和分页有了很大的难度。

这里简单整理当前的实现思路,并指出明显的缺陷和暂时解决不了的问题,待以后有能力解决。

实现思路

这里首先要解决的第一个问题就是将动态转换成静态,然后才能排序。

如果做到根据实时的关注人数进行排序,对于后端是容易实现的,但是要考虑的客户端的处理方式:客户端会缓存已经获取的列表信息,同一个用户分页获取数据的时候,由于关注人数的动态变化,会导致数据出现重复或缺漏的问题。

举个例子说明

某时刻社区的关注人数如下(这里是举个例子说明,所以数据仅列出了4条):

社区id 社区名称 社区关注人数
1 AAA 3
3 CCC 4
2 BBB 3
4 DDD 1

当前时刻为t1,那么此时的社区排序结果如下:

社区id 社区名称 社区关注人数 生成时刻
3 CCC 4 t1
1 AAA 3 t1
2 BBB 3 t1
4 DDD 1 t1

一段时间之后,时刻为t2,那么此时社区的关注人数发生了变化:

社区id 社区名称 社区关注人数
1 AAA 5
3 CCC 7
2 BBB 9
4 DDD 4

那么此时的排序结果相对与t1时刻已经发生了明显的变化:

社区id 社区名称 社区关注人数 生成时刻
2 BBB 9 t2
3 CCC 7 t2
1 AAA 5 t2
4 DDD 4 t2

数据重复或漏缺的复现

这里出现的数据重复漏缺是有前提的:数据条数有点多,不能够一次全部返回给客户端,需要分页获取。

根据上面的那个例子,在t1时刻,用户当前的分页参数 count=2 ,那么返回的是id为 31 的社区信息,当用户在t2时刻继续获取分页的时候,返回的却是id为 14 那么这里id为1的社区就出现重复的问题了,缺漏的原理也类似。

缓存生成的关注排行榜

这里的实现思路是每隔一段时间将当前的关注排行榜进行缓存:

排行榜id 社区id 社区名称 社区关注人数 生成时刻
1 3 CCC 4 t1
2 1 AAA 3 t1
3 2 BBB 3 t1
4 4 DDD 1 t1
5 2 BBB 9 t2
6 3 CCC 7 t2
7 1 AAA 5 t2
8 4 DDD 4 t2

这个时间间隔就是每次任务的时间间隔T,在T间隔内获取的数据都将通过该缓存排行榜中获取。用户在第一次访问的时候,仅携带分页的count即可,返回的数据中,不仅包含社区的相关信息,还包括最新的时刻tn,在以后的分页获取数据过程中,需要携带该时刻。

比如用户在t1时刻传入参数count=2,那么返回的是id为31的社区信息,同时返回参数中也包含t1的值,那么在第二次访问的时候,需要携带count=2&time=t1,这样列表接口将会根据用户的时刻继续获取他的排行队列,那么返回的就应该是id为24的社区信息,同样包括t1的值。

其实也就是用户访问的时候,如果没有携带时刻参数,那么就默认返回距离当前时间最近的时刻。

缓存的过期和时刻参数t的失效设定

讨论一下极端情况:

  • 当时刻为t9的时候,时刻参数是t1的用户获取的将是很久以前的数据,可能这个数据对当前用户来说已经没有意义了。
  • 最理想的情景就是,用户发出请求的时候,刚好有一批新的社区排行缓存生成,这是拿到的数据也是最合理的数据。
  • 还有一种比较不合理的情景,就是用户发出请求的时候,刚好有一批新的社区排行榜将要生成,那么用户拿到的数据也就是间隔时间T之前的缓存。

所以这里就需要进行缓存过期和时刻参数失效的设定。

  • 设定时刻参数比当前时间小N×T的为无效时刻,将自动返回最新的缓存信息。
  • 缓存排行榜列表也会在任务执行的时候清除 N×T 前的缓存数据。

后端的实现

数据库中缓存表的构建

  • 该缓存表专门缓存各个时刻的排行信息,有定时任务进行插入和删除数据,任何用户均不能操作修改该表中数据。
  • 该表包含的基本字段有: 自身的id社区的id关注的人数生成的时刻(时间戳)

定时任务的调度

  • 社区排行榜生成任务,该任务是每T时间执行一次,完成对当前社区排行榜的计算、排序和入缓存库,任务执行时生成当前任务的唯一时刻值并一同存入缓存数据库中。
  • 缓存数据库清理任务,该任务的执行间隔可以是N×T,完成对N×T时刻前的排行榜数据进行清除。

列表接口的实现

  • 判断用户传入时刻值的有效性。如果用户没有传入时刻值或时刻值比当前时间小N×T则分配最新的时刻值。
  • 向缓存表中获取指定分页的社区id,并返回响应的社区信息列表和对应的时刻值。

客户端相关的任务

  • 用户首次进入列表界面时,请求不需要携带时刻值。
  • 用户下拉刷新的时候,请求不需要携带时刻值。
  • 用户上拉浏览列表的时候,请求需要携带时刻值。
  • 用户上拉浏览列表的时候,如果时刻值失效,需要清楚本地的部分缓存。

存在的问题

  • 用户浏览的数据不是最新的数据,在上面的极端情况中已经讨论
  • 客户端处理较为复杂
  • 用户在界面滞留时间越久,客户端的到的数据越不理想
  • 用户在当前列表的上的操作,比如关注某个社区,客户端需要将原本的关注人数+1,但是刷新界面之后,关注的人数又会变成原来的数字。
  • 由于是缓存的数据,当用户点击某个社区的详情时,看到的关注人数可能与列表中的人数不一致。

猜你喜欢

转载自blog.csdn.net/MrTeacher/article/details/102803525