请教大佬,类似蚂蚁森林的能量排行,后端应该怎么设计?

2020-09-09 17:27:57 +08:00
 qwerthhusn

假设系统有 N 万个用户,每个用户都有一个 score 。这个 score 经常发生变化。

需要完成以下功能:

  1. 整个平台,score 最高的 N 个用户的信息
  2. 我的好友 score 排行榜
  3. 我的 score 在整个平台处于的位置

现在没有太好的思路,现在想的是

假设数据存在 MySQL 里面的

create table user (
    id bigint not null primary key,
    name varchar(255) not null,
    score int not null
);

create table user_relation (
   user1_id bigint not null,
   user2_id bigint not null,
   primary key(user1_id, user2_id)
);
5936 次点击
所在节点    程序员
43 条回复
siweipancc
2020-09-09 18:30:36 +08:00
mysql 可以用内存数据库,等个最优解
qwerthhusn
2020-09-09 18:32:38 +08:00
@siweipancc 这东西要持久化的,内存数据库肯定不行
siweipancc
2020-09-09 18:48:14 +08:00
@qwerthhusn 可以晚点同步。我指的是开另一个内存中间表,在一个活动结算周期切换的时候再写入实体表
netty
2020-09-09 19:09:08 +08:00
用 Redis 的 SortedSet 轻松搞定,key 排行榜名称,member 用户 ID,score 为用于排行的值
ffLoveJava
2020-09-09 19:13:48 +08:00
等一个大佬
用户少的话无所谓。我想知道大佬对于超量用户量有什么解决方案?
qwerthhusn
2020-09-09 19:14:13 +08:00
@netty 这个道理都明白,但是数据库和 redis 的同步咋做呢?

首先 redis 不能事务,可能就存在 redis 与真实数据不一致的地方。

我能想到的就是定时全量刷新了,不知道这样弄合理不合理,全量刷新间隔时间也不好定
qwerthhusn
2020-09-09 19:15:41 +08:00
@ffLoveJava 期望来个大厂做过类似场景的的大佬,分享一下 Best Practice 呢。。
smartwusir007
2020-09-09 19:15:44 +08:00
@netty 这样总用户排行有了,怎么做每个用户的好友排行呢
xiaoliu926
2020-09-09 19:18:26 +08:00
@smartwusir007 用户好友排行前端来实现就行了,只需要把用户好友数据丢给前端,前端自己排序
qwerthhusn
2020-09-09 19:23:37 +08:00
@smartwusir007 其实我突然一想,好友那个反而好弄一点,首先拿到好友 ID 列表,然后直接数据库或者 ZSCORE 读取好友们的 score 信息,直接应用排序。毕竟一个人的好友不会太多,
optional
2020-09-09 19:34:32 +08:00
总排行榜和我的位置不是实时的,只要根据分数估算排行就行。
limbo0
2020-09-09 19:48:58 +08:00
海量数据可以用图数据库,技术 janusgraph,保存关系和分数应该问题不大
LostPrayers
2020-09-09 19:49:18 +08:00
简单实现就是 4L 说的 SortedSet,不能事务没有关系, 排行是通过 score 自动计算的, zrank 即可取到 index.
好友 score 排行榜, 就取出所有好友 id 对应的 zrank 再排个序
firefox12
2020-09-09 20:04:46 +08:00
总排行 定期算,拿出 1 个数组 ,长度为 n, 比如 0-10000 最多 10000 点, 然后统计的时候 把你的分数-> index, 在 index 上加 1
最终结果 就是 0 分的 100 代表 100 人 0 分,1 分 200 代表 200 人 1 分。
从 n->0 开始 统计, 把结果写在数组里, 比如 n 里面 10 个人,n-1 里面 100 人, 那么 n 就是 10, n-1 就是 110, 这个 x
的值,就是 n 到 x+1 的和,这个数组的坐标里的值就是 你的排名。

最后拿你的分数 直接在这张表里查 你就知道 你多少名了。
Rheinmetal
2020-09-09 20:07:07 +08:00
十分钟刷新一次排名可破
kusya
2020-09-09 21:33:00 +08:00
数据如果不要求实时性,可以按照 score 索引查询。数据太多还可以分表。
hejw19970413
2020-09-09 21:55:54 +08:00
@Rheinmetal 支付宝几亿的用户,怎么处理?
zhgg0
2020-09-09 22:17:20 +08:00
可以利用桶排序,记录每个分数段的用户数量,根据当前用户的分数能直接算出大概排名。
最高分数段的用户特殊处理,可以计算他们的准确排序。
用户好友数一般不多,直接排就好了,可以把好友的分数缓存到当前用户里并且不用实时更新,只需要实时更新自己的分数就行了。
如果分数跨度不大的话,假设分数只有 0 到 1000 这种,直接记录每个分数有多少用户,这种情况可以 O(1)算出每个人的准确排名。
zxCoder
2020-09-09 22:38:39 +08:00
收藏
yeqizhang
2020-09-09 22:53:50 +08:00
赞同楼上有人说的把用户的好友 ID 去查出来排序就行了。总排名位置这东西实时性应该不高而且是个大概的位置

这是一个专为移动设备优化的页面(即为了让你能够在 Google 搜索结果里秒开这个页面),如果你希望参与 V2EX 社区的讨论,你可以继续到 V2EX 上打开本讨论主题的完整版本。

https://www.v2ex.com/t/705551

V2EX 是创意工作者们的社区,是一个分享自己正在做的有趣事物、交流想法,可以遇见新朋友甚至新机会的地方。

V2EX is a community of developers, designers and creative people.

© 2021 V2EX