阿里云PolarDB游戏场景最佳实践
内容介绍
一、数据库体系演进
二、Polar DB的行业优化
三、Polar DB for Redis的解决方案
四、blob的性能优化
五、场景备份还原能力
六、全球部署与异地容灾能力
本次分享的主题是PolarDB游戏场景最佳实践,由阿里云数据库产品事业部陈宗志(暴跳)分享。
PolarDB开发在游戏行业用的很多,不管是华东的米哈游还是其它的,都作为游戏中主要的数据库。
一、数据库体系演进
1.SQL NOSQL以及NewSQL
团队与游戏行业的开发同学怎么做数据库选型?从最早的关系型数据库开始,到互联网业务的发展,都会有非关系型数据库,但用几年以后会发现关系和可扩展一样都很重要,所以才有NewSQL。
2.NewSQL的简单分类
如果要解决数据库的扩展性问题,对市面的产品进行归类并介绍。从上而下,上面是mysql的进程,底下是一块磁盘,从业时间较长者应该都用过传统的丰富分表的解决方案。切片在最上层,上面要么是传统的分表的中间件,要么是library直接嵌入到业务的代码里面,底下标准的mysql,传统的是在没有新方案之前解决扩展性最好的办法,现在淘宝,天猫的双十一也在使用。方法唯一的缺陷是业务开发的要求比较高。
3.从两个纬度来衡量这些方案
生态的兼容和扩展性该扩展性非常好,业务按照开发提前扩展好分片,比如提前扩展好1014个分片,SQL必须带组件,不能带二级水印查找,排序需要自己在业务逻辑业务大案里面做好。并不是无人使用,只要dba和研发团队在同一团队,并且dba有比较强话语权,方案的扩展性是非常好。
第二套方案:像最早都是以Google spanner为代表,像 spanner 都是类似的解决方案。该种解决方案上层是售后解析,售后解析完,把映射到底下的支持事物的kv或是后层,该解决方案的优点是扩展性做的好,也支持多节点写入,但缺点是兼容性一定不是100%。
底下的这两个方案兼容性可以做到100%,是直接拿MYSQL官方的代码改的,自己写一套的兼容性不可能做到100%,之前客户号称产品可以做到兼容,但SQL语法的报错,事务隔离级别行为不一致也对业务有影响。存在游戏行业的客户服务端的代码是祖传代码,无法改动。过程可能是从一个项目拷贝到另外项目,另外项目突然火,项目又拷贝到另外项目。改售后,后期很难,推荐业务没有把握,尽可能选兼容性100%,99%和100%是两种不同的水平。另外一套像POLARDB Aurora解决方案,上面为标准的mysql,底下是一块云盘。可以认为比Aurora更彻底,是以POLARDB 为mysql跑在云盘上,不推荐将MYSQL跑云盘,跑起来性能很差。
从兼容生态和扩展性两个角度来分析,上面的这些方案,传统的单节点的生态兼容性一定是最好的,传统的丰富分表的扩展性一定是最好的,只要业务按照dba的要求改代码扩展性是可以做得非常好的,像polardb是更多是倾向于兼容生态,底下通过分布式存储尽可能的通过多路解决扩展性问题,但扩展性问题确实不如spanner解决方案解决的更好。
二、Polar DB的行业优化
上面是原神的背景图。整个polarDB,除游戏行业也负责很多行业,游戏行业一直是团队做的最好的行业。这些产品几乎是和原神一起成长、生产起来的,原神不断发展,它有不断的需求,也不断跟着用户成长。
米哈游早期备份耗时比较长,他们是跑在mySQL本地盘上,备份以及备份恢复时间非常长。关于游戏行业发版失败,包括发完以后可能出现配置数字有错误,或玩家跑一会以后才可发现有错。但在电商或金融版本不太可能发布失败。
每个游戏行业版更需要做数据库的备份,备份以及备份恢复的时长非常敏感。游戏行业的问题一般为数据量大,备份时长越来越长。采用标准mySQL,通过 s backup去做备份,备份时常会越来越长,同时备份的恢复时间会比较长,基于binlog的恢复,还有需要把s back up的数据从OSS上面拉下来,在应用时间也是非常长。
游戏行业也会有超大行的数据,之前的单行玩家blob的数据有超过一兆,因此给客户推荐去做自动拆分,但了解所有的游戏行业都很难做自动拆分,用户今天可能要加手的装备,明天可能要加脚的装备,后天还可能加手指的装备,很难做好字段拆分。几乎所有的游戏行业,把玩家的角色的属性信息都会放在大的blob字段里面。blob有可能是拿PB有可能是拿Swift压缩完成在里面,数据库缺点是比如只是捡手环的装备,但写回需要把全身上下所有的装备都写回。但目前行业都采取此类方式,所以PolarDB也针对场景专门去做适配和优化。
异地登录的容灾切换方案以及版更需要停服更短,所以PolarDB跟游戏一起承担,主要是把这些问题都解决,能够做到秒级备份。通过底下自己的存储,备份不需要走s backup,再上传binlog。直接通过快照来做备份,快照是可写的,备份几乎是秒级别的。全场景的备份还原能力,备份除支持整个实例级别的备份,还支持秒级别备份。玩家装备丢失,他要找回玩家身上的装备信息,实现行级别的按时间点还原的能力,同时团队专门针对游戏IO模型自动更新,做blob场景全链路的优化。游戏行业IO特别密集,拿维度的写入来衡量,单节点差不多能够做到2.5G。之前在某游戏里面和mongo PK,差不多为5~7倍量级,以及GDN集群的优化,去解决容灾场景的问题以及启动的优化。
三、Polar DB for Redis的解决方案
1.做共享存储的原因以及在共享存储下面的优势
读扩展方面,可支持一写多读。可支持大容量,之有数据库的最佳实践,包括现在有人在转发单表不要超过500万,这是淘宝的类似于中间件团队写的最佳实践,最佳实践里面是基于当时时代的硬件和软件。单表不要超过500万行的原因是当时整个SD盘只有500 g左右,做备份至少需要有留一半的空间S back up来做数据备份,还得留日志相关的空间。单个盘能用的空间不大,差不多只有两三百g,所以基于环境,如果要做备份实例越大,备份时间会越长,所以基于此软件和硬件提的约束,在现在已经没有约束了。
当时里有100多T的,单表有40多T的都存在。mySQL核心存储引擎是核心数据结构innoDB,其数据可以传到26t,至5层可以存但不能计算的大小。mySQL的最佳时间单表不要超过500万行,对于现在的软件和硬件已经不适用,mySQL官方也在不断去优化,index的大锁,从5.6 5.7~8.0也在不断的优化,这是基于10年前的硬件和软件给出的结论,目前已经可以推翻。官方无论是从基调能力,所优化的能力都已经突破限制,大容量能够支持到100T,现在应该能够支持更多,支持软性的限制,最早跟其它软件相匹配。目前底下是分布式存储、自动扩容、按量付费。
游戏行业存在的情况是需要的数据量不大,全是in place的update,存在iops要求比较高,但是容量是很小。比如400g的数据,一直不断in place Update他不断更新玩家的装备属性信息,但数据的存储空间不大,所以如果是用阿里云盘的解决方案,为获得这么高的iops,必须买非常大的实例存储规格,比如只有买2T,才能达到这么高的iops。但在polarDB上把东西是截版与按量付费,iops跟实例的存储空间大小不绑定。根据具体的业务逻辑而定,所以是按年付费,并且实例的iops跟存储容量的大小是不绑定的,如果遇到必须扩大到的磁盘的大小,才能达到指定的iops在polarDB共享存储的场景,也可以节省一定的成本,此下面是自研的自己的一套存储3副本,如果有用到基于物理复制的主备场景,延迟更低。
如果传统mySQL的主备复制是主节点更新的,比如事务更新100行,不断更新,只有更新到最后一行,才会写binlog同步到被节点,被节点再重新应用Binlog。两边的同步延迟是两边最后事务执行的语句的大小。基于物理复制,即基于mySQL面的INOODB来进行复制而非基于binlog来复制。INOODB每写一行,同步到备节点,同步延迟可以做得更低,等于事务提交,备节点马上也可以提交。更典型的如做Ddl,该过程会持续两分钟,两分钟ddl成功以后才可以写下binlog,备节点才会执行,但是如果是在物理复制上,每执行语句每改一行都会写一条inooDB,可以把binlog同步过去,所以等主节点成功后,备节点也几乎都成功。
此方案存在缺点,如果在逻辑复制里面事物回滚,不计binlog,但在物理复制中,也要把这些回滚的操作在背景里也重新回放一遍。有些场景日志量会比binlog多,但是整体而言,事物的回滚等还是比较少的,所以大部分场景还是适用。
物理复制基础上去做严格的一致。传统的mySQL的主备节点和备节点同步延迟,有一定的大小,mySQL也会做全局一致性,但由于他们同步延迟比较高,所以全局一次性很容易全都达到主节点上,在polarDB上做全局不仅是同步延迟比较低,对比他的 Lsn的大小,比如在主节点写入L3~35,备节点可能慢一点同步到35,有快一点已经同步到35,全局一次性可以保证如果读到的是30节点,会去主动组建,去拉,把对应日志拉过来,放完,再返回。能够将只读节点的利润率给提高上来。
技存分离使得备份以及备份恢复的时间更快,如果是标准的、传统的,需要做备份恢复,要从上面去 OSs,把数据和日志拉到本地盘上,本地盘再实例起来,把binlog重新应用,才可以恢复。随着实例的大小的增加,从oss上面拉的数据的时间也会增加,在polarDB直接通过的快照可写,打快照后,七天以内的快照是直接在本地的,7天的快照按时间点还原,不需要拉数据、拉日志,只有少量的增量需要拉,并且起来后,不需要等日志应用完。
四、blob的性能优化
此图为客户提供的结构,把玩家的装备进入信息,都是通过protobu或Swift放在里面,存在blob字段,行长有时能达到100或一兆。这对场景数据库以及云数库并不友好。
有问题认为所有的数据库都是针本地盘做优化和设计。像提供百万的iops,可发现很多数据库无法应用百万iops。云盘的百万iops可以用到,但场景需要多个线程或者多进程,打赏到多个文件里面,必须打散到底下的存储上,才可以把资源利用起来。如果没有进行IO的配合,进行适配优化,就无法使用底下的云盘的形态。比如所有的数据库,包括mySQL mongoDB都有叫WAL,所有的写入都是顺序的append到维度的日志里,而后台发展,在场景中主要是针对早期的像机械盘去做优化。
因为机械盘顺序io是随机io的100倍,但是到SSD上没有改变这么多,顺序IO也还是随机IO的3~4倍。但是在云盘上不是。典型的是云盘上单线程写单独的文件,底下提供再多的盘,有且仅能用到一块盘的能力,单线程写完4兆要不断重复写4兆,盘提供的再多也只能发挥单个盘的功能。在2022年在polarDB专门写过文章也有相同观点,所有数据库的存储引擎都需要针对云存储去做适配,所以在polarDB最核心的不是WAL,不是单线程顺序append only,而是并发的打赏,写多个报告文件,才能把云传统提供的更高的LPs充分利用。
本地盘的云存储额外要多一个网络,还有副本等一系列的开销,所以IO延迟会比本地盘差很多。举例,在intel p451以上16K大小差不多可以做到50微妙。在polar db采用ADAM才能够做到150微秒。但如果没有用ADAM早期的版本要16k到下来,要做到400微秒,现在的阿里云的esd同样,其IO延迟比本地盘高,因为多了网络成本与开销。polarDB针对云存储的高带宽,高延迟等一系列场景,polarDB 对mySQL针对云存储去做优化,在文章里可以通过优化方法去改,也能够达到新的提升。所以在关键领域下如mongoDB也需要针对云存储去做适配去做优化才能得到相应的技能。数据是测的,典型的如图。
可以看到云存储的带宽可以跑的更高,下图是通过一系列的优化的结果。
观察数据可得,最左边这条线,可以认为是mySQL跑在云盘上。因为mySQL以及PG都是本地盘去做适配研发的,所以不做任何优化的mySQL跑在云盘上差于mySQL跑在本地盘。以图的最中间为例,write only比mySQL跑在本地盘上差非常多,物理环境条件限制延迟问题无法解决,只能充分利用云存储的带宽,在并发高情况下,在带宽上去做优势,能够经过优化的mySQL跑到云盘上比其跑在本地盘比好,但在延迟特别敏感的场景也是比不过mySQL跑在本地。
图为具体的执行的一系列的优化,此图把整个mySQL最核心的从bintree转变成blinktree。
redo文件以前传播的是顺序的append only,wal搭线程顺序往后写,才能充分利用机械盘顺序io能力,但在云存储已经把它打散解压到多个维度文件。
此图为客户测试的单个实例,维度带宽可以写到2g,单实例的只考虑写入2g,刷3是3G,能够差不多能达到5G,大部分的游戏客户带宽写入量已经可以满足。比如玩家的行层是100k,经过计算可得出为20万或两万同时的更新的频率。
图为基准性的测试。客户比较关注的是全场景的还原备份恢复能力。典型的场景要做版更,挂公告,停服。这些步骤都是同时做,包括备份,新包的部署,回归测试等。这是典型版本的过程。
还有闪回查询的需求,客户丢装备,需要回归,回到9点之前的装备数据,所以停服跟他配合协查,另外全量数据备份时间长,还是只想恢复部分玩家丢失的数据,都在polarDB里面跟客户一起去提的解决方案。
五、场景备份还原能力
所以是支持从实例级别,库表恢复,闪回查询进行还原。
备份是秒级备份和分层跟其他出口量不同,一级备份3~14天之内的备份全都存在云盘,不需要上传到OSS,不会需要从OSS上面拉数据过程。
对350gb与100gb redo进行测量,polarDB用时20分钟,标准的mySQL用时两个小时,场景和redo等一系列的时间相关,100g的维度算比较大的,大部分情况下只会有最近的4个,或者到8个,但如果写入量非常大,打得快时间点是12点,正好要恢复到12 :59,则该小时的redo都要应用一遍。
关于闪回查询,通过as of语句,语法相似于olicorp。原理是所有的历史记录都是记录在案,通过闪回把记录保留,查询再带上时间点,精确至某一行某客户某玩家某时间点的数据。对于要还原实例,查丢的玩家时间点的装备信息非常有用。
六、全球部署与异地容灾能力
polarDB能够支持同AC的容灾,默认底下是3副本,rpo等于0。底下是一份共享的存储RW和RO,拉起来不会丢失数据。另外是跨AZ容灾,支持异步与半同步。现在数据大部分都是在毫秒级别的同步延迟,另外除支持az,还支持regions。大部分游戏的平台服,比如瑞典、上海、美西和美东、日本和新加坡、法兰克福和伦敦之间做同步,只支持纯异步。同时支持容灾手自动切换等等这一系列能力,这上面最大的优势做同步或者自己需要搭CEN用的其解决方案,在中间都给屏蔽,两个region之间建立同步链路。中间走并行的维度的复制,不需要binlog的复制,通过延时可以做的更低。
在Redis一体化解决方案中,有些客户想要用更简单的接口去访问,把redis当数据库使用,实际上情况redis还是偏内存,如果真的把当成数据库来用,需要数据库的备份,恢复等相关能力。如果想要对全内存redis进行降能可在polarDB mySQL接口增加Redis接口。
典型传统缓存方案架构,需要做Redis和MySQL的数据一致性保证,很多时候不敢把redis当成真的数据库在用。
这里做法是在polarDB层支持类似的协议,可以直接通过Redis的客户端连接到polarDB,基本上的数据库还是存在存储引擎的INNO DB里。客户是不感知的,存在的INNO DB里面有天然可以支持刚才上面的所有的这些能力,支持100T的容量甚至更大,也支持成本按的持仓空间来计费,并不是按内存来计费,也可以支持多线程,并且可以支持支持一写多读,很多看到在缓存场景,可能有热点数据,如果是在polarDB的场景,支持一起多读的架构,要是有热点数据,直接添加只读节点的热点数据,可以按需的落到内存中,去解决扩展性的问题。所有这些能力都是基于polarDB架构。GDN这些能力全都具备还原,所以在关系数据库接redis中,可以让用户放心的把Redis当成数据库来用,如果是纯Redis当成数据库,不如关系型数据库更稳妥,更保险。
polarDB的原理在mySQL层直接去重新写一遍类似的解析协议,通过代理、一写多读同步到的RW和RO节点上,缓存是典型的写少不多的场景,所以一写多读这套架构特别适合缓存的一套场景原理,直接在底层请求或是走协议去访问MySQL里面的数据,了解如何把多数据结构映射到底下的polarDB的底下标准的innoDB。
在专门polarDB redis场景中,是专门提供百TB级别的高性能的盘。底下的云盘是三层解耦,底下除提供盘,还提供一块高性能的弹性的缓存,弹性的内存池,只不过有热点数据,会保证热点数据全在底下,共享存储的共享内存磁场。所以底下比如最典型的热点场景,如果有热点的key,访问一下增加只读节点,于热点key不管再怎么分辨,最后一定有去缓解他的热点的问题,所以在计算节点加多个指数节点,热点T有更多的分片,存储上有内存值去让访问到的存储时候,不需要落盘,这里面的内存对专门热点key进行加速,这就是三层解耦原理。
还支持通过在Redis中,支持强制的能力去保证只读节点上访问的内容也是读写节点写入。
对比polarDB产品,如图。对比开源的Redis,成本便宜。同时支持一写多读与大容量。很多Redis用户在玩家详情页有头像有排名,有个人信息,理论上最佳实践把头像放到OSS,把排名放在Redis,个人信息放在MySQL,但很多业务写代码、多个对象比较麻烦,会使得将大量数据堆积在一起,本该存内存的Redis里面会存非常多不应该存在内存里面的数据。本产品并不是Redis替换,虽然不如全内存Redis好,但是并不是所有的业务都延迟要求很高,有些一毫秒可以返回,有些4毫秒业务也能接受,10毫秒给返回节省1/10的成本。虽然慢,但是成本能够降下来。还有真的在数据库上展出raise的协议,可以把真的当成持久化的数据库在用,备份能力等都是按关系数据库级别要求的。
这是可购买并直接使用。
此图为专栏月报。这是为解决缓冲和一次性的问题,本身应该算两个,因此更推荐包括之前做皮卡的。
有些行业的开发把Redis当成持久化数据库,在用的没有后面的这层,所以他不需要后面MySQL这层,而是直接传到Redis,不需要把数据再同步到MySQL,数据本来以Redis协议的形式存在。
协议解释差不多,但底下数据的存储有区别。所讲的两种是两个思路。缓冲税后一体化思路,还是有缓存和mysql这两个东西,本来要自己去做数据同步,现在就不用做,来给它去做同步,要去配映射关系,比如在举最典型的在MySQL,玩家信息ID,玩家的身高等将所有的属性信息都打包一下,在Redis去映射,再解析。现在真实情况是race里面缓存的一定不是玩家,包含的所有属性的字段的信息,一定是只需要其中的几个,会去要客户去配关系表。理论上关系数据库的稳定性,可靠性还是跟偏缓存不太一样,客户最关注稳定性,在MySQL里面增加Redis协议,才可以放心的把当成数据库去使用,需要做的工作是将相关数据摘下来映射到自己的表里面,所传的数据都是存在innoDB。但性能比内存Redis差,写入要先落盘再写,测试在只读场景中,数据都是在的MySQL场景,是差不多的,并且MySQL可有更多的线程数,这肯定是不公平的。Redis有单线程会好很多,写入场景差,要保证差不多写入数据能够做到Redis压力最大,做到类似的1/3左右,他的唯一优势成本,的计算按的磁盘来算成本,而不是按的内存来算成本。毛估一下成本,能够降1/10,之前也很多开发,习惯把所有的数据进行多次溜。本产品可以通过一次溜解决所有的问题,也符合预期。
整个两个思路还不太一样,把它真的当成持久性数据库使用,一定是关系型数据库的可靠性是最重要的。性能基于一体化的plus系列, 容量基于ECSD,这样会更好,并且也支持一写多读、备份恢复,成本还会更便宜。
理论上底下备份通过类似于云盘的备份,如果发布能力后,友商一定会跟进的,所以不用担心阿里云有能力,其他友商也会有能力,大部分业务现在选型都是一定要用ABC几个云公共的都有的能力,如果只有阿里云有能力,其他友商没有能力,也不一定会用。可以将其当成大容量Redis使用。
对标是之前市面上的一些开源产品。去解决内存的成本高的问题,数据库内存和存磁盘是最本质的区别,其他没什么区别,它是数据库增加协议、可靠性的关系性数据库的级别,不是缓存的级别,GPA运维MySQL和Redis是不一样的,GPA运维MySQL做定期的备份,并检查备份是不是能够还原出来等。GPA运维Redis缓存一般业务线,不会关心备份与备份是否可还原。