POLARDB作为阿里云下一代关系型云数据库,自去年9月份公测以来,收到了不少客户的重点关注,今年5月份商业化后,许多大客户开始陆续迁移业务到POLARDB上,但是由于POLARDB的很多默认行为与RDS MySQL兼容版不一样,导致很多用户有诸多使用上的困惑,本来总结了几点,给大家答疑解惑。另外,本文提到的参数,在新版本上,用户都可以通过控制台修改,如果没有,可以联系售后服务修改。
本文适合读者:阿里云售后服务,POLARDB用户,POLARDB内核开发者, 需要有基本的数据库知识,最好对MySQL源码有部分了解。
PolarDB技术要点一览
RDS MySQL在购买的时候需要指定购买的磁盘大小,最大为3TB。如果空间不够,需要升级磁盘空间。具体来说,如果实例所在的物理机磁盘空间充足,这个升级磁盘的任务很快就可以完成,但是如果空间不足,就需要在其他物理机上重建实例,大实例需要几天的时间。为了解决这个问题,POLARDB底层使用存储集群的方式,做到磁盘动态扩容,且磁盘扩容过程对用户无感知,具体来说,默认磁盘空间分配为规格内存的10倍,当使用了70%,系统就会自动扩容一部分空间,而且扩容不需要停止实例。
有了这种机制,POLARDB的存储可以做到按照使用量来收费,真正做到使用多少就收多少钱,计费周期是一小时。同时,由于存储按量收费,导致许多用户对存储的使用量非常敏感,在我们的控制台上,有五种空间统计,分别是磁盘空间使用量,数据空间使用量,日志空间使用量,临时空间使用量和系统文件空间使用量。
磁盘空间使用量是后四者之和,数据空间使用量包括用户创建的所有库,mysql库,test库,performance_schema库,日志空间使用量包括redolog,undolog,ibdata1,ib_checkpoint(存储checkpoint信息),http://innodb_repl.info(存储切换信息,物理复制信息等),临时空间使用量包括socket文件,pid文件,临时表(大查询排序用),审计日志文件,系统文件空间使用量包括错误日志,慢日志,general日志以及主库信息(用于构建复制关系)。虽然有四部分空间使用量,但大多数主要被数据空间和日志空间占用,数据空间比较好理解,主要就是表空间聚集索引和二级索引的占用量,但是这个日志空间很多用户不是很了解,常常提上来的问题是,为什么我的日志空间占了100多个G,而数据空间就几个G,这里简单解释一下。
日志空间使用量,如上所述,有很多组成部分。redolog,主要用来构建物理复制,同时也可以被当做增量日志来支持还原到时间点/克隆实例的任务,类似原生的binlog,文件名按顺序递增,主节点产生日志,只读节点/灾备节点应用日志,同时后台管控任务会定时上传redolog(只要发现新的就立即上传)并且定时删除(目前一小时触发一次删除任务),具体大小与DML总量有关。undolog,主要用来构建数据历史版本以支持MVCC机制和回滚机制,不同于RDS MySQL的undolog都在ibdata1文件中,POLARDB的undolog大部分是以独立表空间/文件存在,具体大小与用户使用习惯有关。ibdata1,主要存储系统元数据信息等系统信息,具体大小与用户表数量有关,但是一般不会太大。ib_checkpoint,这个是POLARDB特有的,用于存储checkpoint信息,大小固定。http://innodb_repl.info也是POLARDB独有的,存储物理复制相关的信息以及切换信息,一般不会太大。由此可见,日志空间使用量虽然也有很多组成部分,但主要是被redolog日志和undolog日志占用。
redolog日志,由于对数据的修改都会记录redolog,所以对数据修改的越快,redolog产生的速度就会越快,而且上传OSS(保留下来做增量日志)的速度有限,所以在实例导数据阶段,会导致redolog堆积,当导入完成后,redolog会慢慢上传完然后删除,这样空间就会降下来,但是不会完全降为0。具体原因需要介绍一下:目前所有规格,redolog大小都为1G,被删除的redolog不会马上被删除,而是放入一个缓冲池(rename成一个临时文件),当需要新的redolog时候,先看看缓冲池里面还有没有可用的文件,如果有直接rename成目标文件,如果没有再创建,这个优化主要是为了减少创建新文件时的io对系统的抖动,缓冲池的大小由参数loose_innodb_polar_log_file_max_reuse控制,默认是8,如果用户想减少缓存池的文件个数,就可以减少这个参数从而减少日志空间占用量,但是在压力大的情况下,性能可能会出现周期性的小幅波动。所以当写入大量数据后,即使redolog都被上传,默认也有8G的空间用作缓存。注意,调整这个参数后,缓冲池不会立刻被清空,随着dml被执行,才会慢慢减少,如果需要立即清空,建议联系售后服务。
另外,POLARDB会提前创建好下一个需要写的redolog日志(每个日志都是固定的1G,即使没有被写过),主要目的是当当前的redolog被写完后,能快速的切换到下一个,因此,也会占用额外1G空间。此外,后台定时删除任务目前是一个小时清理一次(还有优化的空间),但是不会清理到最后一个日志,会保留一个日志,主要用来做按时间点还原任务。
接下来,举个经典的例子,方便理解上述的策略:
mysql> show polar logs;
+-----------------+----------------+-------------+
| Log_name | Start_lsn | Log_version |
+-----------------+----------------+-------------+
| ib_logfile41008 | 19089701633024 | 100 |
| ib_logfile41009 | 19090775372800 | 100 |
+-----------------+----------------+-------------+
2 rows in set (0.00 sec)
mysql> show polar status\G
......
-----------------
Log File Info
-----------------
2 active ib_logfiles
The oldest log file number: 41008, start_lsn: 19089701633024
The newest log file number: 41009, start_lsn: 19090775372800
Log purge up to file number: 41008
8 free files for reallocation
Lastest(Doing) checkpoint at lsn 19091025469814(ib_logfile41009, offset 250099062)
......
show polar logs这条命令可以查看系统中的redolog日志,上个例子中,ib_logfile41008这文件已经被写完,但是这个日志需要被保留用来支持按照时间点还原和克隆实例任务,ib_logfile41009是最后一个redolog,表示目前正在写的redolog。
show polar status\G可以显示POLARDB很多内部信息,这里只截取了redolog相关的一部分,前四行就是字面的意思,不具体解释了。第五行表示缓冲池目前有8个redolog。
另外,上文提到过,POLARDB会提前创建一个redolog用以快速的切换,名字一般是最后一个文件编号加一,所以是ib_logfile41010。
结合这些信息,就可以推断出,目前系统中redolog占用量为11G = 8G(缓冲池中的)+1G(保留的ib_logfile41008)+1G(正在被写的ib_logfile41009)+1G(提前创建的ib_logfile41010)。
另外,透露一个好消息,我们内部正在调研redolog日志不收费的可行性,如果通过验证,这部分占用的空间将不会收取用户费用。
讲完了redolog日志,接下里讲讲undolog日志。上文说过在POLARDB中undolog大部分是以独立表空间存在的,也就是说是独立的文件,而不是聚集在ibdata1文件中。目前分了8个文件,文件名为undo001-undo008,每个文件默认初始大小为10M,会随着使用增大,在某些不推荐的用法下,会导致undolog空间增长很快。这里简单举个例子,可以使undolog撑的很大:使用START TRANSACTION WITH consistent snapshot开启一个事务,注意要在RR隔离级别下,然后开启另外一个连接,对库中的表进行高频率的更新,可以使用sysbench辅助,很快,就会发现undolog膨胀。从数据库内核的角度来讲,就是由于一个很老的readview,导致需要把很多的历史版本都保留下来,从而导致undolog膨胀。在线上,往往是一个大查询或者一个长时间不提交的事务导致undolog膨胀。undolog膨胀后,即使所有事务都结束后,也不会自动缩小,需要使用下文的方法进行在线truncate。
目前,用户还不能直接查看undolog的占用量,后续我们会在information_schema加上,方便用户查看,但是可以通过间接的方法:如果控制台上显示日志占用量很大,但是redolog占用量很小,那么一般就是undolog了,因为其他几个都占用很小的空间,几乎可以忽略不计。
如果发现undolog占用量比较大,POLARDB也有办法清理。原理是,等undolog所对应的事务都结束后,把清理开关打开,如果发现大小超过执行大小的undo tablespace,就会在purge线程中进行undo的truncate。尽量在业务低峰期进行,并且保证没有大事务长事务。具体操作方法就两步,首先调整innodb_max_undo_log_size大小,这个参数表示当每个undo tablespace大于这个值时候,后续会把它缩小,重新调整为10M。接着,打开truncate开关innodb_undo_log_truncate,这样,后台线程就会把所有大于innodb_max_undo_log_size设置的undo tablespace调整为10M。注意,这里要保证没有大事务长事务,因为后台线程会等待undo tablespace中所有事务都提交后,才会下发命令,同时也要保证innodb_undo_logs大于等于2。另外,不建议这个功能长期开着,如果在控制台发现日志占用量减少了,建议关闭truncate功能,因为其有可能在您业务高峰期运行,导致数据库延迟。
如果有一个大事务或者长事务长时间未提交,由于其长期持有MDL读锁,这个会带来很多问题。在RDS MySQL上,如果后续对这张表又有DDL操作,那么这个操作会被这个大事务给堵住。在POLARDB上,这个问题更加严重,简单的说,如果只读实例上有一个大事务或者长期未提交的事务,会影响主实例上的DDL,导致其超时失败。纠其本质的原因,是因为POLARDB基于共享存储的架构,因此在对表结构变更前,必须保证所有的读操作(包括主实例上的读和只读实例上的读)结束。
具体解释一下POLARDB上DDL的过程。在DDL的不同阶段,当需要对表进行结构变更前,主实例自己获取MDL锁后,会写一条redolog日志,只读实例解析到这个日志后,会尝试获取同一个表上的MDL锁,如果失败,会反馈给主实例。主实例会等待所有只读实例同步到最新的复制位点,即所有实例都解析到这条加锁日志,主实例同时判断是否有实例加锁失败,如果没有,DDL就成功,否则失败回滚。
这里涉及到两个时间,一个是主实例等待所有只读实例同步的超时时间,这个由参数loose_innodb_primary_abort_ddl_wait_replica_timeout控制,默认是一个小时。另外一个是只读实例尝试加MDL锁的超时时间,由参数loose_replica_lock_wait_timeout控制,默认是50秒。可以调整这两个参数来提前结束回滚DDL,通过返回的错误信息,来判断是否有事务没结束。 loose_innodb_primary_abort_ddl_wait_replica_timeout建议比loose_replica_lock_wait_timeout大。
举个实际例子方便理解: 用户可以通过命令show processlist中的State列观察,如果发现Wait for syncing with replicas字样,那么表示这条DDL目前处在等待只读节点同步的阶段。如果超过loose_innodb_primary_abort_ddl_wait_replica_timeout设置的时间,那么主节点会返回错误:
ERROR HY000: Rollback the statement as connected replica(s) delay too far away. You can kick out the slowest replica or increase variable 'innodb_abort_ddl_wait_replica_timeout'
如果没有超时,那么主节点会检查是否所有只读节点都成功获取MDL锁了,如果失败,那么主节点依然会返回错误:
ERROR HY000: Fail to get MDL on replica during DDL synchronize
如果主实例返回第二个错误,那么建议用户检查一下主实例以及所有只读实例上是否有未结束的大查询或者长时间未提交的事务。
这里顺便介绍一下大事务长事务的防范手段。参数loose_max_statement_time可以控制大查询的最大执行时间,超过这个时间后,会把查询kill掉。参数loose_rds_strict_trx_idle_timeout可以控制空闲事务的最长存活时间,当一个事务空闲状态超过这个值时候,会主动把这个连接断掉,从而结束事务,注意,这个参数应该比wait_timeout/interactive_timeout小,否则无效。
在MySQL低版本,查询缓存(Query Cache)能提高查询的性能,尤其是更新少的情况下,但是由于其本身也容易成为性能瓶颈,所以在最新的MySQL中此特性已经被移除。POLARDB目前的版本兼容MySQL 5.6,所以用户依然可以使用查询缓存,但是我们还是建议不使用,因为我们在引擎存储层做了很多优化,即使不用查询缓存依然有很好的性能。
由于POLARDB使用了物理复制,不同于binlog的逻辑复制,查询缓存在只读实例上的失效,依然需要通过redolog来保证,即当某条查询缓存失效的时候,需要通过redolog来通知所有只读节点,让他们把对应的查询记录也失效掉,否则通过只读节点会读到历史版本的数据。
当查询缓存失效时,会写redolog通知所有只读节点,这个机制默认是关闭的,通过参数loose_innodb_primary_qcache_invalid_log来控制。
综上所示,如果在只读节点上开启了查询缓存(只要有一个开启),那么必须在主节点上开启loose_innodb_primary_qcache_invalid_log,否则只读节点会读到历史版本的数据。考虑到HA切换会切换到任意一个只读节点,因此建议如果开启了查询缓存,在所有只读节点上也把loose_innodb_primary_qcache_invalid_log开启。
POLARDB自带一个只读实例,增减只读实例非常快速,所以用户非常适合使用读写分离的功能,但是从目前用户的反馈来看,如果在插入数据后立刻查询,很容易查询到之前旧版的数据,为了解决这个问题,我们给出两种解法。一种是通过POLARDB数据库内核的强同步保证主实例和只读节点数据一致,另外一种是通过数据库前面的PROXY层来解决。下面简单介绍一下。
POLARDB集群基于物理复制构建,目前复制除了支持常规的异步复制(默认),半同步复制之外,还有强同步复制,即当事务提交时,只有当指定的只读实例应用完redolog日志后,主实例才给用户返回成功。这样即使后续的读请求发送到了只读节点,也能保证读到最新的数据。但是这个配置会导致性能大幅度下降,只有默认异步复制的三分之一左右,在使用之前请做详细的测试。简单说一下配置过程:
首先需要在主实例上设置:设置loose_innodb_primary_sync_slave为3,目的是告诉主实例,它连接的只读实例会有强同步的需求。接着在需要强同步的只读实例上把参数loose_slave_trans_sync_level设置为2,注意这个参数需要重启实例。另外,先设置主实例,再设置只读实例的顺序不能乱。设置成功后,在主实例上执行show polar replicas;(这个命令可以查看所有的只读实例),在sync_level这一列,可以发现由默认的0变成了2,这就表示强同步开启成功了。如果需要关闭强同步,在主实例上设置loose_innodb_primary_sync_slave为0,只读节点上设置loose_slave_trans_sync_level设置为0即可,注意设置的顺序依然不能乱。此外,如果强同步的只读实例在loose_innodb_primary_sync_slave_timeout后还没返回,强同步复制退化为异步复制,还可以通过loose_innodb_primary_sync_slave参数控制当只读节点掉线时是否立刻退化为异步复制。
另外一种解决办法是通过PROXY来解决。主实例每次做完更新就会把当前的日志位点发给PROXY,同时PROXY也会定期去轮询最大的日志位点,当PROXY需要把后续的查询发到只读实例上时,首先会判断只读实例是否应用到了最新的位点,如果不是,就把请求转发到主实例。这个策略操作的单位是连接,即通过这种方法能保证同一个连接中读到的一定是最新的数据。这种方法虽然会导致主库的压力变大,但是其对性能影响较小,是一种推荐的方法。如果用户需要使用,联系售后做一次小版本升级,即可开放这个功能。
POLARDB使用基于redolog的物理复制来构建复制关系,不依赖BINLOG,因此BINLOG默认是关闭的,但是许多用户需要使用BINLOG将数据同步到第三方数据仓库以方便做复杂的数据分析,所以有很多开启BINLOG的需求。用户可以开启BINLOG,但是与RDS不同,后台不但不会有任务定时上传备份BINLOG,而且也不会有定期删除BINGLOG的任务,完全需要用户自己控制何时删除,否则会导致BINLOG堆积,从而造成更多的存储成本。因为POLARDB不依赖BINLOG复制,我们不清楚用户已经消费了多少日志(有可能用户的SLAVE端使用了类似复制延迟的技术),因此,需要用户自己决定何时清除日志。
用户可以通过主实例(考虑到HA切换,最好把所有只读实例也打开)参数loose_polar_log_bin打开BINLOG(需要重启),BINLOG就会自动存储在日志目录下,空间统计在日志空间使用量里面。可以通过常规的show master logs查看BINLOG。每个BINLOG的大小,BINLOG cache的大小,BINLOG格式等参数都可以通过控制台调整。这里注意下,由于POLARDB使用的是自研的存储系统,sync_binlog参数无效,因此没有开放。
如果用户需要删除无用的BINLOG,目前有一种方法:通过调节参数loose_expire_logs_hours来控制BINLOG自动删除的时间,这个参数表示自BINLOG创建后多久系统自动将它删除,单位是小时。注意,删除前请务必确保BINLOG已经无效,误删除后将无法恢复(BINLOG是否需要后台上传OSS来作为备份,这个需求我们会参考用户的反馈来决定是否支持)。
目前,开启BINLOG有一个限制:当底层存储系统升级的时,开启BINLOG的实例不可服务时间目前是分钟级别的,不开启BINLOG的实例是秒级别的。所以,如果用户对实例可用性要求比较高,可以等我们优化后再开启BINLOG。
POLARDB由于使用了自研的文件系统和自研的块设备存储系统,因此在一些限制上与RDS MySQL有所不同。
由于文件系统是集成在数据库里面的,即数据库与文件系统共用一个进程,所以文件系统会占用一部分的规格内存。另外不同规格的文件个数也有上限。目前存储最大支持到10000GB。
此外,文件名,即数据库中的表名和库名都不能超过63个字符,实际使用的时候最好控制在55个字符以下,因为还有.frm,.ibd后缀,中间过程临时表等。详细的说明见这里
数据库最佳性能的线程数一般是CPU核数的2-3倍,线程数太少,不容易发挥出多线程的优势,线程数太多,又容易导致上下文切换过多以及锁争抢严重的问题。不幸的是,很多用户往往会创建很多并发连接,导致数据库CPU打满,性能低下。
为了解决频繁创建释放连接的问题,即高频短连接问题,可以调大thread_cache_size,从而减少频繁创建连接的开销。另外,也建议用户使用客户端连接池来代替高频短连接的方案。
为了解决高并发连接的问题,可以使用Thread Pool功能。在Thread Pool模式下,用户连接和处理线程不再是一一对应关系。处理线程的数量是一个可控的数量,不会随着用户连接数的增多而大幅增加,这样可以减少高并发场景下线程上下文切换的消耗。
用户可以通过调整参数loose_thread_handling为pool-of-threads来打开Thread Pool功能。同时,建议调整参数thread_pool_size为实例CPU核数,其他参数保持默认即可。
Thread Pool比较适合短小的查询和更新,大事务大查询会降低其效果。用户需要依据业务模型来斟酌。另外需要注意一点,Thread Pool不会提高性能,但是其能稳定高并发场景下的性能。
根据官方给出的信息,PolarDB节点共分为3中不同类型的节点,分别为:Primary、Replica、StandBy,3种节点根据不同的角色,内部功能也有所差异。Primary节点为数据读写节点,在整个PolarDB集群中,只能有一个Primary节点,所有数据写入都在Primary节点进行操作;Replica节点为只读节点,在PolarDB集群中,Replica节点可以有多个,Replica节点不允许数据写入,只能同步Primary的数据,Replica节点内部禁止数据写到底层存储设备;StandBy节点功能与Replica类似,只是用于同步Primary节点的数据,但区别于Replica节点的是,StandBy节点允许把数据写入底层存储,一般StandBy节点用于做远程多机房备份等等。
数据库层
PolarDB的数据库层主要是通过定制MySQL实现,PolarDB多个计算节点底层共享一份数据,在MySQL中,多个实例共享一份数据是不被允许的,所以PolarDB在实现的时候必然对MySQL有所内核层面的改动。下面我们来着重分析下PolarDB的数据库内核改动。
先把问题简化下,我们不考虑远程存储,在一台机器上面,我们怎么来实现多个MySQL实例共享一份数据?最简单的想法就是把多个MySQL的data文件夹指向一份数据(假设不考虑MySQL一份数据对应一个实例限制),
如上图所示,3个节点同时指向同一份数据,因为PolarDB自身没有解决多个节点同时对同一行数据修改的问题,所以PolarDB只允许一个节点可以写入。对于上述1主2备的集群,还存在如下一些问题。
Buffer Pool缓存一致性
MySQL通过Buffer Pool缓存数据,对于写入的数据,在写完Redo log以后,缓存在Buffer Pool中,然后通过一个异步线程刷新到磁盘。在上述3个节点的集群这个,A上进行更新的数据可能被缓存在A的Buffer Pool中,如果在数据刷到磁盘之前,在C上读取这些数据是不可见的。
事务数据一致性
除了Buffer Pool缓存数据造成Replica数据读取延迟外,Partial Transaction也是一个比较严重的问题,对于MySQL中的数据,被更改的数据(脏页)会被加入到队列(Flush List),并没有区分操作该数据页的事务是否已经结束,这样的话,可能会造成一个事务修改了部分数据页,然后这些数据页被刷到底层存储上,Replica直接读取这些数据页,然而Primary上的事务可能没有结束,Replica相当于读取了部分事务修改,这个不符合MVCC特性,即:Partial Transaction可能破坏了MySQL本身的MVCC机制。
上图中,A上执行数据插入修改事务,当执行到第二个insert时,A上的Buffer Pool由于Free Page不足导致数据页刷盘,部分当前事务修改的数据页有可能被刷入底层存储中,这个时候,如果C上进行查询,很可能查到被未提交事务修改的数据页。
Redo复制
PolarDB为了解决上述问题,在引擎层引入了物理复制(InnoDB redo log复制),通过物理复制把Primary上的更新直接通过redo log传递到Replica,然后Replica通过apply redo进行更新数据的重放。因为Redo在事务开始时就被写入,不会受Buffer Pool异步刷盘的影响。而且由于undo log的更新也需要记录redo,所以通过redo复制可以把Primary上整个undo段也复制过来,也不会破坏本身的MVCC特性。Redo复制唯一的问题就是会不会像Binlog复制一样存在延迟?对于Binlog复制,由于Slave端Apply log的速度跟不上Binlog产生速度,可能会出现Binlog堆积。而Redo由于是物理日志,不需要通过SQL解析和大量的锁等待,对于相同页面的更新可以batch进行,对于不同页面也不必像Binlog一样考虑事务的互斥性,不同的页面的更新都可以并行执行,所以一般情况下,Redo复制很少有堆积,即使有堆积也可以选择不同的策略(强同步、允许延迟)进行处理。
DDL问题
上面介绍了,物理复制也有可能存在延迟,对于普通的DML来说,极短时间的延迟有时是可以被接受的,但如果对于DDL来说,Primary与Replica之间的延迟,很可能会造成Replica意外宕机,举个例子:在Primary上某个用户执行了drop table tbl操作,这个时候Primary会把整个tbl表锁住来进行相应的数据清理,并且在底层存储上删除该表的物理信息,而如果这个时候在任意一个Replica节点上有对该表的访问,由于数据文件都已经不存在,很可能造成Replica crash。目前官方实现比较简单,在执行DDL之时,需要通知集群中所有的Replica节点(standby节点自身有数据不受影响),Replica节点在接收到DDL执行指令后,会禁止该表上所有操作,只有当所有Replica节点都返回成功时,Primary节点才可以进行后续的操作。所以DDL是一个影响非常大的操作,目前需要整个集群进行同步。
Undo Purge问题
MySQL的MVCC要求能被Purge线程清理的Undo log必须是没有被使用的:
根据上图中相关信息,对于一个RR隔离级别的MySQL来说,transaction1产生的undo log可以被清理的,而transaction3产生的undo,由于transaction2还没有结束,并不能马上被purge线程清理。那么问题来了:前面也说过,对于MySQL来说,Undo log的改变也会被记录到Redo中,考虑一个问题,当Primary上某条undo信息可以被purge线程清理时,如果Replica上该Undo还在被使用会出现什么问题?Replica需要读取的Undo页面可能会被Redo复制清理掉!!细节问题还真多~~~,怎么防止,两种办法:
Replica隔段时间上报自身能清理的Undo位置,然后Primary统一根据所有上报的位置选取最小一个进行清理
Undo清理时Replica如果发现清理了正在被使用的Undo,Block整个Primary的Undo Purge过程。
其他
除了上述一些问题外,其他还有很多小问题,比如:StandBy如何复制物理文件(ibd、opt文件);各种不同角色节点如何进行切换等等一系列问题;当然还有部分优化措施,比如:更多Lock Free数据结构的引入;Redo log写入块从512B改成4KB,分别对应HDD一个扇区大小和SSD一个块大小;latch层面优化等等。
驱动层
相对于DBServer层,驱动层透露的信息就相对比较少,有两块组成,分别为PolarFS和PolarSwitch,PolarFS可以看作是一个存储层的客户端,嵌入在MySQL代码内部,应该是替换了MySQL/InnoDB操作文件系统的I/O模块,PolarFS支持InnoDB数据页的原子写(16KB),所以可以直接关闭MySQL的DoubleWrite功能;而PolarSwitch则是一个主机级别的进程,一台服务器部署一个PolarSwitch即可,不用关心该台服务器上部署了多少个MySQL实例。PolarSwitch响应PolarFS的读写请求,然后反馈到底层存储。
网络层
RDMA网络解决了网络通讯中高延迟的问题,使得远程存储响应时间能控制在10us以下,远程数据的访问速度与本地磁盘访问几乎没有多大差别。目前所知,底层网络都是通过Infiniband设备来组建。
存储层
存储层提供了分chunk、多副本高可用,采用分chunk技术保证单个chunk大小控制在10GB,采用并行Raft实现chunk级别的高可用。chunk的大小设定为10GB主要权衡了Raft副本缺失后恢复的速度,10GB的chunk在RDMA网络下,能在极短的时间内进行恢复。
通过上文中的分析,我们可以知道,即使PolarDB与Aurora的架构比较类似,但是还是有些区别的,Aurora设计的主要思想是日志即数据,在保证日志落盘的前提下,尽量减少磁盘I/O,所以整个Aurora只写一份Redo log到底层存储,由底层存储来实现把redo log‘恢复’成数据页的行为。而PolarDB与之不同的是,PolarDB写入底层存储的数据包含两部分:数据页和redo log,而PolarDB底层的存储PolarStore更像是一个通用的高可用存储,不需要进行类似Aurora一样把Redo日志恢复出数据文件的操作。
本文简单介绍了POLARDB常见的几种问题,大多数来源于用户真实的反馈。我们也在不断的探索更多的功能以及更好的交互。如果在使用POLARDB中遇到疑惑,不要犹豫请立刻联系我们,我们会给您最满意的答复,谢谢对POLARDB的支持。