可暂停加速器的计费逻辑/数据库设计疑问

2024-02-11 10:51:37 +08:00
sduoduo233  sduoduo233

正在设计一个类似雷神/Golink 的加速器系统,没想好怎么实现暂停时长

目前的想法是有一个用户表记录剩余时长和是否暂停:

id int
...
paused bool
time_remain int

然后再开一个定时任务每五分钟把没有暂停的用户时间-5

求教各位老哥有没有更优雅的方法

6207 次点击
所在节点   程序员  程序员
27 条回复
ThirdFlame
ThirdFlame
2024-02-11 10:55:49 +08:00
更好的做法肯定是,暂停时,将用户状态修改为暂停。同时记录暂停开始的时间。
在申请恢复时,给用户的有效期+(恢复时间-暂停时间),同时将状态改为正常
vituralfuture
vituralfuture
2024-02-11 11:21:20 +08:00
通用操作系统不保证实时性,例如你要五分钟后执行某个任务,或者 sleep 五分钟,都只是保证间隔时间大于等于五分钟,长期下来误差累积,结果相去甚远
zhensjoke
zhensjoke
2024-02-11 11:42:40 +08:00
设计 2 个,一个按使用时间扣除。一个按照暂停时间扣除。
双重保障。
ntedshen
ntedshen
2024-02-11 11:51:11 +08:00
雷神不是即点即结算的么。。。
就不说误差的问题哪有每五分钟-5 的,二游签个到光速下线的岂不是往死里亏。。。
vituralfuture
vituralfuture
2024-02-11 11:55:28 +08:00
可以动态计算出总使用时间,也可以定期计算,更新数据库。例如记录一个人的年龄,可以只记录出生时间,用当前时间减去出生时间就得到了年龄,也可以只存储今年的年龄,每年定期把所有年龄+1

在这个场景下,可以拿一张表记录用户使用的情况,包括用户 id ,取消暂停的时间,暂停的时间,需要计算总时长,就根据用户 id 查到所有记录,把每个记录的两个时间相减,再所有记录求和

计算可能比较花费时间,可以想办法把之前计算的结果记录下来避免重复计算,例如记录一下每个用户前 n 条记录的时间总和,也就是定期更新计算的中间结果
Kinnice
Kinnice
2024-02-11 12:00:13 +08:00
暂停恢复时加个 hook 计算
IlllIlllIlIIl
IlllIlllIlIIl
2024-02-11 12:01:17 +08:00
在用户状态为非暂停时,记录用户到期的时间点`time_expire`。
当用户将状态从非暂停改为暂停时,用到期时间点-现在的时间计算出时长`time_remain`保存。
当用户从暂停改为非暂停时,用现在的时间+时长算出新的到期时间点保存。
所以表里加个`time_expire datetime`的数值,用于非暂停状态下的计算.
GooMS
GooMS
2024-02-11 13:33:55 +08:00
暂停是常态,启用是偶尔,所以应该记录使用的时常
leaflxh
leaflxh
2024-02-11 13:38:58 +08:00
remain_seconds BIGINT COMMENT '剩余秒数'
last_start_time TIMESTAMP COMMENT '上次开始加速的时间戳'
is_accelerating TINYINT COMMENT '是否正在使用加速服务'

开始加速时,判断当前是否正在加速。

是,则将当前时间戳 - last_start_time 得到上次使用时长,然后减掉 remain_seconds 。然后如果没欠费,更新 last_start_time 为当前时间,否则停止加速

否,则更新 last_start_time ,设置 is_accelerating = 1

---

暂停加速时

将当前时间戳 - last_start_time 得到上次使用时长,然后减掉 remain_seconds ,设置 is_accelerating = 1

---

充值时,直接按照充的时长,转换成秒数加到 remain_seconds
leaflxh
leaflxh
2024-02-11 13:41:59 +08:00
需要处理的是用户没暂停

如果不想挣这个钱,设置个心跳检测客户端是否在运行,如果没响应超过一定阈值,停止加速
leaflxh
leaflxh
2024-02-11 13:43:26 +08:00
MySQL TIMESTAMP 类型可能会有 2038 的问题,改成 BIGINT 也行
leaflxh
leaflxh
2024-02-11 13:44:25 +08:00
《声明》
以上仅是技术探讨,他要是搞机场业务,本人并不知情,与本人无关
ryd994
2024-02-11 14:45:54 +08:00
表里记录当前 session 开始时间,然后根据余额计算当前 session 最晚结束时间,先不改余额
然后每五分钟查表,如果有 session 超时就踢下线

用户暂停/下线时,根据开始时间和当前时间计算消耗量,从余额中减去。并把当前 session 的开始时间和结束时间设为最大值,这样定期扫描就不会扫到

如果考虑性能的话可以分表,分为活跃 session 表和用户余额表两个表。用户上线时加入活跃表,下线时结算并更新余额表
DeWjjj
2024-02-11 16:36:42 +08:00
我感觉启动时间很明显是要记到 redis 里面的,id+启动时间。
用户不点结束就一直让他存活下去,他扣的是钱还不能让他在 redis 长活?
ccde8259
2024-02-11 17:51:51 +08:00
Database is Log 的思路去做这个事情
第一张表记录充值的分钟数
第二张表记录暂停的时间段
那剩余分钟数=充值分钟数-区间暂停分钟数
如果你要提升性能就减少回溯长度,定每月/每周活跃用户归档表,三表联查来加快查询性能。
Session 是否存活判断就分钟级确认一下是否存在生效暂停记录且剩余分钟数>0
whileFalse
2024-02-11 22:35:54 +08:00
没太明白需求,这是点卡吗?
IlllIlllIlIIl
2024-02-11 22:47:21 +08:00
@ccde8259 你这样子用户的分钟数只会越来越多。

我前面提到的方法只适用于 hobby project , 如果要按照这位 v 友的方法来做的话可以直接在现有的充值系统上改。

创建一张充值记录表,包含充值 ID ,用户 ID ,充值时间,充值时长,和新的到期时间(需要根据上一次的到期时间来计算,如果已经到期了的话就根据现在时间算,如果没有就在之前的到期时间上加)

再创建一张暂停记录表,记录暂停开始,暂停结束的事件。每次暂停开始前要判断一下用户是否到期,如果到期不能给暂停。暂停结束后把暂停时长按照一次充值事件加入充值记录里,计算出新的到期时间。
IlllIlllIlIIl
2024-02-11 22:55:01 +08:00
@IlllIlllIlIIl #17 突然发现 1 楼好像就是这个意思,补充一下暂停事件作为一个特殊的充值事件,不受上一次到期时间的影响,只管我到期时间上加就行了
IlllIlllIlIIl
2024-02-11 23:08:18 +08:00
@IlllIlllIlIIl #18 所以前面那张充值记录表应该叫时长变化表,再加一个叫“变化原因” 的值,里面可以写一些像是“用户充值“,”暂停“,”活动赠送“之类的
IlllIlllIlIIl
2024-02-11 23:15:17 +08:00
@IlllIlllIlIIl #19 , 考虑到一致性的话,那张暂停表也就不要了, 可以像一楼说的把暂停状态和暂停开始时间记录在用户表下

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

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

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

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

© 2021 V2EX