数据倾斜是指,在分布式数据库系统中会因为物理节点、hash或shard分布原因,导致某些DN物理空间不足,而另外的物理空间剩余较大。例如,如果以商户作为分布key,京东每天的数据量和一个普通电商的数据量肯定是天地差别。可能某个大商户一个月的数据就会把一个DN的物理空间塞满,这时系统只有停机扩容一条路。因此我们必须要有一个有效的手段来解决数据倾斜,保证在表数据分布不均匀时系统仍然能够高效稳定的运行。
首先我们把系统的DN分为group(如下图6),每个group里面:
包含一个或者多个DN
每个group有一个shardmap
在建sharded表时,可以指定存储的group,也就是要么存储在group1,要么group2
CN可以访问所有的group,而且CN上也存储所有表的访问方式信息
图6
对于系统中数据量较大用户进行特别的识别,并为他们创建白名单,使用不同的数据分布逻辑(如下图7):普通用户使用默认的数据分布逻辑,也就是:
Shardid = Hash(merchantid) % #shardmap
大商户使用定制的数据分布逻辑,也就是:
Shardid = Hash(merchantid) % #shardmap + fcreate_timedayoffset from 1970-01-01
图7
通过在大商户group分布逻辑中加入日期偏移,来实现同一个用户的数据在group内部多个节点间均匀分布。从而有效的解决数据分布不均匀问题。
下面是一个例子(如下图8):
图8
五.9000W记录高效排序解决方案业务在列表查询场景下会收到如下的查询SQL:
在微信支付的场景中,某个商户每天的数据有300W,一个月数据超过9000W条,也就是说PostgreSQL需要面向一个9000W数据级数据进行快速排序,而且业务逻辑要求需要秒级输出,快速获取排序结果。
为此,我们提供表定义方案,即建立集群分区表。根据上述需求,可以采用按月分表,即每个月一张表,并对排序字段ffinish_time建立索引,这样每个分区进行扫描是可以使用索引。
我们再通过一系列执行计划的优化,CN下推order by和limit offset子句到DN;DN上在执行对应的sql使用使用Merge Append算子对各个子表执行的结果进行汇总输出,这个算子本身会保证输出是有序的,也就是说对子表进行索引扫描,同时Merge Append又对各个子表的结果进行归并,进而保证节点本身的结果是排序的。CN对多个DN的结果同样使用Merge Append进行归并,保证整个输出结果是有序的,从而完成整个排序过程。
下面是我们对排序进行的性能测试结果:
通过在24核CPU,64G内存的机型上进行测试,9000W数据的排序在最短可以在25 ms内完成,QPS最高可达5400。
六.并行优化随着当前硬件的发展,系统资源越来越丰富,多CPU大内存成了系统标配,充分利用这些资源可以有效的提升的处理效率优化性能。腾讯在2014年底开始进行PostgreSQL多核执行优化。
目前PostgreSQL9.6社区版也会包含部分并行化特性,但是没有我们这边这么丰富,下面介绍下腾讯PostgreSQL并行化的原理和效果:
系统创建一个全局的共享内存管理器,使用bitmap管理算法进行管理
系统启动时创建一定数据的Executor,这些Executor用来执行执行计划的碎片
系统会创建一个计划队列,所有的Executor都会在任务队列上等待计划
每个Executor对应一个任务结果队列,Executor在输出结果时就把结果的指针挂到结果队列中去
计划队列,结果队列,计划分片执行结果都存放在共享内存管理器中,这样所有的进程都可以访问到这些结构
Postgres会话进程在收到sql时,判断是否可以并行化,并进行任务的分发;在结果队列中有结果时就读出返回
我们完成优化的算子:
Seqscan
Hash join
Nestloop join
Remote query
Hash Agg
Sort Agg
Append
通过在24核CPU,64G内存的机型下测试,各个算子的优化结果:
整体来说性能普遍是优化前的10-12倍,优化的效果比较明显。
七.腾讯PostgreSQL-XZ的两地三中心容灾