前言
POLARDB For MySQL(下文简称 POLARDB)目前是阿里云数据库团队主推的关系型数据库. 线上已经有很多企业用户在使用并且稳定运行了很久. 当然, 由于 POLARDB 是为云上环境专门打造的数据库, 与原生的官方 MySQL 相比, 有一些需要注意的事项. 前几个月的月报介绍了一些, 详见这篇[月报](http://mysql.taobao.org/monthly/2018/10/01/), 结合笔者最近几个月一线的开发和运维经验, 总结出以下几点新的注意事项并给出了建议.
空表 / 空实例空间问题
由于 POLARDB 除了实例费用外, 用户还需要支付实例占用的存储费用, 并且是按照使用量来收费, 即当前使用多少磁盘就付多少钱. 这一点与 RDS MySQL 兼容版的预付费模式不太一样, 所以很多用户对磁盘使用量非常敏感, 除了上篇月报中提到的空间问题外, 还有以下两类问题: 空实例空间问题和空表空间问题.
空实例空间问题. 常常有用户会问, 我刚买了一个 POLARDB 实例, 但是才刚创建完, 空间就占用了将近 3GB(实际是 2.8G 左右), 这是啥东西? 我的磁盘被什么东西占用了? 这里解释一下一个空实例大概有哪些文件以及他们占用的磁盘大小.
* 系统表 ibdata1 文件. 可以查看系统变量 `innodb_data_file_path`,ibdata 默认大小就是 200M, 即在初始化后, ibdata 就占用了 200M 空间, 后续会按需自动扩展.
* MySQL 系统库. 目前权限信息, 表的元信息等都放在 MySQL 库下, 由于空表的空间占用问题(下一小节介绍), 将近 60 个文件, 占了 230M 左右的空间.
* Redolog 文件. 默认有两个, 每个 1G(Redolog 也是预分配空间), 其中一个是当前正在用的日志文件, 另外一个是为了提高性能而提前分配的 redolog, 主要是为了减少 Redolog 切换时候的性能抖动.
* Undo 文件. 默认有 8 个, 每个 10M.Undo 空间可以放在 ibdata 里面, 也可以挪出来(ibdata 里面只留一个),POLARDB 默认是把 undo 空间挪出来以独立文件的形式存在, 主要是为了方便后续清理.
* Performance_schema 表空间. 虽然目前 POLARDB 5.6 兼容版本, 不太建议使用 Performance_schema, 但是我们还是在编译的时候把相关的功能给加上了, 这就导致在初始化时候就会把 Performance_schema 相关的表空间给初始化好, 占用了一部分空间, 由于空表的空间占用问题(下一小节介绍),50 多个文件, 占了 210M 左右的空间.
* auto.cnf 文件, 存放 server uuid. 由于空表的空间占用问题(下一小节介绍), 占用 4M.
* ib_checkpoint 文件, 存放 checkpoint 信息. 因为 Redolog 是类似 binlog 顺序递增的, 所以第一个 ib_logfile 可能被删掉, 所以 checkpoint 信息不能放在那里. 由于空表的空间占用问题(下一小节介绍), 占用 4M.
* innodb_repl.info, 存放物理复制相关的信息. 主要是 POLARDB 数据库内部使用, 记录复制位点, 切换信息等. 由于空表的空间占用问题(下一小节介绍), 占用 4M.
综上所述, 空实例的主要空间是被 Redolog 给占用了, 当然这个也是为了性能考虑. 每个日志文件大小 1G, 能在大多数场景下保证实例正常运行. 随着 DML 的执行, Redolog 会被使用, 使用完后会上传 OSS, 以便恢复到时间点任务使用.
空表空间问题. 这个问题也常常被用户提起, 我创建了很多表, 但是数据还没导入, 为啥空间增长那么快, 差不多一千张空表就占用了 40G 的空间. 这个问题的主要原因是 POLARDB 底层使用了自研的文件系统 PolarFS, 为了提高性能, 默认的文件块被设置为 4M(Ext4 文件系统这个值为 4K), 换句话说, 由于一个文件至少占用一个块, 所以文件大小最小为 4M, 而在 InnoDB 上, 一张普通的表默认有两个文件, 一个是 FRM 文件, 一个是 IBD 文件, 所以只要一张表成功创建, 就会占用 8M 的空间. 当然, 这些空间可以理解为提前分配预留的空间, 当后续数据被写入的时候, 首先先使用这些预留的空间, 只有被用完后, 才会再分配空间. 这个行为对大多数用户来说影响不大, 但对某些需要提前创建大量表但是数据量不大的用户来说, 影响比较大, 会导致用户存储成本较高. 不过幸运的是, 针对这点, 我们的文件系统已经做了相应的优化, 目前在内部测试阶段, 达到预定的稳定性要求好, 我们会尽快发布到线上, 目标是, 在保证高性能和稳定性的情况下, 尽可能的减少磁盘空间使用量.
复制延迟问题
主备数据库的复制延迟是一个老生常谈的问题, 在传统的主备架构下, 只要主要压力稍微大一点或者做了一个 DDL, 备库有很大概率的发生延迟. 发生延迟后, 不仅会影响应用从备库读取数据的正确性, 也影响主备切换. 由于 POLARDB 在架构上的优势(只有一份数据), 因此大部分用户可能会误认为在 POLARDB 上理论上不应该发生延迟. 因为主备都读取一份数据, 当然都应该看到一致的数据啦. 但是实际上, 复制延迟也还是有的, 因为虽然磁盘上的状态一致了, 但是内存上的状态不一定一致. 在 POLARDB 上, 主库和只读库通过物理复制来同步内存中的状态, 由于同步的数据比较少, 因此发生复制延迟的概率相比传统的 MySQL 复制还是小很多的. 接下来简单介绍一下复制的过程:
Primary 节点会定期告诉 Replica 节点, 可安全读取的日志位点上限, Replica 在这个周期内, 可以安全读取到这个位点以下的日志, 如果超过这个位点, 可能会读到 Primary 节点正在写的日志. Replica 节点定期反馈应用日志的位点, 表示自己应用到的日志位点, 小于这个位点的一定已经应用完, 大于这个的可能还没应用或者正在应用. Primary 节点当前写到的日志位点和 Replica 节点应用到的位点之差即为复制延迟, 如果复制延迟很大, 就会导致 Replica 跟不上 Primary.
另外, 在 POLARDB 上, 所有主库上执行完的 DDL 都要等所有 Replica 应用完相应日志后才能返回成功. 换句话说, 如果 Replica 有很大的复制延迟, 可能会导致主库执行 DDL 不成功. 这一点可以详见上一篇月报中的 "DDL 与大事务" 小节.
由此可看, 我们要尽可能的减小复制延迟. 物理复制有两个阶段, 一个是日志解析的阶段, 另外一个是日志应用的阶段. 任何一个阶段慢了, 都可能导致复制延迟. 日志解析, 目前是单线程解析, 在我们测试情况下, 只有当写入量超过每秒 20W(最大规格)的情况下, 解析线程才会成为瓶颈. 日志应用阶段, 由于应用比较慢, 目前是多线程应用, 不过在 POLARDB 中, 我们只需要应用在内存中的数据页即可, 换句话说, 如果日志涉及的数据页不在内存中, 我们就不需要应用这些日志(目前的方案是把这些日志存在内存中), 直到这些数据页被读入内存, 我们在 IO 线程中把这些拉下的日志都应用掉.
用户可以在只读节点上查询 `Innodb_replication_delay` 这个 status 变量来获取当前复制延迟. 如果复制延迟比较大并且有不断增大的趋势, 可以调大参数 `loose_innodb_slave_recv_hash_cells_max` 和 `loose_innodb_slave_recv_hash_cells_min` 来减少延迟. 这个参数的主要作用就是增加日志 hash 桶的数量, 从而减少日志查找时候的开销. 另外, 我们的 Proxy 支持 Session 一致读, 即同一个 session 内的读和写保证是逻辑相关的, 在写之后立即读, 一定会读到最新的数据(只有由于读写分离, 会把读请求发到有延迟的只读节点, 从而导致读取到历史版本的数据).
内存问题
有部分用户发现, 相比 RDS MySQL 兼容版, POLARDB 的内存使用量会更多, 这里需要说明一下, 这里的主要原因是我们在很多地方使用了以空间换时间的方法, 所以内存使用量上会有一定的上升. 如果用户发现内存占用过多, 可以从以下几个方面诊断:
* 调小 `table_open_cache`, 同时使用 `flush tables` 命令关闭所有表空间. 这招对打开表数量很多且用户连接很多的用户来说, 效果比较明显.
* 关闭自适应哈希.`innodb_adaptive_hash_index`, 这个功能可能会占用很多的内存, 但是在现在的 SSD 磁盘下, 性能提升有限.
* 适当的调小 buffer pool. 这点比较适用于连接数多, 同时又很多复杂查询的用户. 不过目前调整 Buffer pool 需要联系售后.
大部分用户的实例, 在内存上涨到一定数量后, 会停止上涨, 这种情况下, 即使内存占比比较高, 也不用担心, 因为我们是尽可能的使用内存, 把内存尽可能的都用起来, 缓存数据, 提高效率. 但是如果发现实例内存不断上涨, 然后直到 OOM, 这种情况, 请立刻联系我们, 我们会帮您在后台开启一个内存监控工具(依赖 Jemalloc profiling 工具, 但是需要重启数据库), 可以用来发现这些内存去哪儿了, 到底是您使用的问题, 还是内存泄露问题, 如果是我们的问题, 我们会尽快解决并给与一定的补偿, 如果是您使用的问题, 我们也会给您指出, 给出优化的建议等.
在后续的 POLARDB 版本上, 我们会增加更多的内存监控功能, 方便用户自行进行排查.
IOPS 问题
目前 POLARDB 的每种规格的实例, 都有 IOPS 限制. 同时, RDS MySQL 的实例也有 IOPS 限制. 往往有很多用户把这个两个 IOPS 做比较, 其实意义不大.
在 RDS 中, 这个 IOPS 是指日志文件每秒的写盘次数限制, 即主要是 Redolog 和 Binlog 加起来的写盘次数限制, 数据文件 (后台刷脏线程触发) 的写盘次数是不统计在这里面的. 但是在 POLARDB 中, 这个 IOPS 限制不但包括了日志文件的写盘次数限制, 也包括了数据文件的写盘限制, 即两者加起来每秒写盘的次数不能超过这个值. 数据和日志一起限制, 一起隔离, 这样更加合理, 也减少了因为磁盘压力而产生的性能抖动.
因此, 我们在设置同一类型的规格 IOPS 参数时, POLARDB 上的 IOPS 一般都比 RDS 上大好几倍. 多出来的 IOPS 主要是给数据文件刷盘预留的.
目前临时表的磁盘还是普通的 NVME 本地磁盘, 没有放在自研的磁盘上, 因此临时表的 IOPS 暂时不计入总的 IOPS, 而 RDS 上这一部分也是放在数据盘, 也暂时没有记录到 IOPS 限制上. 但是我们在 MySQL 内核代码中, 有部分限制, 主要是为了防止某些用户临时表使用过多从而影响了其他用户.
错误日志, 审计日志, 慢日志的写盘操作同样在本地盘, 没有计入 IOPS 限制.
另外, 我们在 IO 带宽上, 目前还没有硬的限制(目前 MySQL 的实例达不到自研存储的带宽上线), 但是很快, 为了资源隔离的更加彻底, 我们也会加上 IO 带宽的限制和隔离.
升级问题
由于 POLARDB 是阿里云自研的关系数据库产品, 我们在上面不但开发了数据库系统, 还开发了一套对应的文件系统和块存储系统. 不少用户对我们的期望很高, 也提出了许多优化建议, 因此 POLARDB 的系统升级频率会比 RDS 家族的产品高. 一方面, 我们需要修复一些极端情况下会被触发的 BUG, 另外一方面, 我们需要满足用户形形色色的需求. 当然, 我们的系统升级都是热升级, 我们竭尽所能尽可能减少对用户的影响, 例如在系统升级时期的性能抖动时间, 数据库不可服务时间等等. 如果系统要升级, 我们会提前给用户发短信 / 邮件以及大客户的电话通知, 一般系统升级都在凌晨用户设定的可运维时间, 正常的升级流程可能会造成秒级的服务中断, 客户只需要在应用端保证能重连数据库即可. 如果那天晚上, 升级不太方便, 请尽快提工单给我们, 我们再约其他时间. 我们后台也在开发一套主动运维系统, 有了这套系统之后, 用户就可以在控制台上在指定的时间点内主动升级数据库, 同时不同版本的数据库也会有详尽的 releasenote, 便于用户按需升级.
总结
这篇文件简单解答了几个用户常常问到的问题. 希望对大家有所帮助.
最后, 欢迎使用 POLARDB.
来源: https://www.cnblogs.com/coderyuhui/p/10296141.html