研发方还可以根据实际业务情况指定使用哪些Mysql和Redis集群,实现适当的存储和流量分离。毕竟有的列表业务的读写QPS可能不会超过100,而有的业务列表的日读QPS可能会超过10万。排名数据的大小在公司之间差异很大,但即使是那些排名数据量相对较大的公司,其生命周期也很短,这使得他们能够分配单独的存储并提供各种定期清理并制定归档策略。
积分开始时间和积分结束时间实际上是列表上线的有效时间范围,主要用于自动添加积分并计划上线的列表。
分数数字分段配置与上面列表的排序方式有关。针对实际需求,需要有一个排序策略,比如“如果分数相同,则先获得分数的人排在第一位”或者“如果分数相同,则粉丝较高的人”奖牌级别将被授予第一名。”所需的排序策略,例如“排名第一”。我们知道Redis zset使用双精度浮点数(双精度64位浮点数)来表示成员的排序权重分数,而double类型的最大精度为16位。因此,您可以指定n位整数部分代表业务实际得分,指定(16-n)位小数部分辅助二次排序。如果您调用通用接口更新特定时间点的分数(将时间戳记为ts),根据您的设置,有以下三种方式计算最终分数。
按时间顺序排序。获取参数的分数作为整数部分,得到(999999999-ts),并将结果截断为小数部分。
按最新排序。将参数的score作为整数部分,取ts,将结果截去作为小数部分。
自定义排序。参数分数以整数部分形式获得,参数分分数以小数部分形式获得。即整数部分和小数部分均由业务计算。
最后,整数和小数部分按字面意思组合起来作为zset 成员分数。如果列表成员最终得分相同,则根据zset 的内部实现,列表成员根据其键按二进制字典顺序放置。
配置列表维度
在将列表上线之前,您还需要配置列表的奖励维度、排名时间粒度等。
通用维度配置中的维度项是根据直播业务常用的维度预先填充的。检查奖励维度将水平分割列表。一个例子如下所示。
如果您不选中该选项,则不需要创建水平排名,即整个网站的一个列表。例如,锚点人气列表是全站范围内所有锚点的受欢迎程度排名,并且只需要一个列表实例。
如果选中锚点,则意味着每个锚点都有一个列表实例。例如,主播人气支持榜就是对某个主播的人气做出贡献的所有用户的排名。
如果勾选了主播和会话ID选项,则意味着每个主播的每个直播会话都会有一个列表实例。例如主播每次直播的打赏列表就可以这样实现。
当预先配置的维度无法满足逻辑需求时,使用扩展维度,将额外维度的定制留给业务。业务方可以自己想办法。业务方在更新和读取列表时,使用统一的算法来计算维度值。
创建表`some_rank` (`id` bigint(20) unsigned NOT NULL AUTO_INCRMENT COMMENT \’id\’, `rank_id` int(11) NOT NULL DEFAULT \’0\’ COMMENT \’rankID\’, `type_id` varchar(100) NOT NULL DEFAULT \’\’ COMMENT \’子列表标识\’, `item_id` bigint(20) unsigned NOT NULL DEFAULT \’0\’ COMMENT \’列出成员标识\’, `score` bigint(20) unsigned NOT NULL DEFAULT \’0\’ COMMENT \’列出单个成员点\’ , //.) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT=\’xxx 列表数据表\’ 对于id、rank_id、score、rank、score 这样的字段,从name 和name 中提取是非常容易的。评论如果你明白我的意思,就不需要进一步解释了。请注意两个字段:type_id 和item_id。
type_id字段的类型为verchar,其值的计算对应于列表的“维度项”配置。固定逻辑封装在代码实现中,按照所选奖励维度字段名的字典顺序进行组装,组合得到type_id字段的值。列表的奖励维度固定后,算法的结果相对稳定。
例如,针对特定商家列表的奖励维度配置如下:
然后,在计算type_id时,按照字符串格式连接:“${锚定子列表的开始}_${锚定uid}_${other}”。锚定子列表的起点是根据奖励积分或查询请求的时间戳计算的。
例如,奖励积分请求的请求正文和字段注释为:
{ \’rank_id\’: 12345, //列表ID \’item_id\’: 110000653, //列表成员ID。该请求传递用户的UID \’score\’: 1980, //本次请求添加的\’dimensions\’: { //奖励维度必填参数\’ruid\’: 110000260, //主播的UID。与奖励积分通用维度中的“锚定”选项相对应的参数和值。 \’timestamp\’: 1713165315, //用于锚定子列表除以时间戳时间的附加点行为//可能需要的其他维度参数} //需要幂等键,业务标识符等其他需要的参数}将会添加。 如果保留的时间戳分支行为为1713165315,即2024-04-15 15:15:15,时间维度配置为1个自然月,则该奖励行为所属自然月的开始时间为2024-04-01 00:00:00,时间到了。邮票为1711900800,因此本次加分请求计算出的type_id为“1711900800_110000260”,item_id字段中传递的值为用户的uid。
那么这个加点的行为就是用户(uid:110000653)为锚点(uid:110000260)本月榜单贡献了1980点,对应的数据行(主字段)可以解读为:Masu.
Rank_id、type_id、item_id 是数据行的主键。
同样,如果此列表中配置的时间维度为1个自然日,则本次加分操作的自然日开始时间为2024-04-15 00:00:00,时间戳为1713110400,则本次加分请求的计算为:喜欢。 type_id 为“1713110400_110000260”。
这也说明每次加分请求都需要业务方发送动作发生时的时间戳。赠送礼物的加分行为包括用户赠送礼物时的实时时间戳。弹幕加分行为包括用户发表评论时的实时时间戳。这样,即使偶尔出现网络抖动、MQ 消息滞后或其他异常情况,例如消费游标重置或MQ 重新平衡,也不会发生“昨天的礼物是今天的分。”给列表加分”的情况。当然,这也需要幂等性,以免重复加点。
Redis缓存
当Redis缓存排名列表时,zset的键也由rank_id和type_id组成,并且点和查询根据时间戳固定到正确的键。我这里就不详细说了。
更新列表
开发了热点检测组件。热zset 键通过记录列表zset 的访问状态在内存级别进行缓存。
可配置强制热室。 (可选)手动将特定直播间指定为热门直播间,强制内存缓存。
添加二级缓存肯定会牺牲一些实时性能,但会在业务容忍范围内完成。
当前结构
这里提供一个简化的内部架构图,仅供参考。
跟进计划
代码质量的进一步提高
系统的设计离不开实际适用的场景,需要在各方面进行妥协。目前的排名系统实际上是通过“动态改变轮子”创建的。例如,通用链接仍然包含许多业务逻辑。过去有过几种分层的设计理念,也尝试过引入更多精简的设计模型来提高可扩展性和可维护性,但都没有得到充分的落实,需要我们继续推广。
日志管理
目前排名系统的日志量非常大,每天最多达到近20T。有许多不合理的做法,例如嘈杂的日志、重复的含义以及需要组织和管理的大型结构化输出。
存储治理
有很多旧的、过期的数据,很多遗留配置、存储表、非TTL缓存等不再使用,而且mysql数据不具备自动过期的能力。报警和定制存档功能。
虽然有集群隔离,但有些业务列表通过在代码中硬编码的方式交互使用多个集群。所谓“核心”和“非核心”数据分离存储的好处也丧失了,让整体印象变差了一些。变得混乱。
如果你想查看你的列表系统当前存储集群的使用情况,你应该检查多个平台上多个mysql和redis集群的监控,包括容量监控、访问流量监控等。然后,总结评价。
列表系统新结构
考虑当前排名系统的问题
架构层次更加精简,领域划分清晰,列表核心层和业务层支持,可扩展可测试的自洽闭环。
奖励积分的实时处理和数据一致性得到了优化和改进。
更科学的存储选择。
作者:业务线
来源-微信公众号: 哔哩哔哩科技
来源:https://mp.weixin.qq.com/s/XCWM1OFDKXBGxa7TebrrzA
本文和图片来自网络,不代表火豚游戏立场,如若侵权请联系我们删除:https://www.huotun.com/game/663420.html