PolarDB闪电助攻,《香肠派对》百亿好友关系实现毫秒级查询

云原生数据库PolarDB分布式版(PolarDB for Xscale,简称PolarDB-X)有极强的线性扩展能力,能够多写多读;它的全局索引能力,是分布式改造的利器,成功解决了传统分布式方案中多维度查询的难题,在《香肠派对》的好友系统上,实现了百亿好友关系20万QPS的毫秒级查询

——厦门真有趣《香肠派对》服务端主程 洪光裕


真有趣(So Funny)成立于2012年8月,致力于为全球用户提供健康有趣快乐的游戏体验与服务。目前已推出《香肠派对》、《不休的乌拉拉》、《仙侠道》等9款游戏,累计服务2亿多用户。这里聚集着一群有趣的人,秉持用户第一、热爱创作、讲逻辑的理念,为赢得百万人热爱而奋斗!

《香肠派对》是由真有趣游戏开发、由心动网络发行的一款“吃鸡”游戏,“开局一根肠,装备全靠捡”,曾连续三年获得“金翎奖”,拥有非常成熟的职业联赛。

在TAPTAP上,《香肠派对》有2.3亿的下载量,有着庞大的玩家群体:

111.png

用户关系定义

用户关系是游戏类应用非常普遍的场景,需要存储用户或者玩家之间的相互关系,通过社交关系提升用户的活跃度以及黏性,帮助玩家及时找到有关联的好友。在用户关注关系中,主要包含几种状态:

  1. 关注我的人->我的粉丝(fans);
  2. 我关注的人->我的关注(follow);
  3. 相互关注的人->互关(mutual);
  4. 拉黑的人->加黑(黑名单)。

222.png

用户关系系统架构与特征

以《香肠派对》为例,该游戏有比较强的社交属性,其好友功能提供了“关注”、“粉丝”、与推荐(找朋友)功能:

666.jpg

其核心表“关注表”对应的表结构示意:

create table user_focus(
  id bigint primary key,
  uid bigint, -- 用户ID
  focus_uid bigint, -- 关注的用户ID
  extra varchar(1024), -- 其他业务属性
  index idx_focus_uid(focus_uid),
  index idx_uid(uid)
)

如果一个用户关注了100个人,那么在这张表里有100条记录,目前整个关注表达到了百亿的量级。

这张表有以下几种访问模式:

  1. 获取某个用户的关注列表(我关注了谁):
select * from user_focus where uid=xxx;
  1. 获取某个用户的粉丝列表(谁关注了我):
select * from user_focus where focus_uid=xxx;
  1. 圈定一批人,他们关注了谁,谁又关注了他们(用于好友推荐):
select * from user_focus where uid in (xxxx);
select * from user_focus where focus_uid in (xxxx);

很容易理解,该表存在uid与focus_uid两种查询维度。

问题与选型

在这个量级下,传统的单机数据库容易出现以下几类问题:

  1. 索引idx_focus_uid与idx_uid的写入均为随机写入,B+树频繁的SMO(叶子的分裂、合并等),会有各种各样的锁争抢,导致写入RT上升,CPU消耗变多等;
  2. B+树层高变高,查询代价变大等;
  3. 索引太大,Buffer Pool被打爆,产生大量的IO(本质上也是随机写入的问题)等;
  4. 表的DDL耗时过长,时间不可控等。

无论使用哪种选型,核心是将大表进行拆分。在对该表进行分布式改造时,业务团队有几种选择:

1. 使用Redis、Hbase等NoSQL数据库,这类数据库可以解决扩展性问题,但是:

  • 需要业务合理设计Key。如果将uid作为Key,那么无法按照focus_uid进行查询。只能由业务侧将数据写两份,按照uid写一份,按照focus_uid再写一份,并且由业务侧维护两份数据的一致性;
  • 改变了业务之前使用关系型数据库的习惯,需要调整大量的代码。

2. Elasticsearch、MongoDB等文档型数据库:

以ES为例,如果为了支持高性能的查询,需要设计合理的DocumentID,否则,ES中的每次查询都会涉及到所有的节点,非常低效。因此又回到了上面的问题,uid和focus_uid两个维度无法兼得。

本质上,上面几种方案,虽然数据做到了水平拆分,但几种数据库内部只能解决单维度查询,多维度的查询问题只能由应用层解决。

阿里云瑶池数据库旗下的PolarDB分布式版成为了更好的选择,在这个场景中,PolarDB分布式版有着无可比拟的优势:

  1. 最重要的一点,PolarDB分布式版支持全局索引,在对数据做了水平拆分的基础上,还能支持业务的多维度查询的需求;
  2. PolarDB分布式版兼容MySQL的语法和协议,应用从单机MySQL迁移过来无需修改代码,应用研发可以保持以前使用MySQL的思路和习惯。

使用PolarDB分布式版GSI解决多维度查询

在PolarDB分布式版中,我们使用分区表的语法对表进行水平拆分,在本例中,我们对表按照uid进行分区:

create table user_focus(
  id bigint primary key,
  uid bigint, -- 用户ID
  focus_uid bigint, -- 关注的用户ID
  extra varchar(1024), -- 其他业务属性  
  index idx_focus_uid(focus_uid),
  index idx_uid(uid)
) partition by hash(uid);

555.png

此时对于uid上的查询,自然是很高效的。为了满足focus_uid上的查询,我们只需要执行一条DDL语句,即可为表创建一个全局二级索引:

create global index gsi_focus_uid on user_focus(focus_uid) partition by hash(focus_uid);

444.png

全局二级索引本质是一种数据冗余。例如,当执行一条SQL:

INSERT INTO user_focus (id,uid,focus_uid,extra) VALUES (1,99,1000,"xxx");

可以简单理解为,会分别往主表与gsi_focus_uid写入一条记录:

INSERT INTO user_focus (id,uid,focus_uid,extra) VALUES (1,99,1000,"xxx");
INSERT INTO gsi_focus_uid (id,uid,focus_uid) VALUES (1,99,1000);

其中user_focus主表的分区键是uid,gsi_focus_uid的分区键是focus_uid。

同时,由于这两条记录大概率不会在一个DN上,为了保证这两条记录的一致性,我们需要把这两次写入封装到一个分布式事务内(这与单机数据库中,二级索引通过单机事务来写入是类似的)。

当我们所有的DML操作都通过分布式事务来对全局索引进行维护,二级索引和主键索引就能够一直保持一致的状态了。

此外,PolarDB分布式版为GSI的性能也做了非常多的优化,例如:

  • 多分片的并行写入;
  • 唯一约束冲突检测下推;
  • 分布式事务的Grouping优化、一阶段提交优化等。

这里不做过多展开,有兴趣可以参考文章《PolarDB-X全局二级索引》

333.png

性能效果

业务压测过程中进行了全局索引的创建,索引添加过程是Online的,不会锁表。数据库的响应时间由创建前的平均数百毫秒,下降到了创建后的1-2ms,同时TPS提升了数百倍

数据库响应时间,单位毫秒

同时,全局索引的添加,使得绝大多数查询做到了“本地化”,可以理解为,一个SQL只对一个DN发起请求。这样,整个系统拥有了极高的扩展上限,可以做到线性扩展,也即如果10个节点可以支撑50W的QPS,那么20个节点就可以支撑100W的QPS。

下图是业务上线后的效果,使用8个节点,在峰值达到20W QPS的情况下,依然保持着1ms的响应时间:

数据库QPS,峰值20W左右

数据库响应时间,单位毫秒

PolarDB分布式版GSI的最佳实践

使用全局索引,会带来查询性能的提升,但也要注意合理使用,让它发挥更大的效果。下面给出一些最佳实践:

  1. 全局索引的数量不宜过多,通常一个表在2个以内。全局索引通常代表某种业务维度,例如,本例中典型的是关注和被关注,对于其他字段的查询加速,应使用本地索引。在某些场景下,我们也可以使用CO_HASH来实现多维度的查询,可参考《从淘宝订单号的秘密说起......》
  2. 在一对多的场景下,使用聚簇的全局索引,可以有效减少回表的代价。关于聚簇的全局索引,请参考:《PolarDB-X全局二级索引》
  3. 时间、日期等字段,不宜建全局索引,通常使用本地索引即可。
  4. 使用索引诊断功能(执行INSPECT INDEX即可),可以找到一些冗余、未使用的全局索引,避免不必要的空间、资源消耗,可参考:《聊聊数据库中的烂索引》、《如何进行索引诊断》

