3

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

 7 months ago
source link: https://www.v2ex.com/t/1015307
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.
neoserver,ios ssh client

V2EX  ›  程序员

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

  sduoduo233 · 6 小时 5 分钟前 via Android · 779 次点击

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

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

id int
...
paused bool
time_remain int

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

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

14 条回复    2024-02-11 16:36:42 +08:00
ThirdFlame

ThirdFlame      6 小时 0 分钟前

更好的做法肯定是,暂停时,将用户状态修改为暂停。同时记录暂停开始的时间。
在申请恢复时,给用户的有效期+(恢复时间-暂停时间),同时将状态改为正常
vituralfuture

vituralfuture      5 小时 35 分钟前 via Android

通用操作系统不保证实时性,例如你要五分钟后执行某个任务,或者 sleep 五分钟,都只是保证间隔时间大于等于五分钟,长期下来误差累积,结果相去甚远
zhensjoke

zhensjoke      5 小时 14 分钟前

设计 2 个,一个按使用时间扣除。一个按照暂停时间扣除。
双重保障。
ntedshen

ntedshen      5 小时 5 分钟前

雷神不是即点即结算的么。。。
就不说误差的问题哪有每五分钟-5 的,二游签个到光速下线的岂不是往死里亏。。。
vituralfuture

vituralfuture      5 小时 1 分钟前 via Android

可以动态计算出总使用时间,也可以定期计算,更新数据库。例如记录一个人的年龄,可以只记录出生时间,用当前时间减去出生时间就得到了年龄,也可以只存储今年的年龄,每年定期把所有年龄+1

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

计算可能比较花费时间,可以想办法把之前计算的结果记录下来避免重复计算,例如记录一下每个用户前 n 条记录的时间总和,也就是定期更新计算的中间结果
Kinnice

Kinnice      4 小时 56 分钟前 via Android

暂停恢复时加个 hook 计算
IlllIlllIlIIl

IlllIlllIlIIl      4 小时 55 分钟前

在用户状态为非暂停时,记录用户到期的时间点`time_expire`。
当用户将状态从非暂停改为暂停时,用到期时间点-现在的时间计算出时长`time_remain`保存。
当用户从暂停改为非暂停时,用现在的时间+时长算出新的到期时间点保存。
所以表里加个`time_expire datetime`的数值,用于非暂停状态下的计算.
GooMS

GooMS      3 小时 22 分钟前 via Android

暂停是常态,启用是偶尔,所以应该记录使用的时常
leaflxh

leaflxh      3 小时 17 分钟前

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      3 小时 14 分钟前

需要处理的是用户没暂停

如果不想挣这个钱,设置个心跳检测客户端是否在运行,如果没响应超过一定阈值,停止加速
leaflxh

leaflxh      3 小时 13 分钟前

MySQL TIMESTAMP 类型可能会有 2038 的问题,改成 BIGINT 也行
leaflxh

leaflxh      3 小时 12 分钟前

《声明》
以上仅是技术探讨,他要是搞机场业务,本人并不知情,与本人无关
ryd994

ryd994      2 小时 10 分钟前 via Android

表里记录当前 session 开始时间,然后根据余额计算当前 session 最晚结束时间,先不改余额
然后每五分钟查表,如果有 session 超时就踢下线

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

如果考虑性能的话可以分表,分为活跃 session 表和用户余额表两个表。用户上线时加入活跃表,下线时结算并更新余额表
DeWjjj

DeWjjj      20 分钟前

我感觉启动时间很明显是要记到 redis 里面的,id+启动时间。
用户不点结束就一直让他存活下去,他扣的是钱还不能让他在 redis 长活?

About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK