腾讯游戏风雨十年,一直致力于带给玩家最好的快乐体验,为此也取得了巨大的成功。

腾讯游戏的后台数据库一直守护着亿万玩家的数据,提供着稳定透明的服务。


        腾讯后台数据库大部分使用的是MySQL数据库,现已大部分被替换为互娱DBA团队自己定制的TMySQL。IO问题是传统关系型数据库中最热门话题,互娱DBA团队在业务运营过程中同样遇到类似问题。


         案例一:IO问题。某游戏的一个大区DB由于数据量过大,内存缓冲池不能完全cache数据,IO瓶颈制约DB整体性能,导致该大区不能提供稳定服务。


         案例二:存储空间不足。某游戏的DB在合服过程中,由于数据量过大,导致合服效率极低。


         对于上述问题,通用的方案或者是升级硬件,或者是在游戏server层修改存储逻辑,代价都很非常大。互娱DBA团队通过在TMySQL 1.4版本增加InnoDB列压缩功能,对应用层透明并且节省了硬件成本从而有效解决该问题。


列压缩技术方案与应用


         互娱游戏的后台数据库经常使用blob/text类型字段来存储数据,业务中blob/text类型字段占据了很大部分的存储空间,如上述提到的案例二中DB中约90%的存储内容为blob/text类型列。对这些blob/text字段进行压缩存储,将大大降低存储空间,从而提高DB整体性能。


一、列压缩技术方案


TMySQL列压缩的实现主要包括语法层面、存储格式、压缩/解压逻辑及导入导出优化等几个方面。


1.  列压缩功能是可配置的,为此在TMySQL中增加compressed语法。


2. 存储格式:列压缩可以根据字段的长度来判断是否使用压缩存储,因为对于小数据量,压缩比不压缩可能更占用存储空间。目前,判断是否压缩的策略是:如果长度小于256字节,不压缩存储;如果长度大于256字节,压缩存储。压缩格式为:



首字节标记:第一个bit,0表示未压缩(对应就无解压后长度),1表示压缩;第2,3位表示算法类型(现阶段版本只有zlib算法),第6,7,8位表示有几个字节来存储压缩长度。


解压后长度:表示数据在压缩前或解压“压缩的内容”的长度,由于BLOB字段约定的最大长度(longblob)是2^32-1,因此4字节的最大长度已经足够。另外,1-4字节的内容分别表示长度上限为2^8-1、2^16-1、2^24-1,2^32-1。该信息也用于解压后的内存分配。


压缩的内容:就是压缩后的数据。


3.  压缩算法


当前版本,压缩和解压基于mysql内置的zlib(1.2.3)压缩库,函数为:my_compress和my_uncompress。

上述定义的格式中,预留了其它类型的算法标记,后续会结合不同压缩算法中cpu开销与压缩率来权衡一种更适当的算法。


4.  压缩与解压


压缩和解压处理需要在统一的函数调用位置,该位置确定在存储引擎和server数据交换的handler接口中,即


  • Server层从存储引擎获取数据前,存储引擎负责解压。
  • Server层要存储数据,需要把数据压缩处理。


这样解压和压缩都集中在存储引擎和server间的数据交换接口中,存储引擎和SERVER的其他处理就不需考虑数据是否压缩的逻辑,简化整个问题。


压缩接口:row_mysql_store_col_in_innobase_format。由server层传下来的每一个列的数据,都会经由本函数完成数据转换(特殊处理索引)。


解压接口:row_sel_store_mysql_rec。本函数用于将InnoDB层从物理介质上读取到的数据传递到server层的类型。


5.  导入导出优化


导入导出优化主要是通过两方面来实现。首先是在server层增加新的语法SELECT SQL_COMPRESSED 、INSERT SQL_COMPRESSED。在使用SELECTSQL_COMPRESSED时,DB会略过对压缩数据的解压逻辑,直接导出。


INSERT SQL_COMPRESSED与SELECT SQL_COMPRESSED必须是配套使用的,使用INSERT SQL_COMPRESSED略过压缩逻辑直接存储数据。


其次是通过实现tmysqldump使用SELECT SQL_COMPRESSED语法来获取数据内容,在生成SQL语句时使用对符合条件的SQL使用INSERT SQL_COMPRESSED这种语法。


二、列压缩的应用


1.  配置列的压缩属性

在建表时语句指定blob/text类型的列具有compressed属性,这样该列的内容会被压缩存储


支持compressed属性的列类型包括:TINYBLOBBLOB, MEDIUMBLOBLONGBLOB, TINYTEXT, TEXT, MEDIUMTEXT, LONGTEXT


2. 修改列的压缩属性


对于正在线上运行的数据库,要将对其中的字段增加压缩属性,可以通过alter table来修改,alter table可以取消或增加压缩属性。



因此,只需简单的alter table操作,就可以让DB中特定列压缩存储。以上述案例二的游戏DB中数据为例,一个1.3G的表,通过alter table增加compressed特征后为0.19G,压缩率是15%。在DB中,这样的表是100个,收益明显。



3.   透明压缩/解压


列属性指定为compressed之后,TMySQL内部会根据实际需要进行压缩和解压处理。假设ServiceInfo_00.ServiceInfo、ServiceInfo_00.GameInfo列具有compressed属性,以下语句等价关系为


4.  导入导出优化


应用TMySQL的列压缩后,在使用mysqldump进行导入导出时,在导出时会执行select操作,那么会对所有的压缩数据进行解压;同样,在导入时也会对需要压缩的数据执行压缩操作。


通过改造mysqldump,增加选项enable-compress-optimization来控制压缩的数据在导出与导入过程中,分别不进行解压与压缩,明显缩减导出及导入的时间。


三、收益与展望


1、收益


互娱的游戏DB中,具有blob/text类型字段的数据表都能够应用compressed特性,目前已有4款游戏使用上该特性。


上述案例二中游戏某大区的gamedb,进行压缩前数据大小为160G在使用TMySQL的列压缩属性后,数据大小变成20G,压缩率是12.5%


以该游戏一个区的数据作压力测试,使用压缩特性后DB性能提升显著:



如上图,在100并发下,在A5机型中的QPS由未压缩的253提升到列压缩后的2236,提升了8.8倍。


另外,在该业务的合服(两个或多个大区合并成一个大区)操作中,未压缩与压缩的合服时间对比为14239 vs 5749 , 时间节省为原来的40.3%即合服操作导致的停服时间由原来4小时缩短到1.6小时。


2、展望


现阶段已应用TMySQL列压缩功能的游戏DB,已明显感受到使用列压缩带来的收益:包括合服、回档中停机时长大幅度减小等。随着越来越多的游戏DB使用列压缩功能,列压缩带来的收益会越来越可观。


这是典型的使用CPU换取内存和IO的做法,列压缩极大地减少了IO开销,虽说相应增加了CPU消耗,但当前游戏DB服务器的CPU处于相对空闲状态,这是完全可以接受的。后续会对列压缩会提供多种压缩算法,可针对不同应用环境来进行选择从而更合理地平衡IO与CPU的消耗。TMySQL版本未来会不断演进和迭代,内置包括DB云化、冷热数据分离等核心特性,提供业内领先的优质DB服务。