总结

从单机到分布式的过程中,全局索引是非常重要的能力,也是衡量分布式数据库的重要标准。使用没有全局索引的数据库,业务将陷入无穷无尽的与多维查询斗争的局面。

PolarDB分布式版的全局索引可以很好地满足类似于游戏领域好友系统这种多维查询的需求:

  1. 它是强一致的并内聚的,不需要业务通过第三方组件来实现,不需要业务去维护索引数据的一致性;
  2. 它的全局索引本身就是分区的,不需要担心全局索引本身的扩展性问题;
  3. 它上线多年,稳定可靠,有超过80%的PolarDB分布式版用户都在使用全局索引;
  4. 它能极大地减轻开发人员的学习成本,让开发人员能将精力集中在满足业务需求上,例如,可以沿用使用单机数据库时SQL优化的经验,通过加索引的手段去改善SQL的执行性能。

PolarDB分布式版云原生分布式弹性能力,在解决了业务多维查询需求的同时,极大地满足了客户随时扩缩容的诉求,实现了降本增效,是游戏行业中好友关系场景下典型方案的代表。”

—— 阿里云游戏行业架构师 范建文(瑛宸)

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/557275.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

探究欧拉恒等式的美学与数学威力

正如老子所述,“道生一,一生二,二生三,三生万物”,数学作为人类认知自然法则的语言,其数系的不断发展象征着对世界理解的深化。从自然数经由分数、无理数至复数,复数虽看似反直觉,却…

探索AI大模型:理论、技术与应用

引言 近年来,随着深度学习技术的迅猛发展,AI大模型已经成为人工智能领域的重要研究方向和热点话题。AI大模型,指的是拥有巨大参数规模和强大学习能力的神经网络模型,如BERT、GPT等,这些模型在自然语言处理、计算机视觉…

es安装中文分词器

下载地址,尽量选择和自己本地es差不多的版本 https://github.com/infinilabs/analysis-ik/releases 下载好,解压,把里面的文件放到es的plugins/ik目录下 把plugin-descriptor.properties文件里的es版本改成自己对应的 再启动es,能…

2W 3KVDC 隔离单、双输出 DC/DC 电源模块——TPH 系列

TPH系列是一款2W,单、双输出隔离电源模块,特别适合板上只有一种电压而要求有正负电源的场合,工业级温度范围–40℃到105℃,在此温度范围内都可以稳定输出2W,并且效率非常高,高达86%,温升非常低&…

OKCC搭建配置什么样的服务器合适

OKCC呼叫中心系统是一种采用软硬件结合的架构方式、及分布式的IP技术,从多角度为企业提供整合的一体化解决方案。因此,搭建OKCC呼叫中心系统所使用的服务器应该满足以下几点要求: 稳定性:服务器需要具有较高的稳定性和可靠性&…

MinIO + Prometheus + Grafana docker部署

文章目录 说明MinIO简介MinIO 容器化部署Prometheus服务地址配置方法一:先部署后修改方法二:部署时修改compose文件(未验证) MinIO Access Key配置Prometheus 容器化部署MinIO 生成抓取配置修改Prometheus配置文件Grafana 容器化部…

iframe和 blob实现JS,CSS,HTML直接当前页预览

先贴效果图&#xff1a; <template><div><div class"aaa"></div><div class"btn-run" click"tres">运行</div></div></template><script>import { mapState } from vuex;export default …

在线编辑器 CodeMirror

如何优雅的在网页显示代码 如果开发在线编辑器 引入资源&#xff1a; <link rel"stylesheet" href"https://cdnjs.cloudflare.com/ajax/libs/codemirror/5.60.0/codemirror.min.css"><script src"https://cdnjs.cloudflare.com/ajax/libs/c…

【网安小白成长之路】8.sql注入操作1

&#x1f42e;博主syst1m 带你 acquire knowledge&#xff01; ✨博客首页——syst1m的博客&#x1f498; &#x1f51e; 《网安小白成长之路(我要变成大佬&#x1f60e;&#xff01;&#xff01;)》真实小白学习历程&#xff0c;手把手带你一起从入门到入狱&#x1f6ad; &…

店前台安装水离子雾化壁炉前和装后对比

当酒店前台装上水离子雾化壁炉后&#xff0c;整体氛围和客户体验都会发生显著的变化&#xff1a; 装前&#xff1a; 普通的前台氛围&#xff1a;前台可能显得比较普通和传统&#xff0c;可能缺乏独特的装饰元素或视觉焦点。 视觉上缺乏吸引力&#xff1a;前台空间可能比较朴…

现代商业中首席人工智能官(CAIO)的角色与影响

每周跟踪AI热点新闻动向和震撼发展 想要探索生成式人工智能的前沿进展吗&#xff1f;订阅我们的简报&#xff0c;深入解析最新的技术突破、实际应用案例和未来的趋势。与全球数同行一同&#xff0c;从行业内部的深度分析和实用指南中受益。不要错过这个机会&#xff0c;成为AI领…

万字总结!Docker简介及底层关键技术剖析

本文首发在个人博客上&#xff1a;万字总结&#xff01;Docker简介及底层关键技术剖析 Docker 简介 Docker 是一个开源的应用容器引擎&#xff0c;基于 Go 语言 并遵从 Apache2.0 协议开源。Docker 可以让开发者打包他们的应用以及依赖包到一个轻量级、可移植的容器中&#x…

PVE grub resue错误修复 lvmid BUG

服务器断电后启动不起来&#xff0c;显示grub resue 找了半天没有找到修复方法。看官方文档有一处Recovering from grub “disk not found” error when booting from LVM 极为类似。https://pve.proxmox.com/wiki/Recover_From_Grub_Failure 下面是处理过程。 使用PVE 6.4启…

使用示例解释.NET中的Mocking是什么?

让我们踏上探索.NET软件开发中Mocking概念的旅程&#xff0c;让我们深入了解Mocking是多么简单易懂、易于访问。请与我一起穿越这个主题&#xff0c;我将涵盖以下内容&#xff1a; 理解Mocking&#xff1a;为何它对于构建强大的测试策略至关重要。探索一些最常见的Mocking库&a…

python教学入门:字典和集合

字典&#xff08;Dictionary&#xff09;&#xff1a; 定义&#xff1a; 字典是 Python 中的一种数据结构&#xff0c;用于存储键值对&#xff08;key-value pairs&#xff09;。字典使用花括号 {} 定义&#xff0c;键值对之间用冒号 : 分隔&#xff0c;每对键值对之间用逗号 …

SQL-Oracle 获取最大值,第二大,第三大,第 N 大值

目录 1、原始数据2、获取最大值记录3、获取第二大值记录4、获取第三大值记录 1、原始数据 select * from test_2024_04_15_001 order by 销量 desc,渠道2、获取最大值记录 select 渠道,销量 from ( select a.渠道, a.销量 from test_2024_04_15_001 a order by a.销量 desc,…

AI边坡监测识别摄像机

AI边坡监测识别摄像机是一种利用人工智能技术进行边坡监测的智能设备&#xff0c;其作用是及时监测边坡变化并识别潜在的滑坡、崩塌等危险情况&#xff0c;以提供及时预警和采取必要的安全措施。这种摄像机通过高清摄像头实时捕捉边坡的图像&#xff0c;并利用AI算法对边坡的形…

实验室三大常用仪器2---函数信号发生器的基本使用方法(笔记)

目录 函数信号发生器的基本使用方法 如何连接函数信号发生器和示波器 实验室三大常用仪器1---示波器的基本使用方法&#xff08;笔记&#xff09;-CSDN博客 实验室三大常用仪器3---交流毫伏表的使用方法&#xff08;笔记&#xff09;-CSDN博客 示波器是用来显示和测量信号的…

Java | Leetcode Java题解之第35题搜索插入位置

题目&#xff1a; 题解&#xff1a; class Solution {public int searchInsert(int[] nums, int target) {int n nums.length;int left 0, right n - 1, ans n;while (left < right) {int mid ((right - left) >> 1) left;if (target < nums[mid]) {ans mi…

阿里云图片处理之 图片样式(裁剪)

文档 : https://help.aliyun.com/zh/oss/user-guide/image-styles?spma2c4g.11186623.0.0.5961fe7aq3111v 需求 : 由于客户端界面展示的图片较多, 而且每个图片都过大并且高清高分辨率的, 导致打开页面时图片加载很慢, 而且是缩略图, 对图片清晰度要求不是那么得高, 因此可以…